Skip to content

Commit

Permalink
[BOLT] Fix updating DW_AT_stmt_list for DWARF5 TUs (#79374)
Browse files Browse the repository at this point in the history
Changed so that we also update DW_AT_stmt_list for DWARF5 TUs. BOLT was
doing it for DWARF4, but it wasn't doing it for DWARF5.
  • Loading branch information
ayermolo authored Jan 24, 2024
1 parent 1ae0448 commit bb6a485
Show file tree
Hide file tree
Showing 6 changed files with 1,087 additions and 25 deletions.
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

0 comments on commit bb6a485

Please sign in to comment.