Index: include/llvm/DebugInfo/DWARF/DWARFDie.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDie.h +++ include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -252,13 +252,6 @@ void getCallerFrame(uint32_t &CallFile, uint32_t &CallLine, uint32_t &CallColumn, uint32_t &CallDiscriminator) const; - /// Get inlined chain for a given address, rooted at the current DIE. - /// Returns empty chain if address is not contained in address range - /// of current DIE. - void - getInlinedChainForAddress(const uint64_t Address, - SmallVectorImpl &InlinedChain) const; - class attribute_iterator; /// Get an iterator range to all attributes in the current DIE only. Index: include/llvm/DebugInfo/DWARF/DWARFUnit.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -31,6 +31,7 @@ #include #include #include +#include namespace llvm { @@ -134,6 +135,11 @@ uint64_t BaseAddr; // The compile unit debug information entry items. std::vector DieArray; + + // Map from range's start address to end address and corresponding DIE. + // IntervalMap does not support range removal, as a result, we use the + // std::map::upper_bound for address range lookup. + std::map> AddrDieMap; typedef iterator_range::iterator> die_iterator_range; @@ -183,6 +189,9 @@ AddrOffsetSectionBase = Base; } + // Recursively update address to Die map. + void updateAddressDieMap(DWARFDie Die); + void setRangesSection(StringRef RS, uint32_t Base) { RangeSection = RS; RangeSectionBase = Base; @@ -339,10 +348,10 @@ /// it was actually constructed. bool parseDWO(); - /// getSubprogramForAddress - Returns subprogram DIE with address range + /// getSubroutineForAddress - Returns subprogram DIE with address range /// encompassing the provided address. The pointer is alive as long as parsed /// compile unit DIEs are not cleared. - DWARFDie getSubprogramForAddress(uint64_t Address); + DWARFDie getSubroutineForAddress(uint64_t Address); }; } // end namespace llvm Index: lib/DebugInfo/DWARF/DWARFDie.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDie.cpp +++ lib/DebugInfo/DWARF/DWARFDie.cpp @@ -352,32 +352,6 @@ } } -void DWARFDie::getInlinedChainForAddress( - const uint64_t Address, SmallVectorImpl &InlinedChain) const { - if (isNULL()) - return; - DWARFDie DIE(*this); - while (DIE) { - // Append current DIE to inlined chain only if it has correct tag - // (e.g. it is not a lexical block). - if (DIE.isSubroutineDIE()) - InlinedChain.push_back(DIE); - - // Try to get child which also contains provided address. - DWARFDie Child = DIE.getFirstChild(); - while (Child) { - if (Child.addressRangeContainsAddress(Address)) { - // Assume there is only one such child. - break; - } - Child = Child.getSibling(); - } - DIE = Child; - } - // Reverse the obtained chain to make the root of inlined chain last. - std::reverse(InlinedChain.begin(), InlinedChain.end()); -} - DWARFDie DWARFDie::getParent() const { if (isValid()) return U->getParent(Die); Index: lib/DebugInfo/DWARF/DWARFUnit.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFUnit.cpp +++ lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -343,36 +343,67 @@ clearDIEs(true); } -DWARFDie -DWARFUnit::getSubprogramForAddress(uint64_t Address) { - extractDIEsIfNeeded(false); - for (const DWARFDebugInfoEntry &D : DieArray) { - DWARFDie DIE(this, &D); - if (DIE.isSubprogramDIE() && - DIE.addressRangeContainsAddress(Address)) { - return DIE; +void DWARFUnit::updateAddressDieMap(DWARFDie Die) { + if (Die.isSubroutineDIE()) { + for (const auto &R : Die.getAddressRanges()) { + // Ignore 0-sized ranges. + if (R.first == R.second) + continue; + auto B = AddrDieMap.upper_bound(R.first); + if (B != AddrDieMap.begin() && R.first < (--B)->second.first) { + // The range is a sub-range of existing ranges, we need to split the + // existing range. + if (R.second < B->second.first) + AddrDieMap[R.second] = B->second; + if (R.first > B->first) + AddrDieMap[B->first].first = R.first; + } + AddrDieMap[R.first] = std::make_pair(R.second, Die); } } - return DWARFDie(); + // Parent DIEs are added to the AddrDieMap prior to the Children DIEs to + // simplify the logic to update AddrDieMap. The child's range will always + // be equal or smaller than the parent's range. With this assumption, when + // adding one range into the map, it will at most split a range into 3 + // sub-ranges. + for (DWARFDie Child = Die.getFirstChild(); Child; Child = Child.getSibling()) + updateAddressDieMap(Child); +} + +DWARFDie DWARFUnit::getSubroutineForAddress(uint64_t Address) { + extractDIEsIfNeeded(false); + if (AddrDieMap.empty()) + updateAddressDieMap(getUnitDIE()); + auto R = AddrDieMap.upper_bound(Address); + if (R == AddrDieMap.begin()) + return DWARFDie(); + // upper_bound's previous item contains Address. + --R; + if (Address >= R->second.first) + return DWARFDie(); + return R->second.second; } void DWARFUnit::getInlinedChainForAddress(uint64_t Address, SmallVectorImpl &InlinedChain) { - // First, find a subprogram that contains the given address (the root + // First, find the subroutine that contains the given address (the leaf // of inlined chain). - DWARFDie SubprogramDIE; + DWARFDie SubroutineDIE; // Try to look for subprogram DIEs in the DWO file. parseDWO(); if (DWO) - SubprogramDIE = DWO->getUnit()->getSubprogramForAddress(Address); + SubroutineDIE = DWO->getUnit()->getSubroutineForAddress(Address); else - SubprogramDIE = getSubprogramForAddress(Address); + SubroutineDIE = getSubroutineForAddress(Address); - // Get inlined chain rooted at this subprogram DIE. - if (SubprogramDIE) - SubprogramDIE.getInlinedChainForAddress(Address, InlinedChain); - else + if (SubroutineDIE) { + while (SubroutineDIE) { + if (SubroutineDIE.isSubroutineDIE()) + InlinedChain.push_back(SubroutineDIE); + SubroutineDIE = SubroutineDIE.getParent(); + } + } else InlinedChain.clear(); } Index: test/tools/llvm-symbolizer/padding-x86_64.ll =================================================================== --- /dev/null +++ test/tools/llvm-symbolizer/padding-x86_64.ll @@ -0,0 +1,40 @@ +; REQUIRES: x86_64-linux +; Checks if symbolizer can correctly symbolize address in the padding between +; functions. +; RUN: llc -o %t.o -filetype=obj -mtriple=x86_64-pc-linux %s +; RUN: echo 0x5 | llvm-symbolizer -obj=%t.o | FileCheck %s --check-prefix=FOO +; RUN: echo 0xd | llvm-symbolizer -obj=%t.o | FileCheck %s --check-prefix=PADDING +; RUN: echo 0x10 | llvm-symbolizer -obj=%t.o | FileCheck %s --check-prefix=MAIN + +;FOO: foo +;PADDING: ?? +;MAIN: main + +@a = global i32 1, align 4 + +define i32 @foo() !dbg !9 { +entry: + %0 = load i32, i32* @a, align 4 + ret i32 %0 +} + +define i32 @main() !dbg !14 { +entry: + %call = call i32 @foo(), !dbg !18 + ret i32 %call +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!6, !7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "padding-x86_64.c", directory: "/tmp/") +!2 = !{} +!5 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!6 = !{i32 2, !"Dwarf Version", i32 4} +!7 = !{i32 2, !"Debug Info Version", i32 3} +!9 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !10, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, variables: !2) +!10 = !DISubroutineType(types: !11) +!11 = !{!5} +!14 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 6, type: !10, isLocal: false, isDefinition: true, scopeLine: 6, isOptimized: false, unit: !0, variables: !2) +!18 = !DILocation(line: 7, column: 8, scope: !14)