xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-objdump/SourcePrinter.h (revision 8ddb146abcdf061be9f2c0db7e391697dafad85c)
1 //===-- SourcePrinter.h -  source interleaving utilities --------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_TOOLS_LLVM_OBJDUMP_SOURCEPRINTER_H
10 #define LLVM_TOOLS_LLVM_OBJDUMP_SOURCEPRINTER_H
11 
12 #include "llvm/ADT/IndexedMap.h"
13 #include "llvm/ADT/StringSet.h"
14 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
15 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
16 #include "llvm/Support/FormattedStream.h"
17 #include <unordered_map>
18 #include <vector>
19 
20 namespace llvm {
21 namespace objdump {
22 
23 /// Stores a single expression representing the location of a source-level
24 /// variable, along with the PC range for which that expression is valid.
25 struct LiveVariable {
26   DWARFLocationExpression LocExpr;
27   const char *VarName;
28   DWARFUnit *Unit;
29   const DWARFDie FuncDie;
30 
31   LiveVariable(const DWARFLocationExpression &LocExpr, const char *VarName,
32                DWARFUnit *Unit, const DWARFDie FuncDie)
33       : LocExpr(LocExpr), VarName(VarName), Unit(Unit), FuncDie(FuncDie) {}
34 
35   bool liveAtAddress(object::SectionedAddress Addr);
36 
37   void print(raw_ostream &OS, const MCRegisterInfo &MRI) const;
38 };
39 
40 /// Helper class for printing source variable locations alongside disassembly.
41 class LiveVariablePrinter {
42   // Information we want to track about one column in which we are printing a
43   // variable live range.
44   struct Column {
45     unsigned VarIdx = NullVarIdx;
46     bool LiveIn = false;
47     bool LiveOut = false;
48     bool MustDrawLabel = false;
49 
50     bool isActive() const { return VarIdx != NullVarIdx; }
51 
52     static constexpr unsigned NullVarIdx = std::numeric_limits<unsigned>::max();
53   };
54 
55   // All live variables we know about in the object/image file.
56   std::vector<LiveVariable> LiveVariables;
57 
58   // The columns we are currently drawing.
59   IndexedMap<Column> ActiveCols;
60 
61   const MCRegisterInfo &MRI;
62   const MCSubtargetInfo &STI;
63 
64   void addVariable(DWARFDie FuncDie, DWARFDie VarDie);
65 
66   void addFunction(DWARFDie D);
67 
68   // Get the column number (in characters) at which the first live variable
69   // line should be printed.
70   unsigned getIndentLevel() const;
71 
72   // Indent to the first live-range column to the right of the currently
73   // printed line, and return the index of that column.
74   // TODO: formatted_raw_ostream uses "column" to mean a number of characters
75   // since the last \n, and we use it to mean the number of slots in which we
76   // put live variable lines. Pick a less overloaded word.
77   unsigned moveToFirstVarColumn(formatted_raw_ostream &OS);
78 
79   unsigned findFreeColumn();
80 
81 public:
82   LiveVariablePrinter(const MCRegisterInfo &MRI, const MCSubtargetInfo &STI)
83       : ActiveCols(Column()), MRI(MRI), STI(STI) {}
84 
85   void dump() const;
86 
87   void addCompileUnit(DWARFDie D);
88 
89   /// Update to match the state of the instruction between ThisAddr and
90   /// NextAddr. In the common case, any live range active at ThisAddr is
91   /// live-in to the instruction, and any live range active at NextAddr is
92   /// live-out of the instruction. If IncludeDefinedVars is false, then live
93   /// ranges starting at NextAddr will be ignored.
94   void update(object::SectionedAddress ThisAddr,
95               object::SectionedAddress NextAddr, bool IncludeDefinedVars);
96 
97   enum class LineChar {
98     RangeStart,
99     RangeMid,
100     RangeEnd,
101     LabelVert,
102     LabelCornerNew,
103     LabelCornerActive,
104     LabelHoriz,
105   };
106   const char *getLineChar(LineChar C) const;
107 
108   /// Print live ranges to the right of an existing line. This assumes the
109   /// line is not an instruction, so doesn't start or end any live ranges, so
110   /// we only need to print active ranges or empty columns. If AfterInst is
111   /// true, this is being printed after the last instruction fed to update(),
112   /// otherwise this is being printed before it.
113   void printAfterOtherLine(formatted_raw_ostream &OS, bool AfterInst);
114 
115   /// Print any live variable range info needed to the right of a
116   /// non-instruction line of disassembly. This is where we print the variable
117   /// names and expressions, with thin line-drawing characters connecting them
118   /// to the live range which starts at the next instruction. If MustPrint is
119   /// true, we have to print at least one line (with the continuation of any
120   /// already-active live ranges) because something has already been printed
121   /// earlier on this line.
122   void printBetweenInsts(formatted_raw_ostream &OS, bool MustPrint);
123 
124   /// Print the live variable ranges to the right of a disassembled instruction.
125   void printAfterInst(formatted_raw_ostream &OS);
126 };
127 
128 class SourcePrinter {
129 protected:
130   DILineInfo OldLineInfo;
131   const object::ObjectFile *Obj = nullptr;
132   std::unique_ptr<symbolize::LLVMSymbolizer> Symbolizer;
133   // File name to file contents of source.
134   std::unordered_map<std::string, std::unique_ptr<MemoryBuffer>> SourceCache;
135   // Mark the line endings of the cached source.
136   std::unordered_map<std::string, std::vector<StringRef>> LineCache;
137   // Keep track of missing sources.
138   StringSet<> MissingSources;
139   // Only emit 'invalid debug info' warning once.
140   bool WarnedInvalidDebugInfo = false;
141 
142 private:
143   bool cacheSource(const DILineInfo &LineInfoFile);
144 
145   void printLines(formatted_raw_ostream &OS, const DILineInfo &LineInfo,
146                   StringRef Delimiter, LiveVariablePrinter &LVP);
147 
148   void printSources(formatted_raw_ostream &OS, const DILineInfo &LineInfo,
149                     StringRef ObjectFilename, StringRef Delimiter,
150                     LiveVariablePrinter &LVP);
151 
152 public:
153   SourcePrinter() = default;
154   SourcePrinter(const object::ObjectFile *Obj, StringRef DefaultArch);
155   virtual ~SourcePrinter() = default;
156   virtual void printSourceLine(formatted_raw_ostream &OS,
157                                object::SectionedAddress Address,
158                                StringRef ObjectFilename,
159                                LiveVariablePrinter &LVP,
160                                StringRef Delimiter = "; ");
161 };
162 
163 } // namespace objdump
164 } // namespace llvm
165 
166 #endif
167