[BOLT] Rewrite of .debug_info section

Summary:
Changed the behavior of how we handle .debug_info section.
Instead of patching it will now rewrite it.
With this approach we are no longer constrained to having new values
 of the same size.
It handles re-writing by treating .debug_info as raw data.
It copies chunks of data between patches, with new data written in
 between.

(cherry picked from FBD32519952)
This commit is contained in:
Alexander Yermolovich 2021-11-15 17:19:24 -08:00 committed by Maksim Panchenko
parent ccc4d4397f
commit 1c2f4bbe99
5 changed files with 680 additions and 126 deletions

View File

@ -156,7 +156,11 @@ public:
void addCURanges(uint64_t CUOffset, DebugAddressRangesVector &&Ranges);
/// Writes .debug_aranges with the added ranges to the MCObjectWriter.
void writeARangesSection(raw_svector_ostream &RangesStream) const;
/// Takes in \p RangesStream to write into, and \p CUMap which maps CU
/// original offsets to new ones.
void
writeARangesSection(raw_svector_ostream &RangesStream,
const std::unordered_map<uint32_t, uint32_t> CUMap) const;
/// Resets the writer to a clear state.
void reset() { CUAddressRanges.clear(); }
@ -387,13 +391,15 @@ private:
uint64_t DWOId{0};
};
enum class PatcherKind { SimpleBinaryPatcher, DebugInfoBinaryPatcher };
/// Abstract interface for classes that apply modifications to a binary string.
class BinaryPatcher {
public:
virtual ~BinaryPatcher() {}
/// Applies in-place modifications to the binary string \p BinaryContents .
/// \p DWPOffset used to correctly patch sections that come from DWP file.
virtual void patchBinary(std::string &BinaryContents, uint32_t DWPOffset) = 0;
/// Applies modifications to the copy of binary string \p BinaryContents .
/// Implementations do not need to guarantee that size of a new \p
/// BinaryContents remains unchanged.
virtual std::string patchBinary(StringRef BinaryContents) = 0;
};
/// Applies simple modifications to a binary string, such as directly replacing
@ -404,8 +410,8 @@ private:
/// Adds a patch to replace the contents of \p ByteSize bytes with the integer
/// \p NewValue encoded in little-endian, with the least-significant byte
/// being written at the offset \p Offset .
void addLEPatch(uint32_t Offset, uint64_t NewValue, size_t ByteSize);
/// being written at the offset \p Offset.
void addLEPatch(uint64_t Offset, uint64_t NewValue, size_t ByteSize);
/// RangeBase for DWO DebugInfo Patcher.
uint64_t RangeBase{0};
@ -417,26 +423,39 @@ private:
public:
virtual ~SimpleBinaryPatcher() {}
virtual PatcherKind getKind() const {
return PatcherKind::SimpleBinaryPatcher;
}
static bool classof(const SimpleBinaryPatcher *Patcher) {
return Patcher->getKind() == PatcherKind::SimpleBinaryPatcher;
}
/// Adds a patch to replace the contents of the binary string starting at the
/// specified \p Offset with the string \p NewValue.
void addBinaryPatch(uint32_t Offset, const std::string &NewValue);
/// The \p OldValueSize is the size of the old value that will be replaced.
void addBinaryPatch(uint64_t Offset, std::string &&NewValue,
uint32_t OldValueSize);
/// Adds a patch to replace the contents of a single byte of the string, at
/// the offset \p Offset, with the value \Value .
void addBytePatch(uint32_t Offset, uint8_t Value);
/// the offset \p Offset, with the value \Value.
void addBytePatch(uint64_t Offset, uint8_t Value);
/// Adds a patch to put the integer \p NewValue encoded as a 64-bit
/// little-endian value at offset \p Offset.
void addLE64Patch(uint32_t Offset, uint64_t NewValue);
virtual void addLE64Patch(uint64_t Offset, uint64_t NewValue);
/// Adds a patch to put the integer \p NewValue encoded as a 32-bit
/// little-endian value at offset \p Offset.
void addLE32Patch(uint32_t Offset, uint32_t NewValue);
/// The \p OldValueSize is the size of the old value that will be replaced.
virtual void addLE32Patch(uint64_t Offset, uint32_t NewValue,
uint32_t OldValueSize = 4);
/// Add a patch at \p Offset with \p Value using unsigned LEB128 encoding with
/// size \p Size. \p Size should not be less than a minimum number of bytes
/// needed to encode \p Value.
void addUDataPatch(uint32_t Offset, uint64_t Value, uint64_t Size);
/// size \p OldValueSize.
/// The \p OldValueSize is the size of the old value that will be replaced.
virtual void addUDataPatch(uint64_t Offset, uint64_t Value,
uint32_t OldValueSize);
/// Setting DW_AT_GNU_ranges_base
void setRangeBase(uint64_t Rb) {
@ -453,8 +472,193 @@ public:
/// Proxy for if we broke up low_pc/high_pc to ranges.
bool getWasRangBasedUsed() const { return WasRangeBaseUsed; }
virtual void patchBinary(std::string &BinaryContents,
uint32_t DWPOffset) override;
/// This function takes in \p BinaryContents, applies patches to it and
/// returns an updated string.
virtual std::string patchBinary(StringRef BinaryContents) override;
};
class DebugInfoBinaryPatcher : public SimpleBinaryPatcher {
public:
enum class DebugPatchKind {
PatchBaseClass,
PatchValue32,
PatchValue64to32,
PatchValue64,
PatchValueVariable,
ReferencePatchValue,
DWARFUnitOffsetBaseLabel,
DestinationReferenceLabel
};
struct Patch {
Patch(uint32_t O, DebugPatchKind K) : Offset(O), Kind(K) {}
DebugPatchKind getKind() const { return Kind; }
static bool classof(const Patch *Writer) {
return Writer->getKind() == DebugPatchKind::PatchBaseClass;
}
uint32_t Offset;
DebugPatchKind Kind;
};
struct DebugPatch64to32 : public Patch {
DebugPatch64to32(uint32_t O, uint32_t V)
: Patch(O, DebugPatchKind::PatchValue64to32) {
Value = V;
}
DebugPatchKind getKind() const { return Kind; }
static bool classof(const Patch *Writer) {
return Writer->getKind() == DebugPatchKind::PatchValue64to32;
}
uint32_t Value;
};
struct DebugPatch32 : public Patch {
DebugPatch32(uint32_t O, uint32_t V)
: Patch(O, DebugPatchKind::PatchValue32) {
Value = V;
}
DebugPatchKind getKind() const { return Kind; }
static bool classof(const Patch *Writer) {
return Writer->getKind() == DebugPatchKind::PatchValue32;
}
uint32_t Value;
};
struct DebugPatch64 : public Patch {
DebugPatch64(uint32_t O, uint64_t V)
: Patch(O, DebugPatchKind::PatchValue64) {
Value = V;
}
static bool classof(const Patch *Writer) {
return Writer->getKind() == DebugPatchKind::PatchValue64;
}
uint64_t Value;
};
struct DebugPatchVariableSize : public Patch {
DebugPatchVariableSize(uint32_t O, uint32_t OVS, uint32_t V)
: Patch(O, DebugPatchKind::PatchValueVariable) {
OldValueSize = OVS;
Value = V;
}
static bool classof(const Patch *Writer) {
return Writer->getKind() == DebugPatchKind::PatchValueVariable;
}
uint32_t OldValueSize;
uint32_t Value;
};
struct DebugPatchReference : public Patch {
struct Data {
uint32_t OldValueSize : 4;
uint32_t DirectRelative : 1;
uint32_t IndirectRelative : 1;
uint32_t DirectAbsolute : 1;
};
DebugPatchReference(uint32_t O, uint32_t OVS, uint32_t DO, dwarf::Form F)
: Patch(O, DebugPatchKind::ReferencePatchValue) {
PatchInfo.OldValueSize = OVS;
DestinationOffset = DO;
PatchInfo.DirectRelative =
F == dwarf::DW_FORM_ref1 || F == dwarf::DW_FORM_ref2 ||
F == dwarf::DW_FORM_ref4 || F == dwarf::DW_FORM_ref8;
PatchInfo.IndirectRelative = F == dwarf::DW_FORM_ref_udata;
PatchInfo.DirectAbsolute = F == dwarf::DW_FORM_ref_addr;
}
static bool classof(const Patch *Writer) {
return Writer->getKind() == DebugPatchKind::ReferencePatchValue;
}
Data PatchInfo;
uint32_t DestinationOffset;
};
struct DWARFUnitOffsetBaseLabel : public Patch {
DWARFUnitOffsetBaseLabel(uint32_t O)
: Patch(O, DebugPatchKind::DWARFUnitOffsetBaseLabel) {}
static bool classof(const Patch *Writer) {
return Writer->getKind() == DebugPatchKind::DWARFUnitOffsetBaseLabel;
}
};
struct DestinationReferenceLabel : public Patch {
DestinationReferenceLabel() = delete;
DestinationReferenceLabel(uint32_t O)
: Patch(O, DebugPatchKind::DestinationReferenceLabel) {}
static bool classof(const Patch *Writer) {
return Writer->getKind() == DebugPatchKind::DestinationReferenceLabel;
}
};
virtual PatcherKind getKind() const override {
return PatcherKind::DebugInfoBinaryPatcher;
}
static bool classof(const SimpleBinaryPatcher *Patcher) {
return Patcher->getKind() == PatcherKind::DebugInfoBinaryPatcher;
}
/// This function takes in \p BinaryContents, and re-writes it with new
/// patches inserted into it. It returns an updated string.
virtual std::string patchBinary(StringRef BinaryContents) override;
/// Adds a patch to put the integer \p NewValue encoded as a 64-bit
/// little-endian value at offset \p Offset.
virtual void addLE64Patch(uint64_t Offset, uint64_t NewValue) override;
/// Adds a patch to put the integer \p NewValue encoded as a 32-bit
/// little-endian value at offset \p Offset.
/// The \p OldValueSize is the size of the old value that will be replaced.
virtual void addLE32Patch(uint64_t Offset, uint32_t NewValue,
uint32_t OldValueSize = 4) override;
/// Add a patch at \p Offset with \p Value using unsigned LEB128 encoding with
/// size \p OldValueSize.
/// The \p OldValueSize is the size of the old value that will be replaced.
virtual void addUDataPatch(uint64_t Offset, uint64_t Value,
uint32_t OldValueSize) override;
/// Adds a label \p Offset for DWARF UNit.
/// Used to recompute relative references.
void addUnitBaseOffsetLabel(uint64_t Offset);
/// Adds a Label for destination. Either relative or explicit reference.
void addDestinationReferenceLabel(uint64_t Offset);
/// Adds a reference at \p Offset to patch with new fully resolved \p
/// DestinationOffset . The \p OldValueSize is the original size of entry in
/// the DIE. The \p Form is the form of the entry.
void addReferenceToPatch(uint64_t Offset, uint32_t DestinationOffset,
uint32_t OldValueSize, dwarf::Form Form);
/// Clears unordered set for DestinationLabels.
void clearDestinationLabels() { DestinationLabels.clear(); }
/// Sets DWARF Units offset, \p DWPOffset , within DWP file.
void setDWPOffset(uint64_t DWPOffset) { DWPUnitOffset = DWPOffset; }
/// When this function is invoked all of the DebugInfo Patches must be done.
/// Returns a map of old CU offsets to new ones.
std::unordered_map<uint32_t, uint32_t> computeNewOffsets();
private:
uint64_t DWPUnitOffset{0};
uint32_t ChangeInSize{0};
std::vector<std::unique_ptr<Patch>> DebugPatches;
/// Mutex used for parallel processing of debug info.
std::mutex WriterMutex;
/// Stores fully resolved addresses of DIEs that are being referenced.
std::unordered_set<uint32_t> DestinationLabels;
/// Map of original debug info references to new ones.
std::unordered_map<uint32_t, uint32_t> OldToNewOffset;
};
/// Class to facilitate modifying and writing abbreviation sections.

View File

@ -70,7 +70,7 @@ class DWARFRewriter {
/// Update debug info for all DIEs in \p Unit.
void updateUnitDebugInfo(uint64_t CUIndex, DWARFUnit &Unit,
SimpleBinaryPatcher &DebugInfoPatcher,
DebugInfoBinaryPatcher &DebugInfoPatcher,
DebugAbbrevWriter &AbbrevWriter,
Optional<uint64_t> RangesBase = None);
@ -93,7 +93,7 @@ class DWARFRewriter {
makeFinalLocListsSection(SimpleBinaryPatcher &DebugInfoPatcher);
/// Finalize debug sections in the main binary.
void finalizeDebugSections(SimpleBinaryPatcher &DebugInfoPatcher);
void finalizeDebugSections(DebugInfoBinaryPatcher &DebugInfoPatcher);
/// Patches the binary for DWARF address ranges (e.g. in functions and lexical
/// blocks) to be updated.
@ -203,7 +203,8 @@ public:
/// Returns a DWO Debug Info Patcher for DWO ID.
/// Creates a new instance if it does not already exist.
SimpleBinaryPatcher *getBinaryDWODebugInfoPatcher(uint64_t DwoId) {
return getBinaryDWOPatcherHelper<DebugInfoDWOPatchers, SimpleBinaryPatcher>(
return getBinaryDWOPatcherHelper<DebugInfoDWOPatchers,
DebugInfoBinaryPatcher>(
BinaryDWODebugInfoPatchers, DwoId);
}

View File

@ -23,12 +23,13 @@
#include <cassert>
#include <cstdint>
#include <limits>
#include <unordered_map>
#define DEBUG_TYPE "bolt-debug-info"
namespace opts {
extern llvm::cl::opt<unsigned> Verbosity;
}
} // namespace opts
namespace llvm {
namespace bolt {
@ -37,6 +38,15 @@ const DebugLineTableRowRef DebugLineTableRowRef::NULL_ROW{0, 0};
namespace {
LLVM_ATTRIBUTE_UNUSED
static void printLE64(const std::string &S) {
for (uint32_t I = 0, Size = S.size(); I < Size; ++I) {
errs() << Twine::utohexstr(S[I]);
errs() << Twine::utohexstr((int8_t)S[I]);
}
errs() << "\n";
}
// Writes address ranges to Writer as pairs of 64-bit (address, size).
// If RelativeRange is true, assumes the address range to be written must be of
// the form (begin address, range size), otherwise (begin address, end address).
@ -110,7 +120,8 @@ void DebugARangesSectionWriter::addCURanges(uint64_t CUOffset,
}
void DebugARangesSectionWriter::writeARangesSection(
raw_svector_ostream &RangesStream) const {
raw_svector_ostream &RangesStream,
const std::unordered_map<uint32_t, uint32_t> CUMap) const {
// For reference on the format of the .debug_aranges section, see the DWARF4
// specification, section 6.1.4 Lookup by Address
// http://www.dwarfstd.org/doc/DWARF4.pdf
@ -134,8 +145,10 @@ void DebugARangesSectionWriter::writeARangesSection(
support::endian::write(RangesStream, static_cast<uint16_t>(2),
support::little);
assert(CUMap.count(Offset) && "Original CU offset is not found in CU Map");
// Header field #3: debug info offset of the correspondent compile unit.
support::endian::write(RangesStream, static_cast<uint32_t>(Offset),
support::endian::write(RangesStream,
static_cast<uint32_t>(CUMap.find(Offset)->second),
support::little);
// Header field #4: address size.
@ -349,53 +362,297 @@ void DebugLoclistWriter::finalize(uint64_t SectionOffset,
DebugAddrWriter *DebugLoclistWriter::AddrWriter = nullptr;
void SimpleBinaryPatcher::addBinaryPatch(uint32_t Offset,
const std::string &NewValue) {
Patches.emplace_back(Offset, NewValue);
void DebugInfoBinaryPatcher::addUnitBaseOffsetLabel(uint64_t Offset) {
Offset -= DWPUnitOffset;
std::lock_guard<std::mutex> Lock(WriterMutex);
DebugPatches.emplace_back(std::make_unique<DWARFUnitOffsetBaseLabel>(Offset));
}
void SimpleBinaryPatcher::addBytePatch(uint32_t Offset, uint8_t Value) {
Patches.emplace_back(Offset, std::string(1, Value));
void DebugInfoBinaryPatcher::addDestinationReferenceLabel(uint64_t Offset) {
Offset -= DWPUnitOffset;
std::lock_guard<std::mutex> Lock(WriterMutex);
auto RetVal = DestinationLabels.insert(Offset);
if (!RetVal.second)
return;
DebugPatches.emplace_back(
std::make_unique<DestinationReferenceLabel>(Offset));
}
void SimpleBinaryPatcher::addLEPatch(uint32_t Offset, uint64_t NewValue,
size_t ByteSize) {
void DebugInfoBinaryPatcher::addReferenceToPatch(uint64_t Offset,
uint32_t DestinationOffset,
uint32_t OldValueSize,
dwarf::Form Form) {
Offset -= DWPUnitOffset;
DestinationOffset -= DWPUnitOffset;
std::lock_guard<std::mutex> Lock(WriterMutex);
DebugPatches.emplace_back(std::make_unique<DebugPatchReference>(
Offset, OldValueSize, DestinationOffset, Form));
}
void DebugInfoBinaryPatcher::addUDataPatch(uint64_t Offset, uint64_t NewValue,
uint32_t OldValueSize) {
Offset -= DWPUnitOffset;
std::lock_guard<std::mutex> Lock(WriterMutex);
DebugPatches.emplace_back(
std::make_unique<DebugPatchVariableSize>(Offset, OldValueSize, NewValue));
}
void DebugInfoBinaryPatcher::addLE64Patch(uint64_t Offset, uint64_t NewValue) {
Offset -= DWPUnitOffset;
std::lock_guard<std::mutex> Lock(WriterMutex);
DebugPatches.emplace_back(std::make_unique<DebugPatch64>(Offset, NewValue));
}
void DebugInfoBinaryPatcher::addLE32Patch(uint64_t Offset, uint32_t NewValue,
uint32_t OldValueSize) {
Offset -= DWPUnitOffset;
std::lock_guard<std::mutex> Lock(WriterMutex);
if (OldValueSize == 4)
DebugPatches.emplace_back(std::make_unique<DebugPatch32>(Offset, NewValue));
else
DebugPatches.emplace_back(
std::make_unique<DebugPatch64to32>(Offset, NewValue));
}
void SimpleBinaryPatcher::addBinaryPatch(uint64_t Offset,
std::string &&NewValue,
uint32_t OldValueSize) {
Patches.emplace_back(Offset, std::move(NewValue));
}
void SimpleBinaryPatcher::addBytePatch(uint64_t Offset, uint8_t Value) {
auto Str = std::string(1, Value);
Patches.emplace_back(Offset, std::move(Str));
}
static std::string encodeLE(size_t ByteSize, uint64_t NewValue) {
std::string LE64(ByteSize, 0);
for (size_t I = 0; I < ByteSize; ++I) {
LE64[I] = NewValue & 0xff;
NewValue >>= 8;
}
Patches.emplace_back(Offset, LE64);
return LE64;
}
void SimpleBinaryPatcher::addUDataPatch(uint32_t Offset, uint64_t Value,
uint64_t Size) {
void SimpleBinaryPatcher::addLEPatch(uint64_t Offset, uint64_t NewValue,
size_t ByteSize) {
Patches.emplace_back(Offset, encodeLE(ByteSize, NewValue));
}
void SimpleBinaryPatcher::addUDataPatch(uint64_t Offset, uint64_t Value,
uint32_t OldValueSize) {
std::string Buff;
raw_string_ostream OS(Buff);
encodeULEB128(Value, OS, Size);
encodeULEB128(Value, OS, OldValueSize);
Patches.emplace_back(Offset, OS.str());
Patches.emplace_back(Offset, std::move(Buff));
}
void SimpleBinaryPatcher::addLE64Patch(uint32_t Offset, uint64_t NewValue) {
void SimpleBinaryPatcher::addLE64Patch(uint64_t Offset, uint64_t NewValue) {
addLEPatch(Offset, NewValue, 8);
}
void SimpleBinaryPatcher::addLE32Patch(uint32_t Offset, uint32_t NewValue) {
void SimpleBinaryPatcher::addLE32Patch(uint64_t Offset, uint32_t NewValue,
uint32_t OldValueSize) {
addLEPatch(Offset, NewValue, 4);
}
void SimpleBinaryPatcher::patchBinary(std::string &BinaryContents,
uint32_t DWPOffset = 0) {
std::string SimpleBinaryPatcher::patchBinary(StringRef BinaryContents) {
std::string BinaryContentsStr = std::string(BinaryContents);
for (const auto &Patch : Patches) {
uint32_t Offset = Patch.first - DWPOffset;
uint32_t Offset = Patch.first;
const std::string &ByteSequence = Patch.second;
assert(Offset + ByteSequence.size() <= BinaryContents.size() &&
"Applied patch runs over binary size.");
for (uint64_t I = 0, Size = ByteSequence.size(); I < Size; ++I) {
BinaryContents[Offset + I] = ByteSequence[I];
BinaryContentsStr[Offset + I] = ByteSequence[I];
}
}
return BinaryContentsStr;
}
std::unordered_map<uint32_t, uint32_t>
DebugInfoBinaryPatcher::computeNewOffsets() {
std::unordered_map<uint32_t, uint32_t> CUMap;
std::sort(
DebugPatches.begin(), DebugPatches.end(),
[](const std::unique_ptr<Patch> &V1, const std::unique_ptr<Patch> &V2) {
return V1.get()->Offset < V2.get()->Offset;
});
// Calculating changes in .debug_info size from Patches to build a map of old
// to updated reference destination offsets.
for (std::unique_ptr<Patch> &PatchBase : DebugPatches) {
Patch *P = PatchBase.get();
switch (P->Kind) {
default:
continue;
case DebugPatchKind::PatchValue64to32: {
ChangeInSize -= 4;
break;
}
case DebugPatchKind::PatchValueVariable: {
DebugPatchVariableSize *DPV =
reinterpret_cast<DebugPatchVariableSize *>(P);
std::string Temp;
raw_string_ostream OS(Temp);
encodeULEB128(DPV->Value, OS);
ChangeInSize += Temp.size() - DPV->OldValueSize;
break;
}
case DebugPatchKind::DestinationReferenceLabel: {
DestinationReferenceLabel *DRL =
reinterpret_cast<DestinationReferenceLabel *>(P);
OldToNewOffset[DRL->Offset] = DRL->Offset + ChangeInSize;
break;
}
case DebugPatchKind::ReferencePatchValue: {
// This doesn't look to be a common case, so will always encode as 4 bytes
// to reduce algorithmic complexity.
DebugPatchReference *RDP = reinterpret_cast<DebugPatchReference *>(P);
if (RDP->PatchInfo.IndirectRelative) {
ChangeInSize += 4 - RDP->PatchInfo.OldValueSize;
assert(RDP->PatchInfo.OldValueSize <= 4 &&
"Variable encoding reference greater than 4 bytes.");
}
break;
}
case DebugPatchKind::DWARFUnitOffsetBaseLabel: {
DWARFUnitOffsetBaseLabel *BaseLabel =
reinterpret_cast<DWARFUnitOffsetBaseLabel *>(P);
uint32_t CUOffset = BaseLabel->Offset;
uint32_t CUOffsetUpdate = CUOffset + ChangeInSize;
CUMap[CUOffset] = CUOffsetUpdate;
}
}
}
return CUMap;
}
std::string DebugInfoBinaryPatcher::patchBinary(StringRef BinaryContents) {
std::string NewBinaryContents;
NewBinaryContents.reserve(BinaryContents.size() + ChangeInSize);
uint32_t StartOffset = 0;
uint32_t DwarfUnitBaseOffset = 0;
uint32_t OldValueSize = 0;
uint32_t Offset = 0;
std::string ByteSequence;
std::vector<std::pair<uint32_t, uint32_t>> LengthPatches;
// Wasting one entry to avoid checks for first.
LengthPatches.push_back({0, 0});
// Applying all the patches replacing current entry.
// This might change the size of .debug_info section.
for (const std::unique_ptr<Patch> &PatchBase : DebugPatches) {
Patch *P = PatchBase.get();
switch (P->Kind) {
default:
continue;
case DebugPatchKind::ReferencePatchValue: {
DebugPatchReference *RDP = reinterpret_cast<DebugPatchReference *>(P);
uint32_t DestinationOffset = RDP->DestinationOffset;
assert(OldToNewOffset.count(DestinationOffset) &&
"Destination Offset for reference not updated.");
uint32_t UpdatedOffset = OldToNewOffset[DestinationOffset];
Offset = RDP->Offset;
OldValueSize = RDP->PatchInfo.OldValueSize;
if (RDP->PatchInfo.DirectRelative) {
UpdatedOffset -= DwarfUnitBaseOffset;
ByteSequence = encodeLE(OldValueSize, UpdatedOffset);
// In theory reference for DW_FORM_ref{1,2,4,8} can be right on the edge
// and overflow if later debug information grows.
if (ByteSequence.size() > OldValueSize)
errs() << "BOLT-ERROR: Relative reference of size "
<< Twine::utohexstr(OldValueSize)
<< " overflows with the new encoding.\n";
} else if (RDP->PatchInfo.DirectAbsolute) {
ByteSequence = encodeLE(OldValueSize, UpdatedOffset);
} else if (RDP->PatchInfo.IndirectRelative) {
UpdatedOffset -= DwarfUnitBaseOffset;
ByteSequence.clear();
raw_string_ostream OS(ByteSequence);
encodeULEB128(UpdatedOffset, OS, 4);
} else {
llvm_unreachable("Invalid Reference form.");
}
break;
}
case DebugPatchKind::PatchValue32: {
DebugPatch32 *P32 = reinterpret_cast<DebugPatch32 *>(P);
Offset = P32->Offset;
OldValueSize = 4;
ByteSequence = encodeLE(4, P32->Value);
break;
}
case DebugPatchKind::PatchValue64to32: {
DebugPatch64to32 *P64to32 = reinterpret_cast<DebugPatch64to32 *>(P);
Offset = P64to32->Offset;
OldValueSize = 8;
ByteSequence = encodeLE(4, P64to32->Value);
break;
}
case DebugPatchKind::PatchValueVariable: {
DebugPatchVariableSize *PV =
reinterpret_cast<DebugPatchVariableSize *>(P);
Offset = PV->Offset;
OldValueSize = PV->OldValueSize;
ByteSequence.clear();
raw_string_ostream OS(ByteSequence);
encodeULEB128(PV->Value, OS);
break;
}
case DebugPatchKind::PatchValue64: {
DebugPatch64 *P64 = reinterpret_cast<DebugPatch64 *>(P);
Offset = P64->Offset;
OldValueSize = 8;
ByteSequence = encodeLE(8, P64->Value);
break;
}
case DebugPatchKind::DWARFUnitOffsetBaseLabel: {
DWARFUnitOffsetBaseLabel *BaseLabel =
reinterpret_cast<DWARFUnitOffsetBaseLabel *>(P);
Offset = BaseLabel->Offset;
OldValueSize = 0;
ByteSequence.clear();
auto &Patch = LengthPatches.back();
// Length to copy between last patch entry and next compile unit.
uint32_t RemainingLength = Offset - StartOffset;
uint32_t NewCUOffset = NewBinaryContents.size() + RemainingLength;
DwarfUnitBaseOffset = NewCUOffset;
// Length of previous CU = This CU Offset - sizeof(length) - last CU
// Offset.
Patch.second = NewCUOffset - 4 - Patch.first;
LengthPatches.push_back({NewCUOffset, 0});
break;
}
}
assert(Offset + ByteSequence.size() <= BinaryContents.size() &&
"Applied patch runs over binary size.");
uint32_t Length = Offset - StartOffset;
NewBinaryContents.append(BinaryContents.substr(StartOffset, Length).data(),
Length);
NewBinaryContents.append(ByteSequence.data(), ByteSequence.size());
StartOffset = Offset + OldValueSize;
}
uint32_t Length = BinaryContents.size() - StartOffset;
NewBinaryContents.append(BinaryContents.substr(StartOffset, Length).data(),
Length);
DebugPatches.clear();
// Patching lengths of CUs
auto &Patch = LengthPatches.back();
Patch.second = NewBinaryContents.size() - 4 - Patch.first;
for (uint32_t J = 1, Size = LengthPatches.size(); J < Size; ++J) {
const auto &Patch = LengthPatches[J];
ByteSequence = encodeLE(4, Patch.second);
Offset = Patch.first;
for (uint64_t I = 0, Size = ByteSequence.size(); I < Size; ++I)
NewBinaryContents[Offset + I] = ByteSequence[I];
}
return NewBinaryContents;
}
void DebugStrWriter::create() {
@ -467,14 +724,14 @@ void DebugAbbrevWriter::addUnitAbbreviations(DWARFUnit &Unit) {
// FIXME: if we had a full access to DWARFDebugAbbrev::AbbrDeclSets
// we wouldn't have to build our own sorted list for the quick lookup.
if (AbbrevSetOffsets.empty()) {
llvm::for_each(
for_each(
*Unit.getContext().getDebugAbbrev(),
[&](const std::pair<uint64_t, DWARFAbbreviationDeclarationSet> &P) {
AbbrevSetOffsets.push_back(P.first);
});
llvm::sort(AbbrevSetOffsets);
sort(AbbrevSetOffsets);
}
auto It = llvm::upper_bound(AbbrevSetOffsets, StartOffset);
auto It = upper_bound(AbbrevSetOffsets, StartOffset);
const uint64_t EndOffset =
It == AbbrevSetOffsets.end() ? AbbrevSectionContents.size() : *It;
AbbrevContents = AbbrevSectionContents.slice(StartOffset, EndOffset);

View File

@ -54,15 +54,53 @@ static void printDie(const DWARFDie &DIE) {
struct AttrInfo {
DWARFFormValue V;
uint64_t Offset;
uint32_t Size; // Size of the attribute.
};
/// Finds attributes FormValue and Offset.
///
/// \param DIE die to look up in.
/// \param Index the attribute index to extract.
/// \return an optional AttrInfo with DWARFFormValue and Offset.
static Optional<AttrInfo>
findAttributeInfo(const DWARFDie DIE,
const DWARFAbbreviationDeclaration *AbbrevDecl,
uint32_t Index) {
const DWARFUnit &U = *DIE.getDwarfUnit();
uint64_t Offset =
AbbrevDecl->getAttributeOffsetFromIndex(Index, DIE.getOffset(), U);
Optional<DWARFFormValue> Value =
AbbrevDecl->getAttributeValueFromOffset(Index, Offset, U);
if (!Value)
return None;
// AttributeSpec
const DWARFAbbreviationDeclaration::AttributeSpec *AttrVal =
AbbrevDecl->attributes().begin() + Index;
uint32_t ValSize = 0;
Optional<int64_t> ValSizeOpt = AttrVal->getByteSize(U);
if (ValSizeOpt) {
ValSize = static_cast<uint32_t>(*ValSizeOpt);
} else {
DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
uint64_t NewOffset = Offset;
DWARFFormValue::skipValue(Value->getForm(), DebugInfoData, &NewOffset,
U.getFormParams());
// This includes entire size of the entry, which might not be just the
// encoding part. For example for DW_AT_loc it will include expression
// location.
ValSize = NewOffset - Offset;
}
return AttrInfo{*Value, Offset, ValSize};
}
/// Finds attributes FormValue and Offset.
///
/// \param DIE die to look up in.
/// \param Attr the attribute to extract.
/// \return an optional AttrInfo with DWARFFormValue and Offset.
Optional<AttrInfo> findAttributeInfo(const DWARFDie DIE,
dwarf::Attribute Attr) {
static Optional<AttrInfo> findAttributeInfo(const DWARFDie DIE,
dwarf::Attribute Attr) {
if (!DIE.isValid())
return None;
const DWARFAbbreviationDeclaration *AbbrevDecl =
@ -72,14 +110,7 @@ Optional<AttrInfo> findAttributeInfo(const DWARFDie DIE,
Optional<uint32_t> Index = AbbrevDecl->findAttributeIndex(Attr);
if (!Index)
return None;
const DWARFUnit &U = *DIE.getDwarfUnit();
uint64_t Offset =
AbbrevDecl->getAttributeOffsetFromIndex(*Index, DIE.getOffset(), U);
Optional<DWARFFormValue> Value =
AbbrevDecl->getAttributeValueFromOffset(*Index, Offset, U);
if (!Value)
return None;
return AttrInfo{*Value, Offset};
return findAttributeInfo(DIE, AbbrevDecl, *Index);
}
using namespace llvm;
@ -165,9 +196,8 @@ void DWARFRewriter::updateDebugInfo() {
if (!DebugInfo)
return;
DebugInfo->registerPatcher(std::make_unique<SimpleBinaryPatcher>());
auto *DebugInfoPatcher =
static_cast<SimpleBinaryPatcher *>(DebugInfo->getPatcher());
static_cast<DebugInfoBinaryPatcher *>(DebugInfo->getPatcher());
ARangesSectionWriter = std::make_unique<DebugARangesSectionWriter>();
RangesSectionWriter = std::make_unique<DebugRangesSectionWriter>();
@ -203,7 +233,8 @@ void DWARFRewriter::updateDebugInfo() {
std::string ObjectName = getDWOName(Unit, &NameToIndexMap, DWOIdToName);
uint32_t NewOffset = StrWriter->addString(ObjectName.c_str());
DebugInfoPatcher->addLE32Patch(AttrInfoVal->Offset, NewOffset);
DebugInfoPatcher->addLE32Patch(AttrInfoVal->Offset, NewOffset,
AttrInfoVal->Size);
AttrInfoVal = findAttributeInfo(DIE, dwarf::DW_AT_comp_dir);
(void)AttrInfoVal;
@ -211,7 +242,8 @@ void DWARFRewriter::updateDebugInfo() {
if (!opts::DwarfOutputPath.empty()) {
uint32_t NewOffset = StrWriter->addString(opts::DwarfOutputPath.c_str());
DebugInfoPatcher->addLE32Patch(AttrInfoVal->Offset, NewOffset);
DebugInfoPatcher->addLE32Patch(AttrInfoVal->Offset, NewOffset,
AttrInfoVal->Size);
}
};
@ -234,18 +266,26 @@ void DWARFRewriter::updateDebugInfo() {
"LocList writer for DWO unit already exists.");
LocListWritersByCU[*DWOId] =
std::make_unique<DebugLoclistWriter>(&BC, *DWOId);
SimpleBinaryPatcher *DwoDebugInfoPatcher =
getBinaryDWODebugInfoPatcher(*DWOId);
DebugInfoBinaryPatcher *DwoDebugInfoPatcher =
llvm::cast<DebugInfoBinaryPatcher>(
getBinaryDWODebugInfoPatcher(*DWOId));
RangesBase = RangesSectionWriter->getSectionOffset();
DWARFContext *DWOCtx = BC.getDWOContext();
// Setting this CU offset with DWP to normalize DIE offsets to uint32_t
if (DWOCtx && !DWOCtx->getCUIndex().getRows().empty())
DwoDebugInfoPatcher->setDWPOffset((*SplitCU)->getOffset());
DwoDebugInfoPatcher->setRangeBase(*RangesBase);
DwoDebugInfoPatcher->addUnitBaseOffsetLabel((*SplitCU)->getOffset());
DebugAbbrevWriter *DWOAbbrevWriter =
createBinaryDWOAbbrevWriter((*SplitCU)->getContext(), *DWOId);
updateUnitDebugInfo(*DWOId, *(*SplitCU), *DwoDebugInfoPatcher,
*DWOAbbrevWriter);
DwoDebugInfoPatcher->clearDestinationLabels();
if (!DwoDebugInfoPatcher->getWasRangBasedUsed())
RangesBase = None;
}
DebugInfoPatcher->addUnitBaseOffsetLabel(Unit->getOffset());
updateUnitDebugInfo(CUIndex, *Unit, *DebugInfoPatcher, *AbbrevWriter,
RangesBase);
};
@ -264,6 +304,7 @@ void DWARFRewriter::updateDebugInfo() {
ThreadPool.wait();
}
DebugInfoPatcher->clearDestinationLabels();
flushPendingRanges(*DebugInfoPatcher);
finalizeDebugSections(*DebugInfoPatcher);
@ -276,10 +317,9 @@ void DWARFRewriter::updateDebugInfo() {
updateGdbIndexSection();
}
void DWARFRewriter::updateUnitDebugInfo(uint64_t CUIndex, DWARFUnit &Unit,
SimpleBinaryPatcher &DebugInfoPatcher,
DebugAbbrevWriter &AbbrevWriter,
Optional<uint64_t> RangesBase) {
void DWARFRewriter::updateUnitDebugInfo(
uint64_t CUIndex, DWARFUnit &Unit, DebugInfoBinaryPatcher &DebugInfoPatcher,
DebugAbbrevWriter &AbbrevWriter, Optional<uint64_t> RangesBase) {
// Cache debug ranges so that the offset for identical ranges could be reused.
std::map<DebugAddressRangesVector, uint64_t> CachedRanges;
@ -315,7 +355,7 @@ void DWARFRewriter::updateUnitDebugInfo(uint64_t CUIndex, DWARFUnit &Unit,
consumeError(ModuleRangesOrError.takeError());
break;
}
DWARFAddressRangesVector ModuleRanges = *ModuleRangesOrError;
DWARFAddressRangesVector &ModuleRanges = *ModuleRangesOrError;
DebugAddressRangesVector OutputRanges =
BC.translateModuleAddressRanges(ModuleRanges);
const uint64_t RangesSectionOffset =
@ -561,8 +601,39 @@ void DWARFRewriter::updateUnitDebugInfo(uint64_t CUIndex, DWARFUnit &Unit,
}
}
}
}
// Handling references.
assert(DIE.isValid() && "Invalid DIE.");
const DWARFAbbreviationDeclaration *AbbrevDecl =
DIE.getAbbreviationDeclarationPtr();
if (!AbbrevDecl)
continue;
uint32_t Index = 0;
for (const DWARFAbbreviationDeclaration::AttributeSpec &Decl :
AbbrevDecl->attributes()) {
switch (Decl.Form) {
default:
break;
case dwarf::DW_FORM_ref1:
case dwarf::DW_FORM_ref2:
case dwarf::DW_FORM_ref4:
case dwarf::DW_FORM_ref8:
case dwarf::DW_FORM_ref_udata:
case dwarf::DW_FORM_ref_addr: {
Optional<AttrInfo> AttrVal = findAttributeInfo(DIE, AbbrevDecl, Index);
uint32_t DestinationAddress =
AttrVal->V.getRawUValue() +
(Decl.Form == dwarf::DW_FORM_ref_addr ? 0 : Unit.getOffset());
DebugInfoPatcher.addReferenceToPatch(
AttrVal->Offset, DestinationAddress, AttrVal->Size, Decl.Form);
// We can have only one reference, and it can be backward one.
DebugInfoPatcher.addDestinationReferenceLabel(DestinationAddress);
break;
}
}
++Index;
}
}
if (DIEOffset > NextCUOffset)
errs() << "BOLT-WARNING: corrupt DWARF detected at 0x"
<< Twine::utohexstr(Unit.getOffset()) << '\n';
@ -595,7 +666,8 @@ void DWARFRewriter::updateDWARFObjectAddressRanges(
findAttributeInfo(DIE, dwarf::DW_AT_GNU_ranges_base);
if (RangesBaseAttrInfo) {
DebugInfoPatcher.addLE32Patch(RangesBaseAttrInfo->Offset,
static_cast<uint32_t>(*RangesBase));
static_cast<uint32_t>(*RangesBase),
RangesBaseAttrInfo->Size);
RangesBase = None;
}
}
@ -608,7 +680,8 @@ void DWARFRewriter::updateDWARFObjectAddressRanges(
std::lock_guard<std::mutex> Lock(DebugInfoPatcherMutex);
DebugInfoPatcher.addLE32Patch(
AttrVal->Offset, DebugRangesOffset - DebugInfoPatcher.getRangeBase());
AttrVal->Offset, DebugRangesOffset - DebugInfoPatcher.getRangeBase(),
AttrVal->Size);
if (!RangesBase)
return;
@ -656,6 +729,15 @@ void DWARFRewriter::updateLineTableOffsets(const MCAsmLayout &Layout) {
BC.DwCtx->getNumTypeUnits() == 0) &&
"Was not able to retrieve Debug Types section.");
// We will be re-writing .debug_info so relocation mechanism doesn't work for
// Debug Info Patcher.
DebugInfoBinaryPatcher *DebugInfoPatcher = nullptr;
if (BC.DwCtx->getNumCompileUnits()) {
DbgInfoSection->registerPatcher(std::make_unique<DebugInfoBinaryPatcher>());
DebugInfoPatcher =
static_cast<DebugInfoBinaryPatcher *>(DbgInfoSection->getPatcher());
}
// There is no direct connection between CU and TU, but same offsets,
// encoded in DW_AT_stmt_list, into .debug_line get modified.
// We take advantage of that to map original CU line table offsets to new
@ -689,8 +771,7 @@ void DWARFRewriter::updateLineTableOffsets(const MCAsmLayout &Layout) {
const uint64_t LineTableOffset = Layout.getSymbolOffset(*Label);
DebugLineOffsetMap[GetStatementListValue(CU.get())] = LineTableOffset;
assert(DbgInfoSection && ".debug_info section must exist");
DbgInfoSection->addRelocation(AttributeOffset, nullptr, Reloc32Type,
LineTableOffset, 0, /*Pending=*/true);
DebugInfoPatcher->addLE32Patch(AttributeOffset, LineTableOffset);
}
for (const std::unique_ptr<DWARFUnit> &TU : BC.DwCtx->types_section_units()) {
@ -718,23 +799,7 @@ void DWARFRewriter::updateLineTableOffsets(const MCAsmLayout &Layout) {
}
void DWARFRewriter::finalizeDebugSections(
SimpleBinaryPatcher &DebugInfoPatcher) {
// Skip .debug_aranges if we are re-generating .gdb_index.
if (opts::KeepARanges || !BC.getGdbIndexSection()) {
SmallVector<char, 16> ARangesBuffer;
raw_svector_ostream OS(ARangesBuffer);
auto MAB = std::unique_ptr<MCAsmBackend>(
BC.TheTarget->createMCAsmBackend(*BC.STI, *BC.MRI, MCTargetOptions()));
ARangesSectionWriter->writeARangesSection(OS);
const StringRef &ARangesContents = OS.str();
BC.registerOrUpdateNoteSection(".debug_aranges",
copyByteArray(ARangesContents),
ARangesContents.size());
}
DebugInfoBinaryPatcher &DebugInfoPatcher) {
if (StrWriter->isInitialized()) {
RewriteInstance::addToDebugSectionsToOverwrite(".debug_str");
std::unique_ptr<DebugStrBufferVector> DebugStrSectionContents =
@ -768,8 +833,8 @@ void DWARFRewriter::finalizeDebugSections(
if (Optional<AttrInfo> AttrVal =
findAttributeInfo(DIE, dwarf::DW_AT_GNU_addr_base)) {
uint64_t Offset = AddrWriter->getOffset(*CU->getDWOId());
DebugInfoPatcher.addLE32Patch(AttrVal->Offset,
static_cast<int32_t>(Offset));
DebugInfoPatcher.addLE32Patch(
AttrVal->Offset, static_cast<int32_t>(Offset), AttrVal->Size);
}
}
}
@ -809,6 +874,26 @@ void DWARFRewriter::finalizeDebugSections(
DebugTypesPatcher->addLE32Patch(Unit->getOffset() + AbbrevFieldOffset,
static_cast<uint32_t>(NewAbbrevOffset));
}
// No more creating new DebugInfoPatches.
std::unordered_map<uint32_t, uint32_t> CUMap =
DebugInfoPatcher.computeNewOffsets();
// Skip .debug_aranges if we are re-generating .gdb_index.
if (opts::KeepARanges || !BC.getGdbIndexSection()) {
SmallVector<char, 16> ARangesBuffer;
raw_svector_ostream OS(ARangesBuffer);
auto MAB = std::unique_ptr<MCAsmBackend>(
BC.TheTarget->createMCAsmBackend(*BC.STI, *BC.MRI, MCTargetOptions()));
ARangesSectionWriter->writeARangesSection(OS, CUMap);
const StringRef &ARangesContents = OS.str();
BC.registerOrUpdateNoteSection(".debug_aranges",
copyByteArray(ARangesContents),
ARangesContents.size());
}
}
// Creates all the data structures necessary for creating MCStreamer.
@ -857,10 +942,10 @@ updateDebugData(std::string &Storage, const SectionRef &Section,
MCStreamer &Streamer, DWARFRewriter &Writer,
const DWARFUnitIndex::Entry *DWOEntry, uint64_t DWOId,
std::unique_ptr<DebugBufferVector> &OutputBuffer) {
auto applyPatch = [&](BinaryPatcher *Patcher, StringRef Data,
uint32_t Offset) -> StringRef {
Storage = Data.str();
Patcher->patchBinary(Storage, Offset);
auto applyPatch = [&](DebugInfoBinaryPatcher *Patcher,
StringRef Data) -> StringRef {
Patcher->computeNewOffsets();
Storage = Patcher->patchBinary(Data);
return StringRef(Storage.c_str(), Storage.size());
};
@ -896,8 +981,9 @@ updateDebugData(std::string &Storage, const SectionRef &Section,
case DWARFSectionKind::DW_SECT_INFO: {
OutData = getSliceData(DWOEntry, OutData, DWARFSectionKind::DW_SECT_INFO,
DWPOffset);
SimpleBinaryPatcher *Patcher = Writer.getBinaryDWODebugInfoPatcher(DWOId);
return applyPatch(Patcher, OutData, DWPOffset);
DebugInfoBinaryPatcher *Patcher = llvm::cast<DebugInfoBinaryPatcher>(
Writer.getBinaryDWODebugInfoPatcher(DWOId));
return applyPatch(Patcher, OutData);
}
case DWARFSectionKind::DW_SECT_EXT_TYPES: {
return getSliceData(DWOEntry, OutData, DWARFSectionKind::DW_SECT_EXT_TYPES,
@ -1342,15 +1428,14 @@ void DWARFRewriter::flushPendingRanges(SimpleBinaryPatcher &DebugInfoPatcher) {
namespace {
void getRangeAttrData(DWARFDie DIE, uint64_t &LowPCOffset,
uint64_t &HighPCOffset, DWARFFormValue &LowPCFormValue,
DWARFFormValue &HighPCFormValue) {
Optional<AttrInfo> LowPCVal = findAttributeInfo(DIE, dwarf::DW_AT_low_pc);
Optional<AttrInfo> HighPCVal = findAttributeInfo(DIE, dwarf::DW_AT_high_pc);
LowPCOffset = LowPCVal->Offset;
HighPCOffset = HighPCVal->Offset;
LowPCFormValue = LowPCVal->V;
HighPCFormValue = HighPCVal->V;
void getRangeAttrData(DWARFDie DIE, Optional<AttrInfo> &LowPCVal,
Optional<AttrInfo> &HighPCVal) {
LowPCVal = findAttributeInfo(DIE, dwarf::DW_AT_low_pc);
HighPCVal = findAttributeInfo(DIE, dwarf::DW_AT_high_pc);
uint64_t LowPCOffset = LowPCVal->Offset;
uint64_t HighPCOffset = HighPCVal->Offset;
DWARFFormValue LowPCFormValue = LowPCVal->V;
DWARFFormValue HighPCFormValue = HighPCVal->V;
if ((LowPCFormValue.getForm() != dwarf::DW_FORM_addr &&
LowPCFormValue.getForm() != dwarf::DW_FORM_GNU_addr_index) ||
@ -1374,12 +1459,13 @@ void getRangeAttrData(DWARFDie DIE, uint64_t &LowPCOffset,
void DWARFRewriter::patchLowHigh(DWARFDie DIE, DebugAddressRange Range,
SimpleBinaryPatcher &DebugInfoPatcher) {
uint64_t LowPCOffset, HighPCOffset;
DWARFFormValue LowPCFormValue, HighPCFormValue;
getRangeAttrData(DIE, LowPCOffset, HighPCOffset, LowPCFormValue,
HighPCFormValue);
Optional<AttrInfo> LowPCVal = None;
Optional<AttrInfo> HighPCVal = None;
getRangeAttrData(DIE, LowPCVal, HighPCVal);
uint64_t LowPCOffset = LowPCVal->Offset;
uint64_t HighPCOffset = HighPCVal->Offset;
auto *TempDebugPatcher = &DebugInfoPatcher;
if (LowPCFormValue.getForm() == dwarf::DW_FORM_GNU_addr_index) {
if (LowPCVal->V.getForm() == dwarf::DW_FORM_GNU_addr_index) {
DWARFUnit *Unit = DIE.getDwarfUnit();
assert(Unit->isDWOUnit() && "DW_FORM_GNU_addr_index not part of DWO.");
uint32_t AddressIndex =
@ -1392,10 +1478,11 @@ void DWARFRewriter::patchLowHigh(DWARFDie DIE, DebugAddressRange Range,
TempDebugPatcher->addLE64Patch(LowPCOffset, Range.LowPC);
}
if (isHighPcFormEightBytes(HighPCFormValue.getForm()))
if (isHighPcFormEightBytes(HighPCVal->V.getForm()))
TempDebugPatcher->addLE64Patch(HighPCOffset, Range.HighPC - Range.LowPC);
else
TempDebugPatcher->addLE32Patch(HighPCOffset, Range.HighPC - Range.LowPC);
TempDebugPatcher->addLE32Patch(HighPCOffset, Range.HighPC - Range.LowPC,
HighPCVal->Size);
}
void DWARFRewriter::convertToRanges(const DWARFUnit &Unit,
@ -1435,17 +1522,18 @@ void DWARFRewriter::convertToRanges(const DWARFUnit &Unit,
void DWARFRewriter::convertToRanges(DWARFDie DIE, uint64_t RangesSectionOffset,
SimpleBinaryPatcher &DebugInfoPatcher,
Optional<uint64_t> RangesBase) {
uint64_t LowPCOffset, HighPCOffset;
DWARFFormValue LowPCFormValue, HighPCFormValue;
getRangeAttrData(DIE, LowPCOffset, HighPCOffset, LowPCFormValue,
HighPCFormValue);
Optional<AttrInfo> LowPCVal = None;
Optional<AttrInfo> HighPCVal = None;
getRangeAttrData(DIE, LowPCVal, HighPCVal);
uint64_t LowPCOffset = LowPCVal->Offset;
uint64_t HighPCOffset = HighPCVal->Offset;
// Size to fill with the first field (DW_AT_low_pc or DW_AT_GNU_ranges_base).
unsigned NumBytesToFill = 0;
assert(DIE.getDwarfUnit()->getAddressByteSize() == 8);
if (isHighPcFormEightBytes(HighPCFormValue.getForm())) {
if (isHighPcFormEightBytes(HighPCVal->V.getForm())) {
NumBytesToFill = 12;
} else if (HighPCFormValue.getForm() == dwarf::DW_FORM_data4) {
} else if (HighPCVal->V.getForm() == dwarf::DW_FORM_data4) {
NumBytesToFill = 8;
} else {
llvm_unreachable("unexpected DW_AT_high_pc form");
@ -1453,7 +1541,7 @@ void DWARFRewriter::convertToRanges(DWARFDie DIE, uint64_t RangesSectionOffset,
std::lock_guard<std::mutex> Lock(DebugInfoPatcherMutex);
uint32_t BaseOffset = 0;
if (LowPCFormValue.getForm() == dwarf::DW_FORM_GNU_addr_index) {
if (LowPCVal->V.getForm() == dwarf::DW_FORM_GNU_addr_index) {
// Use ULEB128 for the value.
DebugInfoPatcher.addUDataPatch(LowPCOffset, 0,
std::abs(int(HighPCOffset - LowPCOffset)) +
@ -1462,9 +1550,11 @@ void DWARFRewriter::convertToRanges(DWARFDie DIE, uint64_t RangesSectionOffset,
BaseOffset = DebugInfoPatcher.getRangeBase();
} else {
if (RangesBase) {
assert(NumBytesToFill == LowPCVal->Size &&
"Bytes to fill not equal to LocPCVal Size");
DebugInfoPatcher.addUDataPatch(LowPCOffset, dwarf::DW_FORM_udata, 1);
DebugInfoPatcher.addUDataPatch(LowPCOffset + 1, *RangesBase,
NumBytesToFill - 1);
LowPCVal->Size - 1);
} else if (NumBytesToFill == 12) {
// Creatively encoding dwarf::DW_FORM_addr in to 4 bytes.
// Write an indirect 0 value for DW_AT_low_pc so that we can fill

View File

@ -3834,18 +3834,20 @@ void RewriteInstance::rewriteNoteSections() {
// Copy over section contents unless it's one of the sections we overwrite.
if (!willOverwriteSection(SectionName)) {
Size = Section.sh_size;
std::string Data =
std::string(InputFile->getData().substr(Section.sh_offset, Size));
if (BSec && BSec->getPatcher())
BSec->getPatcher()->patchBinary(Data, 0);
StringRef Dataref = InputFile->getData().substr(Section.sh_offset, Size);
std::string Data;
if (BSec && BSec->getPatcher()) {
Data = BSec->getPatcher()->patchBinary(Dataref);
Dataref = StringRef(Data);
}
// Section was expanded, so need to treat it as overwrite.
if (Size != Data.size()) {
BSec = BC->registerOrUpdateNoteSection(SectionName, copyByteArray(Data),
Data.size());
if (Size != Dataref.size()) {
BSec = BC->registerOrUpdateNoteSection(
SectionName, copyByteArray(Dataref), Dataref.size());
Size = 0;
} else {
OS << Data;
OS << Dataref;
DataWritten = true;
// Add padding as the section extension might rely on the alignment.