aboutsummaryrefslogtreecommitdiff
path: root/bolt
diff options
context:
space:
mode:
authorAlexander Yermolovich <43973793+ayermolo@users.noreply.github.com>2024-01-24 15:34:29 -0800
committerGitHub <noreply@github.com>2024-01-24 15:34:29 -0800
commitbb6a4850553dd4140a5bd63187ec1b14d0b731f9 (patch)
tree1ad9498f084d5e738b668cf3c26e65d67246bb79 /bolt
parent1ae0448ed37654529b7172aa643ce7ba5735fb3a (diff)
downloadllvm-bb6a4850553dd4140a5bd63187ec1b14d0b731f9.zip
llvm-bb6a4850553dd4140a5bd63187ec1b14d0b731f9.tar.gz
llvm-bb6a4850553dd4140a5bd63187ec1b14d0b731f9.tar.bz2
[BOLT] Fix updating DW_AT_stmt_list for DWARF5 TUs (#79374)
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.
Diffstat (limited to 'bolt')
-rw-r--r--bolt/include/bolt/Rewrite/DWARFRewriter.h2
-rw-r--r--bolt/lib/Rewrite/DWARFRewriter.cpp70
-rw-r--r--bolt/test/X86/Inputs/dwarf4-debug-line-offset-change-after-bolt-helper.s194
-rw-r--r--bolt/test/X86/Inputs/dwarf4-debug-line-offset-change-after-bolt-main.s339
-rw-r--r--bolt/test/X86/Inputs/dwarf5-debug-line-offset-change-after-bolt-main.s394
-rw-r--r--bolt/test/X86/dwarf-debug-line-stmt-list-offset-change.test113
6 files changed, 1087 insertions, 25 deletions
diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h
index c0ec386..ba6775f 100644
--- a/bolt/include/bolt/Rewrite/DWARFRewriter.h
+++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h
@@ -96,7 +96,7 @@ private:
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>;
diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp
index 8e20306..3e63e33 100644
--- a/bolt/lib/Rewrite/DWARFRewriter.cpp
+++ b/bolt/lib/Rewrite/DWARFRewriter.cpp
@@ -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
@@ -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();
@@ -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());
@@ -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();
diff --git a/bolt/test/X86/Inputs/dwarf4-debug-line-offset-change-after-bolt-helper.s b/bolt/test/X86/Inputs/dwarf4-debug-line-offset-change-after-bolt-helper.s
new file mode 100644
index 0000000..3a4ec30
--- /dev/null
+++ b/bolt/test/X86/Inputs/dwarf4-debug-line-offset-change-after-bolt-helper.s
@@ -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:
diff --git a/bolt/test/X86/Inputs/dwarf4-debug-line-offset-change-after-bolt-main.s b/bolt/test/X86/Inputs/dwarf4-debug-line-offset-change-after-bolt-main.s
new file mode 100644
index 0000000..0071fdf
--- /dev/null
+++ b/bolt/test/X86/Inputs/dwarf4-debug-line-offset-change-after-bolt-main.s
@@ -0,0 +1,339 @@
+# clang++ -g2 -fdebug-types-section -gdwarf-4 -ffunction-sections
+# struct Foo {
+# int i;
+# };
+# Foo f2;
+
+ .text
+ .file "main.cpp"
+ .section .text._Z3fooi,"ax",@progbits
+ .globl _Z3fooi # -- Begin function _Z3fooi
+ .p2align 4, 0x90
+ .type _Z3fooi,@function
+_Z3fooi: # @_Z3fooi
+.Lfunc_begin0:
+ .file 1 "/test" "main.cpp"
+ .loc 1 1 0 # main.cpp:1:0
+ .cfi_startproc
+# %bb.0: # %entry
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset %rbp, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register %rbp
+ movl %edi, -8(%rbp)
+.Ltmp0:
+ .loc 1 2 9 prologue_end # main.cpp:2:9
+ cmpl $1, -8(%rbp)
+.Ltmp1:
+ .loc 1 2 7 is_stmt 0 # main.cpp:2:7
+ jne .LBB0_2
+# %bb.1: # %if.then
+.Ltmp2:
+ .loc 1 3 5 is_stmt 1 # main.cpp:3:5
+ movl $2, -4(%rbp)
+ jmp .LBB0_3
+.Ltmp3:
+.LBB0_2: # %if.end
+ .loc 1 4 3 # main.cpp:4:3
+ movl $1, -4(%rbp)
+.LBB0_3: # %return
+ .loc 1 5 1 # main.cpp:5:1
+ movl -4(%rbp), %eax
+ .loc 1 5 1 epilogue_begin is_stmt 0 # main.cpp:5:1
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+ retq
+.Ltmp4:
+.Lfunc_end0:
+ .size _Z3fooi, .Lfunc_end0-_Z3fooi
+ .cfi_endproc
+ # -- End function
+ .section .text.main,"ax",@progbits
+ .globl main # -- Begin function main
+ .p2align 4, 0x90
+ .type main,@function
+main: # @main
+.Lfunc_begin1:
+ .loc 1 6 0 is_stmt 1 # main.cpp:6:0
+ .cfi_startproc
+# %bb.0: # %entry
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset %rbp, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register %rbp
+ subq $32, %rsp
+ movl $0, -4(%rbp)
+ movl %edi, -8(%rbp)
+ movq %rsi, -16(%rbp)
+.Ltmp5:
+ .loc 1 7 11 prologue_end # main.cpp:7:11
+ movl -8(%rbp), %eax
+ .loc 1 7 7 is_stmt 0 # main.cpp:7:7
+ movl %eax, -20(%rbp)
+.Ltmp6:
+ .loc 1 8 9 is_stmt 1 # main.cpp:8:9
+ cmpl $3, -20(%rbp)
+.Ltmp7:
+ .loc 1 8 7 is_stmt 0 # main.cpp:8:7
+ jne .LBB1_2
+# %bb.1: # %if.then
+.Ltmp8:
+ .loc 1 9 13 is_stmt 1 # main.cpp:9:13
+ movl -8(%rbp), %edi
+ .loc 1 9 9 is_stmt 0 # main.cpp:9:9
+ callq _Z3fooi
+ .loc 1 9 6 # main.cpp:9:6
+ addl -20(%rbp), %eax
+ movl %eax, -20(%rbp)
+.Ltmp9:
+.LBB1_2: # %if.end
+ .loc 1 10 10 is_stmt 1 # main.cpp:10:10
+ movl -20(%rbp), %eax
+ .loc 1 10 3 epilogue_begin is_stmt 0 # main.cpp:10:3
+ addq $32, %rsp
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+ retq
+.Ltmp10:
+.Lfunc_end1:
+ .size main, .Lfunc_end1-main
+ .cfi_endproc
+ # -- End function
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # 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 17 # DW_AT_low_pc
+ .byte 1 # DW_FORM_addr
+ .byte 85 # DW_AT_ranges
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 1 # DW_FORM_addr
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 110 # DW_AT_linkage_name
+ .byte 14 # DW_FORM_strp
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 4 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 1 # DW_FORM_addr
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 14 # DW_FORM_strp
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 6 # 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 7 # Abbreviation Code
+ .byte 15 # DW_TAG_pointer_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@progbits
+.Lcu_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)
+ .byte 1 # Abbrev [1] 0xb:0xa8 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
+ .quad 0 # DW_AT_low_pc
+ .long .Ldebug_ranges0 # DW_AT_ranges
+ .byte 2 # Abbrev [2] 0x2a:0x2c DW_TAG_subprogram
+ .quad .Lfunc_begin0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .long .Linfo_string3 # DW_AT_linkage_name
+ .long .Linfo_string4 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .long 154 # DW_AT_type
+ # DW_AT_external
+ .byte 3 # Abbrev [3] 0x47:0xe DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 120
+ .long .Linfo_string7 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .long 154 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 4 # Abbrev [4] 0x56:0x44 DW_TAG_subprogram
+ .quad .Lfunc_begin1 # DW_AT_low_pc
+ .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .long .Linfo_string6 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 6 # DW_AT_decl_line
+ .long 154 # DW_AT_type
+ # DW_AT_external
+ .byte 3 # Abbrev [3] 0x6f:0xe DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 120
+ .long .Linfo_string8 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 6 # DW_AT_decl_line
+ .long 154 # DW_AT_type
+ .byte 3 # Abbrev [3] 0x7d:0xe DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 112
+ .long .Linfo_string9 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 6 # DW_AT_decl_line
+ .long 161 # DW_AT_type
+ .byte 5 # Abbrev [5] 0x8b:0xe DW_TAG_variable
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 108
+ .long .Linfo_string11 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 7 # DW_AT_decl_line
+ .long 154 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 6 # Abbrev [6] 0x9a:0x7 DW_TAG_base_type
+ .long .Linfo_string5 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 7 # Abbrev [7] 0xa1:0x5 DW_TAG_pointer_type
+ .long 166 # DW_AT_type
+ .byte 7 # Abbrev [7] 0xa6:0x5 DW_TAG_pointer_type
+ .long 171 # DW_AT_type
+ .byte 6 # Abbrev [6] 0xab:0x7 DW_TAG_base_type
+ .long .Linfo_string10 # DW_AT_name
+ .byte 6 # DW_AT_encoding
+ .byte 1 # DW_AT_byte_size
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end0:
+ .section .debug_ranges,"",@progbits
+.Ldebug_ranges0:
+ .quad .Lfunc_begin0
+ .quad .Lfunc_end0
+ .quad .Lfunc_begin1
+ .quad .Lfunc_end1
+ .quad 0
+ .quad 0
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 18.0.0git" # string offset=0
+.Linfo_string1:
+ .asciz "main.cpp" # string offset=24
+.Linfo_string2:
+ .asciz "/test" # string offset=33
+.Linfo_string3:
+ .asciz "_Z3fooi" # string offset=71
+.Linfo_string4:
+ .asciz "foo" # string offset=79
+.Linfo_string5:
+ .asciz "int" # string offset=83
+.Linfo_string6:
+ .asciz "main" # string offset=87
+.Linfo_string7:
+ .asciz "i" # string offset=92
+.Linfo_string8:
+ .asciz "argc" # string offset=94
+.Linfo_string9:
+ .asciz "argv" # string offset=99
+.Linfo_string10:
+ .asciz "char" # string offset=104
+.Linfo_string11:
+ .asciz "j" # string offset=109
+ .ident "clang version 18.0.0git"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .addrsig_sym _Z3fooi
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/bolt/test/X86/Inputs/dwarf5-debug-line-offset-change-after-bolt-main.s b/bolt/test/X86/Inputs/dwarf5-debug-line-offset-change-after-bolt-main.s
new file mode 100644
index 0000000..d3df204
--- /dev/null
+++ b/bolt/test/X86/Inputs/dwarf5-debug-line-offset-change-after-bolt-main.s
@@ -0,0 +1,394 @@
+# clang++ -g2 -fdebug-types-section -gdwarf-5 -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 "main.cpp"
+ .section .text._Z3fooi,"ax",@progbits
+ .globl _Z3fooi # -- Begin function _Z3fooi
+ .p2align 4, 0x90
+ .type _Z3fooi,@function
+_Z3fooi: # @_Z3fooi
+.Lfunc_begin0:
+ .file 0 "/test" "main.cpp" md5 0x485e4f4a4784830c686905cfd190e444
+ .loc 0 1 0 # main.cpp:1:0
+ .cfi_startproc
+# %bb.0: # %entry
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset %rbp, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register %rbp
+ movl %edi, -8(%rbp)
+.Ltmp0:
+ .loc 0 2 9 prologue_end # main.cpp:2:9
+ cmpl $1, -8(%rbp)
+.Ltmp1:
+ .loc 0 2 7 is_stmt 0 # main.cpp:2:7
+ jne .LBB0_2
+# %bb.1: # %if.then
+.Ltmp2:
+ .loc 0 3 5 is_stmt 1 # main.cpp:3:5
+ movl $2, -4(%rbp)
+ jmp .LBB0_3
+.Ltmp3:
+.LBB0_2: # %if.end
+ .loc 0 4 3 # main.cpp:4:3
+ movl $1, -4(%rbp)
+.LBB0_3: # %return
+ .loc 0 5 1 # main.cpp:5:1
+ movl -4(%rbp), %eax
+ .loc 0 5 1 epilogue_begin is_stmt 0 # main.cpp:5:1
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+ retq
+.Ltmp4:
+.Lfunc_end0:
+ .size _Z3fooi, .Lfunc_end0-_Z3fooi
+ .cfi_endproc
+ # -- End function
+ .section .text.main,"ax",@progbits
+ .globl main # -- Begin function main
+ .p2align 4, 0x90
+ .type main,@function
+main: # @main
+.Lfunc_begin1:
+ .loc 0 6 0 is_stmt 1 # main.cpp:6:0
+ .cfi_startproc
+# %bb.0: # %entry
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset %rbp, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register %rbp
+ subq $32, %rsp
+ movl $0, -4(%rbp)
+ movl %edi, -8(%rbp)
+ movq %rsi, -16(%rbp)
+.Ltmp5:
+ .loc 0 7 11 prologue_end # main.cpp:7:11
+ movl -8(%rbp), %eax
+ .loc 0 7 7 is_stmt 0 # main.cpp:7:7
+ movl %eax, -20(%rbp)
+.Ltmp6:
+ .loc 0 8 9 is_stmt 1 # main.cpp:8:9
+ cmpl $3, -20(%rbp)
+.Ltmp7:
+ .loc 0 8 7 is_stmt 0 # main.cpp:8:7
+ jne .LBB1_2
+# %bb.1: # %if.then
+.Ltmp8:
+ .loc 0 9 13 is_stmt 1 # main.cpp:9:13
+ movl -8(%rbp), %edi
+ .loc 0 9 9 is_stmt 0 # main.cpp:9:9
+ callq _Z3fooi
+ .loc 0 9 6 # main.cpp:9:6
+ addl -20(%rbp), %eax
+ movl %eax, -20(%rbp)
+.Ltmp9:
+.LBB1_2: # %if.end
+ .loc 0 10 10 is_stmt 1 # main.cpp:10:10
+ movl -20(%rbp), %eax
+ .loc 0 10 3 epilogue_begin is_stmt 0 # main.cpp:10:3
+ addq $32, %rsp
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+ retq
+.Ltmp10:
+.Lfunc_end1:
+ .size main, .Lfunc_end1-main
+ .cfi_endproc
+ # -- End function
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 17 # DW_AT_low_pc
+ .byte 1 # DW_FORM_addr
+ .byte 85 # DW_AT_ranges
+ .byte 35 # DW_FORM_rnglistx
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 116 # DW_AT_rnglists_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 110 # DW_AT_linkage_name
+ .byte 37 # DW_FORM_strx1
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 4 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 6 # Abbreviation Code
+ .byte 36 # DW_TAG_base_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .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 7 # Abbreviation Code
+ .byte 15 # DW_TAG_pointer_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 1 # Abbrev [1] 0xc:0x7f DW_TAG_compile_unit
+ .byte 0 # DW_AT_producer
+ .short 33 # DW_AT_language
+ .byte 1 # DW_AT_name
+ .long .Lstr_offsets_base0 # DW_AT_str_offsets_base
+ .long .Lline_table_start0 # DW_AT_stmt_list
+ .byte 2 # DW_AT_comp_dir
+ .quad 0 # DW_AT_low_pc
+ .byte 0 # DW_AT_ranges
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .long .Lrnglists_table_base0 # DW_AT_rnglists_base
+ .byte 2 # Abbrev [2] 0x2b:0x1c DW_TAG_subprogram
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .byte 3 # DW_AT_linkage_name
+ .byte 4 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .long 120 # DW_AT_type
+ # DW_AT_external
+ .byte 3 # Abbrev [3] 0x3b:0xb DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 120
+ .byte 7 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .long 120 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 4 # Abbrev [4] 0x47:0x31 DW_TAG_subprogram
+ .byte 1 # DW_AT_low_pc
+ .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .byte 6 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 6 # DW_AT_decl_line
+ .long 120 # DW_AT_type
+ # DW_AT_external
+ .byte 3 # Abbrev [3] 0x56:0xb DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 120
+ .byte 8 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 6 # DW_AT_decl_line
+ .long 120 # DW_AT_type
+ .byte 3 # Abbrev [3] 0x61:0xb DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 112
+ .byte 9 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 6 # DW_AT_decl_line
+ .long 124 # DW_AT_type
+ .byte 5 # Abbrev [5] 0x6c:0xb DW_TAG_variable
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 108
+ .byte 11 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 7 # DW_AT_decl_line
+ .long 120 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 6 # Abbrev [6] 0x78:0x4 DW_TAG_base_type
+ .byte 5 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 7 # Abbrev [7] 0x7c:0x5 DW_TAG_pointer_type
+ .long 129 # DW_AT_type
+ .byte 7 # Abbrev [7] 0x81:0x5 DW_TAG_pointer_type
+ .long 134 # DW_AT_type
+ .byte 6 # Abbrev [6] 0x86:0x4 DW_TAG_base_type
+ .byte 10 # DW_AT_name
+ .byte 6 # DW_AT_encoding
+ .byte 1 # DW_AT_byte_size
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end0:
+ .section .debug_rnglists,"",@progbits
+ .long .Ldebug_list_header_end0-.Ldebug_list_header_start0 # Length
+.Ldebug_list_header_start0:
+ .short 5 # Version
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+ .long 1 # Offset entry count
+.Lrnglists_table_base0:
+ .long .Ldebug_ranges0-.Lrnglists_table_base0
+.Ldebug_ranges0:
+ .byte 3 # DW_RLE_startx_length
+ .byte 0 # start index
+ .uleb128 .Lfunc_end0-.Lfunc_begin0 # length
+ .byte 3 # DW_RLE_startx_length
+ .byte 1 # start index
+ .uleb128 .Lfunc_end1-.Lfunc_begin1 # length
+ .byte 0 # DW_RLE_end_of_list
+.Ldebug_list_header_end0:
+ .section .debug_str_offsets,"",@progbits
+ .long 52 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 18.0.0git" # string offset=0
+.Linfo_string1:
+ .asciz "main.cpp" # string offset=24
+.Linfo_string2:
+ .asciz "/test" # string offset=33
+.Linfo_string3:
+ .asciz "_Z3fooi" # string offset=71
+.Linfo_string4:
+ .asciz "foo" # string offset=79
+.Linfo_string5:
+ .asciz "int" # string offset=83
+.Linfo_string6:
+ .asciz "main" # string offset=87
+.Linfo_string7:
+ .asciz "i" # string offset=92
+.Linfo_string8:
+ .asciz "argc" # string offset=94
+.Linfo_string9:
+ .asciz "argv" # string offset=99
+.Linfo_string10:
+ .asciz "char" # string offset=104
+.Linfo_string11:
+ .asciz "j" # string offset=109
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string3
+ .long .Linfo_string4
+ .long .Linfo_string5
+ .long .Linfo_string6
+ .long .Linfo_string7
+ .long .Linfo_string8
+ .long .Linfo_string9
+ .long .Linfo_string10
+ .long .Linfo_string11
+ .section .debug_addr,"",@progbits
+ .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution
+.Ldebug_addr_start0:
+ .short 5 # DWARF version number
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+ .quad .Lfunc_begin1
+.Ldebug_addr_end0:
+ .ident "clang version 18.0.0git"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .addrsig_sym _Z3fooi
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/bolt/test/X86/dwarf-debug-line-stmt-list-offset-change.test b/bolt/test/X86/dwarf-debug-line-stmt-list-offset-change.test
new file mode 100644
index 0000000..9795aad
--- /dev/null
+++ b/bolt/test/X86/dwarf-debug-line-stmt-list-offset-change.test
@@ -0,0 +1,113 @@
+# REQUIRES: system-linux
+
+## Check that BOLT updates DW_AT_stmt_list correctly for TUs when both objects are built with DWARF5.
+
+# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-debug-line-offset-change-after-bolt-main.s -o %tmain.o
+# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-types-dwarf5-types-helper.s -o %thelper.o
+# RUN: %clang %cflags %tmain.o %thelper.o -o %t.exe -Wl,-q
+# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections --lite=0 --reorder-blocks=reverse
+# RUN: llvm-dwarfdump --debug-info -r 0 %t.exe > %tlogOffsetNotEqual.txt
+# RUN: llvm-dwarfdump --debug-info -r 0 %t.bolt >> %tlogOffsetNotEqual.txt
+# RUN: llvm-dwarfdump --debug-info -r 0 --debug-line %t.bolt > %tlogCheckLineTable.txt
+# RUN: cat %tlogOffsetNotEqual.txt | FileCheck --check-prefix=CHECK1 %s
+# RUN: cat %tlogCheckLineTable.txt | FileCheck --check-prefix=CHECK2 %s
+
+## Check offset gets modified.
+# CHECK1: DW_TAG_compile_unit
+# CHECK1: DW_AT_stmt_list
+# CHECK1: DW_TAG_type_unit
+# CHECK1: DW_AT_stmt_list ([[OFFSET:0x[0-9a-f]*]])
+# CHECK1: DW_TAG_type_unit
+# CHECK1: DW_AT_stmt_list ([[OFFSET]])
+# CHECK1: DW_TAG_compile_unit
+# CHECK1: DW_AT_stmt_list ([[OFFSET]])
+# CHECK1: DW_TAG_type_unit
+# CHECK1-NOT: DW_AT_stmt_list ([[OFFSET]])
+# CHECK1: DW_TAG_type_unit
+# CHECK1-NOT: DW_AT_stmt_list ([[OFFSET]])
+# CHECK1: DW_TAG_compile_unit
+# CHECK1: DW_TAG_compile_unit
+# CHECK1-NOT: DW_AT_stmt_list ([[OFFSET]])
+
+## Check that offset is correct.
+# CHECK2: DW_TAG_type_unit
+# CHECK2: DW_AT_stmt_list ([[OFFSET1:0x[0-9a-f]*]])
+# CHECK2: DW_TAG_type_unit
+# CHECK2: DW_AT_stmt_list ([[OFFSET1]])
+# CHECK2: DW_TAG_compile_unit
+# CHECK2: DW_AT_stmt_list
+# CHECK2: DW_TAG_compile_unit
+# CHECK2: DW_AT_stmt_list ([[OFFSET1]])
+# CHECK2: debug_line
+# CHECK2: debug_line[[[OFFSET1]]]
+# CHECK2-NOT: debug_line
+
+## Check that BOLT updates DW_AT_stmt_list correctly for TUs when both objects are built with DWARF4.
+
+# RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-debug-line-offset-change-after-bolt-main.s -o %tmain.o
+# RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-debug-line-offset-change-after-bolt-helper.s -o %thelper.o
+# RUN: %clang %cflags %tmain.o %thelper.o -o %t.exe -Wl,-q
+# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections --lite=0 --reorder-blocks=reverse
+# RUN: llvm-dwarfdump --debug-info --debug-types -r 0 %t.exe > %tlogOffsetNotEqual.txt
+# RUN: llvm-dwarfdump --debug-info --debug-types -r 0 %t.bolt >> %tlogOffsetNotEqual.txt
+# RUN: llvm-dwarfdump --debug-info --debug-types -r 0 --debug-line %t.bolt > %tlogCheckLineTable.txt
+# RUN: cat %tlogOffsetNotEqual.txt | FileCheck --check-prefix=CHECK3 %s
+# RUN: cat %tlogCheckLineTable.txt | FileCheck --check-prefix=CHECK4 %s
+## Check offset gets modified.
+# CHECK3: DW_TAG_compile_unit
+# CHECK3: DW_TAG_compile_unit
+# CHECK3: DW_AT_stmt_list ([[OFFSET2:0x[0-9a-f]*]])
+# CHECK3: DW_TAG_type_unit
+# CHECK3: DW_AT_stmt_list ([[OFFSET2]])
+# CHECK3: DW_TAG_compile_unit
+# CHECK3-NOT: DW_AT_stmt_list ([[OFFSET2]])
+# CHECK3: DW_TAG_type_unit
+# CHECK3-NOT: DW_AT_stmt_list ([[OFFSET2]])
+
+## Check that offset is correct.
+# CHECK4: DW_TAG_compile_unit
+# CHECK4: DW_TAG_compile_unit
+# CHECK4: DW_TAG_type_unit
+# CHECK4: DW_AT_stmt_list ([[OFFSET3:0x[0-9a-f]*]])
+# CHECK4: debug_line
+# CHECK4: debug_line[[[OFFSET3]]]
+# CHECK4-NOT: debug_line
+
+## Check that BOLT updates DW_AT_stmt_list correctly for TUs when objects are built with DWARF4/DWARF5.
+
+# RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-debug-line-offset-change-after-bolt-main.s -o %tmain.o
+# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-types-dwarf5-types-helper.s -o %thelper.o
+# RUN: %clang %cflags %tmain.o %thelper.o -o %t.exe -Wl,-q
+# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections --lite=0 --reorder-blocks=reverse
+# RUN: llvm-dwarfdump --debug-info --debug-types -r 0 %t.exe > %tlogOffsetNotEqual.txt
+# RUN: llvm-dwarfdump --debug-info --debug-types -r 0 %t.bolt >> %tlogOffsetNotEqual.txt
+# RUN: llvm-dwarfdump --debug-info --debug-types -r 0 --debug-line %t.bolt > %tlogCheckLineTable.txt
+# RUN: cat %tlogOffsetNotEqual.txt | FileCheck --check-prefix=CHECK5 %s
+# RUN: cat %tlogCheckLineTable.txt | FileCheck --check-prefix=CHECK6 %s
+
+## Check offset gets modified.
+# CHECK5: DW_TAG_compile_unit
+# CHECK5: DW_TAG_type_unit
+# CHECK5: DW_AT_stmt_list ([[OFFSET4:0x[0-9a-f]*]])
+# CHECK5: DW_TAG_type_unit
+# CHECK5: DW_AT_stmt_list ([[OFFSET4]])
+# CHECK5: DW_TAG_compile_unit
+# CHECK5: DW_AT_stmt_list ([[OFFSET4]])
+# CHECK5: DW_TAG_type_unit
+# CHECK5-NOT: DW_AT_stmt_list ([[OFFSET4]])
+# CHECK5: DW_TAG_type_unit
+# CHECK5-NOT: DW_AT_stmt_list ([[OFFSET4]])
+# CHECK5: DW_TAG_compile_unit
+# CHECK5: DW_TAG_compile_unit
+# CHECK5-NOT: DW_AT_stmt_list ([[OFFSET4]])
+
+# CHECK6: DW_TAG_type_unit
+# CHECK6: DW_AT_stmt_list ([[OFFSET5:0x[0-9a-f]*]])
+# CHECK6: DW_TAG_type_unit
+# CHECK6: DW_AT_stmt_list ([[OFFSET5]])
+# CHECK6: DW_TAG_compile_unit
+# CHECK6: DW_TAG_compile_unit
+# CHECK6: DW_AT_stmt_list ([[OFFSET5]])
+# CHECK6: debug_line
+# CHECK6: debug_line[[[OFFSET5]]]
+# CHECK6-NOT: debug_line