mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-14 19:49:36 +00:00
[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:
parent
ccc4d4397f
commit
1c2f4bbe99
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user