Group debugging info representation and serialization code.

Summary:
Moved the classes related to representing and serializing DWARF entities into a single
header, DebugData.h.

(cherry picked from FBD3153279)
This commit is contained in:
Gabriel Poesia 2016-04-07 15:06:43 -07:00 committed by Maksim Panchenko
parent f6c8929799
commit ad344c4387
20 changed files with 668 additions and 925 deletions

View File

@ -1,76 +0,0 @@
//===--- AddressRangesDWARFObject.h - DWARF Entities with address ranges --===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Represents DWARF lexical blocks, maintaining their list of address ranges to
// be updated in the output debugging information.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVM_BOLT_ADDRESS_RANGES_DWARF_OBJECT_H
#define LLVM_TOOLS_LLVM_BOLT_ADDRESS_RANGES_DWARF_OBJECT_H
#include "DebugRangesSectionsWriter.h"
#include "BasicBlockOffsetRanges.h"
namespace llvm {
class DWARFCompileUnit;
class DWARFDebugInfoEntryMinimal;
namespace bolt {
class BasicBlockTable;
class BinaryBasicBlock;
class BinaryFunction;
class AddressRangesDWARFObject : public AddressRangesOwner {
public:
AddressRangesDWARFObject(const DWARFCompileUnit *CU,
const DWARFDebugInfoEntryMinimal *DIE)
: CU(CU), DIE(DIE) { }
/// Add range [BeginAddress, EndAddress) to this object.
void addAddressRange(BinaryFunction &Function,
uint64_t BeginAddress,
uint64_t EndAddress) {
BBOffsetRanges.addAddressRange(Function, BeginAddress, EndAddress);
}
std::vector<std::pair<uint64_t, uint64_t>> getAbsoluteAddressRanges() const {
auto AddressRangesWithData = BBOffsetRanges.getAbsoluteAddressRanges();
std::vector<std::pair<uint64_t, uint64_t>> AddressRanges(
AddressRangesWithData.size());
for (unsigned I = 0, S = AddressRanges.size(); I != S; ++I) {
AddressRanges[I] = std::make_pair(AddressRangesWithData[I].Begin,
AddressRangesWithData[I].End);
}
return AddressRanges;
}
void setAddressRangesOffset(uint32_t Offset) { AddressRangesOffset = Offset; }
uint32_t getAddressRangesOffset() const { return AddressRangesOffset; }
const DWARFCompileUnit *getCompileUnit() const { return CU; }
const DWARFDebugInfoEntryMinimal *getDIE() const { return DIE; }
private:
const DWARFCompileUnit *CU;
const DWARFDebugInfoEntryMinimal *DIE;
BasicBlockOffsetRanges BBOffsetRanges;
// Offset of the address ranges of this object in the output .debug_ranges.
uint32_t AddressRangesOffset;
};
} // namespace bolt
} // namespace llvm
#endif

View File

@ -1,96 +0,0 @@
//===- BasicBlockOffsetRanges.cpp - list of address ranges relative to BBs ===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
#include "BasicBlockOffsetRanges.h"
#include "BinaryBasicBlock.h"
#include "BinaryFunction.h"
#include <algorithm>
namespace llvm {
namespace bolt {
void BasicBlockOffsetRanges::addAddressRange(BinaryFunction &Function,
uint64_t BeginAddress,
uint64_t EndAddress,
const BinaryData *Data) {
auto FirstBB = Function.getBasicBlockContainingOffset(
BeginAddress - Function.getAddress());
assert(FirstBB && "No basic blocks in the function intersect given range.");
for (auto I = Function.getIndex(FirstBB), S = Function.size(); I != S; ++I) {
auto BB = Function.getBasicBlockAtIndex(I);
uint64_t BBAddress = Function.getAddress() + BB->getOffset();
if (BBAddress >= EndAddress)
break;
uint64_t InternalAddressRangeBegin = std::max(BBAddress, BeginAddress);
assert(BB->getFunction() == &Function &&
"Mismatching functions.\n");
uint64_t InternalAddressRangeEnd =
std::min(BBAddress + Function.getBasicBlockOriginalSize(BB),
EndAddress);
AddressRanges.push_back(
BBAddressRange{
BB,
static_cast<uint16_t>(InternalAddressRangeBegin - BBAddress),
static_cast<uint16_t>(InternalAddressRangeEnd - BBAddress),
Data});
}
}
std::vector<BasicBlockOffsetRanges::AbsoluteRange>
BasicBlockOffsetRanges::getAbsoluteAddressRanges() const {
std::vector<AbsoluteRange> AbsoluteRanges;
for (const auto &BBAddressRange : AddressRanges) {
auto BBOutputAddressRange =
BBAddressRange.BasicBlock->getOutputAddressRange();
uint64_t NewRangeBegin = BBOutputAddressRange.first +
BBAddressRange.RangeBeginOffset;
// If the end offset pointed to the end of the basic block, then we set
// the new end range to cover the whole basic block as the BB's size
// might have increased.
auto BBFunction = BBAddressRange.BasicBlock->getFunction();
uint64_t NewRangeEnd =
(BBAddressRange.RangeEndOffset ==
BBFunction->getBasicBlockOriginalSize(BBAddressRange.BasicBlock))
? BBOutputAddressRange.second
: (BBOutputAddressRange.first + BBAddressRange.RangeEndOffset);
AbsoluteRanges.emplace_back(AbsoluteRange{NewRangeBegin, NewRangeEnd,
BBAddressRange.Data});
}
if (AbsoluteRanges.empty()) {
return AbsoluteRanges;
}
// Merge adjacent ranges that have the same data.
std::sort(AbsoluteRanges.begin(), AbsoluteRanges.end(),
[](const AbsoluteRange &A, const AbsoluteRange &B) {
return A.Begin < B.Begin;
});
decltype(AbsoluteRanges) MergedRanges;
MergedRanges.emplace_back(AbsoluteRanges[0]);
for (unsigned I = 1, S = AbsoluteRanges.size(); I != S; ++I) {
// If this range complements the last one and they point to the same
// (possibly null) data, merge them instead of creating another one.
if (AbsoluteRanges[I].Begin == MergedRanges.back().End &&
AbsoluteRanges[I].Data == MergedRanges.back().Data) {
MergedRanges.back().End = AbsoluteRanges[I].End;
} else {
MergedRanges.emplace_back(AbsoluteRanges[I]);
}
}
return MergedRanges;
}
} // namespace bolt
} // namespace llvm

View File

@ -1,70 +0,0 @@
//===--- BasicBlockOffsetRanges.h - list of address ranges relative to BBs ===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Represents a list of address ranges where addresses are relative to the
// beginning of basic blocks. Useful for converting address ranges in the input
// binary to equivalent ranges after optimizations take place.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVM_BOLT_BASIC_BLOCK_OFFSET_RANGES_H
#define LLVM_TOOLS_LLVM_BOLT_BASIC_BLOCK_OFFSET_RANGES_H
#include "llvm/ADT/SmallVector.h"
#include <map>
#include <string>
#include <utility>
#include <vector>
namespace llvm {
namespace bolt {
class BinaryFunction;
class BinaryBasicBlock;
class BasicBlockOffsetRanges {
public:
typedef SmallVectorImpl<unsigned char> BinaryData;
struct AbsoluteRange {
uint64_t Begin;
uint64_t End;
const BinaryData *Data;
};
/// Add range [BeginAddress, EndAddress) to the address ranges list.
/// \p Function is the function that contains the given address range.
void addAddressRange(BinaryFunction &Function,
uint64_t BeginAddress,
uint64_t EndAddress,
const BinaryData *Data = nullptr);
/// Returns the list of absolute addresses calculated using the output address
/// of the basic blocks, i.e. the input ranges updated after basic block
/// addresses might have changed, together with the data associated to them.
std::vector<AbsoluteRange> getAbsoluteAddressRanges() const;
private:
/// An address range inside one basic block.
struct BBAddressRange {
const BinaryBasicBlock *BasicBlock;
/// Beginning of the range counting from BB's start address.
uint16_t RangeBeginOffset;
/// (Exclusive) end of the range counting from BB's start address.
uint16_t RangeEndOffset;
/// Binary data associated with this range.
const BinaryData *Data;
};
std::vector<BBAddressRange> AddressRanges;
};
} // namespace bolt
} // namespace llvm
#endif

View File

@ -14,8 +14,7 @@
#ifndef LLVM_TOOLS_LLVM_BOLT_BINARY_CONTEXT_H
#define LLVM_TOOLS_LLVM_BOLT_BINARY_CONTEXT_H
#include "AddressRangesDWARFObject.h"
#include "LocationList.h"
#include "DebugData.h"
#include "llvm/ADT/Triple.h"
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
@ -75,14 +74,14 @@ public:
/// Maps DWARF CUID to offset of stmt_list attribute in .debug_info.
std::map<unsigned, uint32_t> LineTableOffsetCUMap;
/// List of DWARF location lists in .debug_loc.
std::vector<LocationList> LocationLists;
/// List of DWARF entries in .debug_info that have address ranges to be
/// updated. These include lexical blocks (DW_TAG_lexical_block) and concrete
/// instances of inlined subroutines (DW_TAG_inlined_subroutine).
std::vector<AddressRangesDWARFObject> AddressRangesObjects;
/// List of DWARF location lists in .debug_loc.
std::vector<LocationList> LocationLists;
using DIECompileUnitVector =
std::vector<std::pair<const DWARFDebugInfoEntryMinimal *,
const DWARFCompileUnit *>> ;

View File

@ -13,7 +13,6 @@
#include "BinaryBasicBlock.h"
#include "BinaryFunction.h"
#include "DataReader.h"
#include "DebugLineTableRowRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/MC/MCAsmInfo.h"

View File

@ -19,7 +19,7 @@
#include "BinaryBasicBlock.h"
#include "BinaryContext.h"
#include "DebugRangesSectionsWriter.h"
#include "DebugData.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/ilist.h"
#include "llvm/MC/MCCodeEmitter.h"

View File

@ -1,109 +0,0 @@
//===--- BinaryPatcher.h - Classes for modifying sections of the binary --===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
#include "BinaryPatcher.h"
#include <algorithm>
#include <cassert>
namespace llvm {
namespace bolt {
void SimpleBinaryPatcher::addBinaryPatch(uint32_t Offset,
const std::string &NewValue) {
Patches.emplace_back(std::make_pair(Offset, NewValue));
}
void SimpleBinaryPatcher::addBytePatch(uint32_t Offset, uint8_t Value) {
Patches.emplace_back(std::make_pair(Offset, std::string(1, Value)));
}
void SimpleBinaryPatcher::addLEPatch(uint32_t Offset, uint64_t NewValue,
size_t ByteSize) {
std::string LE64(ByteSize, 0);
for (size_t I = 0; I < ByteSize; ++I) {
LE64[I] = NewValue & 0xff;
NewValue >>= 8;
}
Patches.emplace_back(std::make_pair(Offset, LE64));
}
void SimpleBinaryPatcher::addLE64Patch(uint32_t Offset, uint64_t NewValue) {
addLEPatch(Offset, NewValue, 8);
}
void SimpleBinaryPatcher::addLE32Patch(uint32_t Offset, uint32_t NewValue) {
addLEPatch(Offset, NewValue, 4);
}
void SimpleBinaryPatcher::patchBinary(std::string &BinaryContents) {
for (const auto &Patch : Patches) {
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];
}
}
}
void DebugAbbrevPatcher::addAttributePatch(const DWARFUnit *Unit,
uint32_t AbbrevCode,
uint16_t AttrTag,
uint8_t NewAttrTag,
uint8_t NewAttrForm) {
assert(Unit && "No compile unit specified.");
Patches[Unit].push_back(
AbbrevAttrPatch{AbbrevCode, AttrTag, NewAttrTag, NewAttrForm});
}
void DebugAbbrevPatcher::patchBinary(std::string &Contents) {
SimpleBinaryPatcher Patcher;
for (const auto &UnitPatchesPair : Patches) {
const auto *Unit = UnitPatchesPair.first;
const auto *UnitAbbreviations = Unit->getAbbreviations();
assert(UnitAbbreviations &&
"Compile unit doesn't have associated abbreviations.");
const auto &UnitPatches = UnitPatchesPair.second;
for (const auto &AttrPatch : UnitPatches) {
const auto *AbbreviationDeclaration =
UnitAbbreviations->getAbbreviationDeclaration(AttrPatch.Code);
assert(AbbreviationDeclaration && "No abbreviation with given code.");
const auto *Attribute = AbbreviationDeclaration->findAttribute(
AttrPatch.Attr);
if (!Attribute) {
errs() << "Attribute " << AttrPatch.Attr << " does not occur in "
<< " abbrev " << AttrPatch.Code << " of CU " << Unit->getOffset()
<< " in decl@" << AbbreviationDeclaration
<< " and index = " << AbbreviationDeclaration->findAttributeIndex(AttrPatch.Attr)
<< "\n";
errs() << "Look at the abbrev:\n";
AbbreviationDeclaration->dump(errs());
assert(Attribute && "Specified attribute doesn't occur in abbreviation.");
}
// Because we're only handling standard values (i.e. no DW_FORM_GNU_* or
// DW_AT_APPLE_*), they are all small (< 128) and encoded in a single
// byte in ULEB128, otherwise it'll be more tricky as we may need to
// grow or shrink the section.
Patcher.addBytePatch(Attribute->AttrOffset,
AttrPatch.NewAttr);
Patcher.addBytePatch(Attribute->FormOffset,
AttrPatch.NewForm);
}
}
Patcher.patchBinary(Contents);
}
} // namespace llvm
} // namespace bolt

View File

@ -1,101 +0,0 @@
//===--- BinaryPatcher.h - Classes for modifying sections of the binary --===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Interfaces for applying small modifications to parts of a binary file. Some
// specializations facilitate the modification of specific ELF/DWARF sections.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVM_BOLT_BINARY_PATCHER_H
#define LLVM_TOOLS_LLVM_BOLT_BINARY_PATCHER_H
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
#include <string>
#include <utility>
#include <vector>
namespace llvm {
namespace bolt {
/// 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 .
virtual void patchBinary(std::string &BinaryContents) = 0;
};
/// Applies simple modifications to a binary string, such as directly replacing
/// the contents of a certain portion with a string or an integer.
class SimpleBinaryPatcher : public BinaryPatcher {
private:
std::vector<std::pair<uint32_t, std::string>> Patches;
/// 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);
public:
~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);
/// 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);
/// 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);
/// 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);
void patchBinary(std::string &BinaryContents) override;
};
/// Apply small modifications to the .debug_abbrev DWARF section.
class DebugAbbrevPatcher : public BinaryPatcher {
private:
/// Patch of changing one attribute to another.
struct AbbrevAttrPatch {
uint32_t Code; // Code of abbreviation to be modified.
uint16_t Attr; // ID of attribute to be replaced.
uint8_t NewAttr; // ID of the new attribute.
uint8_t NewForm; // Form of the new attribute.
};
std::map<const DWARFUnit *, std::vector<AbbrevAttrPatch>> Patches;
public:
~DebugAbbrevPatcher() { }
/// Adds a patch to change an attribute of an abbreviation that belongs to
/// \p Unit to another attribute.
/// \p AbbrevCode code of the abbreviation to be modified.
/// \p AttrTag ID of the attribute to be replaced.
/// \p NewAttrTag ID of the new attribute.
/// \p NewAttrForm Form of the new attribute.
/// We only handle standard forms, that are encoded in a single byte.
void addAttributePatch(const DWARFUnit *Unit,
uint32_t AbbrevCode,
uint16_t AttrTag,
uint8_t NewAttrTag,
uint8_t NewAttrForm);
void patchBinary(std::string &Contents) override;
};
} // namespace llvm
} // namespace bolt
#endif

View File

@ -13,15 +13,11 @@ set(LLVM_LINK_COMPONENTS
add_llvm_tool(llvm-bolt
llvm-bolt.cpp
BasicBlockOffsetRanges.cpp
BinaryBasicBlock.cpp
BinaryContext.cpp
BinaryFunction.cpp
BinaryPatcher.cpp
DataReader.cpp
DebugLineTableRowRef.cpp
DebugLocWriter.cpp
DebugRangesSectionsWriter.cpp
DebugData.cpp
Exceptions.cpp
RewriteInstance.cpp
)

306
bolt/DebugData.cpp Normal file
View File

@ -0,0 +1,306 @@
//===- DebugData.cpp - Representation and writing of debugging information. ==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
#include "DebugData.h"
#include "BinaryBasicBlock.h"
#include "BinaryFunction.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCObjectWriter.h"
#include <algorithm>
#include <cassert>
namespace llvm {
namespace bolt {
const DebugLineTableRowRef DebugLineTableRowRef::NULL_ROW{0, 0};
void BasicBlockOffsetRanges::addAddressRange(BinaryFunction &Function,
uint64_t BeginAddress,
uint64_t EndAddress,
const BinaryData *Data) {
auto FirstBB = Function.getBasicBlockContainingOffset(
BeginAddress - Function.getAddress());
assert(FirstBB && "No basic blocks in the function intersect given range.");
for (auto I = Function.getIndex(FirstBB), S = Function.size(); I != S; ++I) {
auto BB = Function.getBasicBlockAtIndex(I);
uint64_t BBAddress = Function.getAddress() + BB->getOffset();
if (BBAddress >= EndAddress)
break;
uint64_t InternalAddressRangeBegin = std::max(BBAddress, BeginAddress);
assert(BB->getFunction() == &Function &&
"Mismatching functions.\n");
uint64_t InternalAddressRangeEnd =
std::min(BBAddress + Function.getBasicBlockOriginalSize(BB),
EndAddress);
AddressRanges.push_back(
BBAddressRange{
BB,
static_cast<uint16_t>(InternalAddressRangeBegin - BBAddress),
static_cast<uint16_t>(InternalAddressRangeEnd - BBAddress),
Data});
}
}
std::vector<BasicBlockOffsetRanges::AbsoluteRange>
BasicBlockOffsetRanges::getAbsoluteAddressRanges() const {
std::vector<AbsoluteRange> AbsoluteRanges;
for (const auto &BBAddressRange : AddressRanges) {
auto BBOutputAddressRange =
BBAddressRange.BasicBlock->getOutputAddressRange();
uint64_t NewRangeBegin = BBOutputAddressRange.first +
BBAddressRange.RangeBeginOffset;
// If the end offset pointed to the end of the basic block, then we set
// the new end range to cover the whole basic block as the BB's size
// might have increased.
auto BBFunction = BBAddressRange.BasicBlock->getFunction();
uint64_t NewRangeEnd =
(BBAddressRange.RangeEndOffset ==
BBFunction->getBasicBlockOriginalSize(BBAddressRange.BasicBlock))
? BBOutputAddressRange.second
: (BBOutputAddressRange.first + BBAddressRange.RangeEndOffset);
AbsoluteRanges.emplace_back(AbsoluteRange{NewRangeBegin, NewRangeEnd,
BBAddressRange.Data});
}
if (AbsoluteRanges.empty()) {
return AbsoluteRanges;
}
// Merge adjacent ranges that have the same data.
std::sort(AbsoluteRanges.begin(), AbsoluteRanges.end(),
[](const AbsoluteRange &A, const AbsoluteRange &B) {
return A.Begin < B.Begin;
});
decltype(AbsoluteRanges) MergedRanges;
MergedRanges.emplace_back(AbsoluteRanges[0]);
for (unsigned I = 1, S = AbsoluteRanges.size(); I != S; ++I) {
// If this range complements the last one and they point to the same
// (possibly null) data, merge them instead of creating another one.
if (AbsoluteRanges[I].Begin == MergedRanges.back().End &&
AbsoluteRanges[I].Data == MergedRanges.back().Data) {
MergedRanges.back().End = AbsoluteRanges[I].End;
} else {
MergedRanges.emplace_back(AbsoluteRanges[I]);
}
}
return MergedRanges;
}
void DebugRangesSectionsWriter::AddRange(uint32_t CompileUnitOffset,
uint64_t Address,
uint64_t Size) {
CUAddressRanges[CompileUnitOffset].push_back(std::make_pair(Address, Size));
}
void DebugRangesSectionsWriter::AddRange(AddressRangesOwner *BF,
uint64_t Address,
uint64_t Size) {
ObjectAddressRanges[BF].push_back(std::make_pair(Address, Size));
}
namespace {
// 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).
// Terminates the list by writing a pair of two zeroes.
// Returns the number of written bytes.
uint32_t WriteAddressRanges(
MCObjectWriter *Writer,
const std::vector<std::pair<uint64_t, uint64_t>> &AddressRanges,
bool RelativeRange) {
// Write entries.
for (auto &Range : AddressRanges) {
Writer->writeLE64(Range.first);
Writer->writeLE64((!RelativeRange) * Range.first + Range.second);
}
// Finish with 0 entries.
Writer->writeLE64(0);
Writer->writeLE64(0);
return AddressRanges.size() * 16 + 16;
}
} // namespace
void DebugRangesSectionsWriter::WriteRangesSection(MCObjectWriter *Writer) {
uint32_t SectionOffset = 0;
for (const auto &CUOffsetAddressRangesPair : CUAddressRanges) {
uint64_t CUOffset = CUOffsetAddressRangesPair.first;
RangesSectionOffsetCUMap[CUOffset] = SectionOffset;
const auto &AddressRanges = CUOffsetAddressRangesPair.second;
SectionOffset += WriteAddressRanges(Writer, AddressRanges, false);
}
for (const auto &BFAddressRangesPair : ObjectAddressRanges) {
BFAddressRangesPair.first->setAddressRangesOffset(SectionOffset);
const auto &AddressRanges = BFAddressRangesPair.second;
SectionOffset += WriteAddressRanges(Writer, AddressRanges, false);
}
// Write an empty address list to be used for objects with unknown address
// ranges.
EmptyRangesListOffset = SectionOffset;
SectionOffset += WriteAddressRanges(
Writer,
std::vector<std::pair<uint64_t, uint64_t>>{},
false);
}
void
DebugRangesSectionsWriter::WriteArangesSection(MCObjectWriter *Writer) 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
for (const auto &CUOffsetAddressRangesPair : CUAddressRanges) {
uint64_t Offset = CUOffsetAddressRangesPair.first;
const auto &AddressRanges = CUOffsetAddressRangesPair.second;
// Emit header.
// Size of this set: 8 (size of the header) + 4 (padding after header)
// + 2*sizeof(uint64_t) bytes for each of the ranges, plus an extra
// pair of uint64_t's for the terminating, zero-length range.
// Does not include size field itself.
uint64_t Size = 8 + 4 + 2*sizeof(uint64_t) * (AddressRanges.size() + 1);
// Header field #1: set size.
Writer->writeLE32(Size);
// Header field #2: version number, 2 as per the specification.
Writer->writeLE16(2);
// Header field #3: debug info offset of the correspondent compile unit.
Writer->writeLE32(Offset);
// Header field #4: address size.
// 8 since we only write ELF64 binaries for now.
Writer->write8(8);
// Header field #5: segment size of target architecture.
Writer->write8(0);
// Padding before address table - 4 bytes in the 64-bit-pointer case.
Writer->writeLE32(0);
WriteAddressRanges(Writer, AddressRanges, true);
}
}
void DebugLocWriter::write(const LocationList &LocList,
MCObjectWriter *Writer) {
// Reference: DWARF 4 specification section 7.7.3.
UpdatedOffsets[LocList.getOriginalOffset()] = SectionOffset;
auto AbsoluteRanges = LocList.getAbsoluteAddressRanges();
for (const auto &Entry : LocList.getAbsoluteAddressRanges()) {
Writer->writeLE64(Entry.Begin);
Writer->writeLE64(Entry.End);
assert(Entry.Data && "Entry with null location expression.");
Writer->writeLE16(Entry.Data->size());
// Need to convert binary data from unsigned char to char.
Writer->writeBytes(
StringRef(reinterpret_cast<const char *>(Entry.Data->data()),
Entry.Data->size()));
SectionOffset += 2 * 8 + 2 + Entry.Data->size();
}
Writer->writeLE64(0);
Writer->writeLE64(0);
SectionOffset += 2 * 8;
}
void SimpleBinaryPatcher::addBinaryPatch(uint32_t Offset,
const std::string &NewValue) {
Patches.emplace_back(std::make_pair(Offset, NewValue));
}
void SimpleBinaryPatcher::addBytePatch(uint32_t Offset, uint8_t Value) {
Patches.emplace_back(std::make_pair(Offset, std::string(1, Value)));
}
void SimpleBinaryPatcher::addLEPatch(uint32_t Offset, uint64_t NewValue,
size_t ByteSize) {
std::string LE64(ByteSize, 0);
for (size_t I = 0; I < ByteSize; ++I) {
LE64[I] = NewValue & 0xff;
NewValue >>= 8;
}
Patches.emplace_back(std::make_pair(Offset, LE64));
}
void SimpleBinaryPatcher::addLE64Patch(uint32_t Offset, uint64_t NewValue) {
addLEPatch(Offset, NewValue, 8);
}
void SimpleBinaryPatcher::addLE32Patch(uint32_t Offset, uint32_t NewValue) {
addLEPatch(Offset, NewValue, 4);
}
void SimpleBinaryPatcher::patchBinary(std::string &BinaryContents) {
for (const auto &Patch : Patches) {
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];
}
}
}
void DebugAbbrevPatcher::addAttributePatch(const DWARFUnit *Unit,
uint32_t AbbrevCode,
uint16_t AttrTag,
uint8_t NewAttrTag,
uint8_t NewAttrForm) {
assert(Unit && "No compile unit specified.");
Patches[Unit].push_back(
AbbrevAttrPatch{AbbrevCode, AttrTag, NewAttrTag, NewAttrForm});
}
void DebugAbbrevPatcher::patchBinary(std::string &Contents) {
SimpleBinaryPatcher Patcher;
for (const auto &UnitPatchesPair : Patches) {
const auto *Unit = UnitPatchesPair.first;
const auto *UnitAbbreviations = Unit->getAbbreviations();
assert(UnitAbbreviations &&
"Compile unit doesn't have associated abbreviations.");
const auto &UnitPatches = UnitPatchesPair.second;
for (const auto &AttrPatch : UnitPatches) {
const auto *AbbreviationDeclaration =
UnitAbbreviations->getAbbreviationDeclaration(AttrPatch.Code);
assert(AbbreviationDeclaration && "No abbreviation with given code.");
const auto *Attribute = AbbreviationDeclaration->findAttribute(
AttrPatch.Attr);
assert(Attribute && "Specified attribute doesn't occur in abbreviation.");
// Because we're only handling standard values (i.e. no DW_FORM_GNU_* or
// DW_AT_APPLE_*), they are all small (< 128) and encoded in a single
// byte in ULEB128, otherwise it'll be more tricky as we may need to
// grow or shrink the section.
Patcher.addBytePatch(Attribute->AttrOffset,
AttrPatch.NewAttr);
Patcher.addBytePatch(Attribute->FormOffset,
AttrPatch.NewForm);
}
}
Patcher.patchBinary(Contents);
}
} // namespace bolt
} // namespace llvm

355
bolt/DebugData.h Normal file
View File

@ -0,0 +1,355 @@
//===-- DebugData.h - Representation and writing of debugging information. -==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Classes that represent and serialize DWARF-related entities.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVM_BOLT_DEBUG_DATA_H
#define LLVM_TOOLS_LLVM_BOLT_DEBUG_DATA_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/Support/SMLoc.h"
#include <map>
#include <string>
#include <utility>
#include <vector>
namespace llvm {
class DWARFCompileUnit;
class DWARFDebugInfoEntryMinimal;
class MCObjectWriter;
namespace bolt {
class BasicBlockTable;
class BinaryBasicBlock;
class BinaryFunction;
/// Eeferences a row in a DWARFDebugLine::LineTable by the DWARF
/// Context index of the DWARF Compile Unit that owns the Line Table and the row
/// index. This is tied to our IR during disassembly so that we can later update
/// .debug_line information. RowIndex has a base of 1, which means a RowIndex
/// of 1 maps to the first row of the line table and a RowIndex of 0 is invalid.
struct DebugLineTableRowRef {
uint32_t DwCompileUnitIndex;
uint32_t RowIndex;
const static DebugLineTableRowRef NULL_ROW;
bool operator==(const DebugLineTableRowRef &Rhs) const {
return DwCompileUnitIndex == Rhs.DwCompileUnitIndex &&
RowIndex == Rhs.RowIndex;
}
bool operator!=(const DebugLineTableRowRef &Rhs) const {
return !(*this == Rhs);
}
static DebugLineTableRowRef fromSMLoc(const SMLoc &Loc) {
union {
decltype(Loc.getPointer()) Ptr;
DebugLineTableRowRef Ref;
} U;
U.Ptr = Loc.getPointer();
return U.Ref;
}
SMLoc toSMLoc() const {
union {
decltype(SMLoc().getPointer()) Ptr;
DebugLineTableRowRef Ref;
} U;
U.Ref = *this;
return SMLoc::getFromPointer(U.Ptr);
}
};
/// Represents a list of address ranges where addresses are relative to the
/// beginning of basic blocks. Useful for converting address ranges in the input
/// binary to equivalent ranges after optimizations take place.
class BasicBlockOffsetRanges {
public:
typedef SmallVectorImpl<unsigned char> BinaryData;
struct AbsoluteRange {
uint64_t Begin;
uint64_t End;
const BinaryData *Data;
};
/// Add range [BeginAddress, EndAddress) to the address ranges list.
/// \p Function is the function that contains the given address range.
void addAddressRange(BinaryFunction &Function,
uint64_t BeginAddress,
uint64_t EndAddress,
const BinaryData *Data = nullptr);
/// Returns the list of absolute addresses calculated using the output address
/// of the basic blocks, i.e. the input ranges updated after basic block
/// addresses might have changed, together with the data associated to them.
std::vector<AbsoluteRange> getAbsoluteAddressRanges() const;
private:
/// An address range inside one basic block.
struct BBAddressRange {
const BinaryBasicBlock *BasicBlock;
/// Beginning of the range counting from BB's start address.
uint16_t RangeBeginOffset;
/// (Exclusive) end of the range counting from BB's start address.
uint16_t RangeEndOffset;
/// Binary data associated with this range.
const BinaryData *Data;
};
std::vector<BBAddressRange> AddressRanges;
};
/// Abstract interface for classes that represent objects that have
/// associated address ranges in .debug_ranges. These address ranges can
/// be serialized by DebugRangesSectionsWriter which notifies the object
/// of where in the section its address ranges list was written.
class AddressRangesOwner {
public:
virtual void setAddressRangesOffset(uint32_t Offset) = 0;
};
/// Represents DWARF entities that have generic address ranges, maintaining
/// their address ranges to be updated on the output debugging information.
class AddressRangesDWARFObject : public AddressRangesOwner {
public:
AddressRangesDWARFObject(const DWARFCompileUnit *CU,
const DWARFDebugInfoEntryMinimal *DIE)
: CU(CU), DIE(DIE) { }
/// Add range [BeginAddress, EndAddress) to this object.
void addAddressRange(BinaryFunction &Function,
uint64_t BeginAddress,
uint64_t EndAddress) {
BBOffsetRanges.addAddressRange(Function, BeginAddress, EndAddress);
}
std::vector<std::pair<uint64_t, uint64_t>> getAbsoluteAddressRanges() const {
auto AddressRangesWithData = BBOffsetRanges.getAbsoluteAddressRanges();
std::vector<std::pair<uint64_t, uint64_t>> AddressRanges(
AddressRangesWithData.size());
for (unsigned I = 0, S = AddressRanges.size(); I != S; ++I) {
AddressRanges[I] = std::make_pair(AddressRangesWithData[I].Begin,
AddressRangesWithData[I].End);
}
return AddressRanges;
}
void setAddressRangesOffset(uint32_t Offset) { AddressRangesOffset = Offset; }
uint32_t getAddressRangesOffset() const { return AddressRangesOffset; }
const DWARFCompileUnit *getCompileUnit() const { return CU; }
const DWARFDebugInfoEntryMinimal *getDIE() const { return DIE; }
private:
const DWARFCompileUnit *CU;
const DWARFDebugInfoEntryMinimal *DIE;
BasicBlockOffsetRanges BBOffsetRanges;
// Offset of the address ranges of this object in the output .debug_ranges.
uint32_t AddressRangesOffset;
};
/// Represents DWARF location lists, maintaining their list of location
/// expressions and the address ranges in which they are valid to be updated in
/// the output debugging information.
class LocationList {
public:
LocationList(uint32_t Offset) : DebugLocOffset(Offset) { }
/// Add a location expression that is valid in [BeginAddress, EndAddress)
/// within Function to location list.
void addLocation(const BasicBlockOffsetRanges::BinaryData *Expression,
BinaryFunction &Function,
uint64_t BeginAddress,
uint64_t EndAddress) {
BBOffsetRanges.addAddressRange(Function, BeginAddress, EndAddress,
Expression);
}
std::vector<BasicBlockOffsetRanges::AbsoluteRange>
getAbsoluteAddressRanges() const {
return BBOffsetRanges.getAbsoluteAddressRanges();
}
uint32_t getOriginalOffset() const { return DebugLocOffset; }
private:
BasicBlockOffsetRanges BBOffsetRanges;
// Offset of this location list in the input .debug_loc section.
uint32_t DebugLocOffset;
};
/// Serializes the .debug_ranges and .debug_aranges DWARF sections.
class DebugRangesSectionsWriter {
public:
DebugRangesSectionsWriter() = default;
/// Adds a range to the .debug_arange section.
void AddRange(uint32_t CompileUnitOffset, uint64_t Address, uint64_t Size);
/// Adds an address range that belongs to a given object.
/// When .debug_ranges is written, the offset of the range corresponding
/// to the function will be set using BF->setAddressRangesOffset().
void AddRange(AddressRangesOwner *ARO, uint64_t Address, uint64_t Size);
using RangesCUMapType = std::map<uint32_t, uint32_t>;
/// Writes .debug_aranges with the added ranges to the MCObjectWriter.
void WriteArangesSection(MCObjectWriter *Writer) const;
/// Writes .debug_ranges with the added ranges to the MCObjectWriter.
void WriteRangesSection(MCObjectWriter *Writer);
/// Resets the writer to a clear state.
void reset() {
CUAddressRanges.clear();
ObjectAddressRanges.clear();
RangesSectionOffsetCUMap.clear();
}
/// Return mapping of CUs to offsets in .debug_ranges.
const RangesCUMapType &getRangesOffsetCUMap() const {
return RangesSectionOffsetCUMap;
}
/// Returns an offset of an empty address ranges list that is always written
/// to .debug_ranges
uint32_t getEmptyRangesListOffset() const { return EmptyRangesListOffset; }
private:
// Map from compile unit offset to the list of address intervals that belong
// to that compile unit. Each interval is a pair
// (first address, interval size).
std::map<uint32_t, std::vector<std::pair<uint64_t, uint64_t>>>
CUAddressRanges;
// Map from BinaryFunction to the list of address intervals that belong
// to that function, represented like CUAddressRanges.
std::map<AddressRangesOwner *, std::vector<std::pair<uint64_t, uint64_t>>>
ObjectAddressRanges;
// Offset of an empty address ranges list.
uint32_t EmptyRangesListOffset;
/// When writing data to .debug_ranges remember offset per CU.
RangesCUMapType RangesSectionOffsetCUMap;
};
/// Serializes the .debug_loc DWARF section with LocationLists.
class DebugLocWriter {
public:
/// Writes the given location list to the writer.
void write(const LocationList &LocList, MCObjectWriter *Writer);
using UpdatedOffsetMapType = std::map<uint32_t, uint32_t>;
/// Returns mapping from offsets in the input .debug_loc to offsets in the
/// output .debug_loc section with the corresponding updated location list
/// entry.
const UpdatedOffsetMapType &getUpdatedLocationListOffsets() const {
return UpdatedOffsets;
}
private:
/// Current offset in the section (updated as new entries are written).
uint32_t SectionOffset{0};
/// Map from input offsets to output offsets for location lists that were
/// updated, generated after write().
UpdatedOffsetMapType UpdatedOffsets;
};
/// 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 .
virtual void patchBinary(std::string &BinaryContents) = 0;
};
/// Applies simple modifications to a binary string, such as directly replacing
/// the contents of a certain portion with a string or an integer.
class SimpleBinaryPatcher : public BinaryPatcher {
private:
std::vector<std::pair<uint32_t, std::string>> Patches;
/// 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);
public:
~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);
/// 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);
/// 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);
/// 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);
void patchBinary(std::string &BinaryContents) override;
};
/// Apply small modifications to the .debug_abbrev DWARF section.
class DebugAbbrevPatcher : public BinaryPatcher {
private:
/// Patch of changing one attribute to another.
struct AbbrevAttrPatch {
uint32_t Code; // Code of abbreviation to be modified.
uint16_t Attr; // ID of attribute to be replaced.
uint8_t NewAttr; // ID of the new attribute.
uint8_t NewForm; // Form of the new attribute.
};
std::map<const DWARFUnit *, std::vector<AbbrevAttrPatch>> Patches;
public:
~DebugAbbrevPatcher() { }
/// Adds a patch to change an attribute of an abbreviation that belongs to
/// \p Unit to another attribute.
/// \p AbbrevCode code of the abbreviation to be modified.
/// \p AttrTag ID of the attribute to be replaced.
/// \p NewAttrTag ID of the new attribute.
/// \p NewAttrForm Form of the new attribute.
/// We only handle standard forms, that are encoded in a single byte.
void addAttributePatch(const DWARFUnit *Unit,
uint32_t AbbrevCode,
uint16_t AttrTag,
uint8_t NewAttrTag,
uint8_t NewAttrForm);
void patchBinary(std::string &Contents) override;
};
} // namespace bolt
} // namespace llvm
#endif

View File

@ -1,21 +0,0 @@
//===--- DebugLineTableRowRef.cpp - Identifies a row in a .debug_line table ==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
#include "DebugLineTableRowRef.h"
namespace llvm {
namespace bolt {
const DebugLineTableRowRef DebugLineTableRowRef::NULL_ROW{0, 0};
} // namespace bolt
} // namespace llvm

View File

@ -1,64 +0,0 @@
//===--- DebugLineTableRowRef.h - Identifies a row in a .debug_line table -===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Class that references a row in a DWARFDebugLine::LineTable by the DWARF
// Context index of the DWARF Compile Unit that owns the Line Table and the row
// index. This is tied to our IR during disassembly so that we can later update
// .debug_line information. The RowIndex has a base of 1, which means a RowIndex
// of 1 maps to the first row of the line table and a RowIndex of 0 is invalid.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVM_BOLT_DEBUGLINETABLEROWREF_H
#define LLVM_TOOLS_LLVM_BOLT_DEBUGLINETABLEROWREF_H
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/Support/SMLoc.h"
namespace llvm {
namespace bolt {
struct DebugLineTableRowRef {
uint32_t DwCompileUnitIndex;
uint32_t RowIndex;
const static DebugLineTableRowRef NULL_ROW;
bool operator==(const DebugLineTableRowRef &Rhs) const {
return DwCompileUnitIndex == Rhs.DwCompileUnitIndex &&
RowIndex == Rhs.RowIndex;
}
bool operator!=(const DebugLineTableRowRef &Rhs) const {
return !(*this == Rhs);
}
static DebugLineTableRowRef fromSMLoc(const SMLoc &Loc) {
union {
decltype(Loc.getPointer()) Ptr;
DebugLineTableRowRef Ref;
} U;
U.Ptr = Loc.getPointer();
return U.Ref;
}
SMLoc toSMLoc() const {
union {
decltype(SMLoc().getPointer()) Ptr;
DebugLineTableRowRef Ref;
} U;
U.Ref = *this;
return SMLoc::getFromPointer(U.Ptr);
}
};
} // namespace bolt
} // namespace llvm
#endif

View File

@ -1,45 +0,0 @@
//===-- DebugLocWriter.cpp - Writes the DWARF .debug_loc section. ----------==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//===----------------------------------------------------------------------===//
#include "DebugLocWriter.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCObjectWriter.h"
#include <algorithm>
namespace llvm {
namespace bolt {
void DebugLocWriter::write(const LocationList &LocList,
MCObjectWriter *Writer) {
// Reference: DWARF 4 specification section 7.7.3.
UpdatedOffsets[LocList.getOriginalOffset()] = SectionOffset;
auto AbsoluteRanges = LocList.getAbsoluteAddressRanges();
for (const auto &Entry : LocList.getAbsoluteAddressRanges()) {
Writer->writeLE64(Entry.Begin);
Writer->writeLE64(Entry.End);
assert(Entry.Data && "Entry with null location expression.");
Writer->writeLE16(Entry.Data->size());
// Need to convert binary data from unsigned char to char.
Writer->writeBytes(
StringRef(reinterpret_cast<const char *>(Entry.Data->data()),
Entry.Data->size()));
SectionOffset += 2 * 8 + 2 + Entry.Data->size();
}
Writer->writeLE64(0);
Writer->writeLE64(0);
SectionOffset += 2 * 8;
}
} // namespace bolt
} // namespace llvm

View File

@ -1,53 +0,0 @@
//===-- DebugLocWriter.h - Writes the DWARF .debug_loc section -------------==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Class that serializes the .debug_loc section given LocationLists.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVM_BOLT_DEBUG_LOC_WRITER_H
#define LLVM_TOOLS_LLVM_BOLT_DEBUG_LOC_WRITER_H
#include "LocationList.h"
#include <map>
#include <vector>
namespace llvm {
class MCObjectWriter;
namespace bolt {
class DebugLocWriter {
public:
/// Writes the given location list to the writer.
void write(const LocationList &LocList, MCObjectWriter *Writer);
using UpdatedOffsetMapType = std::map<uint32_t, uint32_t>;
/// Returns mapping from offsets in the input .debug_loc to offsets in the
/// output .debug_loc section with the corresponding updated location list
/// entry.
const UpdatedOffsetMapType &getUpdatedLocationListOffsets() const {
return UpdatedOffsets;
}
private:
/// Current offset in the section (updated as new entries are written).
uint32_t SectionOffset{0};
/// Map from input offsets to output offsets for location lists that were
/// updated, generated after write().
UpdatedOffsetMapType UpdatedOffsets;
};
} // namespace bolt
} // namespace llvm
#endif

View File

@ -1,119 +0,0 @@
//===-- DebugRangesSectionsWriter.h - Writes DWARF address ranges sections -==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DebugRangesSectionsWriter.h"
#include "BinaryFunction.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCObjectWriter.h"
namespace llvm {
namespace bolt {
void DebugRangesSectionsWriter::AddRange(uint32_t CompileUnitOffset,
uint64_t Address,
uint64_t Size) {
CUAddressRanges[CompileUnitOffset].push_back(std::make_pair(Address, Size));
}
void DebugRangesSectionsWriter::AddRange(AddressRangesOwner *BF,
uint64_t Address,
uint64_t Size) {
ObjectAddressRanges[BF].push_back(std::make_pair(Address, Size));
}
namespace {
// 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).
// Terminates the list by writing a pair of two zeroes.
// Returns the number of written bytes.
uint32_t WriteAddressRanges(
MCObjectWriter *Writer,
const std::vector<std::pair<uint64_t, uint64_t>> &AddressRanges,
bool RelativeRange) {
// Write entries.
for (auto &Range : AddressRanges) {
Writer->writeLE64(Range.first);
Writer->writeLE64((!RelativeRange) * Range.first + Range.second);
}
// Finish with 0 entries.
Writer->writeLE64(0);
Writer->writeLE64(0);
return AddressRanges.size() * 16 + 16;
}
} // namespace
void DebugRangesSectionsWriter::WriteRangesSection(MCObjectWriter *Writer) {
uint32_t SectionOffset = 0;
for (const auto &CUOffsetAddressRangesPair : CUAddressRanges) {
uint64_t CUOffset = CUOffsetAddressRangesPair.first;
RangesSectionOffsetCUMap[CUOffset] = SectionOffset;
const auto &AddressRanges = CUOffsetAddressRangesPair.second;
SectionOffset += WriteAddressRanges(Writer, AddressRanges, false);
}
for (const auto &BFAddressRangesPair : ObjectAddressRanges) {
BFAddressRangesPair.first->setAddressRangesOffset(SectionOffset);
const auto &AddressRanges = BFAddressRangesPair.second;
SectionOffset += WriteAddressRanges(Writer, AddressRanges, false);
}
// Write an empty address list to be used for objects with unknown address
// ranges.
EmptyRangesListOffset = SectionOffset;
SectionOffset += WriteAddressRanges(
Writer,
std::vector<std::pair<uint64_t, uint64_t>>{},
false);
}
void
DebugRangesSectionsWriter::WriteArangesSection(MCObjectWriter *Writer) 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
for (const auto &CUOffsetAddressRangesPair : CUAddressRanges) {
uint64_t Offset = CUOffsetAddressRangesPair.first;
const auto &AddressRanges = CUOffsetAddressRangesPair.second;
// Emit header.
// Size of this set: 8 (size of the header) + 4 (padding after header)
// + 2*sizeof(uint64_t) bytes for each of the ranges, plus an extra
// pair of uint64_t's for the terminating, zero-length range.
// Does not include size field itself.
uint64_t Size = 8 + 4 + 2*sizeof(uint64_t) * (AddressRanges.size() + 1);
// Header field #1: set size.
Writer->writeLE32(Size);
// Header field #2: version number, 2 as per the specification.
Writer->writeLE16(2);
// Header field #3: debug info offset of the correspondent compile unit.
Writer->writeLE32(Offset);
// Header field #4: address size.
// 8 since we only write ELF64 binaries for now.
Writer->write8(8);
// Header field #5: segment size of target architecture.
Writer->write8(0);
// Padding before address table - 4 bytes in the 64-bit-pointer case.
Writer->writeLE32(0);
WriteAddressRanges(Writer, AddressRanges, true);
}
}
} // namespace bolt
} // namespace llvm

View File

@ -1,94 +0,0 @@
//===-- DebugRangesSectionsWriter.h - Writes DWARF address ranges sections -==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Class that serializes the .debug_ranges and .debug_aranges sections.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVM_BOLT_DEBUG_RANGES_SECTIONS_WRITER_H
#define LLVM_TOOLS_LLVM_BOLT_DEBUG_RANGES_SECTIONS_WRITER_H
#include <map>
#include <vector>
#include <utility>
namespace llvm {
class MCObjectWriter;
namespace bolt {
/// Abstract interface for classes that represent objects that have
/// associated address ranges in .debug_ranges. These address ranges can
/// be serialized by DebugRangesSectionsWriter which notifies the object
/// of where in the section its address ranges list was written.
class AddressRangesOwner {
public:
virtual void setAddressRangesOffset(uint32_t Offset) = 0;
};
class DebugRangesSectionsWriter {
public:
DebugRangesSectionsWriter() = default;
/// Adds a range to the .debug_arange section.
void AddRange(uint32_t CompileUnitOffset, uint64_t Address, uint64_t Size);
/// Adds an address range that belongs to a given object.
/// When .debug_ranges is written, the offset of the range corresponding
/// to the function will be set using BF->setAddressRangesOffset().
void AddRange(AddressRangesOwner *ARO, uint64_t Address, uint64_t Size);
using RangesCUMapType = std::map<uint32_t, uint32_t>;
/// Writes .debug_aranges with the added ranges to the MCObjectWriter.
void WriteArangesSection(MCObjectWriter *Writer) const;
/// Writes .debug_ranges with the added ranges to the MCObjectWriter.
void WriteRangesSection(MCObjectWriter *Writer);
/// Resets the writer to a clear state.
void reset() {
CUAddressRanges.clear();
ObjectAddressRanges.clear();
RangesSectionOffsetCUMap.clear();
}
/// Return mapping of CUs to offsets in .debug_ranges.
const RangesCUMapType &getRangesOffsetCUMap() const {
return RangesSectionOffsetCUMap;
}
/// Returns an offset of an empty address ranges list that is always written
/// to .debug_ranges
uint32_t getEmptyRangesListOffset() const { return EmptyRangesListOffset; }
private:
// Map from compile unit offset to the list of address intervals that belong
// to that compile unit. Each interval is a pair
// (first address, interval size).
std::map<uint32_t, std::vector<std::pair<uint64_t, uint64_t>>>
CUAddressRanges;
// Map from BinaryFunction to the list of address intervals that belong
// to that function, represented like CUAddressRanges.
std::map<AddressRangesOwner *, std::vector<std::pair<uint64_t, uint64_t>>>
ObjectAddressRanges;
// Offset of an empty address ranges list.
uint32_t EmptyRangesListOffset;
/// When writing data to .debug_ranges remember offset per CU.
RangesCUMapType RangesSectionOffsetCUMap;
};
} // namespace bolt
} // namespace llvm
#endif

View File

@ -1,61 +0,0 @@
//===--- LocationList.h - DWARF location lists ----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Represents DWARF location lists, maintaining their list of location
// expressions and the address ranges in which they are valid to be updated in
// the output debugging information.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVM_BOLT_LOCATION_LIST_H
#define LLVM_TOOLS_LLVM_BOLT_LOCATION_LIST_H
#include "BasicBlockOffsetRanges.h"
namespace llvm {
class DWARFCompileUnit;
class DWARFDebugInfoEntryMinimal;
namespace bolt {
class BinaryBasicBlock;
class LocationList {
public:
LocationList(uint32_t Offset) : DebugLocOffset(Offset) { }
/// Add a location expression that is valid in [BeginAddress, EndAddress)
/// within Function to location list.
void addLocation(const BasicBlockOffsetRanges::BinaryData *Expression,
BinaryFunction &Function,
uint64_t BeginAddress,
uint64_t EndAddress) {
BBOffsetRanges.addAddressRange(Function, BeginAddress, EndAddress,
Expression);
}
std::vector<BasicBlockOffsetRanges::AbsoluteRange>
getAbsoluteAddressRanges() const {
return BBOffsetRanges.getAbsoluteAddressRanges();
}
uint32_t getOriginalOffset() const { return DebugLocOffset; }
private:
BasicBlockOffsetRanges BBOffsetRanges;
// Offset of this location list in the input .debug_loc section.
uint32_t DebugLocOffset;
};
} // namespace bolt
} // namespace llvm
#endif

View File

@ -14,7 +14,6 @@
#include "BinaryContext.h"
#include "BinaryFunction.h"
#include "DataReader.h"
#include "DebugLineTableRowRef.h"
#include "Exceptions.h"
#include "RewriteInstance.h"
#include "llvm/ADT/STLExtras.h"

View File

@ -14,9 +14,7 @@
#ifndef LLVM_TOOLS_LLVM_BOLT_REWRITE_INSTANCE_H
#define LLVM_TOOLS_LLVM_BOLT_REWRITE_INSTANCE_H
#include "BinaryPatcher.h"
#include "DebugLocWriter.h"
#include "DebugRangesSectionsWriter.h"
#include "DebugData.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/Object/ELFObjectFile.h"