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