Skip to content

[BOLT] Fix updating DW_AT_stmt_list for DWARF5 TUs #79374

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bolt/include/bolt/Rewrite/DWARFRewriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class DWARFRewriter {
std::unordered_map<uint64_t, uint64_t> DwoRangesBase;

std::unordered_map<DWARFUnit *, uint64_t> LineTablePatchMap;
std::unordered_map<DWARFUnit *, uint64_t> TypeUnitRelocMap;
std::unordered_map<const DWARFUnit *, uint64_t> TypeUnitRelocMap;

/// Entries for GDB Index Types CU List
using GDBIndexTUEntryType = std::vector<GDBIndexTUEntry>;
Expand Down
70 changes: 46 additions & 24 deletions bolt/lib/Rewrite/DWARFRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1393,41 +1393,60 @@ void DWARFRewriter::updateLineTableOffsets(const MCAsmLayout &Layout) {
// ones.
std::unordered_map<uint64_t, uint64_t> DebugLineOffsetMap;

auto GetStatementListValue = [](DWARFUnit *Unit) {
std::optional<DWARFFormValue> StmtList =
Unit->getUnitDIE().find(dwarf::DW_AT_stmt_list);
auto GetStatementListValue =
[](const DWARFDie &DIE) -> std::optional<uint64_t> {
std::optional<DWARFFormValue> StmtList = DIE.find(dwarf::DW_AT_stmt_list);
if (!StmtList)
return std::nullopt;
std::optional<uint64_t> Offset = dwarf::toSectionOffset(StmtList);
assert(Offset && "Was not able to retrieve value of DW_AT_stmt_list.");
return *Offset;
};

for (const std::unique_ptr<DWARFUnit> &CU : BC.DwCtx->compile_units()) {
SmallVector<DWARFUnit *, 1> TUs;
for (const std::unique_ptr<DWARFUnit> &CU : BC.DwCtx->info_section_units()) {
if (CU->isTypeUnit()) {
TUs.push_back(CU.get());
continue;
}
const unsigned CUID = CU->getOffset();
MCSymbol *Label = BC.getDwarfLineTable(CUID).getLabel();
if (!Label)
continue;

std::optional<AttrInfo> AttrVal =
findAttributeInfo(CU.get()->getUnitDIE(), dwarf::DW_AT_stmt_list);
if (!AttrVal)
std::optional<uint64_t> StmtOffset =
GetStatementListValue(CU.get()->getUnitDIE());
if (!StmtOffset)
continue;

const uint64_t LineTableOffset = Layout.getSymbolOffset(*Label);
DebugLineOffsetMap[GetStatementListValue(CU.get())] = LineTableOffset;
DebugLineOffsetMap[*StmtOffset] = LineTableOffset;
assert(DbgInfoSection && ".debug_info section must exist");
LineTablePatchMap[CU.get()] = LineTableOffset;
}

for (const std::unique_ptr<DWARFUnit> &TU : BC.DwCtx->types_section_units()) {
DWARFUnit *Unit = TU.get();
std::optional<AttrInfo> AttrVal =
findAttributeInfo(TU.get()->getUnitDIE(), dwarf::DW_AT_stmt_list);
if (!AttrVal)
for (const std::unique_ptr<DWARFUnit> &TU : BC.DwCtx->types_section_units())
TUs.push_back(TU.get());

for (DWARFUnit *TU : TUs) {
std::optional<uint64_t> StmtOffset =
GetStatementListValue(TU->getUnitDIE());
if (!StmtOffset)
continue;
auto Iter = DebugLineOffsetMap.find(*StmtOffset);
if (Iter == DebugLineOffsetMap.end()) {
// Implementation depends on TU sharing DW_AT_stmt_list with a CU.
// Only case that it hasn't been true was for manually modified assembly
// file. Adding this warning in case assumption is false.
errs()
<< "BOLT-WARNING: [internal-dwarf-error]: A TU at offset: 0x"
<< Twine::utohexstr(TU->getOffset())
<< " is not sharing "
".debug_line entry with CU. DW_AT_stmt_list for this TU won't be "
"updated.\n";
continue;
auto Iter = DebugLineOffsetMap.find(GetStatementListValue(Unit));
assert(Iter != DebugLineOffsetMap.end() &&
"Type Unit Updated Line Number Entry does not exist.");
TypeUnitRelocMap[Unit] = Iter->second;
}
TypeUnitRelocMap[TU] = Iter->second;
}

// Set .debug_info as finalized so it won't be skipped over when
Expand All @@ -1443,15 +1462,15 @@ void DWARFRewriter::updateLineTableOffsets(const MCAsmLayout &Layout) {
CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder &DIEBlder,
DIEStreamer &Streamer) {
// update TypeUnit DW_AT_stmt_list with new .debug_line information.
for (const std::unique_ptr<DWARFUnit> &TU : BC.DwCtx->types_section_units()) {
DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*TU.get());
auto updateLineTable = [&](const DWARFUnit &Unit) -> void {
DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(Unit);
DIEValue StmtAttrInfo = UnitDIE->findAttribute(dwarf::DW_AT_stmt_list);
if (!StmtAttrInfo || !TypeUnitRelocMap.count(TU.get()))
continue;
if (!StmtAttrInfo || !TypeUnitRelocMap.count(&Unit))
return;
DIEBlder.replaceValue(UnitDIE, dwarf::DW_AT_stmt_list,
StmtAttrInfo.getForm(),
DIEInteger(TypeUnitRelocMap[TU.get()]));
}
DIEInteger(TypeUnitRelocMap[&Unit]));
};

// generate and populate abbrevs here
DIEBlder.generateAbbrevs();
Expand All @@ -1469,6 +1488,7 @@ CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder &DIEBlder,
for (std::unique_ptr<llvm::DWARFUnit> &CU : BC.DwCtx->info_section_units()) {
if (!CU->isTypeUnit())
continue;
updateLineTable(*CU.get());
emitUnit(DIEBlder, Streamer, *CU.get());
uint32_t StartOffset = CUOffset;
DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU.get());
Expand All @@ -1478,8 +1498,10 @@ CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder &DIEBlder,
}

// Emit Type Unit of DWARF 4 to .debug_type section
for (DWARFUnit *TU : DIEBlder.getDWARF4TUVector())
for (DWARFUnit *TU : DIEBlder.getDWARF4TUVector()) {
updateLineTable(*TU);
emitUnit(DIEBlder, *TypeStreamer, *TU);
}

TypeStreamer->finish();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
# clang++ -g2 -fdebug-types-section -gdwarf-4 -ffunction-sections
# int foo(int i) {
# if (i == 1)
# return 2;
# return 1;
# }
# int main(int argc, char* argv[]) {
# int j = argc;
# if (j ==3)
# j+= foo(argc);
# return j;
# }
.text
.file "helper.cpp"
.file 1 "/test" "helper.cpp"
.section .debug_types,"G",@progbits,7448148824980338162,comdat
.Ltu_begin0:
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
.Ldebug_info_start0:
.short 4 # DWARF version number
.long .debug_abbrev # Offset Into Abbrev. Section
.byte 8 # Address Size (in bytes)
.quad 7448148824980338162 # Type Signature
.long 30 # Type DIE Offset
.byte 1 # Abbrev [1] 0x17:0x25 DW_TAG_type_unit
.short 33 # DW_AT_language
.long .Lline_table_start0 # DW_AT_stmt_list
.byte 2 # Abbrev [2] 0x1e:0x16 DW_TAG_structure_type
.byte 5 # DW_AT_calling_convention
.long .Linfo_string6 # DW_AT_name
.byte 4 # DW_AT_byte_size
.byte 1 # DW_AT_decl_file
.byte 1 # DW_AT_decl_line
.byte 3 # Abbrev [3] 0x27:0xc DW_TAG_member
.long .Linfo_string4 # DW_AT_name
.long 52 # DW_AT_type
.byte 1 # DW_AT_decl_file
.byte 2 # DW_AT_decl_line
.byte 0 # DW_AT_data_member_location
.byte 0 # End Of Children Mark
.byte 4 # Abbrev [4] 0x34:0x7 DW_TAG_base_type
.long .Linfo_string5 # DW_AT_name
.byte 5 # DW_AT_encoding
.byte 4 # DW_AT_byte_size
.byte 0 # End Of Children Mark
.Ldebug_info_end0:
.type f2,@object # @f2
.bss
.globl f2
.p2align 2, 0x0
f2:
.zero 4
.size f2, 4

.section .debug_abbrev,"",@progbits
.byte 1 # Abbreviation Code
.byte 65 # DW_TAG_type_unit
.byte 1 # DW_CHILDREN_yes
.byte 19 # DW_AT_language
.byte 5 # DW_FORM_data2
.byte 16 # DW_AT_stmt_list
.byte 23 # DW_FORM_sec_offset
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 2 # Abbreviation Code
.byte 19 # DW_TAG_structure_type
.byte 1 # DW_CHILDREN_yes
.byte 54 # DW_AT_calling_convention
.byte 11 # DW_FORM_data1
.byte 3 # DW_AT_name
.byte 14 # DW_FORM_strp
.byte 11 # DW_AT_byte_size
.byte 11 # DW_FORM_data1
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 3 # Abbreviation Code
.byte 13 # DW_TAG_member
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 14 # DW_FORM_strp
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 56 # DW_AT_data_member_location
.byte 11 # DW_FORM_data1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 4 # Abbreviation Code
.byte 36 # DW_TAG_base_type
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 14 # DW_FORM_strp
.byte 62 # DW_AT_encoding
.byte 11 # DW_FORM_data1
.byte 11 # DW_AT_byte_size
.byte 11 # DW_FORM_data1
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 5 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 1 # DW_CHILDREN_yes
.byte 37 # DW_AT_producer
.byte 14 # DW_FORM_strp
.byte 19 # DW_AT_language
.byte 5 # DW_FORM_data2
.byte 3 # DW_AT_name
.byte 14 # DW_FORM_strp
.byte 16 # DW_AT_stmt_list
.byte 23 # DW_FORM_sec_offset
.byte 27 # DW_AT_comp_dir
.byte 14 # DW_FORM_strp
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 6 # Abbreviation Code
.byte 52 # DW_TAG_variable
.byte 0 # DW_CHILDREN_no
.byte 3 # DW_AT_name
.byte 14 # DW_FORM_strp
.byte 73 # DW_AT_type
.byte 19 # DW_FORM_ref4
.byte 63 # DW_AT_external
.byte 25 # DW_FORM_flag_present
.byte 58 # DW_AT_decl_file
.byte 11 # DW_FORM_data1
.byte 59 # DW_AT_decl_line
.byte 11 # DW_FORM_data1
.byte 2 # DW_AT_location
.byte 24 # DW_FORM_exprloc
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 7 # Abbreviation Code
.byte 19 # DW_TAG_structure_type
.byte 0 # DW_CHILDREN_no
.byte 60 # DW_AT_declaration
.byte 25 # DW_FORM_flag_present
.byte 105 # DW_AT_signature
.byte 32 # DW_FORM_ref_sig8
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)
.section .debug_info,"",@progbits
.Lcu_begin0:
.long .Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit
.Ldebug_info_start1:
.short 4 # DWARF version number
.long .debug_abbrev # Offset Into Abbrev. Section
.byte 8 # Address Size (in bytes)
.byte 5 # Abbrev [5] 0xb:0x32 DW_TAG_compile_unit
.long .Linfo_string0 # DW_AT_producer
.short 33 # DW_AT_language
.long .Linfo_string1 # DW_AT_name
.long .Lline_table_start0 # DW_AT_stmt_list
.long .Linfo_string2 # DW_AT_comp_dir
.byte 6 # Abbrev [6] 0x1e:0x15 DW_TAG_variable
.long .Linfo_string3 # DW_AT_name
.long 51 # DW_AT_type
# DW_AT_external
.byte 1 # DW_AT_decl_file
.byte 4 # DW_AT_decl_line
.byte 9 # DW_AT_location
.byte 3
.quad f2
.byte 7 # Abbrev [7] 0x33:0x9 DW_TAG_structure_type
# DW_AT_declaration
.quad 7448148824980338162 # DW_AT_signature
.byte 0 # End Of Children Mark
.Ldebug_info_end1:
.section .debug_str,"MS",@progbits,1
.Linfo_string0:
.asciz "clang version 18.0.0git" # string offset=0
.Linfo_string1:
.asciz "helper.cpp" # string offset=24
.Linfo_string2:
.asciz "/test" # string offset=35
.Linfo_string3:
.asciz "f2" # string offset=73
.Linfo_string4:
.asciz "i" # string offset=76
.Linfo_string5:
.asciz "int" # string offset=78
.Linfo_string6:
.asciz "Foo" # string offset=82
.ident "clang version 18.0.0git"
.section ".note.GNU-stack","",@progbits
.addrsig
.section .debug_line,"",@progbits
.Lline_table_start0:
Loading