Skip to content

Commit

Permalink
[BOLT][DWARF] Add support for base address in DWARF location lists
Browse files Browse the repository at this point in the history
Summary:
The version of LLVM that we are based on lacks the support for base
address in DWARF location lists. Add the missing pieces.

(cherry picked from FBD20640784)
  • Loading branch information
maksfb committed Mar 25, 2020
1 parent bbbf679 commit 58b0d9e
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 35 deletions.
132 changes: 120 additions & 12 deletions bolt/llvm.patch
Expand Up @@ -67,20 +67,21 @@ index 84b23398b8c..9ed1792f0c9 100644
bool extract(DataExtractor Data, uint32_t* OffsetPtr);
void dump(raw_ostream &OS) const;
diff --git a/include/llvm/DebugInfo/DWARF/DWARFContext.h b/include/llvm/DebugInfo/DWARF/DWARFContext.h
index e842cf231e7..83b0dbe0676 100644
index e842cf231e7..90eb7961649 100644
--- a/include/llvm/DebugInfo/DWARF/DWARFContext.h
+++ b/include/llvm/DebugInfo/DWARF/DWARFContext.h
@@ -225,6 +225,9 @@ public:
@@ -225,6 +225,10 @@ public:
/// Get a pointer to the parsed DebugLoc object.
const DWARFDebugLoc *getDebugLoc();

+ /// Extract one location list corresponding in \p Offset
+ Optional<DWARFDebugLoc::LocationList> getOneDebugLocList(uint32_t *Offset);
+ Optional<DWARFDebugLoc::LocationList>
+ getOneDebugLocList(uint32_t *Offset, uint64_t CUBaseAddress = 0);
+
/// Get a pointer to the parsed dwo abbreviations object.
const DWARFDebugAbbrev *getDebugAbbrevDWO();

@@ -280,6 +283,10 @@ public:
@@ -280,6 +284,10 @@ public:
/// given address where applicable.
DIEsForAddress getDIEsForAddress(uint64_t Address);

Expand All @@ -91,7 +92,7 @@ index e842cf231e7..83b0dbe0676 100644
DILineInfo getLineInfoForAddress(uint64_t Address,
DILineInfoSpecifier Specifier = DILineInfoSpecifier()) override;
DILineInfoTable getLineInfoForAddressRange(uint64_t Address, uint64_t Size,
@@ -302,7 +309,7 @@ public:
@@ -302,7 +310,7 @@ public:
static std::unique_ptr<DWARFContext>
create(const object::ObjectFile &Obj, const LoadedObjectInfo *L = nullptr,
function_ref<ErrorPolicy(Error)> HandleError = defaultErrorHandler,
Expand All @@ -100,7 +101,7 @@ index e842cf231e7..83b0dbe0676 100644

static std::unique_ptr<DWARFContext>
create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
@@ -313,7 +320,6 @@ public:
@@ -313,7 +321,6 @@ public:
/// have initialized the relevant target descriptions.
Error loadRegisterInfo(const object::ObjectFile &Obj);

Expand Down Expand Up @@ -156,19 +157,23 @@ index ff1c7fb3838..2622a4e7eef 100644
};

diff --git a/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h b/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h
index a6d319a9045..39674a9d499 100644
index a6d319a9045..c099007c132 100644
--- a/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h
+++ b/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h
@@ -68,6 +68,9 @@ public:
@@ -68,8 +68,12 @@ public:
/// Return the location list at the given offset or nullptr.
LocationList const *getLocationListAtOffset(uint64_t Offset) const;

+ /// Returns the parsed location lists.
+ const LocationLists &getLocationLists() const { return Locations; }
+
Optional<LocationList> parseOneLocationList(DWARFDataExtractor Data,
uint32_t *Offset);
- uint32_t *Offset);
+ uint32_t *Offset,
+ uint64_t CUBaseAddress = 0);
};

class DWARFDebugLocDWO {
diff --git a/include/llvm/DebugInfo/DWARF/DWARFDie.h b/include/llvm/DebugInfo/DWARF/DWARFDie.h
index 39a3dd32c0f..84279875611 100644
--- a/include/llvm/DebugInfo/DWARF/DWARFDie.h
Expand Down Expand Up @@ -1795,20 +1800,20 @@ index adada672af0..b3d68ed66af 100644
if (Spec.isImplicitConst()) {
FormValue.setSValue(Spec.getImplicitConstValue());
diff --git a/lib/DebugInfo/DWARF/DWARFContext.cpp b/lib/DebugInfo/DWARF/DWARFContext.cpp
index 3a974dddc4e..65bd4a69db8 100644
index 3a974dddc4e..4ad1ecbc080 100644
--- a/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -681,6 +681,15 @@ const DWARFDebugLoc *DWARFContext::getDebugLoc() {
return Loc.get();
}

+Optional<DWARFDebugLoc::LocationList>
+DWARFContext::getOneDebugLocList(uint32_t *Offset) {
+DWARFContext::getOneDebugLocList(uint32_t *Offset, uint64_t CUBaseAddress) {
+ DWARFDebugLoc L;
+ DWARFDataExtractor LocData(*DObj, DObj->getLocSection(), isLittleEndian(),
+ getCompileUnitAtIndex(0)->getAddressByteSize());
+
+ return L.parseOneLocationList(LocData, Offset);
+ return L.parseOneLocationList(LocData, Offset, CUBaseAddress);
+}
+
const DWARFDebugLocDWO *DWARFContext::getDebugLocDWO() {
Expand Down Expand Up @@ -2009,6 +2014,109 @@ index b9dc2151e06..f3c7c81bb10 100644
void DWARFDebugFrame::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
Optional<uint64_t> Offset) const {
if (Offset) {
diff --git a/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
index 02d17b278b4..fe9a339be7a 100644
--- a/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
+++ b/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
@@ -82,47 +82,69 @@ void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
}

Optional<DWARFDebugLoc::LocationList>
-DWARFDebugLoc::parseOneLocationList(DWARFDataExtractor Data, unsigned *Offset) {
+DWARFDebugLoc::parseOneLocationList(DWARFDataExtractor Data, unsigned *Offset,
+ uint64_t CUBaseAddress) {
LocationList LL;
LL.Offset = *Offset;

// 2.6.2 Location Lists
- // A location list entry consists of:
+ //
+ // Each entry in a location list is either a location list entry, a base
+ // address selection entry, or an end of list entry.
+
+ // The applicable base address of a location list entry is determined by the
+ // closest preceding base address selection entry (see below) in the same
+ // location list. If there is no such selection entry, then the applicable
+ // base address defaults to the base address of the compilation unit.
+ uint64_t BaseAddress = CUBaseAddress;
while (true) {
- Entry E;
if (!Data.isValidOffsetForDataOfSize(*Offset, 2 * Data.getAddressSize())) {
llvm::errs() << "Location list overflows the debug_loc section.\n";
return None;
}

- // 1. A beginning address offset. ...
- E.Begin = Data.getRelocatedAddress(Offset);
-
- // 2. An ending address offset. ...
- E.End = Data.getRelocatedAddress(Offset);
-
- // The end of any given location list is marked by an end of list entry,
- // which consists of a 0 for the beginning address offset and a 0 for the
- // ending address offset.
- if (E.Begin == 0 && E.End == 0)
+ const uint64_t Value0 = Data.getRelocatedAddress(Offset);
+ const uint64_t Value1 = Data.getRelocatedAddress(Offset);
+ if (Value0 == (Data.getAddressSize() == 4 ? -1U : -1ULL)) {
+ // A base address selection entry consists of:
+ // 1. The value of the largest representable address offset (for example,
+ // 0xffffffff when the size of an address is 32 bits).
+ // 2. An address, which defines the appropriate base address for use in
+ // interpreting the beginning and ending address offsets of subsequent
+ // entries of the location list.
+ BaseAddress = Value1;
+ } else if (Value0 == 0 && Value1 == 0) {
+ // The end of any given location list is marked by an end of list entry,
+ // which consists of a 0 for the beginning address offset and a 0 for the
+ // ending address offset.
return LL;
-
- if (!Data.isValidOffsetForDataOfSize(*Offset, 2)) {
- llvm::errs() << "Location list overflows the debug_loc section.\n";
- return None;
+ } else {
+ // A location list entry consists of:
+ Entry E;
+
+ // 1. A beginning address offset. ...
+ E.Begin = Value0 + BaseAddress;
+
+ // 2. An ending address offset. ...
+ E.End = Value1 + BaseAddress;
+
+ if (!Data.isValidOffsetForDataOfSize(*Offset, 2)) {
+ llvm::errs() << "Location list overflows the debug_loc section.\n";
+ return None;
+ }
+
+ unsigned Bytes = Data.getU16(Offset);
+ if (!Data.isValidOffsetForDataOfSize(*Offset, Bytes)) {
+ llvm::errs() << "Location list overflows the debug_loc section.\n";
+ return None;
+ }
+ // A single location description describing the location of the object...
+ StringRef str = Data.getData().substr(*Offset, Bytes);
+ *Offset += Bytes;
+ E.Loc.reserve(str.size());
+ std::copy(str.begin(), str.end(), std::back_inserter(E.Loc));
+ LL.Entries.push_back(std::move(E));
}
-
- unsigned Bytes = Data.getU16(Offset);
- if (!Data.isValidOffsetForDataOfSize(*Offset, Bytes)) {
- llvm::errs() << "Location list overflows the debug_loc section.\n";
- return None;
- }
- // A single location description describing the location of the object...
- StringRef str = Data.getData().substr(*Offset, Bytes);
- *Offset += Bytes;
- E.Loc.reserve(str.size());
- std::copy(str.begin(), str.end(), std::back_inserter(E.Loc));
- LL.Entries.push_back(std::move(E));
}
}

diff --git a/lib/DebugInfo/DWARF/DWARFDie.cpp b/lib/DebugInfo/DWARF/DWARFDie.cpp
index 7ae38e6e053..f1fd34af238 100644
--- a/lib/DebugInfo/DWARF/DWARFDie.cpp
Expand Down
23 changes: 6 additions & 17 deletions bolt/src/BinaryFunction.cpp
Expand Up @@ -3970,29 +3970,18 @@ std::set<BinaryData *> BinaryFunction::dataUses(bool OnlyHot) const {
}

DWARFDebugLoc::LocationList BinaryFunction::translateInputToOutputLocationList(
const DWARFDebugLoc::LocationList &InputLL,
BaseAddress BaseAddr) const {
uint64_t BAddr = BaseAddr.Address;
// If the function wasn't changed - there's nothing to update.
DWARFDebugLoc::LocationList InputLL) const {
// If the function hasn't changed - there's nothing to update.
if (!isEmitted() && !BC.HasRelocations) {
if (!BAddr) {
return InputLL;
} else {
auto OutputLL = std::move(InputLL);
for (auto &Entry : OutputLL.Entries) {
Entry.Begin += BAddr;
Entry.End += BAddr;
}
return OutputLL;
}
return InputLL;
}

uint64_t PrevEndAddress = 0;
SmallVectorImpl<char> *PrevLoc = nullptr;
DWARFDebugLoc::LocationList OutputLL;
for (auto &Entry : InputLL.Entries) {
const auto Start = Entry.Begin + BAddr;
const auto End = Entry.End + BAddr;
for (const auto &Entry : InputLL.Entries) {
const auto Start = Entry.Begin;
const auto End = Entry.End;
if (!containsAddress(Start)) {
DEBUG(dbgs() << "BOLT-DEBUG: invalid debug address range detected for "
<< *this << " : [0x" << Twine::utohexstr(Start)
Expand Down
3 changes: 1 addition & 2 deletions bolt/src/BinaryFunction.h
Expand Up @@ -2378,8 +2378,7 @@ class BinaryFunction {
///
/// \p BaseAddress is applied to all addresses in \pInputLL.
DWARFDebugLoc::LocationList translateInputToOutputLocationList(
const DWARFDebugLoc::LocationList &InputLL,
BaseAddress BaseAddr) const;
DWARFDebugLoc::LocationList InputLL) const;

/// Return true if the function is an AArch64 linker inserted veneer
bool isAArch64Veneer() const;
Expand Down
9 changes: 5 additions & 4 deletions bolt/src/DWARFRewriter.cpp
Expand Up @@ -244,9 +244,10 @@ void DWARFRewriter::updateUnitDebugInfo(
Value.getAsSectionOffset().getValue();

uint32_t LLOff = LL.Offset;
auto OptLL =
DIE.getDwarfUnit()->getContext().getOneDebugLocList(&LLOff);
if (!OptLL || OptLL->Entries.empty()) {
auto InputLL =
DIE.getDwarfUnit()->getContext().getOneDebugLocList(
&LLOff, DIE.getDwarfUnit()->getBaseAddress()->Address);
if (!InputLL || InputLL->Entries.empty()) {
errs() << "BOLT-WARNING: empty location list detected at 0x"
<< Twine::utohexstr(LLOff) << " for DIE at 0x"
<< Twine::utohexstr(DIE.getOffset()) << " in CU at 0x"
Expand All @@ -255,7 +256,7 @@ void DWARFRewriter::updateUnitDebugInfo(
} else {
const auto OutputLL =
Function->translateInputToOutputLocationList(
*OptLL, *DIE.getDwarfUnit()->getBaseAddress());
std::move(*InputLL));
DEBUG(if (OutputLL.Entries.empty()) {
dbgs() << "BOLT-DEBUG: location list translated to an empty "
"one at 0x"
Expand Down

0 comments on commit 58b0d9e

Please sign in to comment.