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