#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/LEB128.h"
typedef HalfOpenIntervalMap<uint64_t, int64_t> FunctionIntervals;
+// FIXME: Delete this structure.
+struct PatchLocation {
+ DIE::value_iterator I;
+
+ PatchLocation() = default;
+ PatchLocation(DIE::value_iterator I) : I(I) {}
+
+ void set(uint64_t New) const {
+ assert(I);
+ const auto &Old = *I;
+ assert(Old.getType() == DIEValue::isInteger);
+ *I = DIEValue(Old.getAttribute(), Old.getForm(), DIEInteger(New));
+ }
+
+ uint64_t get() const {
+ assert(I);
+ return I->getDIEInteger().getValue();
+ }
+};
+
/// \brief Stores all information relating to a compile unit, be it in
/// its original instance in the object file to its brand new cloned
/// and linked DIE tree.
CompileUnit(DWARFUnit &OrigUnit, unsigned ID)
: OrigUnit(OrigUnit), ID(ID), LowPc(UINT64_MAX), HighPc(0), RangeAlloc(),
- Ranges(RangeAlloc), UnitRangeAttribute(nullptr) {
+ Ranges(RangeAlloc) {
Info.resize(OrigUnit.getNumDIEs());
}
unsigned getUniqueID() const { return ID; }
- DIE *getOutputUnitDIE() const { return CUDie.get(); }
- void setOutputUnitDIE(DIE *Die) { CUDie.reset(Die); }
+ DIE *getOutputUnitDIE() const { return CUDie; }
+ void setOutputUnitDIE(DIE *Die) { CUDie = Die; }
DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; }
const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; }
uint64_t getLowPc() const { return LowPc; }
uint64_t getHighPc() const { return HighPc; }
- DIEInteger *getUnitRangesAttribute() const { return UnitRangeAttribute; }
+ Optional<PatchLocation> getUnitRangesAttribute() const {
+ return UnitRangeAttribute;
+ }
const FunctionIntervals &getFunctionRanges() const { return Ranges; }
- const std::vector<DIEInteger *> &getRangesAttributes() const {
+ const std::vector<PatchLocation> &getRangesAttributes() const {
return RangeAttributes;
}
- const std::vector<std::pair<DIEInteger *, int64_t>> &
+ const std::vector<std::pair<PatchLocation, int64_t>> &
getLocationAttributes() const {
return LocationAttributes;
}
/// RefUnit by \p Attr. The attribute should be fixed up later to
/// point to the absolute offset of \p Die in the debug_info section.
void noteForwardReference(DIE *Die, const CompileUnit *RefUnit,
- DIEInteger *Attr);
+ PatchLocation Attr);
/// \brief Apply all fixups recored by noteForwardReference().
void fixupForwardReferences();
/// \brief Keep track of a DW_AT_range attribute that we will need to
/// patch up later.
- void noteRangeAttribute(const DIE &Die, DIEInteger *Attr);
+ void noteRangeAttribute(const DIE &Die, PatchLocation Attr);
/// \brief Keep track of a location attribute pointing to a location
/// list in the debug_loc section.
- void noteLocationAttribute(DIEInteger *Attr, int64_t PcOffset);
+ void noteLocationAttribute(PatchLocation Attr, int64_t PcOffset);
/// \brief Add a name accelerator entry for \p Die with \p Name
/// which is stored in the string table at \p Offset.
void addTypeAccelerator(const DIE *Die, const char *Name, uint32_t Offset);
struct AccelInfo {
- StringRef Name; ///< Name of the entry.
- const DIE *Die; ///< DIE this entry describes.
+ StringRef Name; ///< Name of the entry.
+ const DIE *Die; ///< DIE this entry describes.
uint32_t NameOffset; ///< Offset of Name in the string pool.
bool SkipPubSection; ///< Emit this entry only in the apple_* sections.
DWARFUnit &OrigUnit;
unsigned ID;
std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index.
- std::unique_ptr<DIE> CUDie; ///< Root of the linked DIE tree.
+ DIE *CUDie; ///< Root of the linked DIE tree.
uint64_t StartOffset;
uint64_t NextUnitOffset;
/// The offsets for the attributes in this array couldn't be set while
/// cloning because for cross-cu forward refences the target DIE's
/// offset isn't known you emit the reference attribute.
- std::vector<std::tuple<DIE *, const CompileUnit *, DIEInteger *>>
+ std::vector<std::tuple<DIE *, const CompileUnit *, PatchLocation>>
ForwardDIEReferences;
FunctionIntervals::Allocator RangeAlloc;
/// \brief DW_AT_ranges attributes to patch after we have gathered
/// all the unit's function addresses.
/// @{
- std::vector<DIEInteger *> RangeAttributes;
- DIEInteger *UnitRangeAttribute;
+ std::vector<PatchLocation> RangeAttributes;
+ Optional<PatchLocation> UnitRangeAttribute;
/// @}
/// \brief Location attributes that need to be transfered from th
/// original debug_loc section to the liked one. They are stored
/// along with the PC offset that is to be applied to their
/// function's address.
- std::vector<std::pair<DIEInteger *, int64_t>> LocationAttributes;
+ std::vector<std::pair<PatchLocation, int64_t>> LocationAttributes;
/// \brief Accelerator entries for the unit, both for the pub*
/// sections and the apple* ones.
/// \brief Keep track of a forward cross-cu reference from this unit
/// to \p Die that lives in \p RefUnit.
void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit *RefUnit,
- DIEInteger *Attr) {
+ PatchLocation Attr) {
ForwardDIEReferences.emplace_back(Die, RefUnit, Attr);
}
for (const auto &Ref : ForwardDIEReferences) {
DIE *RefDie;
const CompileUnit *RefUnit;
- DIEInteger *Attr;
+ PatchLocation Attr;
std::tie(RefDie, RefUnit, Attr) = Ref;
- Attr->setValue(RefDie->getOffset() + RefUnit->getStartOffset());
+ Attr.set(RefDie->getOffset() + RefUnit->getStartOffset());
}
}
this->HighPc = std::max(HighPc, FuncHighPc + PcOffset);
}
-void CompileUnit::noteRangeAttribute(const DIE &Die, DIEInteger *Attr) {
+void CompileUnit::noteRangeAttribute(const DIE &Die, PatchLocation Attr) {
if (Die.getTag() != dwarf::DW_TAG_compile_unit)
RangeAttributes.push_back(Attr);
else
UnitRangeAttribute = Attr;
}
-void CompileUnit::noteLocationAttribute(DIEInteger *Attr, int64_t PcOffset) {
+void CompileUnit::noteLocationAttribute(PatchLocation Attr, int64_t PcOffset) {
LocationAttributes.emplace_back(Attr, PcOffset);
}
uint32_t RangesSectionSize;
uint32_t LocSectionSize;
uint32_t LineSectionSize;
+ uint32_t FrameSectionSize;
/// \brief Emit the pubnames or pubtypes section contribution for \p
/// Unit into \p Sec. The data is provided in \p Names.
- void emitPubSectionForUnit(const MCSection *Sec, StringRef Name,
+ void emitPubSectionForUnit(MCSection *Sec, StringRef Name,
const CompileUnit &Unit,
const std::vector<CompileUnit::AccelInfo> &Names);
/// \brief Emit the .debug_pubtypes contribution for \p Unit.
void emitPubTypesForUnit(const CompileUnit &Unit);
+
+ /// \brief Emit a CIE.
+ void emitCIE(StringRef CIEBytes);
+
+ /// \brief Emit an FDE with data \p Bytes.
+ void emitFDE(uint32_t CIEOffset, uint32_t AddreSize, uint32_t Address,
+ StringRef Bytes);
+
+ uint32_t getFrameSectionSize() const { return FrameSectionSize; }
};
bool DwarfStreamer::init(Triple TheTriple, StringRef OutputFilename) {
MOFI.reset(new MCObjectFileInfo);
MC.reset(new MCContext(MAI.get(), MRI.get(), MOFI.get()));
- MOFI->InitMCObjectFileInfo(TripleName, Reloc::Default, CodeModel::Default,
+ MOFI->InitMCObjectFileInfo(TheTriple, Reloc::Default, CodeModel::Default,
*MC);
MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, "");
RangesSectionSize = 0;
LocSectionSize = 0;
LineSectionSize = 0;
+ FrameSectionSize = 0;
return true;
}
/// point to the new entries.
void DwarfStreamer::emitLocationsForUnit(const CompileUnit &Unit,
DWARFContext &Dwarf) {
- const std::vector<std::pair<DIEInteger *, int64_t>> &Attributes =
- Unit.getLocationAttributes();
+ const auto &Attributes = Unit.getLocationAttributes();
if (Attributes.empty())
return;
const DWARFSection &InputSec = Dwarf.getLocSection();
DataExtractor Data(InputSec.Data, Dwarf.isLittleEndian(), AddressSize);
DWARFUnit &OrigUnit = Unit.getOrigUnit();
- const auto *OrigUnitDie = OrigUnit.getCompileUnitDIE(false);
+ const auto *OrigUnitDie = OrigUnit.getUnitDIE(false);
int64_t UnitPcOffset = 0;
uint64_t OrigLowPc = OrigUnitDie->getAttributeValueAsAddress(
&OrigUnit, dwarf::DW_AT_low_pc, -1ULL);
UnitPcOffset = int64_t(OrigLowPc) - Unit.getLowPc();
for (const auto &Attr : Attributes) {
- uint32_t Offset = Attr.first->getValue();
- Attr.first->setValue(LocSectionSize);
+ uint32_t Offset = Attr.first.get();
+ Attr.first.set(LocSectionSize);
// This is the quantity to add to the old location address to get
// the correct address for the new one.
int64_t LocPcOffset = Attr.second + UnitPcOffset;
unsigned PointerSize) {
// Switch to the section where the table will be emitted into.
MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLineSection());
- MCSymbol *LineStartSym = MC->CreateTempSymbol();
- MCSymbol *LineEndSym = MC->CreateTempSymbol();
+ MCSymbol *LineStartSym = MC->createTempSymbol();
+ MCSymbol *LineEndSym = MC->createTempSymbol();
// The first 4 bytes is the total length of the information for this
// compilation unit (not including these 4 bytes for the length).
/// \brief Emit the pubnames or pubtypes section contribution for \p
/// Unit into \p Sec. The data is provided in \p Names.
void DwarfStreamer::emitPubSectionForUnit(
- const MCSection *Sec, StringRef SecName, const CompileUnit &Unit,
+ MCSection *Sec, StringRef SecName, const CompileUnit &Unit,
const std::vector<CompileUnit::AccelInfo> &Names) {
if (Names.empty())
return;
Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); // Length
Asm->OutStreamer->EmitLabel(BeginLabel);
Asm->EmitInt16(dwarf::DW_PUBNAMES_VERSION); // Version
- Asm->EmitInt32(Unit.getStartOffset()); // Unit offset
+ Asm->EmitInt32(Unit.getStartOffset()); // Unit offset
Asm->EmitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset()); // Size
HeaderEmitted = true;
}
"types", Unit, Unit.getPubtypes());
}
+/// \brief Emit a CIE into the debug_frame section.
+void DwarfStreamer::emitCIE(StringRef CIEBytes) {
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfFrameSection());
+
+ MS->EmitBytes(CIEBytes);
+ FrameSectionSize += CIEBytes.size();
+}
+
+/// \brief Emit a FDE into the debug_frame section. \p FDEBytes
+/// contains the FDE data without the length, CIE offset and address
+/// which will be replaced with the paramter values.
+void DwarfStreamer::emitFDE(uint32_t CIEOffset, uint32_t AddrSize,
+ uint32_t Address, StringRef FDEBytes) {
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfFrameSection());
+
+ MS->EmitIntValue(FDEBytes.size() + 4 + AddrSize, 4);
+ MS->EmitIntValue(CIEOffset, 4);
+ MS->EmitIntValue(Address, AddrSize);
+ MS->EmitBytes(FDEBytes);
+ FrameSectionSize += FDEBytes.size() + 8 + AddrSize;
+}
+
/// \brief The core of the Dwarf linking logic.
///
/// The link of the dwarf information from the object files will be
public:
DwarfLinker(StringRef OutputFilename, const LinkOptions &Options)
: OutputFilename(OutputFilename), Options(Options),
- BinHolder(Options.Verbose) {}
+ BinHolder(Options.Verbose), LastCIEOffset(0) {}
~DwarfLinker() {
for (auto *Abbrev : Abbreviations)
/// \brief Emit the accelerator entries for \p Unit.
void emitAcceleratorEntriesForUnit(CompileUnit &Unit);
+ /// \brief Patch the frame info for an object file and emit it.
+ void patchFrameInfoForObject(const DebugMapObject &, DWARFContext &,
+ unsigned AddressSize);
+
/// \brief DIELoc objects that need to be destructed (but not freed!).
std::vector<DIELoc *> DIELocs;
/// \brief DIEBlock objects that need to be destructed (but not freed!).
///
/// See startDebugObject() for a more complete description of its use.
std::map<uint64_t, std::pair<uint64_t, int64_t>> Ranges;
+
+ /// \brief The CIEs that have been emitted in the output
+ /// section. The actual CIE data serves a the key to this StringMap,
+ /// this takes care of comparing the semantics of CIEs defined in
+ /// different object files.
+ StringMap<uint32_t> EmittedCIEs;
+
+ /// Offset of the last CIE that has been emitted in the output
+ /// debug_frame section.
+ uint32_t LastCIEOffset;
};
/// \brief Similar to DWARFUnitSection::getUnitForOffset(), but
ValidRelocs.clear();
Ranges.clear();
- for (auto *Block : DIEBlocks)
- Block->~DIEBlock();
- for (auto *Loc : DIELocs)
- Loc->~DIELoc();
+ for (auto I = DIEBlocks.begin(), E = DIEBlocks.end(); I != E; ++I)
+ (*I)->~DIEBlock();
+ for (auto I = DIELocs.begin(), E = DIELocs.end(); I != E; ++I)
+ (*I)->~DIELoc();
DIEBlocks.clear();
DIELocs.clear();
object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl();
MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef);
unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc);
- uint64_t Offset64;
- if ((RelocSize != 4 && RelocSize != 8) || Reloc.getOffset(Offset64)) {
+ uint64_t Offset64 = Reloc.getOffset();
+ if ((RelocSize != 4 && RelocSize != 8)) {
reportWarning(" unsupported relocation in debug_info section.");
continue;
}
auto Sym = Reloc.getSymbol();
if (Sym != Obj.symbol_end()) {
- StringRef SymbolName;
- if (Sym->getName(SymbolName)) {
+ ErrorOr<StringRef> SymbolName = Sym->getName();
+ if (!SymbolName) {
reportWarning("error getting relocation symbol name.");
continue;
}
- if (const auto *Mapping = DMO.lookupSymbol(SymbolName))
+ if (const auto *Mapping = DMO.lookupSymbol(*SymbolName))
ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping);
} else if (const auto *Mapping = DMO.lookupObjectAddress(Addend)) {
// Do not store the addend. The addend was the address of the
return false;
const auto &ValidReloc = ValidRelocs[NextValidReloc++];
+ const auto &Mapping = ValidReloc.Mapping->getValue();
if (Options.Verbose)
outs() << "Found valid debug map entry: " << ValidReloc.Mapping->getKey()
<< " " << format("\t%016" PRIx64 " => %016" PRIx64,
- ValidReloc.Mapping->getValue().ObjectAddress,
- ValidReloc.Mapping->getValue().BinaryAddress);
+ uint64_t(Mapping.ObjectAddress),
+ uint64_t(Mapping.BinaryAddress));
- Info.AddrAdjust = int64_t(ValidReloc.Mapping->getValue().BinaryAddress) +
- ValidReloc.Addend -
- ValidReloc.Mapping->getValue().ObjectAddress;
+ Info.AddrAdjust = int64_t(Mapping.BinaryAddress) + ValidReloc.Addend -
+ Mapping.ObjectAddress;
Info.InDebugMap = true;
return true;
}
// Switch everything to out of line strings.
const char *String = *Val.getAsCString(&U);
unsigned Offset = StringPool.getStringOffset(String);
- Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_strp,
- new (DIEAlloc) DIEInteger(Offset));
+ Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_strp,
+ DIEInteger(Offset));
return 4;
}
assert(Ref > InputDIE.getOffset());
// We haven't cloned this DIE yet. Just create an empty one and
// store it. It'll get really cloned when we process it.
- RefInfo.Clone = new DIE(dwarf::Tag(RefDie->getTag()));
+ RefInfo.Clone = DIE::get(DIEAlloc, dwarf::Tag(RefDie->getTag()));
}
NewRefDie = RefInfo.Clone;
// to find the unit offset. (We don't have a DwarfDebug)
// FIXME: we should be able to design DIEEntry reliance on
// DwarfDebug away.
- DIEInteger *Attr;
+ uint64_t Attr;
if (Ref < InputDIE.getOffset()) {
// We must have already cloned that DIE.
uint32_t NewRefOffset =
RefUnit->getStartOffset() + NewRefDie->getOffset();
- Attr = new (DIEAlloc) DIEInteger(NewRefOffset);
+ Attr = NewRefOffset;
+ Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
+ dwarf::DW_FORM_ref_addr, DIEInteger(Attr));
} else {
// A forward reference. Note and fixup later.
- Attr = new (DIEAlloc) DIEInteger(0xBADDEF);
- Unit.noteForwardReference(NewRefDie, RefUnit, Attr);
+ Attr = 0xBADDEF;
+ Unit.noteForwardReference(
+ NewRefDie, RefUnit,
+ Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
+ dwarf::DW_FORM_ref_addr, DIEInteger(Attr)));
}
- Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_ref_addr,
- Attr);
return AttrSize;
}
- Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form),
- new (DIEAlloc) DIEEntry(*NewRefDie));
+ Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
+ dwarf::Form(AttrSpec.Form), DIEEntry(*NewRefDie));
return AttrSize;
}
const DWARFFormValue &Val,
unsigned AttrSize) {
DIE *Attr;
- DIEValue *Value;
+ DIEValue Value;
DIELoc *Loc = nullptr;
DIEBlock *Block = nullptr;
// Just copy the block data over.
if (AttrSpec.Form == dwarf::DW_FORM_exprloc) {
- Loc = new (DIEAlloc) DIELoc();
+ Loc = new (DIEAlloc) DIELoc;
DIELocs.push_back(Loc);
} else {
- Block = new (DIEAlloc) DIEBlock();
+ Block = new (DIEAlloc) DIEBlock;
DIEBlocks.push_back(Block);
}
Attr = Loc ? static_cast<DIE *>(Loc) : static_cast<DIE *>(Block);
- Value = Loc ? static_cast<DIEValue *>(Loc) : static_cast<DIEValue *>(Block);
+
+ if (Loc)
+ Value = DIEValue(dwarf::Attribute(AttrSpec.Attr),
+ dwarf::Form(AttrSpec.Form), Loc);
+ else
+ Value = DIEValue(dwarf::Attribute(AttrSpec.Attr),
+ dwarf::Form(AttrSpec.Form), Block);
ArrayRef<uint8_t> Bytes = *Val.getAsBlock();
for (auto Byte : Bytes)
- Attr->addValue(static_cast<dwarf::Attribute>(0), dwarf::DW_FORM_data1,
- new (DIEAlloc) DIEInteger(Byte));
+ Attr->addValue(DIEAlloc, static_cast<dwarf::Attribute>(0),
+ dwarf::DW_FORM_data1, DIEInteger(Byte));
// FIXME: If DIEBlock and DIELoc just reuses the Size field of
// the DIE class, this if could be replaced by
// Attr->setSize(Bytes.size()).
else
Block->ComputeSize(&Streamer->getAsmPrinter());
}
- Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form),
- Value);
+ Die.addValue(DIEAlloc, Value);
return AttrSize;
}
Addr = (Info.OrigHighPc ? Info.OrigHighPc : Addr) + Info.PCOffset;
}
- Die.addValue(static_cast<dwarf::Attribute>(AttrSpec.Attr),
- static_cast<dwarf::Form>(AttrSpec.Form),
- new (DIEAlloc) DIEInteger(Addr));
+ Die.addValue(DIEAlloc, static_cast<dwarf::Attribute>(AttrSpec.Attr),
+ static_cast<dwarf::Form>(AttrSpec.Form), DIEInteger(Addr));
return Unit.getOrigUnit().getAddressByteSize();
}
&Unit.getOrigUnit(), &InputDIE);
return 0;
}
- DIEInteger *Attr = new (DIEAlloc) DIEInteger(Value);
+ PatchLocation Patch =
+ Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
+ dwarf::Form(AttrSpec.Form), DIEInteger(Value));
if (AttrSpec.Attr == dwarf::DW_AT_ranges)
- Unit.noteRangeAttribute(Die, Attr);
+ Unit.noteRangeAttribute(Die, Patch);
// A more generic way to check for location attributes would be
// nice, but it's very unlikely that any other attribute needs a
// location list.
else if (AttrSpec.Attr == dwarf::DW_AT_location ||
AttrSpec.Attr == dwarf::DW_AT_frame_base)
- Unit.noteLocationAttribute(Attr, Info.PCOffset);
+ Unit.noteLocationAttribute(Patch, Info.PCOffset);
else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
Info.IsDeclaration = true;
- Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form),
- Attr);
return AttrSize;
}
// (see cloneDieReferenceAttribute()).
DIE *Die = Info.Clone;
if (!Die)
- Die = Info.Clone = new DIE(dwarf::Tag(InputDIE.getTag()));
+ Die = Info.Clone = DIE::get(DIEAlloc, dwarf::Tag(InputDIE.getTag()));
assert(Die->getTag() == InputDIE.getTag());
Die->setOffset(OutOffset);
Unit.addTypeAccelerator(Die, AttrInfo.Name, AttrInfo.NameOffset);
}
- DIEAbbrev &NewAbbrev = Die->getAbbrev();
+ DIEAbbrev NewAbbrev = Die->generateAbbrev();
// If a scope DIE is kept, we must have kept at least one child. If
// it's not the case, we'll just be emitting one wasteful end of
// children marker, but things won't break.
if (InputDIE.hasChildren())
NewAbbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes);
// Assign a permanent abbrev number
- AssignAbbrev(Die->getAbbrev());
+ AssignAbbrev(NewAbbrev);
+ Die->setAbbrevNumber(NewAbbrev.getNumber());
// Add the size of the abbreviation number to the output offset.
OutOffset += getULEB128Size(Die->getAbbrevNumber());
for (auto *Child = InputDIE.getFirstChild(); Child && !Child->isNULL();
Child = Child->getSibling()) {
if (DIE *Clone = cloneDIE(*Child, Unit, PCOffset, OutOffset)) {
- Die->addChild(std::unique_ptr<DIE>(Clone));
+ Die->addChild(Clone);
OutOffset = Clone->getOffset() + Clone->getSize();
}
}
OrigDwarf.isLittleEndian(), AddressSize);
auto InvalidRange = FunctionRanges.end(), CurrRange = InvalidRange;
DWARFUnit &OrigUnit = Unit.getOrigUnit();
- const auto *OrigUnitDie = OrigUnit.getCompileUnitDIE(false);
+ const auto *OrigUnitDie = OrigUnit.getUnitDIE(false);
uint64_t OrigLowPc = OrigUnitDie->getAttributeValueAsAddress(
&OrigUnit, dwarf::DW_AT_low_pc, -1ULL);
// Ranges addresses are based on the unit's low_pc. Compute the
UnitPcOffset = int64_t(OrigLowPc) - Unit.getLowPc();
for (const auto &RangeAttribute : Unit.getRangesAttributes()) {
- uint32_t Offset = RangeAttribute->getValue();
- RangeAttribute->setValue(Streamer->getRangesSectionSize());
+ uint32_t Offset = RangeAttribute.get();
+ RangeAttribute.set(Streamer->getRangesSectionSize());
RangeList.extract(RangeExtractor, &Offset);
const auto &Entries = RangeList.getEntries();
const DWARFDebugRangeList::RangeListEntry &First = Entries.front();
/// but for the sake of initial bit-for-bit compatibility with legacy
/// dsymutil, we have to do it in a delayed pass.
void DwarfLinker::generateUnitRanges(CompileUnit &Unit) const {
- DIEInteger *Attr = Unit.getUnitRangesAttribute();
+ auto Attr = Unit.getUnitRangesAttribute();
if (Attr)
- Attr->setValue(Streamer->getRangesSectionSize());
- Streamer->emitUnitRangesEntries(Unit, Attr != nullptr);
+ Attr->set(Streamer->getRangesSectionSize());
+ Streamer->emitUnitRangesEntries(Unit, static_cast<bool>(Attr));
}
/// \brief Insert the new line info sequence \p Seq into the current
Seq.clear();
}
+static void patchStmtList(DIE &Die, DIEInteger Offset) {
+ for (auto &V : Die.values())
+ if (V.getAttribute() == dwarf::DW_AT_stmt_list) {
+ V = DIEValue(V.getAttribute(), V.getForm(), Offset);
+ return;
+ }
+
+ llvm_unreachable("Didn't find DW_AT_stmt_list in cloned DIE!");
+}
+
/// \brief Extract the line table for \p Unit from \p OrigDwarf, and
/// recreate a relocated version of these for the address ranges that
/// are present in the binary.
void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit,
DWARFContext &OrigDwarf) {
- const DWARFDebugInfoEntryMinimal *CUDie =
- Unit.getOrigUnit().getCompileUnitDIE();
+ const DWARFDebugInfoEntryMinimal *CUDie = Unit.getOrigUnit().getUnitDIE();
uint64_t StmtList = CUDie->getAttributeValueAsSectionOffset(
&Unit.getOrigUnit(), dwarf::DW_AT_stmt_list, -1ULL);
if (StmtList == -1ULL)
return;
// Update the cloned DW_AT_stmt_list with the correct debug_line offset.
- if (auto *OutputDIE = Unit.getOutputUnitDIE()) {
- const auto &Abbrev = OutputDIE->getAbbrev().getData();
- auto Stmt = std::find_if(
- Abbrev.begin(), Abbrev.end(), [](const DIEAbbrevData &AbbrevData) {
- return AbbrevData.getAttribute() == dwarf::DW_AT_stmt_list;
- });
- assert(Stmt < Abbrev.end() && "Didn't find DW_AT_stmt_list in cloned DIE!");
- DIEInteger *StmtAttr =
- cast<DIEInteger>(OutputDIE->getValues()[Stmt - Abbrev.begin()]);
- StmtAttr->setValue(Streamer->getLineSectionSize());
- }
+ if (auto *OutputDIE = Unit.getOutputUnitDIE())
+ patchStmtList(*OutputDIE, DIEInteger(Streamer->getLineSectionSize()));
// Parse the original line info for the unit.
DWARFDebugLine::LineTable LineTable;
Streamer->emitPubTypesForUnit(Unit);
}
+/// \brief Read the frame info stored in the object, and emit the
+/// patched frame descriptions for the linked binary.
+///
+/// This is actually pretty easy as the data of the CIEs and FDEs can
+/// be considered as black boxes and moved as is. The only thing to do
+/// is to patch the addresses in the headers.
+void DwarfLinker::patchFrameInfoForObject(const DebugMapObject &DMO,
+ DWARFContext &OrigDwarf,
+ unsigned AddrSize) {
+ StringRef FrameData = OrigDwarf.getDebugFrameSection();
+ if (FrameData.empty())
+ return;
+
+ DataExtractor Data(FrameData, OrigDwarf.isLittleEndian(), 0);
+ uint32_t InputOffset = 0;
+
+ // Store the data of the CIEs defined in this object, keyed by their
+ // offsets.
+ DenseMap<uint32_t, StringRef> LocalCIES;
+
+ while (Data.isValidOffset(InputOffset)) {
+ uint32_t EntryOffset = InputOffset;
+ uint32_t InitialLength = Data.getU32(&InputOffset);
+ if (InitialLength == 0xFFFFFFFF)
+ return reportWarning("Dwarf64 bits no supported");
+
+ uint32_t CIEId = Data.getU32(&InputOffset);
+ if (CIEId == 0xFFFFFFFF) {
+ // This is a CIE, store it.
+ StringRef CIEData = FrameData.substr(EntryOffset, InitialLength + 4);
+ LocalCIES[EntryOffset] = CIEData;
+ // The -4 is to account for the CIEId we just read.
+ InputOffset += InitialLength - 4;
+ continue;
+ }
+
+ uint32_t Loc = Data.getUnsigned(&InputOffset, AddrSize);
+
+ // Some compilers seem to emit frame info that doesn't start at
+ // the function entry point, thus we can't just lookup the address
+ // in the debug map. Use the linker's range map to see if the FDE
+ // describes something that we can relocate.
+ auto Range = Ranges.upper_bound(Loc);
+ if (Range != Ranges.begin())
+ --Range;
+ if (Range == Ranges.end() || Range->first > Loc ||
+ Range->second.first <= Loc) {
+ // The +4 is to account for the size of the InitialLength field itself.
+ InputOffset = EntryOffset + InitialLength + 4;
+ continue;
+ }
+
+ // This is an FDE, and we have a mapping.
+ // Have we already emitted a corresponding CIE?
+ StringRef CIEData = LocalCIES[CIEId];
+ if (CIEData.empty())
+ return reportWarning("Inconsistent debug_frame content. Dropping.");
+
+ // Look if we already emitted a CIE that corresponds to the
+ // referenced one (the CIE data is the key of that lookup).
+ auto IteratorInserted = EmittedCIEs.insert(
+ std::make_pair(CIEData, Streamer->getFrameSectionSize()));
+ // If there is no CIE yet for this ID, emit it.
+ if (IteratorInserted.second ||
+ // FIXME: dsymutil-classic only caches the last used CIE for
+ // reuse. Mimic that behavior for now. Just removing that
+ // second half of the condition and the LastCIEOffset variable
+ // makes the code DTRT.
+ LastCIEOffset != IteratorInserted.first->getValue()) {
+ LastCIEOffset = Streamer->getFrameSectionSize();
+ IteratorInserted.first->getValue() = LastCIEOffset;
+ Streamer->emitCIE(CIEData);
+ }
+
+ // Emit the FDE with updated address and CIE pointer.
+ // (4 + AddrSize) is the size of the CIEId + initial_location
+ // fields that will get reconstructed by emitFDE().
+ unsigned FDERemainingBytes = InitialLength - (4 + AddrSize);
+ Streamer->emitFDE(IteratorInserted.first->getValue(), AddrSize,
+ Loc + Range->second.second,
+ FrameData.substr(InputOffset, FDERemainingBytes));
+ InputOffset += FDERemainingBytes;
+ }
+}
+
bool DwarfLinker::link(const DebugMap &Map) {
if (Map.begin() == Map.end()) {
// In a first phase, just read in the debug info and store the DIE
// parent links that we will use during the next phase.
for (const auto &CU : DwarfContext.compile_units()) {
- auto *CUDie = CU->getCompileUnitDIE(false);
+ auto *CUDie = CU->getUnitDIE(false);
if (Options.Verbose) {
outs() << "Input compilation unit:";
CUDie->dump(outs(), CU.get(), 0);
// references require the ParentIdx to be setup for every CU in
// the object file before calling this.
for (auto &CurrentUnit : Units)
- lookForDIEsToKeep(*CurrentUnit.getOrigUnit().getCompileUnitDIE(), *Obj,
+ lookForDIEsToKeep(*CurrentUnit.getOrigUnit().getUnitDIE(), *Obj,
CurrentUnit, 0);
// The calls to applyValidRelocs inside cloneDIE will walk the
// to clone/emit.
if (!ValidRelocs.empty())
for (auto &CurrentUnit : Units) {
- const auto *InputDIE = CurrentUnit.getOrigUnit().getCompileUnitDIE();
+ const auto *InputDIE = CurrentUnit.getOrigUnit().getUnitDIE();
CurrentUnit.setStartOffset(OutputDebugInfoSize);
DIE *OutputDIE = cloneDIE(*InputDIE, CurrentUnit, 0 /* PCOffset */,
11 /* Unit Header size */);
Streamer->emitDIE(*CurrentUnit.getOutputUnitDIE());
}
+ if (!ValidRelocs.empty() && !Options.NoOutput && !Units.empty())
+ patchFrameInfoForObject(*Obj, DwarfContext,
+ Units[0].getOrigUnit().getAddressByteSize());
+
// Clean-up before starting working on the next object.
endDebugObject();
}