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