mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-18 13:34:04 +00:00
[dsymutil] Add debug_str construction support.
With this comes the ability to correctly clone string attributes in DIEs. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@231493 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
2d6b5022c4
commit
98ecf5a7ed
@ -13,29 +13,36 @@ CHECK: debug_info contents
|
||||
CHECK: Compile Unit:
|
||||
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000001] = "Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
|
||||
CHECK: DW_AT_language [DW_FORM_data2] (DW_LANG_C99)
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000040] = "basic1.c")
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x00000049] = "/Inputs")
|
||||
CHECK: DW_TAG_subprogram [2] *
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000051] = "main")
|
||||
CHECK: DW_AT_decl_line [DW_FORM_data1] (23)
|
||||
CHECK: DW_AT_prototyped [DW_FORM_flag] (0x01)
|
||||
CHECK: DW_AT_external [DW_FORM_flag] (0x01)
|
||||
CHECK: DW_AT_accessibility [DW_FORM_data1] (DW_ACCESS_public)
|
||||
CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 )
|
||||
CHECK: DW_TAG_formal_parameter [3]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000056] = "argc")
|
||||
CHECK: DW_AT_decl_line [DW_FORM_data1] (23)
|
||||
CHECK: DW_AT_location [DW_FORM_block1] (<0x02> 91 78 )
|
||||
CHECK: DW_TAG_formal_parameter [3]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000005b] = "argv")
|
||||
CHECK: DW_AT_decl_file [DW_FORM_data1] (0x01)
|
||||
CHECK: DW_AT_decl_line [DW_FORM_data1] (23)
|
||||
CHECK: DW_AT_location [DW_FORM_block1] (<0x02> 91 70 )
|
||||
CHECK: NULL
|
||||
CHECK: DW_TAG_base_type [4]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000000] = )
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000060] = "int")
|
||||
CHECK: DW_AT_encoding [DW_FORM_data1] (DW_ATE_signed)
|
||||
CHECK: DW_AT_byte_size [DW_FORM_data1] (0x04)
|
||||
CHECK: DW_TAG_pointer_type [5]
|
||||
CHECK: DW_TAG_pointer_type [5]
|
||||
CHECK: DW_TAG_const_type [6]
|
||||
CHECK: DW_TAG_base_type [4]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000064] = "char")
|
||||
CHECK: DW_AT_encoding [DW_FORM_data1] (DW_ATE_signed_char)
|
||||
CHECK: DW_AT_byte_size [DW_FORM_data1] (0x01)
|
||||
CHECK: NULL
|
||||
@ -43,30 +50,47 @@ CHECK: NULL
|
||||
CHECK: Compile Unit:
|
||||
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000001] = "Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000069] = "basic2.c")
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x00000049] = "/Inputs")
|
||||
CHECK: DW_TAG_base_type [4]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000060] = "int")
|
||||
CHECK: DW_TAG_variable [7]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000072] = "private_int")
|
||||
CHECK: DW_TAG_variable [7]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000007e] = "baz")
|
||||
CHECK: DW_TAG_subprogram [2] *
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000082] = "foo")
|
||||
CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 )
|
||||
CHECK: DW_TAG_formal_parameter [3]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000086] = "arg")
|
||||
CHECK: DW_AT_location [DW_FORM_block1] (<0x02> 91 7c )
|
||||
CHECK: NULL
|
||||
CHECK: DW_TAG_subprogram [8]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000008a] = "inc")
|
||||
CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 )
|
||||
CHECK: NULL
|
||||
|
||||
CHECK: Compile Unit:
|
||||
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000001] = "Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000008e] = "basic3.c")
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x00000049] = "/Inputs")
|
||||
CHECK: DW_TAG_variable [9]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000097] = "val")
|
||||
CHECK: DW_TAG_volatile_type [10]
|
||||
CHECK: DW_TAG_base_type [4]
|
||||
CHACK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000060] = "int")
|
||||
CHECK: DW_TAG_subprogram [2] *
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000009b] = "bar")
|
||||
CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 )
|
||||
CHECK: DW_TAG_formal_parameter [3]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000086] = "arg")
|
||||
CHECK: DW_AT_location [DW_FORM_block1] (<0x02> 91 78 )
|
||||
CHECK: NULL
|
||||
CHECK: DW_TAG_subprogram [8]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000008a] = "inc")
|
||||
CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 )
|
||||
|
||||
CHECK: NULL
|
||||
|
@ -7,25 +7,33 @@ CHECK: debug_info contents
|
||||
CHECK: Compile Unit:
|
||||
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000001] = "Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
|
||||
CHECK: DW_AT_language [DW_FORM_data2] (DW_LANG_C99)
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000040] = "basic1.c")
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x00000049] = "/Inputs")
|
||||
CHECK: DW_TAG_subprogram [2] *
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000051] = "main")
|
||||
CHECK: DW_AT_decl_line [DW_FORM_data1] (23)
|
||||
CHECK: DW_AT_prototyped [DW_FORM_flag] (0x01)
|
||||
CHECK: DW_AT_external [DW_FORM_flag] (0x01)
|
||||
CHECK: DW_AT_accessibility [DW_FORM_data1] (DW_ACCESS_public)
|
||||
CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 )
|
||||
CHECK: DW_TAG_formal_parameter [3]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000056] = "argc")
|
||||
CHECK: DW_AT_location [DW_FORM_block1] (<0x03> 55 93 04 )
|
||||
CHECK: DW_TAG_formal_parameter [3]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000005b] = "argv")
|
||||
CHECK: DW_AT_location [DW_FORM_block1] (<0x01> 54 )
|
||||
CHECK: NULL
|
||||
CHECK: DW_TAG_base_type [4
|
||||
CHECK: DW_TAG_base_type [4]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000060] = "int")
|
||||
CHECK: DW_AT_encoding [DW_FORM_data1] (DW_ATE_signed)
|
||||
CHECK: DW_AT_byte_size [DW_FORM_data1] (0x04)
|
||||
CHECK: DW_TAG_pointer_type [5]
|
||||
CHECK: DW_TAG_pointer_type [5]
|
||||
CHECK: DW_TAG_const_type [6]
|
||||
CHECK: DW_TAG_base_type [4]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000064] = "char")
|
||||
CHECK: DW_AT_encoding [DW_FORM_data1] (DW_ATE_signed_char)
|
||||
CHECK: DW_AT_byte_size [DW_FORM_data1] (0x01)
|
||||
CHECK: NULL
|
||||
@ -33,29 +41,44 @@ CHECK: NULL
|
||||
CHECK: Compile Unit:
|
||||
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000001] = "Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000069] = "basic2.c")
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x00000049] = "/Inputs")
|
||||
CHECK: DW_TAG_variable [7]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000072] = "private_int")
|
||||
CHECK: DW_TAG_variable [7]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000007e] = "baz")
|
||||
CHECK: DW_TAG_subprogram [8] *
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000082] = "foo")
|
||||
CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 )
|
||||
CHECK: DW_TAG_formal_parameter [9]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000086] = "arg")
|
||||
CHECK: DW_TAG_inlined_subroutine [10]
|
||||
CHECK: DW_AT_call_line [DW_FORM_data1] (20)
|
||||
CHECK: NULL
|
||||
CHECK: DW_TAG_subprogram [11]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000008a] = "inc")
|
||||
CHECK: DW_AT_inline [DW_FORM_data1] (DW_INL_inlined)
|
||||
CHECK: NULL
|
||||
|
||||
CHECK: Compile Unit:
|
||||
|
||||
CHECK: DW_TAG_compile_unit [1] *
|
||||
CHECK: DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000001] = "Apple LLVM version 6.0 (clang-600.0.39) (based on LLVM 3.5svn)")
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000008e] = "basic3.c")
|
||||
CHECK: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x00000049] = "/Inputs")
|
||||
CHECK: DW_TAG_variable [12]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000097] = "val")
|
||||
CHECK: DW_TAG_volatile_type [13]
|
||||
CHECK: DW_TAG_subprogram [8] *
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000009b] = "bar")
|
||||
CHECK: DW_AT_frame_base [DW_FORM_block1] (<0x01> 56 )
|
||||
CHECK: DW_TAG_formal_parameter [9]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000086] = "arg")
|
||||
CHECK: DW_TAG_lexical_block [14] *
|
||||
CHECK: DW_TAG_inlined_subroutine [15]
|
||||
CHECK: NULL
|
||||
CHECK: NULL
|
||||
CHECK: DW_TAG_subprogram [11]
|
||||
CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x0000008a] = "inc")
|
||||
CHECK: NULL
|
||||
|
@ -108,6 +108,91 @@ uint64_t CompileUnit::computeOffsets(uint64_t DebugInfoSize) {
|
||||
return NextUnitOffset;
|
||||
}
|
||||
|
||||
/// \brief A string table that doesn't need relocations.
|
||||
///
|
||||
/// We are doing a final link, no need for a string table that
|
||||
/// has relocation entries for every reference to it. This class
|
||||
/// provides this ablitity by just associating offsets with
|
||||
/// strings.
|
||||
class NonRelocatableStringpool {
|
||||
public:
|
||||
/// \brief Entries are stored into the StringMap and simply linked
|
||||
/// together through the second element of this pair in order to
|
||||
/// keep track of insertion order.
|
||||
typedef StringMap<std::pair<uint32_t, StringMapEntryBase *>, BumpPtrAllocator>
|
||||
MapTy;
|
||||
|
||||
NonRelocatableStringpool()
|
||||
: CurrentEndOffset(0), Sentinel(0), Last(&Sentinel) {
|
||||
// Legacy dsymutil puts an empty string at the start of the line
|
||||
// table.
|
||||
getStringOffset("");
|
||||
}
|
||||
|
||||
/// \brief Get the offset of string \p S in the string table. This
|
||||
/// can insert a new element or return the offset of a preexisitng
|
||||
/// one.
|
||||
uint32_t getStringOffset(StringRef S);
|
||||
|
||||
/// \brief Get permanent storage for \p S (but do not necessarily
|
||||
/// emit \p S in the output section).
|
||||
/// \returns The StringRef that points to permanent storage to use
|
||||
/// in place of \p S.
|
||||
StringRef internString(StringRef S);
|
||||
|
||||
// \brief Return the first entry of the string table.
|
||||
const MapTy::MapEntryTy *getFirstEntry() const {
|
||||
return getNextEntry(&Sentinel);
|
||||
}
|
||||
|
||||
// \brief Get the entry following \p E in the string table or null
|
||||
// if \p E was the last entry.
|
||||
const MapTy::MapEntryTy *getNextEntry(const MapTy::MapEntryTy *E) const {
|
||||
return static_cast<const MapTy::MapEntryTy *>(E->getValue().second);
|
||||
}
|
||||
|
||||
uint64_t getSize() { return CurrentEndOffset; }
|
||||
|
||||
private:
|
||||
MapTy Strings;
|
||||
uint32_t CurrentEndOffset;
|
||||
MapTy::MapEntryTy Sentinel, *Last;
|
||||
};
|
||||
|
||||
/// \brief Get the offset of string \p S in the string table. This
|
||||
/// can insert a new element or return the offset of a preexisitng
|
||||
/// one.
|
||||
uint32_t NonRelocatableStringpool::getStringOffset(StringRef S) {
|
||||
if (S.empty() && !Strings.empty())
|
||||
return 0;
|
||||
|
||||
std::pair<uint32_t, StringMapEntryBase *> Entry(0, nullptr);
|
||||
MapTy::iterator It;
|
||||
bool Inserted;
|
||||
|
||||
// A non-empty string can't be at offset 0, so if we have an entry
|
||||
// with a 0 offset, it must be a previously interned string.
|
||||
std::tie(It, Inserted) = Strings.insert(std::make_pair(S, Entry));
|
||||
if (Inserted || It->getValue().first == 0) {
|
||||
// Set offset and chain at the end of the entries list.
|
||||
It->getValue().first = CurrentEndOffset;
|
||||
CurrentEndOffset += S.size() + 1; // +1 for the '\0'.
|
||||
Last->getValue().second = &*It;
|
||||
Last = &*It;
|
||||
}
|
||||
return It->getValue().first;
|
||||
};
|
||||
|
||||
/// \brief Put \p S into the StringMap so that it gets permanent
|
||||
/// storage, but do not actually link it in the chain of elements
|
||||
/// that go into the output section. A latter call to
|
||||
/// getStringOffset() with the same string will chain it though.
|
||||
StringRef NonRelocatableStringpool::internString(StringRef S) {
|
||||
std::pair<uint32_t, StringMapEntryBase *> Entry(0, nullptr);
|
||||
auto InsertResult = Strings.insert(std::make_pair(S, Entry));
|
||||
return InsertResult.first->getKey();
|
||||
};
|
||||
|
||||
/// \brief The Dwarf streaming logic
|
||||
///
|
||||
/// All interactions with the MC layer that is used to build the debug
|
||||
@ -160,6 +245,9 @@ public:
|
||||
/// \brief Emit the abbreviation table \p Abbrevs to the
|
||||
/// debug_abbrev section.
|
||||
void emitAbbrevs(const std::vector<DIEAbbrev *> &Abbrevs);
|
||||
|
||||
/// \brief Emit the string table described by \p Pool.
|
||||
void emitStrings(const NonRelocatableStringpool &Pool);
|
||||
};
|
||||
|
||||
bool DwarfStreamer::init(Triple TheTriple, StringRef OutputFilename) {
|
||||
@ -278,6 +366,15 @@ void DwarfStreamer::emitDIE(DIE &Die) {
|
||||
Asm->emitDwarfDIE(Die);
|
||||
}
|
||||
|
||||
/// \brief Emit the debug_str section stored in \p Pool.
|
||||
void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) {
|
||||
Asm->OutStreamer.SwitchSection(MOFI->getDwarfStrSection());
|
||||
for (auto *Entry = Pool.getFirstEntry(); Entry;
|
||||
Entry = Pool.getNextEntry(Entry))
|
||||
Asm->OutStreamer.EmitBytes(
|
||||
StringRef(Entry->getKey().data(), Entry->getKey().size() + 1));
|
||||
}
|
||||
|
||||
/// \brief The core of the Dwarf linking logic.
|
||||
///
|
||||
/// The link of the dwarf information from the object files will be
|
||||
@ -417,7 +514,8 @@ private:
|
||||
const AttributeSpec AttrSpec, unsigned AttrSize);
|
||||
|
||||
/// \brief Helper for cloneDIE.
|
||||
unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec);
|
||||
unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec,
|
||||
const DWARFFormValue &Val, const DWARFUnit &U);
|
||||
|
||||
/// \brief Helper for cloneDIE.
|
||||
unsigned cloneDieReferenceAttribute(DIE &Die, AttributeSpec AttrSpec,
|
||||
@ -478,6 +576,9 @@ private:
|
||||
|
||||
/// The debug map object curently under consideration.
|
||||
DebugMapObject *CurrentDebugObject;
|
||||
|
||||
/// \brief The Dwarf string pool
|
||||
NonRelocatableStringpool StringPool;
|
||||
};
|
||||
|
||||
/// \brief Similar to DWARFUnitSection::getUnitForOffset(), but
|
||||
@ -944,11 +1045,14 @@ void DwarfLinker::AssignAbbrev(DIEAbbrev &Abbrev) {
|
||||
/// \brief Clone a string attribute described by \p AttrSpec and add
|
||||
/// it to \p Die.
|
||||
/// \returns the size of the new attribute.
|
||||
unsigned DwarfLinker::cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec) {
|
||||
unsigned DwarfLinker::cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec,
|
||||
const DWARFFormValue &Val,
|
||||
const DWARFUnit &U) {
|
||||
// Switch everything to out of line strings.
|
||||
// FIXME: Construct the actual string table.
|
||||
const char *String = *Val.getAsCString(&U);
|
||||
unsigned Offset = StringPool.getStringOffset(String);
|
||||
Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_strp,
|
||||
new (DIEAlloc) DIEInteger(0));
|
||||
new (DIEAlloc) DIEInteger(Offset));
|
||||
return 4;
|
||||
}
|
||||
|
||||
@ -1040,7 +1144,7 @@ unsigned DwarfLinker::cloneAttribute(DIE &Die,
|
||||
switch (AttrSpec.Form) {
|
||||
case dwarf::DW_FORM_strp:
|
||||
case dwarf::DW_FORM_string:
|
||||
return cloneStringAttribute(Die, AttrSpec);
|
||||
return cloneStringAttribute(Die, AttrSpec, Val, U);
|
||||
case dwarf::DW_FORM_ref_addr:
|
||||
case dwarf::DW_FORM_ref1:
|
||||
case dwarf::DW_FORM_ref2:
|
||||
@ -1223,8 +1327,10 @@ bool DwarfLinker::link(const DebugMap &Map) {
|
||||
}
|
||||
|
||||
// Emit everything that's global.
|
||||
if (!Options.NoOutput)
|
||||
if (!Options.NoOutput) {
|
||||
Streamer->emitAbbrevs(Abbreviations);
|
||||
Streamer->emitStrings(StringPool);
|
||||
}
|
||||
|
||||
return Options.NoOutput ? true : Streamer->finish();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user