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