[dsymutil] Add support to generate .debug_pubnames and .debug_pubtypes

The information gathering part of the patch stores a bit more information
than what is strictly necessary for these 2 sections. The rest will
become useful when we start emitting __apple_* type accelerator tables.

llvm-svn: 232342
This commit is contained in:
Frederic Riss 2015-03-16 02:05:10 +00:00
parent 9fdb81d09b
commit bce93ff011
4 changed files with 279 additions and 4 deletions

View File

@ -186,4 +186,32 @@ CHECK-NEXT: 0x0000000100000f7b 20 0 1 0 0 is_stmt
CHECK-NEXT: 0x0000000100000f84 20 0 1 0 0 is_stmt end_sequence
CHECK-NEXT: 0x0000000100000f90 11 0 1 0 0 is_stmt
CHECK-NEXT: 0x0000000100000f9b 12 0 1 0 0 is_stmt prologue_end
CHECK-NEXT: 0x0000000100000fa9 12 0 1 0 0 is_stmt end_sequence
CHECK-NEXT: 0x0000000100000fa9 12 0 1 0 0 is_stmt end_sequence
CHECK: .debug_pubnames contents:
CHECK-NEXT: length = 0x00000017 version = 0x0002 unit_offset = 0x00000000 unit_size = 0x00000081
CHECK-NEXT: Offset Name
CHECK-NEXT: 0x00000026 "main"
CHECK-NEXT: length = 0x00000036 version = 0x0002 unit_offset = 0x00000081 unit_size = 0x000000a5
CHECK-NEXT: Offset Name
CHECK-NEXT: 0x0000002d "private_int"
CHECK-NEXT: 0x00000042 "baz"
CHECK-NEXT: 0x00000057 "foo"
CHECK-NEXT: 0x00000086 "inc"
CHECK-NEXT: length = 0x00000026 version = 0x0002 unit_offset = 0x00000126 unit_size = 0x00000096
CHECK-NEXT: Offset Name
CHECK-NEXT: 0x00000026 "val"
CHECK-NEXT: 0x00000048 "bar"
CHECK-NEXT: 0x00000077 "inc"
CHECK: .debug_pubtypes contents:
CHECK-NEXT: length = 0x0000001f version = 0x0002 unit_offset = 0x00000000 unit_size = 0x00000081
CHECK-NEXT: Offset Name
CHECK-NEXT: 0x00000063 "int"
CHECK-NEXT: 0x00000079 "char"
CHECK-NEXT: length = 0x00000016 version = 0x0002 unit_offset = 0x00000081 unit_size = 0x000000a5
CHECK-NEXT: Offset Name
CHECK-NEXT: 0x00000026 "int"
CHECK-NEXT: length = 0x00000016 version = 0x0002 unit_offset = 0x00000126 unit_size = 0x00000096
CHECK-NEXT: Offset Name
CHECK-NEXT: 0x00000041 "int"

View File

@ -179,3 +179,25 @@ CHECK-NEXT: 0x0000000100000fa9 19 18 1 0 0 is_stmt
CHECK-NEXT: 0x0000000100000fab 19 10 1 0 0
CHECK-NEXT: 0x0000000100000fb2 20 1 1 0 0 is_stmt
CHECK-NEXT: 0x0000000100000fb4 20 1 1 0 0 is_stmt end_sequence
CHECK: .debug_pubnames contents:
CHECK-NEXT: length = 0x00000017 version = 0x0002 unit_offset = 0x00000000 unit_size = 0x00000077
CHECK-NEXT: Offset Name
CHECK-NEXT: 0x0000002a "main"
CHECK-NEXT: length = 0x0000002e version = 0x0002 unit_offset = 0x00000077 unit_size = 0x000000a4
CHECK-NEXT: Offset Name
CHECK-NEXT: 0x00000031 "baz"
CHECK-NEXT: 0x00000046 "private_int"
CHECK-NEXT: 0x00000067 "foo"
CHECK-NEXT: length = 0x0000001e version = 0x0002 unit_offset = 0x0000011b unit_size = 0x00000085
CHECK-NEXT: Offset Name
CHECK-NEXT: 0x0000002a "val"
CHECK-NEXT: 0x00000050 "bar"
CHECK: .debug_pubtypes contents:
CHECK-NEXT: length = 0x00000017 version = 0x0002 unit_offset = 0x00000000 unit_size = 0x00000077
CHECK-NEXT: Offset Name
CHECK-NEXT: 0x0000006f "char"
CHECK-NEXT: length = 0x00000016 version = 0x0002 unit_offset = 0x00000077 unit_size = 0x000000a4
CHECK-NEXT: Offset Name
CHECK-NEXT: 0x0000002a "int"

View File

@ -184,3 +184,23 @@ CHECK-NEXT: 0x0000000100000fa7 20 0 1 0 0 is_stmt
CHECK-NEXT: 0x0000000100000fa9 19 0 1 0 0 is_stmt
CHECK-NEXT: 0x0000000100000fb2 20 0 1 0 0 is_stmt
CHECK-NEXT: 0x0000000100000fb4 20 0 1 0 0 is_stmt end_sequence
CHECK: .debug_pubnames contents:
CHECK-NEXT: length = 0x00000017 version = 0x0002 unit_offset = 0x00000000 unit_size = 0x00000081
CHECK-NEXT: Offset Name
CHECK-NEXT: 0x00000026 "main"
CHECK-NEXT: length = 0x0000002e version = 0x0002 unit_offset = 0x00000081 unit_size = 0x000000b9
CHECK-NEXT: Offset Name
CHECK-NEXT: 0x00000026 "private_int"
CHECK-NEXT: 0x0000003f "baz"
CHECK-NEXT: 0x00000058 "foo"
CHECK-NEXT: length = 0x0000001e version = 0x0002 unit_offset = 0x0000013a unit_size = 0x000000ac
CHECK-NEXT: Offset Name
CHECK-NEXT: 0x00000026 "val"
CHECK-NEXT: 0x00000045 "bar"
CHECK: .debug_pubtypes contents:
CHECK-NEXT: length = 0x0000001f version = 0x0002 unit_offset = 0x00000000 unit_size = 0x00000081
CHECK-NEXT: Offset Name
CHECK-NEXT: 0x00000063 "int"
CHECK-NEXT: 0x00000079 "char"

View File

@ -143,6 +143,30 @@ public:
/// list in the debug_loc section.
void noteLocationAttribute(DIEInteger *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 addNameAccelerator(const DIE *Die, const char *Name, uint32_t Offset,
bool SkipPubnamesSection = false);
/// \brief Add a type 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.
uint32_t NameOffset; ///< Offset of Name in the string pool.
bool SkipPubSection; ///< Emit this entry only in the apple_* sections.
AccelInfo(StringRef Name, const DIE *Die, uint32_t NameOffset,
bool SkipPubSection = false)
: Name(Name), Die(Die), NameOffset(NameOffset),
SkipPubSection(SkipPubSection) {}
};
const std::vector<AccelInfo> &getPubnames() const { return Pubnames; }
const std::vector<AccelInfo> &getPubtypes() const { return Pubtypes; }
private:
DWARFUnit &OrigUnit;
unsigned ID;
@ -182,6 +206,13 @@ private:
/// along with the PC offset that is to be applied to their
/// function's address.
std::vector<std::pair<DIEInteger *, int64_t>> LocationAttributes;
/// \brief Accelerator entries for the unit, both for the pub*
/// sections and the apple* ones.
/// @{
std::vector<AccelInfo> Pubnames;
std::vector<AccelInfo> Pubtypes;
/// @}
};
uint64_t CompileUnit::computeNextUnitOffset() {
@ -230,6 +261,20 @@ void CompileUnit::noteLocationAttribute(DIEInteger *Attr, int64_t PcOffset) {
LocationAttributes.emplace_back(Attr, PcOffset);
}
/// \brief Add a name accelerator entry for \p Die with \p Name
/// which is stored in the string table at \p Offset.
void CompileUnit::addNameAccelerator(const DIE *Die, const char *Name,
uint32_t Offset, bool SkipPubSection) {
Pubnames.emplace_back(Name, Die, Offset, SkipPubSection);
}
/// \brief Add a type accelerator entry for \p Die with \p Name
/// which is stored in the string table at \p Offset.
void CompileUnit::addTypeAccelerator(const DIE *Die, const char *Name,
uint32_t Offset) {
Pubtypes.emplace_back(Name, Die, Offset, false);
}
/// \brief A string table that doesn't need relocations.
///
/// We are doing a final link, no need for a string table that
@ -342,6 +387,12 @@ class DwarfStreamer {
uint32_t LocSectionSize;
uint32_t LineSectionSize;
/// \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,
const CompileUnit &Unit,
const std::vector<CompileUnit::AccelInfo> &Names);
public:
/// \brief Actually create the streamer and the ouptut file.
///
@ -402,6 +453,12 @@ public:
unsigned AdddressSize);
uint32_t getLineSectionSize() const { return LineSectionSize; }
/// \brief Emit the .debug_pubnames contribution for \p Unit.
void emitPubNamesForUnit(const CompileUnit &Unit);
/// \brief Emit the .debug_pubtypes contribution for \p Unit.
void emitPubTypesForUnit(const CompileUnit &Unit);
};
bool DwarfStreamer::init(Triple TheTriple, StringRef OutputFilename) {
@ -851,6 +908,59 @@ void DwarfStreamer::emitLineTableForUnit(StringRef PrologueBytes,
MS->EmitLabel(LineEndSym);
}
/// \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,
const std::vector<CompileUnit::AccelInfo> &Names) {
if (Names.empty())
return;
// Start the dwarf pubnames section.
Asm->OutStreamer.SwitchSection(Sec);
MCSymbol *BeginLabel =
Asm->GetTempSymbol("pub" + SecName + "_begin", Unit.getUniqueID());
MCSymbol *EndLabel =
Asm->GetTempSymbol("pub" + SecName + "_end", Unit.getUniqueID());
bool HeaderEmitted = false;
// Emit the pubnames for this compilation unit.
for (const auto &Name : Names) {
if (Name.SkipPubSection)
continue;
if (!HeaderEmitted) {
// Emit the header.
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.getNextUnitOffset() - Unit.getStartOffset()); // Size
HeaderEmitted = true;
}
Asm->EmitInt32(Name.Die->getOffset());
Asm->OutStreamer.EmitBytes(
StringRef(Name.Name.data(), Name.Name.size() + 1));
}
if (!HeaderEmitted)
return;
Asm->EmitInt32(0); // End marker.
Asm->OutStreamer.EmitLabel(EndLabel);
}
/// \brief Emit .debug_pubnames for \p Unit.
void DwarfStreamer::emitPubNamesForUnit(const CompileUnit &Unit) {
emitPubSectionForUnit(MC->getObjectFileInfo()->getDwarfPubNamesSection(),
"names", Unit, Unit.getPubnames());
}
/// \brief Emit .debug_pubtypes for \p Unit.
void DwarfStreamer::emitPubTypesForUnit(const CompileUnit &Unit) {
emitPubSectionForUnit(MC->getObjectFileInfo()->getDwarfPubTypesSection(),
"types", Unit, Unit.getPubtypes());
}
/// \brief The core of the Dwarf linking logic.
///
/// The link of the dwarf information from the object files will be
@ -989,10 +1099,19 @@ private:
/// \brief Information gathered and exchanged between the various
/// clone*Attributes helpers about the attributes of a particular DIE.
struct AttributesInfo {
const char *Name, *MangledName; ///< Names.
uint32_t NameOffset, MangledNameOffset; ///< Offsets in the string pool.
uint64_t OrigHighPc; ///< Value of AT_high_pc in the input DIE
int64_t PCOffset; ///< Offset to apply to PC addresses inside a function.
AttributesInfo() : OrigHighPc(0), PCOffset(0) {}
bool HasLowPc; ///< Does the DIE have a low_pc attribute?
bool IsDeclaration; ///< Is this DIE only a declaration?
AttributesInfo()
: Name(nullptr), MangledName(nullptr), NameOffset(0),
MangledNameOffset(0), OrigHighPc(0), PCOffset(0), HasLowPc(false),
IsDeclaration(false) {}
};
/// \brief Helper for cloneDIE.
@ -1026,7 +1145,7 @@ private:
const DWARFDebugInfoEntryMinimal &InputDIE,
CompileUnit &U, AttributeSpec AttrSpec,
const DWARFFormValue &Val, unsigned AttrSize,
const AttributesInfo &Info);
AttributesInfo &Info);
/// \brief Helper for cloneDIE.
bool applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset,
@ -1055,6 +1174,9 @@ private:
/// emit the result in the debug_line section.
void patchLineTableForUnit(CompileUnit &Unit, DWARFContext &OrigDwarf);
/// \brief Emit the accelerator entries for \p Unit.
void emitAcceleratorEntriesForUnit(CompileUnit &Unit);
/// \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!).
@ -1073,6 +1195,9 @@ private:
CompileUnit *getUnitForOffset(unsigned Offset);
bool getDIENames(const DWARFDebugInfoEntryMinimal &Die, DWARFUnit &U,
AttributesInfo &Info);
void reportWarning(const Twine &Warning, const DWARFUnit *Unit = nullptr,
const DWARFDebugInfoEntryMinimal *DIE = nullptr) const;
@ -1132,6 +1257,24 @@ const DWARFDebugInfoEntryMinimal *DwarfLinker::resolveDIEReference(
return nullptr;
}
/// \brief Get the potential name and mangled name for the entity
/// described by \p Die and store them in \Info if they are not
/// already there.
/// \returns is a name was found.
bool DwarfLinker::getDIENames(const DWARFDebugInfoEntryMinimal &Die,
DWARFUnit &U, AttributesInfo &Info) {
// FIXME: a bit wastefull as the first getName might return the
// short name.
if (!Info.MangledName &&
(Info.MangledName = Die.getName(&U, DINameKind::LinkageName)))
Info.MangledNameOffset = StringPool.getStringOffset(Info.MangledName);
if (!Info.Name && (Info.Name = Die.getName(&U, DINameKind::ShortName)))
Info.NameOffset = StringPool.getStringOffset(Info.Name);
return Info.Name || Info.MangledName;
}
/// \brief Report a warning to the user, optionaly including
/// information about a specific \p DIE related to the warning.
void DwarfLinker::reportWarning(const Twine &Warning, const DWARFUnit *Unit,
@ -1735,6 +1878,7 @@ unsigned DwarfLinker::cloneAddressAttribute(DIE &Die, AttributeSpec AttrSpec,
if (Addr == UINT64_MAX)
return 0;
}
Info.HasLowPc = true;
} else if (AttrSpec.Attr == dwarf::DW_AT_high_pc) {
if (Die.getTag() == dwarf::DW_TAG_compile_unit) {
if (uint64_t HighPc = Unit.getHighPc())
@ -1759,7 +1903,7 @@ unsigned DwarfLinker::cloneAddressAttribute(DIE &Die, AttributeSpec AttrSpec,
unsigned DwarfLinker::cloneScalarAttribute(
DIE &Die, const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &Unit,
AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize,
const AttributesInfo &Info) {
AttributesInfo &Info) {
uint64_t Value;
if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&
Die.getTag() == dwarf::DW_TAG_compile_unit) {
@ -1787,6 +1931,8 @@ unsigned DwarfLinker::cloneScalarAttribute(
else if (AttrSpec.Attr == dwarf::DW_AT_location ||
AttrSpec.Attr == dwarf::DW_AT_frame_base)
Unit.noteLocationAttribute(Attr, 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);
@ -1886,6 +2032,39 @@ bool DwarfLinker::applyValidRelocs(MutableArrayRef<char> Data,
return Applied;
}
static bool isTypeTag(uint16_t Tag) {
switch (Tag) {
case dwarf::DW_TAG_array_type:
case dwarf::DW_TAG_class_type:
case dwarf::DW_TAG_enumeration_type:
case dwarf::DW_TAG_pointer_type:
case dwarf::DW_TAG_reference_type:
case dwarf::DW_TAG_string_type:
case dwarf::DW_TAG_structure_type:
case dwarf::DW_TAG_subroutine_type:
case dwarf::DW_TAG_typedef:
case dwarf::DW_TAG_union_type:
case dwarf::DW_TAG_ptr_to_member_type:
case dwarf::DW_TAG_set_type:
case dwarf::DW_TAG_subrange_type:
case dwarf::DW_TAG_base_type:
case dwarf::DW_TAG_const_type:
case dwarf::DW_TAG_constant:
case dwarf::DW_TAG_file_type:
case dwarf::DW_TAG_namelist:
case dwarf::DW_TAG_packed_type:
case dwarf::DW_TAG_volatile_type:
case dwarf::DW_TAG_restrict_type:
case dwarf::DW_TAG_interface_type:
case dwarf::DW_TAG_unspecified_type:
case dwarf::DW_TAG_shared_type:
return true;
default:
break;
}
return false;
}
/// \brief Recursively clone \p InputDIE's subtrees that have been
/// selected to appear in the linked output.
///
@ -1958,6 +2137,26 @@ DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE,
cloneAttribute(*Die, InputDIE, Unit, Val, AttrSpec, AttrSize, AttrInfo);
}
// Look for accelerator entries.
uint16_t Tag = InputDIE.getTag();
// FIXME: This is slightly wrong. An inline_subroutine without a
// low_pc, but with AT_ranges might be interesting to get into the
// accelerator tables too. For now stick with dsymutil's behavior.
if ((Info.InDebugMap || AttrInfo.HasLowPc) &&
Tag != dwarf::DW_TAG_compile_unit &&
getDIENames(InputDIE, Unit.getOrigUnit(), AttrInfo)) {
if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
Unit.addNameAccelerator(Die, AttrInfo.MangledName,
AttrInfo.MangledNameOffset,
Tag == dwarf::DW_TAG_inlined_subroutine);
if (AttrInfo.Name)
Unit.addNameAccelerator(Die, AttrInfo.Name, AttrInfo.NameOffset,
Tag == dwarf::DW_TAG_inlined_subroutine);
} else if (isTypeTag(Tag) && !AttrInfo.IsDeclaration &&
getDIENames(InputDIE, Unit.getOrigUnit(), AttrInfo)) {
Unit.addTypeAccelerator(Die, AttrInfo.Name, AttrInfo.NameOffset);
}
DIEAbbrev &NewAbbrev = Die->getAbbrev();
// 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
@ -2218,6 +2417,11 @@ void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit,
Unit.getOrigUnit().getAddressByteSize());
}
void DwarfLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
Streamer->emitPubNamesForUnit(Unit);
Streamer->emitPubTypesForUnit(Unit);
}
bool DwarfLinker::link(const DebugMap &Map) {
if (Map.begin() == Map.end()) {
@ -2301,6 +2505,7 @@ bool DwarfLinker::link(const DebugMap &Map) {
continue;
patchRangesForUnit(CurrentUnit, DwarfContext);
Streamer->emitLocationsForUnit(CurrentUnit, DwarfContext);
emitAcceleratorEntriesForUnit(CurrentUnit);
}
// Emit all the compile unit's debug information.