Commit 046adb70 authored by Matt Ma's avatar Matt Ma Committed by Facebook GitHub Bot

Use compilation unit as base address when no base address exists for range.

Summary:
From Dwarf4 standard

http://dwarfstd.org/doc/DWARF4.pdf#page=53

```name=2.17.3 Non-Contiguous Address Ranges
The applicable base address of a range list entry is determined by the closest preceding base
address selection entry (see below) in the same range list. If there is no such selection entry, then
the applicable base address defaults to the base address of the compilation unit (see Section
3.1.1).

In the case of a compilation unit where all of the machine code is contained in a single
contiguous section, no base address selection entry is needed.
```

http://dwarfstd.org/doc/DWARF4.pdf#page=58

```name=3.1.1 Normal and Partial Compilation Unit Entries
Compilation unit entries may have the following attributes:

1. Either a DW_AT_low_pc and DW_AT_high_pc pair of attributes or a DW_AT_ranges
attribute whose values encode the contiguous or non-contiguous address ranges, respectively,
of the machine instructions generated for the compilation unit (see Section 2.17).
A DW_AT_low_pc attribute may also be specified in combination with DW_AT_ranges to
specify the default base address for use in location lists (see Section 2.6.2) and range lists
(see Section 2.17.3).
```

http://dwarfstd.org/doc/DWARF4.pdf#page=61

```name=3.1.1 Normal and Partial Compilation Unit Entries
The base address of a compilation unit is defined as the value of the DW_AT_low_pc attribute,
if present; otherwise, it is undefined. If the base address is undefined, then any DWARF entry or
structure defined in terms of the base address of that compilation unit is not valid.
```

http://dwarfstd.org/doc/DWARF4.pdf#page=52
```name=2.17 Code Addresses and Ranges  - 2.17.1 Single Address
When there is a single address associated with an entity, such as a label or alternate entry point
of a subprogram, the entry has a DW_AT_low_pc attribute whose value is the relocated address
for the entity.

While the DW_AT_entry_pc attribute might also seem appropriate for this purpose, historically
the DW_AT_low_pc attribute was used before the DW_AT_entry_pc was introduced (in DWARF
Version 3). There is insufficient reason to change this.
```

Reviewed By: luciang

Differential Revision: D23422082

fbshipit-source-id: 4de79fa81e6c323095bb7c79faf87369998138c6
parent dcbe5421
...@@ -478,6 +478,7 @@ bool Dwarf::findLocation( ...@@ -478,6 +478,7 @@ bool Dwarf::findLocation(
folly::Optional<uint64_t> lineOffset; folly::Optional<uint64_t> lineOffset;
folly::StringPiece compilationDirectory; folly::StringPiece compilationDirectory;
folly::Optional<folly::StringPiece> mainFileName; folly::Optional<folly::StringPiece> mainFileName;
folly::Optional<uint64_t> baseAddrCU;
forEachAttribute(cu, die, [&](const detail::Attribute& attr) { forEachAttribute(cu, die, [&](const detail::Attribute& attr) {
switch (attr.spec.name) { switch (attr.spec.name) {
case DW_AT_stmt_list: case DW_AT_stmt_list:
...@@ -493,6 +494,13 @@ bool Dwarf::findLocation( ...@@ -493,6 +494,13 @@ bool Dwarf::findLocation(
// File name of main file being compiled // File name of main file being compiled
mainFileName = boost::get<folly::StringPiece>(attr.attrValue); mainFileName = boost::get<folly::StringPiece>(attr.attrValue);
break; break;
case DW_AT_low_pc:
case DW_AT_entry_pc:
// 2.17.1: historically DW_AT_low_pc was used. DW_AT_entry_pc was
// introduced in DWARF3. Support either to determine the base address of
// the CU.
baseAddrCU = boost::get<uint64_t>(attr.attrValue);
break;
} }
// Iterate through all attributes until find all above. // Iterate through all attributes until find all above.
return true; return true;
...@@ -527,7 +535,7 @@ bool Dwarf::findLocation( ...@@ -527,7 +535,7 @@ bool Dwarf::findLocation(
// Find the subprogram that matches the given address. // Find the subprogram that matches the given address.
detail::Die subprogram; detail::Die subprogram;
findSubProgramDieForAddress(cu, die, address, subprogram); findSubProgramDieForAddress(cu, die, address, baseAddrCU, subprogram);
if (eachParameterName) { if (eachParameterName) {
forEachChild(cu, subprogram, [&](const detail::Die& child) { forEachChild(cu, subprogram, [&](const detail::Die& child) {
...@@ -561,6 +569,7 @@ bool Dwarf::findLocation( ...@@ -561,6 +569,7 @@ bool Dwarf::findLocation(
subprogram, subprogram,
lineVM, lineVM,
address, address,
baseAddrCU,
folly::Range<detail::CallLocation*>(callLocations, size), folly::Range<detail::CallLocation*>(callLocations, size),
numFound); numFound);
...@@ -776,8 +785,11 @@ folly::Optional<T> Dwarf::getAttribute( ...@@ -776,8 +785,11 @@ folly::Optional<T> Dwarf::getAttribute(
return result; return result;
} }
bool Dwarf::isAddrInRangeList(uint64_t address, size_t offset, uint8_t addrSize) bool Dwarf::isAddrInRangeList(
const { uint64_t address,
folly::Optional<uint64_t> baseAddr,
size_t offset,
uint8_t addrSize) const {
FOLLY_SAFE_CHECK(addrSize == 4 || addrSize == 8, "wrong address size"); FOLLY_SAFE_CHECK(addrSize == 4 || addrSize == 8, "wrong address size");
if (debugRanges_.empty()) { if (debugRanges_.empty()) {
return false; return false;
...@@ -788,7 +800,6 @@ bool Dwarf::isAddrInRangeList(uint64_t address, size_t offset, uint8_t addrSize) ...@@ -788,7 +800,6 @@ bool Dwarf::isAddrInRangeList(uint64_t address, size_t offset, uint8_t addrSize)
sp.advance(offset); sp.advance(offset);
const uint64_t maxAddr = is64BitAddr ? std::numeric_limits<uint64_t>::max() const uint64_t maxAddr = is64BitAddr ? std::numeric_limits<uint64_t>::max()
: std::numeric_limits<uint32_t>::max(); : std::numeric_limits<uint32_t>::max();
uint64_t baseAddr = 0;
while (!sp.empty()) { while (!sp.empty()) {
uint64_t begin = readOffset(sp, is64BitAddr); uint64_t begin = readOffset(sp, is64BitAddr);
uint64_t end = readOffset(sp, is64BitAddr); uint64_t end = readOffset(sp, is64BitAddr);
...@@ -802,7 +813,12 @@ bool Dwarf::isAddrInRangeList(uint64_t address, size_t offset, uint8_t addrSize) ...@@ -802,7 +813,12 @@ bool Dwarf::isAddrInRangeList(uint64_t address, size_t offset, uint8_t addrSize)
break; break;
} }
// Check if the given address falls in the range list entry. // Check if the given address falls in the range list entry.
if (address >= begin + baseAddr && address < end + baseAddr) { // 2.17.3 Non-Contiguous Address Ranges
// The applicable base address of a range list entry is determined by the
// closest preceding base address selection entry (see below) in the same
// range list. If there is no such selection entry, then the applicable base
// address defaults to the base address of the compilation unit.
if (baseAddr && address >= begin + *baseAddr && address < end + *baseAddr) {
return true; return true;
} }
}; };
...@@ -814,6 +830,7 @@ void Dwarf::findSubProgramDieForAddress( ...@@ -814,6 +830,7 @@ void Dwarf::findSubProgramDieForAddress(
const detail::CompilationUnit& cu, const detail::CompilationUnit& cu,
const detail::Die& die, const detail::Die& die,
uint64_t address, uint64_t address,
folly::Optional<uint64_t> baseAddrCU,
detail::Die& subprogram) const { detail::Die& subprogram) const {
forEachChild(cu, die, [&](const detail::Die& childDie) { forEachChild(cu, die, [&](const detail::Die& childDie) {
if (childDie.abbr.tag == DW_TAG_subprogram) { if (childDie.abbr.tag == DW_TAG_subprogram) {
...@@ -839,18 +856,20 @@ void Dwarf::findSubProgramDieForAddress( ...@@ -839,18 +856,20 @@ void Dwarf::findSubProgramDieForAddress(
// Iterate through all attributes until find all above. // Iterate through all attributes until find all above.
return true; return true;
}); });
if ((lowPc && highPc && isHighPcAddr && address >= *lowPc && bool pcMatch = lowPc && highPc && isHighPcAddr && address >= *lowPc &&
address < (*isHighPcAddr ? *highPc : *lowPc + *highPc)) || (address < (*isHighPcAddr ? *highPc : *lowPc + *highPc));
(rangeOffset && bool rangeMatch =
isAddrInRangeList(address, *rangeOffset, cu.addrSize))) { rangeOffset &&
isAddrInRangeList(
address, baseAddrCU, rangeOffset.value(), cu.addrSize);
if (pcMatch || rangeMatch) {
subprogram = childDie; subprogram = childDie;
return false; return false;
} }
} else if (
childDie.abbr.tag == DW_TAG_namespace ||
childDie.abbr.tag == DW_TAG_class_type) {
findSubProgramDieForAddress(cu, childDie, address, subprogram);
} }
findSubProgramDieForAddress(cu, childDie, address, baseAddrCU, subprogram);
// Iterates through children until find the inline subprogram. // Iterates through children until find the inline subprogram.
return true; return true;
}); });
...@@ -871,6 +890,7 @@ void Dwarf::findInlinedSubroutineDieForAddress( ...@@ -871,6 +890,7 @@ void Dwarf::findInlinedSubroutineDieForAddress(
const detail::Die& die, const detail::Die& die,
const LineNumberVM& lineVM, const LineNumberVM& lineVM,
uint64_t address, uint64_t address,
folly::Optional<uint64_t> baseAddrCU,
folly::Range<detail::CallLocation*> locations, folly::Range<detail::CallLocation*> locations,
size_t& numFound) const { size_t& numFound) const {
if (numFound >= locations.size()) { if (numFound >= locations.size()) {
...@@ -878,6 +898,24 @@ void Dwarf::findInlinedSubroutineDieForAddress( ...@@ -878,6 +898,24 @@ void Dwarf::findInlinedSubroutineDieForAddress(
} }
forEachChild(cu, die, [&](const detail::Die& childDie) { forEachChild(cu, die, [&](const detail::Die& childDie) {
// Between a DW_TAG_subprogram and and DW_TAG_inlined_subroutine we might
// have arbitrary intermediary "nodes", including DW_TAG_common_block,
// DW_TAG_lexical_block, DW_TAG_try_block, DW_TAG_catch_block and
// DW_TAG_with_stmt, etc.
// We can't filter with locationhere since its range may be not specified.
// See section 2.6.2: A location list containing only an end of list entry
// describes an object that exists in the source code but not in the
// executable program.
if (childDie.abbr.tag == DW_TAG_try_block ||
childDie.abbr.tag == DW_TAG_catch_block ||
childDie.abbr.tag == DW_TAG_entry_point ||
childDie.abbr.tag == DW_TAG_common_block ||
childDie.abbr.tag == DW_TAG_lexical_block) {
findInlinedSubroutineDieForAddress(
cu, childDie, lineVM, address, baseAddrCU, locations, numFound);
return true;
}
folly::Optional<uint64_t> lowPc; folly::Optional<uint64_t> lowPc;
folly::Optional<uint64_t> highPc; folly::Optional<uint64_t> highPc;
folly::Optional<bool> isHighPcAddr; folly::Optional<bool> isHighPcAddr;
...@@ -926,31 +964,18 @@ void Dwarf::findInlinedSubroutineDieForAddress( ...@@ -926,31 +964,18 @@ void Dwarf::findInlinedSubroutineDieForAddress(
// - A DW_AT_ranges attribute for a non-contiguous range of addresses. // - A DW_AT_ranges attribute for a non-contiguous range of addresses.
// TODO: Support DW_TAG_entry_point and DW_TAG_common_block that don't // TODO: Support DW_TAG_entry_point and DW_TAG_common_block that don't
// have DW_AT_low_pc/DW_AT_high_pc pairs and DW_AT_ranges. // have DW_AT_low_pc/DW_AT_high_pc pairs and DW_AT_ranges.
// TODO: Support relocated address which requires lookup in relocation map.
bool pcMatch = lowPc && highPc && isHighPcAddr && address >= *lowPc && bool pcMatch = lowPc && highPc && isHighPcAddr && address >= *lowPc &&
(address < (*isHighPcAddr ? *highPc : *lowPc + *highPc)); (address < (*isHighPcAddr ? *highPc : *lowPc + *highPc));
bool rangeMatch = rangeOffset && bool rangeMatch =
isAddrInRangeList(address, rangeOffset.value(), cu.addrSize); rangeOffset &&
isAddrInRangeList(
address, baseAddrCU, rangeOffset.value(), cu.addrSize);
if (!pcMatch && !rangeMatch) { if (!pcMatch && !rangeMatch) {
// Address doesn't match. Keep searching other children. // Address doesn't match. Keep searching other children.
return true; return true;
} }
// Between a DW_TAG_subprogram and and DW_TAG_inlined_subroutine we might
// have arbitrary intermediary "nodes", including DW_TAG_common_block,
// DW_TAG_lexical_block, DW_TAG_try_block, DW_TAG_catch_block and
// DW_TAG_with_stmt, etc.
if (childDie.abbr.tag == DW_TAG_try_block ||
childDie.abbr.tag == DW_TAG_catch_block ||
childDie.abbr.tag == DW_TAG_entry_point ||
childDie.abbr.tag == DW_TAG_common_block ||
childDie.abbr.tag == DW_TAG_lexical_block) {
findInlinedSubroutineDieForAddress(
cu, childDie, lineVM, address, locations, numFound);
// We expect a single sibling DIE to match on addr. Stop searching for
// other DIEs.
return false;
}
if (!abstractOrigin || !abstractOriginRefType || !callLine || !callFile) { if (!abstractOrigin || !abstractOriginRefType || !callLine || !callFile) {
// We expect a single sibling DIE to match on addr, but it's missing // We expect a single sibling DIE to match on addr, but it's missing
// required fields. Stop searching for other DIEs. // required fields. Stop searching for other DIEs.
...@@ -1009,7 +1034,7 @@ void Dwarf::findInlinedSubroutineDieForAddress( ...@@ -1009,7 +1034,7 @@ void Dwarf::findInlinedSubroutineDieForAddress(
*abstractOrigin); *abstractOrigin);
findInlinedSubroutineDieForAddress( findInlinedSubroutineDieForAddress(
cu, childDie, lineVM, address, locations, ++numFound); cu, childDie, lineVM, address, baseAddrCU, locations, ++numFound);
return false; return false;
}); });
......
...@@ -138,6 +138,7 @@ class Dwarf { ...@@ -138,6 +138,7 @@ class Dwarf {
const detail::CompilationUnit& cu, const detail::CompilationUnit& cu,
const detail::Die& die, const detail::Die& die,
uint64_t address, uint64_t address,
folly::Optional<uint64_t> baseAddrCU,
detail::Die& subprogram) const; detail::Die& subprogram) const;
/** /**
...@@ -149,6 +150,7 @@ class Dwarf { ...@@ -149,6 +150,7 @@ class Dwarf {
const detail::Die& die, const detail::Die& die,
const LineNumberVM& lineVM, const LineNumberVM& lineVM,
uint64_t address, uint64_t address,
folly::Optional<uint64_t> baseAddrCU,
folly::Range<detail::CallLocation*> locations, folly::Range<detail::CallLocation*> locations,
size_t& numFound) const; size_t& numFound) const;
...@@ -205,8 +207,11 @@ class Dwarf { ...@@ -205,8 +207,11 @@ class Dwarf {
* Check if the given address is in the range list at the given offset in * Check if the given address is in the range list at the given offset in
* .debug_ranges. * .debug_ranges.
*/ */
bool isAddrInRangeList(uint64_t address, size_t offset, uint8_t addrSize) bool isAddrInRangeList(
const; uint64_t address,
folly::Optional<uint64_t> baseAddr,
size_t offset,
uint8_t addrSize) const;
const ElfFile* elf_; const ElfFile* elf_;
const folly::StringPiece debugInfo_; // .debug_info const folly::StringPiece debugInfo_; // .debug_info
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment