1fe6060f1SDimitry Andric //===-- SourcePrinter.cpp - source interleaving utilities ----------------===//
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 // This file implements the LiveVariablePrinter and SourcePrinter classes to
10fe6060f1SDimitry Andric // keep track of DWARF info as the current address is updated, and print out the
11fe6060f1SDimitry Andric // source file line and variable liveness as needed.
12fe6060f1SDimitry Andric //
13fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
14fe6060f1SDimitry Andric
15fe6060f1SDimitry Andric #include "SourcePrinter.h"
16fe6060f1SDimitry Andric #include "llvm-objdump.h"
17fe6060f1SDimitry Andric #include "llvm/ADT/SmallSet.h"
18fe6060f1SDimitry Andric #include "llvm/ADT/StringSet.h"
1981ad6265SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
2081ad6265SDimitry Andric #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
21fe6060f1SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
22fe6060f1SDimitry Andric #include "llvm/Support/FormatVariadic.h"
23fe6060f1SDimitry Andric
24fe6060f1SDimitry Andric #define DEBUG_TYPE "objdump"
25fe6060f1SDimitry Andric
26fe6060f1SDimitry Andric namespace llvm {
27fe6060f1SDimitry Andric namespace objdump {
28fe6060f1SDimitry Andric
liveAtAddress(object::SectionedAddress Addr)29fe6060f1SDimitry Andric bool LiveVariable::liveAtAddress(object::SectionedAddress Addr) {
30bdd1243dSDimitry Andric if (LocExpr.Range == std::nullopt)
31fe6060f1SDimitry Andric return false;
32fe6060f1SDimitry Andric return LocExpr.Range->SectionIndex == Addr.SectionIndex &&
33fe6060f1SDimitry Andric LocExpr.Range->LowPC <= Addr.Address &&
34fe6060f1SDimitry Andric LocExpr.Range->HighPC > Addr.Address;
35fe6060f1SDimitry Andric }
36fe6060f1SDimitry Andric
print(raw_ostream & OS,const MCRegisterInfo & MRI) const37fe6060f1SDimitry Andric void LiveVariable::print(raw_ostream &OS, const MCRegisterInfo &MRI) const {
38fe6060f1SDimitry Andric DataExtractor Data({LocExpr.Expr.data(), LocExpr.Expr.size()},
39fe6060f1SDimitry Andric Unit->getContext().isLittleEndian(), 0);
40fe6060f1SDimitry Andric DWARFExpression Expression(Data, Unit->getAddressByteSize());
41bdd1243dSDimitry Andric
42bdd1243dSDimitry Andric auto GetRegName = [&MRI, &OS](uint64_t DwarfRegNum, bool IsEH) -> StringRef {
43bdd1243dSDimitry Andric if (std::optional<unsigned> LLVMRegNum =
44bdd1243dSDimitry Andric MRI.getLLVMRegNum(DwarfRegNum, IsEH))
45bdd1243dSDimitry Andric if (const char *RegName = MRI.getName(*LLVMRegNum))
46bdd1243dSDimitry Andric return StringRef(RegName);
47bdd1243dSDimitry Andric OS << "<unknown register " << DwarfRegNum << ">";
48bdd1243dSDimitry Andric return {};
49bdd1243dSDimitry Andric };
50bdd1243dSDimitry Andric
51bdd1243dSDimitry Andric Expression.printCompact(OS, GetRegName);
52fe6060f1SDimitry Andric }
53fe6060f1SDimitry Andric
addVariable(DWARFDie FuncDie,DWARFDie VarDie)54fe6060f1SDimitry Andric void LiveVariablePrinter::addVariable(DWARFDie FuncDie, DWARFDie VarDie) {
55fe6060f1SDimitry Andric uint64_t FuncLowPC, FuncHighPC, SectionIndex;
56fe6060f1SDimitry Andric FuncDie.getLowAndHighPC(FuncLowPC, FuncHighPC, SectionIndex);
57fe6060f1SDimitry Andric const char *VarName = VarDie.getName(DINameKind::ShortName);
58fe6060f1SDimitry Andric DWARFUnit *U = VarDie.getDwarfUnit();
59fe6060f1SDimitry Andric
60fe6060f1SDimitry Andric Expected<DWARFLocationExpressionsVector> Locs =
61fe6060f1SDimitry Andric VarDie.getLocations(dwarf::DW_AT_location);
62fe6060f1SDimitry Andric if (!Locs) {
63fe6060f1SDimitry Andric // If the variable doesn't have any locations, just ignore it. We don't
64fe6060f1SDimitry Andric // report an error or warning here as that could be noisy on optimised
65fe6060f1SDimitry Andric // code.
66fe6060f1SDimitry Andric consumeError(Locs.takeError());
67fe6060f1SDimitry Andric return;
68fe6060f1SDimitry Andric }
69fe6060f1SDimitry Andric
70fe6060f1SDimitry Andric for (const DWARFLocationExpression &LocExpr : *Locs) {
71fe6060f1SDimitry Andric if (LocExpr.Range) {
72fe6060f1SDimitry Andric LiveVariables.emplace_back(LocExpr, VarName, U, FuncDie);
73fe6060f1SDimitry Andric } else {
74fe6060f1SDimitry Andric // If the LocExpr does not have an associated range, it is valid for
75fe6060f1SDimitry Andric // the whole of the function.
76fe6060f1SDimitry Andric // TODO: technically it is not valid for any range covered by another
77fe6060f1SDimitry Andric // LocExpr, does that happen in reality?
78fe6060f1SDimitry Andric DWARFLocationExpression WholeFuncExpr{
79fe6060f1SDimitry Andric DWARFAddressRange(FuncLowPC, FuncHighPC, SectionIndex), LocExpr.Expr};
80fe6060f1SDimitry Andric LiveVariables.emplace_back(WholeFuncExpr, VarName, U, FuncDie);
81fe6060f1SDimitry Andric }
82fe6060f1SDimitry Andric }
83fe6060f1SDimitry Andric }
84fe6060f1SDimitry Andric
addFunction(DWARFDie D)85fe6060f1SDimitry Andric void LiveVariablePrinter::addFunction(DWARFDie D) {
86fe6060f1SDimitry Andric for (const DWARFDie &Child : D.children()) {
87fe6060f1SDimitry Andric if (Child.getTag() == dwarf::DW_TAG_variable ||
88fe6060f1SDimitry Andric Child.getTag() == dwarf::DW_TAG_formal_parameter)
89fe6060f1SDimitry Andric addVariable(D, Child);
90fe6060f1SDimitry Andric else
91fe6060f1SDimitry Andric addFunction(Child);
92fe6060f1SDimitry Andric }
93fe6060f1SDimitry Andric }
94fe6060f1SDimitry Andric
95fe6060f1SDimitry Andric // Get the column number (in characters) at which the first live variable
96fe6060f1SDimitry Andric // line should be printed.
getIndentLevel() const97fe6060f1SDimitry Andric unsigned LiveVariablePrinter::getIndentLevel() const {
98fe6060f1SDimitry Andric return DbgIndent + getInstStartColumn(STI);
99fe6060f1SDimitry Andric }
100fe6060f1SDimitry Andric
101fe6060f1SDimitry Andric // Indent to the first live-range column to the right of the currently
102fe6060f1SDimitry Andric // printed line, and return the index of that column.
103fe6060f1SDimitry Andric // TODO: formatted_raw_ostream uses "column" to mean a number of characters
104fe6060f1SDimitry Andric // since the last \n, and we use it to mean the number of slots in which we
105fe6060f1SDimitry Andric // put live variable lines. Pick a less overloaded word.
moveToFirstVarColumn(formatted_raw_ostream & OS)106fe6060f1SDimitry Andric unsigned LiveVariablePrinter::moveToFirstVarColumn(formatted_raw_ostream &OS) {
107fe6060f1SDimitry Andric // Logical column number: column zero is the first column we print in, each
108fe6060f1SDimitry Andric // logical column is 2 physical columns wide.
109fe6060f1SDimitry Andric unsigned FirstUnprintedLogicalColumn =
110fe6060f1SDimitry Andric std::max((int)(OS.getColumn() - getIndentLevel() + 1) / 2, 0);
111fe6060f1SDimitry Andric // Physical column number: the actual column number in characters, with
112fe6060f1SDimitry Andric // zero being the left-most side of the screen.
113fe6060f1SDimitry Andric unsigned FirstUnprintedPhysicalColumn =
114fe6060f1SDimitry Andric getIndentLevel() + FirstUnprintedLogicalColumn * 2;
115fe6060f1SDimitry Andric
116fe6060f1SDimitry Andric if (FirstUnprintedPhysicalColumn > OS.getColumn())
117fe6060f1SDimitry Andric OS.PadToColumn(FirstUnprintedPhysicalColumn);
118fe6060f1SDimitry Andric
119fe6060f1SDimitry Andric return FirstUnprintedLogicalColumn;
120fe6060f1SDimitry Andric }
121fe6060f1SDimitry Andric
findFreeColumn()122fe6060f1SDimitry Andric unsigned LiveVariablePrinter::findFreeColumn() {
123fe6060f1SDimitry Andric for (unsigned ColIdx = 0; ColIdx < ActiveCols.size(); ++ColIdx)
124fe6060f1SDimitry Andric if (!ActiveCols[ColIdx].isActive())
125fe6060f1SDimitry Andric return ColIdx;
126fe6060f1SDimitry Andric
127fe6060f1SDimitry Andric size_t OldSize = ActiveCols.size();
128fe6060f1SDimitry Andric ActiveCols.grow(std::max<size_t>(OldSize * 2, 1));
129fe6060f1SDimitry Andric return OldSize;
130fe6060f1SDimitry Andric }
131fe6060f1SDimitry Andric
dump() const132fe6060f1SDimitry Andric void LiveVariablePrinter::dump() const {
133fe6060f1SDimitry Andric for (const LiveVariable &LV : LiveVariables) {
134fe6060f1SDimitry Andric dbgs() << LV.VarName << " @ " << LV.LocExpr.Range << ": ";
135fe6060f1SDimitry Andric LV.print(dbgs(), MRI);
136fe6060f1SDimitry Andric dbgs() << "\n";
137fe6060f1SDimitry Andric }
138fe6060f1SDimitry Andric }
139fe6060f1SDimitry Andric
addCompileUnit(DWARFDie D)140fe6060f1SDimitry Andric void LiveVariablePrinter::addCompileUnit(DWARFDie D) {
141fe6060f1SDimitry Andric if (D.getTag() == dwarf::DW_TAG_subprogram)
142fe6060f1SDimitry Andric addFunction(D);
143fe6060f1SDimitry Andric else
144fe6060f1SDimitry Andric for (const DWARFDie &Child : D.children())
145fe6060f1SDimitry Andric addFunction(Child);
146fe6060f1SDimitry Andric }
147fe6060f1SDimitry Andric
148fe6060f1SDimitry Andric /// Update to match the state of the instruction between ThisAddr and
149fe6060f1SDimitry Andric /// NextAddr. In the common case, any live range active at ThisAddr is
150fe6060f1SDimitry Andric /// live-in to the instruction, and any live range active at NextAddr is
151fe6060f1SDimitry Andric /// live-out of the instruction. If IncludeDefinedVars is false, then live
152fe6060f1SDimitry Andric /// ranges starting at NextAddr will be ignored.
update(object::SectionedAddress ThisAddr,object::SectionedAddress NextAddr,bool IncludeDefinedVars)153fe6060f1SDimitry Andric void LiveVariablePrinter::update(object::SectionedAddress ThisAddr,
154fe6060f1SDimitry Andric object::SectionedAddress NextAddr,
155fe6060f1SDimitry Andric bool IncludeDefinedVars) {
156fe6060f1SDimitry Andric // First, check variables which have already been assigned a column, so
157fe6060f1SDimitry Andric // that we don't change their order.
158fe6060f1SDimitry Andric SmallSet<unsigned, 8> CheckedVarIdxs;
159fe6060f1SDimitry Andric for (unsigned ColIdx = 0, End = ActiveCols.size(); ColIdx < End; ++ColIdx) {
160fe6060f1SDimitry Andric if (!ActiveCols[ColIdx].isActive())
161fe6060f1SDimitry Andric continue;
162fe6060f1SDimitry Andric CheckedVarIdxs.insert(ActiveCols[ColIdx].VarIdx);
163fe6060f1SDimitry Andric LiveVariable &LV = LiveVariables[ActiveCols[ColIdx].VarIdx];
164fe6060f1SDimitry Andric ActiveCols[ColIdx].LiveIn = LV.liveAtAddress(ThisAddr);
165fe6060f1SDimitry Andric ActiveCols[ColIdx].LiveOut = LV.liveAtAddress(NextAddr);
166fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "pass 1, " << ThisAddr.Address << "-"
167fe6060f1SDimitry Andric << NextAddr.Address << ", " << LV.VarName << ", Col "
168fe6060f1SDimitry Andric << ColIdx << ": LiveIn=" << ActiveCols[ColIdx].LiveIn
169fe6060f1SDimitry Andric << ", LiveOut=" << ActiveCols[ColIdx].LiveOut << "\n");
170fe6060f1SDimitry Andric
171fe6060f1SDimitry Andric if (!ActiveCols[ColIdx].LiveIn && !ActiveCols[ColIdx].LiveOut)
172fe6060f1SDimitry Andric ActiveCols[ColIdx].VarIdx = Column::NullVarIdx;
173fe6060f1SDimitry Andric }
174fe6060f1SDimitry Andric
175fe6060f1SDimitry Andric // Next, look for variables which don't already have a column, but which
176fe6060f1SDimitry Andric // are now live.
177fe6060f1SDimitry Andric if (IncludeDefinedVars) {
178fe6060f1SDimitry Andric for (unsigned VarIdx = 0, End = LiveVariables.size(); VarIdx < End;
179fe6060f1SDimitry Andric ++VarIdx) {
180fe6060f1SDimitry Andric if (CheckedVarIdxs.count(VarIdx))
181fe6060f1SDimitry Andric continue;
182fe6060f1SDimitry Andric LiveVariable &LV = LiveVariables[VarIdx];
183fe6060f1SDimitry Andric bool LiveIn = LV.liveAtAddress(ThisAddr);
184fe6060f1SDimitry Andric bool LiveOut = LV.liveAtAddress(NextAddr);
185fe6060f1SDimitry Andric if (!LiveIn && !LiveOut)
186fe6060f1SDimitry Andric continue;
187fe6060f1SDimitry Andric
188fe6060f1SDimitry Andric unsigned ColIdx = findFreeColumn();
189fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "pass 2, " << ThisAddr.Address << "-"
190fe6060f1SDimitry Andric << NextAddr.Address << ", " << LV.VarName << ", Col "
191fe6060f1SDimitry Andric << ColIdx << ": LiveIn=" << LiveIn
192fe6060f1SDimitry Andric << ", LiveOut=" << LiveOut << "\n");
193fe6060f1SDimitry Andric ActiveCols[ColIdx].VarIdx = VarIdx;
194fe6060f1SDimitry Andric ActiveCols[ColIdx].LiveIn = LiveIn;
195fe6060f1SDimitry Andric ActiveCols[ColIdx].LiveOut = LiveOut;
196fe6060f1SDimitry Andric ActiveCols[ColIdx].MustDrawLabel = true;
197fe6060f1SDimitry Andric }
198fe6060f1SDimitry Andric }
199fe6060f1SDimitry Andric }
200fe6060f1SDimitry Andric
201fe6060f1SDimitry Andric enum class LineChar {
202fe6060f1SDimitry Andric RangeStart,
203fe6060f1SDimitry Andric RangeMid,
204fe6060f1SDimitry Andric RangeEnd,
205fe6060f1SDimitry Andric LabelVert,
206fe6060f1SDimitry Andric LabelCornerNew,
207fe6060f1SDimitry Andric LabelCornerActive,
208fe6060f1SDimitry Andric LabelHoriz,
209fe6060f1SDimitry Andric };
getLineChar(LineChar C) const210fe6060f1SDimitry Andric const char *LiveVariablePrinter::getLineChar(LineChar C) const {
211fe6060f1SDimitry Andric bool IsASCII = DbgVariables == DVASCII;
212fe6060f1SDimitry Andric switch (C) {
213fe6060f1SDimitry Andric case LineChar::RangeStart:
214fe6060f1SDimitry Andric return IsASCII ? "^" : (const char *)u8"\u2548";
215fe6060f1SDimitry Andric case LineChar::RangeMid:
216fe6060f1SDimitry Andric return IsASCII ? "|" : (const char *)u8"\u2503";
217fe6060f1SDimitry Andric case LineChar::RangeEnd:
218fe6060f1SDimitry Andric return IsASCII ? "v" : (const char *)u8"\u253b";
219fe6060f1SDimitry Andric case LineChar::LabelVert:
220fe6060f1SDimitry Andric return IsASCII ? "|" : (const char *)u8"\u2502";
221fe6060f1SDimitry Andric case LineChar::LabelCornerNew:
222fe6060f1SDimitry Andric return IsASCII ? "/" : (const char *)u8"\u250c";
223fe6060f1SDimitry Andric case LineChar::LabelCornerActive:
224fe6060f1SDimitry Andric return IsASCII ? "|" : (const char *)u8"\u2520";
225fe6060f1SDimitry Andric case LineChar::LabelHoriz:
226fe6060f1SDimitry Andric return IsASCII ? "-" : (const char *)u8"\u2500";
227fe6060f1SDimitry Andric }
228fe6060f1SDimitry Andric llvm_unreachable("Unhandled LineChar enum");
229fe6060f1SDimitry Andric }
230fe6060f1SDimitry Andric
231fe6060f1SDimitry Andric /// Print live ranges to the right of an existing line. This assumes the
232fe6060f1SDimitry Andric /// line is not an instruction, so doesn't start or end any live ranges, so
233fe6060f1SDimitry Andric /// we only need to print active ranges or empty columns. If AfterInst is
234fe6060f1SDimitry Andric /// true, this is being printed after the last instruction fed to update(),
235fe6060f1SDimitry Andric /// otherwise this is being printed before it.
printAfterOtherLine(formatted_raw_ostream & OS,bool AfterInst)236fe6060f1SDimitry Andric void LiveVariablePrinter::printAfterOtherLine(formatted_raw_ostream &OS,
237fe6060f1SDimitry Andric bool AfterInst) {
238fe6060f1SDimitry Andric if (ActiveCols.size()) {
239fe6060f1SDimitry Andric unsigned FirstUnprintedColumn = moveToFirstVarColumn(OS);
240fe6060f1SDimitry Andric for (size_t ColIdx = FirstUnprintedColumn, End = ActiveCols.size();
241fe6060f1SDimitry Andric ColIdx < End; ++ColIdx) {
242fe6060f1SDimitry Andric if (ActiveCols[ColIdx].isActive()) {
243fe6060f1SDimitry Andric if ((AfterInst && ActiveCols[ColIdx].LiveOut) ||
244fe6060f1SDimitry Andric (!AfterInst && ActiveCols[ColIdx].LiveIn))
245fe6060f1SDimitry Andric OS << getLineChar(LineChar::RangeMid);
246fe6060f1SDimitry Andric else if (!AfterInst && ActiveCols[ColIdx].LiveOut)
247fe6060f1SDimitry Andric OS << getLineChar(LineChar::LabelVert);
248fe6060f1SDimitry Andric else
249fe6060f1SDimitry Andric OS << " ";
250fe6060f1SDimitry Andric }
251fe6060f1SDimitry Andric OS << " ";
252fe6060f1SDimitry Andric }
253fe6060f1SDimitry Andric }
254fe6060f1SDimitry Andric OS << "\n";
255fe6060f1SDimitry Andric }
256fe6060f1SDimitry Andric
257fe6060f1SDimitry Andric /// Print any live variable range info needed to the right of a
258fe6060f1SDimitry Andric /// non-instruction line of disassembly. This is where we print the variable
259fe6060f1SDimitry Andric /// names and expressions, with thin line-drawing characters connecting them
260fe6060f1SDimitry Andric /// to the live range which starts at the next instruction. If MustPrint is
261fe6060f1SDimitry Andric /// true, we have to print at least one line (with the continuation of any
262fe6060f1SDimitry Andric /// already-active live ranges) because something has already been printed
263fe6060f1SDimitry Andric /// earlier on this line.
printBetweenInsts(formatted_raw_ostream & OS,bool MustPrint)264fe6060f1SDimitry Andric void LiveVariablePrinter::printBetweenInsts(formatted_raw_ostream &OS,
265fe6060f1SDimitry Andric bool MustPrint) {
266fe6060f1SDimitry Andric bool PrintedSomething = false;
267fe6060f1SDimitry Andric for (unsigned ColIdx = 0, End = ActiveCols.size(); ColIdx < End; ++ColIdx) {
268fe6060f1SDimitry Andric if (ActiveCols[ColIdx].isActive() && ActiveCols[ColIdx].MustDrawLabel) {
269fe6060f1SDimitry Andric // First we need to print the live range markers for any active
270fe6060f1SDimitry Andric // columns to the left of this one.
271fe6060f1SDimitry Andric OS.PadToColumn(getIndentLevel());
272fe6060f1SDimitry Andric for (unsigned ColIdx2 = 0; ColIdx2 < ColIdx; ++ColIdx2) {
273fe6060f1SDimitry Andric if (ActiveCols[ColIdx2].isActive()) {
274fe6060f1SDimitry Andric if (ActiveCols[ColIdx2].MustDrawLabel && !ActiveCols[ColIdx2].LiveIn)
275fe6060f1SDimitry Andric OS << getLineChar(LineChar::LabelVert) << " ";
276fe6060f1SDimitry Andric else
277fe6060f1SDimitry Andric OS << getLineChar(LineChar::RangeMid) << " ";
278fe6060f1SDimitry Andric } else
279fe6060f1SDimitry Andric OS << " ";
280fe6060f1SDimitry Andric }
281fe6060f1SDimitry Andric
282fe6060f1SDimitry Andric // Then print the variable name and location of the new live range,
283fe6060f1SDimitry Andric // with box drawing characters joining it to the live range line.
284fe6060f1SDimitry Andric OS << getLineChar(ActiveCols[ColIdx].LiveIn ? LineChar::LabelCornerActive
285fe6060f1SDimitry Andric : LineChar::LabelCornerNew)
286fe6060f1SDimitry Andric << getLineChar(LineChar::LabelHoriz) << " ";
287fe6060f1SDimitry Andric WithColor(OS, raw_ostream::GREEN)
288fe6060f1SDimitry Andric << LiveVariables[ActiveCols[ColIdx].VarIdx].VarName;
289fe6060f1SDimitry Andric OS << " = ";
290fe6060f1SDimitry Andric {
291fe6060f1SDimitry Andric WithColor ExprColor(OS, raw_ostream::CYAN);
292fe6060f1SDimitry Andric LiveVariables[ActiveCols[ColIdx].VarIdx].print(OS, MRI);
293fe6060f1SDimitry Andric }
294fe6060f1SDimitry Andric
295fe6060f1SDimitry Andric // If there are any columns to the right of the expression we just
296fe6060f1SDimitry Andric // printed, then continue their live range lines.
297fe6060f1SDimitry Andric unsigned FirstUnprintedColumn = moveToFirstVarColumn(OS);
298fe6060f1SDimitry Andric for (unsigned ColIdx2 = FirstUnprintedColumn, End = ActiveCols.size();
299fe6060f1SDimitry Andric ColIdx2 < End; ++ColIdx2) {
300fe6060f1SDimitry Andric if (ActiveCols[ColIdx2].isActive() && ActiveCols[ColIdx2].LiveIn)
301fe6060f1SDimitry Andric OS << getLineChar(LineChar::RangeMid) << " ";
302fe6060f1SDimitry Andric else
303fe6060f1SDimitry Andric OS << " ";
304fe6060f1SDimitry Andric }
305fe6060f1SDimitry Andric
306fe6060f1SDimitry Andric OS << "\n";
307fe6060f1SDimitry Andric PrintedSomething = true;
308fe6060f1SDimitry Andric }
309fe6060f1SDimitry Andric }
310fe6060f1SDimitry Andric
311fe6060f1SDimitry Andric for (unsigned ColIdx = 0, End = ActiveCols.size(); ColIdx < End; ++ColIdx)
312fe6060f1SDimitry Andric if (ActiveCols[ColIdx].isActive())
313fe6060f1SDimitry Andric ActiveCols[ColIdx].MustDrawLabel = false;
314fe6060f1SDimitry Andric
315fe6060f1SDimitry Andric // If we must print something (because we printed a line/column number),
316fe6060f1SDimitry Andric // but don't have any new variables to print, then print a line which
317fe6060f1SDimitry Andric // just continues any existing live ranges.
318fe6060f1SDimitry Andric if (MustPrint && !PrintedSomething)
319fe6060f1SDimitry Andric printAfterOtherLine(OS, false);
320fe6060f1SDimitry Andric }
321fe6060f1SDimitry Andric
322fe6060f1SDimitry Andric /// Print the live variable ranges to the right of a disassembled instruction.
printAfterInst(formatted_raw_ostream & OS)323fe6060f1SDimitry Andric void LiveVariablePrinter::printAfterInst(formatted_raw_ostream &OS) {
324fe6060f1SDimitry Andric if (!ActiveCols.size())
325fe6060f1SDimitry Andric return;
326fe6060f1SDimitry Andric unsigned FirstUnprintedColumn = moveToFirstVarColumn(OS);
327fe6060f1SDimitry Andric for (unsigned ColIdx = FirstUnprintedColumn, End = ActiveCols.size();
328fe6060f1SDimitry Andric ColIdx < End; ++ColIdx) {
329fe6060f1SDimitry Andric if (!ActiveCols[ColIdx].isActive())
330fe6060f1SDimitry Andric OS << " ";
331fe6060f1SDimitry Andric else if (ActiveCols[ColIdx].LiveIn && ActiveCols[ColIdx].LiveOut)
332fe6060f1SDimitry Andric OS << getLineChar(LineChar::RangeMid) << " ";
333fe6060f1SDimitry Andric else if (ActiveCols[ColIdx].LiveOut)
334fe6060f1SDimitry Andric OS << getLineChar(LineChar::RangeStart) << " ";
335fe6060f1SDimitry Andric else if (ActiveCols[ColIdx].LiveIn)
336fe6060f1SDimitry Andric OS << getLineChar(LineChar::RangeEnd) << " ";
337fe6060f1SDimitry Andric else
338fe6060f1SDimitry Andric llvm_unreachable("var must be live in or out!");
339fe6060f1SDimitry Andric }
340fe6060f1SDimitry Andric }
341fe6060f1SDimitry Andric
cacheSource(const DILineInfo & LineInfo)342fe6060f1SDimitry Andric bool SourcePrinter::cacheSource(const DILineInfo &LineInfo) {
343fe6060f1SDimitry Andric std::unique_ptr<MemoryBuffer> Buffer;
344fe6060f1SDimitry Andric if (LineInfo.Source) {
345fe6060f1SDimitry Andric Buffer = MemoryBuffer::getMemBuffer(*LineInfo.Source);
346fe6060f1SDimitry Andric } else {
347fe6060f1SDimitry Andric auto BufferOrError = MemoryBuffer::getFile(LineInfo.FileName);
348fe6060f1SDimitry Andric if (!BufferOrError) {
349fe6060f1SDimitry Andric if (MissingSources.insert(LineInfo.FileName).second)
350fe6060f1SDimitry Andric reportWarning("failed to find source " + LineInfo.FileName,
351fe6060f1SDimitry Andric Obj->getFileName());
352fe6060f1SDimitry Andric return false;
353fe6060f1SDimitry Andric }
354fe6060f1SDimitry Andric Buffer = std::move(*BufferOrError);
355fe6060f1SDimitry Andric }
356fe6060f1SDimitry Andric // Chomp the file to get lines
357fe6060f1SDimitry Andric const char *BufferStart = Buffer->getBufferStart(),
358fe6060f1SDimitry Andric *BufferEnd = Buffer->getBufferEnd();
359fe6060f1SDimitry Andric std::vector<StringRef> &Lines = LineCache[LineInfo.FileName];
360fe6060f1SDimitry Andric const char *Start = BufferStart;
361fe6060f1SDimitry Andric for (const char *I = BufferStart; I != BufferEnd; ++I)
362fe6060f1SDimitry Andric if (*I == '\n') {
363fe6060f1SDimitry Andric Lines.emplace_back(Start, I - Start - (BufferStart < I && I[-1] == '\r'));
364fe6060f1SDimitry Andric Start = I + 1;
365fe6060f1SDimitry Andric }
366fe6060f1SDimitry Andric if (Start < BufferEnd)
367fe6060f1SDimitry Andric Lines.emplace_back(Start, BufferEnd - Start);
368fe6060f1SDimitry Andric SourceCache[LineInfo.FileName] = std::move(Buffer);
369fe6060f1SDimitry Andric return true;
370fe6060f1SDimitry Andric }
371fe6060f1SDimitry Andric
printSourceLine(formatted_raw_ostream & OS,object::SectionedAddress Address,StringRef ObjectFilename,LiveVariablePrinter & LVP,StringRef Delimiter)372fe6060f1SDimitry Andric void SourcePrinter::printSourceLine(formatted_raw_ostream &OS,
373fe6060f1SDimitry Andric object::SectionedAddress Address,
374fe6060f1SDimitry Andric StringRef ObjectFilename,
375fe6060f1SDimitry Andric LiveVariablePrinter &LVP,
376fe6060f1SDimitry Andric StringRef Delimiter) {
377fe6060f1SDimitry Andric if (!Symbolizer)
378fe6060f1SDimitry Andric return;
379fe6060f1SDimitry Andric
380fe6060f1SDimitry Andric DILineInfo LineInfo = DILineInfo();
381fe6060f1SDimitry Andric Expected<DILineInfo> ExpectedLineInfo =
382fe6060f1SDimitry Andric Symbolizer->symbolizeCode(*Obj, Address);
383fe6060f1SDimitry Andric std::string ErrorMessage;
384fe6060f1SDimitry Andric if (ExpectedLineInfo) {
385fe6060f1SDimitry Andric LineInfo = *ExpectedLineInfo;
386fe6060f1SDimitry Andric } else if (!WarnedInvalidDebugInfo) {
387fe6060f1SDimitry Andric WarnedInvalidDebugInfo = true;
388fe6060f1SDimitry Andric // TODO Untested.
389fe6060f1SDimitry Andric reportWarning("failed to parse debug information: " +
390fe6060f1SDimitry Andric toString(ExpectedLineInfo.takeError()),
391fe6060f1SDimitry Andric ObjectFilename);
392fe6060f1SDimitry Andric }
393fe6060f1SDimitry Andric
394fe6060f1SDimitry Andric if (!objdump::Prefix.empty() &&
395fe6060f1SDimitry Andric sys::path::is_absolute_gnu(LineInfo.FileName)) {
396fe6060f1SDimitry Andric // FileName has at least one character since is_absolute_gnu is false for
397fe6060f1SDimitry Andric // an empty string.
398fe6060f1SDimitry Andric assert(!LineInfo.FileName.empty());
399fe6060f1SDimitry Andric if (PrefixStrip > 0) {
400fe6060f1SDimitry Andric uint32_t Level = 0;
401fe6060f1SDimitry Andric auto StrippedNameStart = LineInfo.FileName.begin();
402fe6060f1SDimitry Andric
403fe6060f1SDimitry Andric // Path.h iterator skips extra separators. Therefore it cannot be used
404fe6060f1SDimitry Andric // here to keep compatibility with GNU Objdump.
405fe6060f1SDimitry Andric for (auto Pos = StrippedNameStart + 1, End = LineInfo.FileName.end();
406fe6060f1SDimitry Andric Pos != End && Level < PrefixStrip; ++Pos) {
407fe6060f1SDimitry Andric if (sys::path::is_separator(*Pos)) {
408fe6060f1SDimitry Andric StrippedNameStart = Pos;
409fe6060f1SDimitry Andric ++Level;
410fe6060f1SDimitry Andric }
411fe6060f1SDimitry Andric }
412fe6060f1SDimitry Andric
413fe6060f1SDimitry Andric LineInfo.FileName =
414fe6060f1SDimitry Andric std::string(StrippedNameStart, LineInfo.FileName.end());
415fe6060f1SDimitry Andric }
416fe6060f1SDimitry Andric
417fe6060f1SDimitry Andric SmallString<128> FilePath;
418fe6060f1SDimitry Andric sys::path::append(FilePath, Prefix, LineInfo.FileName);
419fe6060f1SDimitry Andric
420fe6060f1SDimitry Andric LineInfo.FileName = std::string(FilePath);
421fe6060f1SDimitry Andric }
422fe6060f1SDimitry Andric
423fe6060f1SDimitry Andric if (PrintLines)
424fe6060f1SDimitry Andric printLines(OS, LineInfo, Delimiter, LVP);
425fe6060f1SDimitry Andric if (PrintSource)
426fe6060f1SDimitry Andric printSources(OS, LineInfo, ObjectFilename, Delimiter, LVP);
427fe6060f1SDimitry Andric OldLineInfo = LineInfo;
428fe6060f1SDimitry Andric }
429fe6060f1SDimitry Andric
printLines(formatted_raw_ostream & OS,const DILineInfo & LineInfo,StringRef Delimiter,LiveVariablePrinter & LVP)430fe6060f1SDimitry Andric void SourcePrinter::printLines(formatted_raw_ostream &OS,
431fe6060f1SDimitry Andric const DILineInfo &LineInfo, StringRef Delimiter,
432fe6060f1SDimitry Andric LiveVariablePrinter &LVP) {
433fe6060f1SDimitry Andric bool PrintFunctionName = LineInfo.FunctionName != DILineInfo::BadString &&
434fe6060f1SDimitry Andric LineInfo.FunctionName != OldLineInfo.FunctionName;
435fe6060f1SDimitry Andric if (PrintFunctionName) {
436fe6060f1SDimitry Andric OS << Delimiter << LineInfo.FunctionName;
437fe6060f1SDimitry Andric // If demangling is successful, FunctionName will end with "()". Print it
438fe6060f1SDimitry Andric // only if demangling did not run or was unsuccessful.
439*5f757f3fSDimitry Andric if (!StringRef(LineInfo.FunctionName).ends_with("()"))
440fe6060f1SDimitry Andric OS << "()";
441fe6060f1SDimitry Andric OS << ":\n";
442fe6060f1SDimitry Andric }
443fe6060f1SDimitry Andric if (LineInfo.FileName != DILineInfo::BadString && LineInfo.Line != 0 &&
444fe6060f1SDimitry Andric (OldLineInfo.Line != LineInfo.Line ||
445fe6060f1SDimitry Andric OldLineInfo.FileName != LineInfo.FileName || PrintFunctionName)) {
446fe6060f1SDimitry Andric OS << Delimiter << LineInfo.FileName << ":" << LineInfo.Line;
447fe6060f1SDimitry Andric LVP.printBetweenInsts(OS, true);
448fe6060f1SDimitry Andric }
449fe6060f1SDimitry Andric }
450fe6060f1SDimitry Andric
45106c3fb27SDimitry Andric // Get the source line text for LineInfo:
45206c3fb27SDimitry Andric // - use LineInfo::LineSource if available;
45306c3fb27SDimitry Andric // - use LineCache if LineInfo::Source otherwise.
getLine(const DILineInfo & LineInfo,StringRef ObjectFilename)45406c3fb27SDimitry Andric StringRef SourcePrinter::getLine(const DILineInfo &LineInfo,
45506c3fb27SDimitry Andric StringRef ObjectFilename) {
45606c3fb27SDimitry Andric if (LineInfo.LineSource)
45706c3fb27SDimitry Andric return LineInfo.LineSource.value();
45806c3fb27SDimitry Andric
45906c3fb27SDimitry Andric if (SourceCache.find(LineInfo.FileName) == SourceCache.end())
46006c3fb27SDimitry Andric if (!cacheSource(LineInfo))
46106c3fb27SDimitry Andric return {};
46206c3fb27SDimitry Andric
46306c3fb27SDimitry Andric auto LineBuffer = LineCache.find(LineInfo.FileName);
46406c3fb27SDimitry Andric if (LineBuffer == LineCache.end())
46506c3fb27SDimitry Andric return {};
46606c3fb27SDimitry Andric
46706c3fb27SDimitry Andric if (LineInfo.Line > LineBuffer->second.size()) {
46806c3fb27SDimitry Andric reportWarning(
46906c3fb27SDimitry Andric formatv("debug info line number {0} exceeds the number of lines in {1}",
47006c3fb27SDimitry Andric LineInfo.Line, LineInfo.FileName),
47106c3fb27SDimitry Andric ObjectFilename);
47206c3fb27SDimitry Andric return {};
47306c3fb27SDimitry Andric }
47406c3fb27SDimitry Andric
47506c3fb27SDimitry Andric // Vector begins at 0, line numbers are non-zero
47606c3fb27SDimitry Andric return LineBuffer->second[LineInfo.Line - 1];
47706c3fb27SDimitry Andric }
47806c3fb27SDimitry Andric
printSources(formatted_raw_ostream & OS,const DILineInfo & LineInfo,StringRef ObjectFilename,StringRef Delimiter,LiveVariablePrinter & LVP)479fe6060f1SDimitry Andric void SourcePrinter::printSources(formatted_raw_ostream &OS,
480fe6060f1SDimitry Andric const DILineInfo &LineInfo,
481fe6060f1SDimitry Andric StringRef ObjectFilename, StringRef Delimiter,
482fe6060f1SDimitry Andric LiveVariablePrinter &LVP) {
483fe6060f1SDimitry Andric if (LineInfo.FileName == DILineInfo::BadString || LineInfo.Line == 0 ||
484fe6060f1SDimitry Andric (OldLineInfo.Line == LineInfo.Line &&
485fe6060f1SDimitry Andric OldLineInfo.FileName == LineInfo.FileName))
486fe6060f1SDimitry Andric return;
487fe6060f1SDimitry Andric
48806c3fb27SDimitry Andric StringRef Line = getLine(LineInfo, ObjectFilename);
48906c3fb27SDimitry Andric if (!Line.empty()) {
49006c3fb27SDimitry Andric OS << Delimiter << Line;
491fe6060f1SDimitry Andric LVP.printBetweenInsts(OS, true);
492fe6060f1SDimitry Andric }
493fe6060f1SDimitry Andric }
494fe6060f1SDimitry Andric
SourcePrinter(const object::ObjectFile * Obj,StringRef DefaultArch)495fe6060f1SDimitry Andric SourcePrinter::SourcePrinter(const object::ObjectFile *Obj,
496fe6060f1SDimitry Andric StringRef DefaultArch)
497fe6060f1SDimitry Andric : Obj(Obj) {
498fe6060f1SDimitry Andric symbolize::LLVMSymbolizer::Options SymbolizerOpts;
499fe6060f1SDimitry Andric SymbolizerOpts.PrintFunctions =
500fe6060f1SDimitry Andric DILineInfoSpecifier::FunctionNameKind::LinkageName;
501fe6060f1SDimitry Andric SymbolizerOpts.Demangle = Demangle;
502fe6060f1SDimitry Andric SymbolizerOpts.DefaultArch = std::string(DefaultArch);
503fe6060f1SDimitry Andric Symbolizer.reset(new symbolize::LLVMSymbolizer(SymbolizerOpts));
504fe6060f1SDimitry Andric }
505fe6060f1SDimitry Andric
506fe6060f1SDimitry Andric } // namespace objdump
507fe6060f1SDimitry Andric } // namespace llvm
508