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