llvm.org GIT mirror llvm / 3e25c4a
This patch extends the libLLVMDebugInfo which contains a minimalistic DWARF parser: 1) DIContext is now able to return function name for a given instruction address (besides file/line info). 2) llvm-dwarfdump accepts flag --functions that prints the function name (if address is specified by --address flag). 3) test case that checks the basic functionality of llvm-dwarfdump added git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@159512 91177308-0d34-0410-b5e6-96231b3b80d8 Alexey Samsonov 7 years ago
12 changed file(s) with 174 addition(s) and 31 deletion(s). Raw diff Collapse all Expand all
2525 /// DILineInfo - a format-neutral container for source line information.
2626 class DILineInfo {
2727 const char *FileName;
28 const char *FunctionName;
2829 uint32_t Line;
2930 uint32_t Column;
3031 public:
31 DILineInfo() : FileName(""), Line(0), Column(0) {}
32 DILineInfo(const char *fileName, uint32_t line, uint32_t column)
33 : FileName(fileName), Line(line), Column(column) {}
32 DILineInfo()
33 : FileName(""), FunctionName(""),
34 Line(0), Column(0) {}
35 DILineInfo(const char *fileName, const char *functionName,
36 uint32_t line, uint32_t column)
37 : FileName(fileName), FunctionName(functionName),
38 Line(line), Column(column) {}
3439
3540 const char *getFileName() const { return FileName; }
41 const char *getFunctionName() const { return FunctionName; }
3642 uint32_t getLine() const { return Line; }
3743 uint32_t getColumn() const { return Column; }
3844
3945 bool operator==(const DILineInfo &RHS) const {
4046 return Line == RHS.Line && Column == RHS.Column &&
41 std::strcmp(FileName, RHS.FileName) == 0;
47 std::strcmp(FileName, RHS.FileName) == 0 &&
48 std::strcmp(FunctionName, RHS.FunctionName) == 0;
4249 }
4350 bool operator!=(const DILineInfo &RHS) const {
4451 return !(*this == RHS);
52 }
53 };
54
55 /// DILineInfoSpecifier - controls which fields of DILineInfo container
56 /// should be filled with data.
57 class DILineInfoSpecifier {
58 const uint32_t Flags; // Or'ed flags that set the info we want to fetch.
59 public:
60 enum Specification {
61 FileLineInfo = 1 << 0,
62 FunctionName = 1 << 1
63 };
64 // Use file/line info by default.
65 DILineInfoSpecifier(uint32_t flags = FileLineInfo) : Flags(flags) {}
66 bool needs(Specification spec) const {
67 return (Flags & spec) > 0;
4568 }
4669 };
4770
5982
6083 virtual void dump(raw_ostream &OS) = 0;
6184
62 virtual DILineInfo getLineInfoForAddress(uint64_t address) = 0;
85 virtual DILineInfo getLineInfoForAddress(uint64_t address,
86 DILineInfoSpecifier specifier = DILineInfoSpecifier()) = 0;
6387 };
6488
6589 }
8181 Abbrevs = 0;
8282 AddrSize = 0;
8383 BaseAddr = 0;
84 DieArray.clear();
84 clearDIEs(false);
8585 }
8686
8787 void DWARFCompileUnit::dump(raw_ostream &OS) {
200200 }
201201
202202 void DWARFCompileUnit::clearDIEs(bool keep_compile_unit_die) {
203 if (DieArray.size() > 1) {
203 if (DieArray.size() > (unsigned)keep_compile_unit_die) {
204204 // std::vectors never get any smaller when resized to a smaller size,
205205 // or when clear() or erase() are called, the size will report that it
206206 // is smaller, but the memory allocated remains intact (call capacity()
226226 // all compile units to stay loaded when they weren't needed. So we can end
227227 // up parsing the DWARF and then throwing them all away to keep memory usage
228228 // down.
229 const bool clear_dies = extractDIEsIfNeeded(false) > 1;
230
229 const bool clear_dies = extractDIEsIfNeeded(false) > 1 &&
230 clear_dies_if_already_not_parsed;
231231 DieArray[0].buildAddressRangeTable(this, debug_aranges);
232232
233233 // Keep memory down by clearing DIEs if this generate function
235235 if (clear_dies)
236236 clearDIEs(true);
237237 }
238
239 const DWARFDebugInfoEntryMinimal*
240 DWARFCompileUnit::getFunctionDIEForAddress(int64_t address) {
241 size_t n = extractDIEsIfNeeded(false);
242 for (size_t i = 0; i != n; i++) {
243 if (DieArray[i].addressRangeContainsAddress(this, address))
244 return &DieArray[i];
245 }
246 return 0;
247 }
103103
104104 void buildAddressRangeTable(DWARFDebugAranges *debug_aranges,
105105 bool clear_dies_if_already_not_parsed);
106 /// getFunctionDIEForAddress - Returns pointer to parsed subprogram DIE,
107 /// address ranges of which contain the provided address,
108 /// or NULL if there is no such subprogram. The pointer
109 /// is valid until DWARFCompileUnit::clear() or clearDIEs() is called.
110 const DWARFDebugInfoEntryMinimal *getFunctionDIEForAddress(int64_t address);
106111 };
107112
108113 }
139139 return 0;
140140 }
141141
142 DILineInfo DWARFContext::getLineInfoForAddress(uint64_t address) {
142 DILineInfo DWARFContext::getLineInfoForAddress(uint64_t address,
143 DILineInfoSpecifier specifier) {
143144 // First, get the offset of the compile unit.
144145 uint32_t cuOffset = getDebugAranges()->findAddress(address);
145146 // Retrieve the compile unit.
146147 DWARFCompileUnit *cu = getCompileUnitForOffset(cuOffset);
147148 if (!cu)
148 return DILineInfo("", 0, 0);
149 // Get the line table for this compile unit.
150 const DWARFDebugLine::LineTable *lineTable = getLineTableForCompileUnit(cu);
151 if (!lineTable)
152 return DILineInfo("", 0, 0);
153 // Get the index of the row we're looking for in the line table.
154 uint64_t hiPC =
155 cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(cu, DW_AT_high_pc,
156 -1ULL);
157 uint32_t rowIndex = lineTable->lookupAddress(address, hiPC);
158 if (rowIndex == -1U)
159 return DILineInfo("", 0, 0);
160
161 // From here, contruct the DILineInfo.
162 const DWARFDebugLine::Row &row = lineTable->Rows[rowIndex];
163 const std::string &fileName = lineTable->Prologue.FileNames[row.File-1].Name;
164
165 return DILineInfo(fileName.c_str(), row.Line, row.Column);
149 return DILineInfo();
150 const char *fileName = "";
151 const char *functionName = "";
152 uint32_t line = 0;
153 uint32_t column = 0;
154 if (specifier.needs(DILineInfoSpecifier::FunctionName)) {
155 const DWARFDebugInfoEntryMinimal *function_die =
156 cu->getFunctionDIEForAddress(address);
157 if (function_die)
158 functionName = function_die->getSubprogramName(cu);
159 }
160 if (specifier.needs(DILineInfoSpecifier::FileLineInfo)) {
161 // Get the line table for this compile unit.
162 const DWARFDebugLine::LineTable *lineTable = getLineTableForCompileUnit(cu);
163 if (lineTable) {
164 // Get the index of the row we're looking for in the line table.
165 uint64_t hiPC = cu->getCompileUnitDIE()->getAttributeValueAsUnsigned(
166 cu, DW_AT_high_pc, -1ULL);
167 uint32_t rowIndex = lineTable->lookupAddress(address, hiPC);
168 if (rowIndex != -1U) {
169 const DWARFDebugLine::Row &row = lineTable->Rows[rowIndex];
170 // Take file/line info from the line table.
171 fileName = lineTable->Prologue.FileNames[row.File - 1].Name.c_str();
172 line = row.Line;
173 column = row.Column;
174 }
175 }
176 }
177 return DILineInfo(fileName, functionName, line, column);
166178 }
167179
168180 void DWARFContextInMemory::anchor() { }
6565 const DWARFDebugLine::LineTable *
6666 getLineTableForCompileUnit(DWARFCompileUnit *cu);
6767
68 virtual DILineInfo getLineInfoForAddress(uint64_t address);
68 virtual DILineInfo getLineInfoForAddress(uint64_t address,
69 DILineInfoSpecifier specifier = DILineInfoSpecifier());
6970
7071 bool isLittleEndian() const { return IsLittleEndian; }
7172
9292 cu->buildAddressRangeTable(this, true);
9393 }
9494 }
95 sort(true, /* overlap size */ 0);
9596 return !isEmpty();
9697 }
9798
220221 HiPC = Aranges.back().HiPC();
221222 return true;
222223 }
223
439439 }
440440 }
441441 }
442
443 bool
444 DWARFDebugInfoEntryMinimal::addressRangeContainsAddress(
445 const DWARFCompileUnit *cu, const uint64_t address) const {
446 if (!isNULL() && getTag() == DW_TAG_subprogram) {
447 uint64_t hi_pc = -1ULL;
448 uint64_t lo_pc = getAttributeValueAsUnsigned(cu, DW_AT_low_pc, -1ULL);
449 if (lo_pc != -1ULL)
450 hi_pc = getAttributeValueAsUnsigned(cu, DW_AT_high_pc, -1ULL);
451 if (hi_pc != -1ULL) {
452 return (lo_pc <= address && address < hi_pc);
453 }
454 }
455 return false;
456 }
457
458 static inline const char*
459 getSubprogramNameFromDie(const DWARFCompileUnit *cu,
460 const DWARFDebugInfoEntryMinimal *die) {
461 const char *result = 0;
462 if (!die->isNULL() && die->getTag() == DW_TAG_subprogram) {
463 // Try to get mangled name if possible.
464 result = die->getAttributeValueAsString(cu, DW_AT_MIPS_linkage_name, 0);
465 if (result == 0)
466 result = die->getAttributeValueAsString(cu, DW_AT_linkage_name, 0);
467 if (result == 0)
468 result = die->getAttributeValueAsString(cu, DW_AT_name, 0);
469 }
470 return result;
471 }
472
473 const char*
474 DWARFDebugInfoEntryMinimal::getSubprogramName(
475 const DWARFCompileUnit *cu) const {
476 if (isNULL() || getTag() != DW_TAG_subprogram)
477 return 0;
478 const char *name = getSubprogramNameFromDie(cu, this);
479 if (name == 0) {
480 // Try to get name from specification DIE.
481 uint32_t ref = getAttributeValueAsReference(cu, DW_AT_specification, -1U);
482 if (ref != -1U) {
483 DWARFDebugInfoEntryMinimal spec_die;
484 if (spec_die.extract(cu, &ref))
485 name = getSubprogramNameFromDie(cu, &spec_die);
486 }
487 }
488 return name;
489 }
127127
128128 void buildAddressRangeTable(const DWARFCompileUnit *cu,
129129 DWARFDebugAranges *debug_aranges) const;
130
131 bool addressRangeContainsAddress(const DWARFCompileUnit *cu,
132 const uint64_t address) const;
133
134 // If a DIE represents a subroutine, returns its mangled name
135 // (or short name, if mangled is missing). Otherwise returns null.
136 const char* getSubprogramName(const DWARFCompileUnit *cu) const;
130137 };
131138
132139 }
0 RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test.elf-x86-64 \
1 RUN: --address=0x400589 --functions | FileCheck %s -check-prefix MAIN
2 RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test.elf-x86-64 \
3 RUN: --address=0x400558 --functions | FileCheck %s -check-prefix FUNCTION
4 RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test.elf-x86-64 \
5 RUN: --address=0x4005b6 --functions | FileCheck %s -check-prefix CTOR_WITH_SPEC
6 RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test2.elf-x86-64 \
7 RUN: --address=0x4004b8 --functions | FileCheck %s -check-prefix MANY_CU_1
8 RUN: llvm-dwarfdump %p/Inputs/dwarfdump-test2.elf-x86-64 \
9 RUN: --address=0x4004c4 --functions | FileCheck %s -check-prefix MANY_CU_2
10
11 MAIN: main
12 MAIN-NEXT: dwarfdump-test.cc:16:10
13
14 FUNCTION: _Z1fii
15 FUNCTION-NEXT: dwarfdump-test.cc:11:18
16
17 CTOR_WITH_SPEC: _ZN10DummyClassC1Ei
18 CTOR_WITH_SPEC-NEXT: dwarfdump-test.cc:4:30
19
20 MANY_CU_1: a
21 MANY_CU_1-NEXT: a.cc:2:0
22
23 MANY_CU_2: main
24 MANY_CU_2-NEXT: main.cc:4:0
3737 static cl::opt
3838 Address("address", cl::init(-1ULL),
3939 cl::desc("Print line information for a given address"));
40
41 static cl::opt
42 PrintFunctions("functions", cl::init(false),
43 cl::desc("Print function names as well as line information "
44 "for a given address"));
4045
4146 static void DumpInput(const StringRef &Filename) {
4247 OwningPtr Buff;
9196 dictx->dump(outs());
9297 } else {
9398 // Print line info for the specified address.
94 DILineInfo dli = dictx->getLineInfoForAddress(Address);
99 int spec_flags = DILineInfoSpecifier::FileLineInfo;
100 if (PrintFunctions)
101 spec_flags |= DILineInfoSpecifier::FunctionName;
102 DILineInfo dli = dictx->getLineInfoForAddress(Address, spec_flags);
103 if (PrintFunctions)
104 outs() << (dli.getFunctionName() ? dli.getFunctionName() : "")
105 << "\n";
95106 outs() << (dli.getFileName() ? dli.getFileName() : "") << ':'
96107 << dli.getLine() << ':' << dli.getColumn() << '\n';
97108 }