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