summaryrefslogtreecommitdiff
path: root/bolt/test
diff options
context:
space:
mode:
Diffstat (limited to 'bolt/test')
-rw-r--r--bolt/test/AArch64/long-jmp-one-stub.s32
-rw-r--r--bolt/test/AArch64/pad-before-funcs.s29
-rw-r--r--bolt/test/CMakeLists.txt1
-rw-r--r--bolt/test/RISCV/call-annotations.s8
-rw-r--r--bolt/test/RISCV/relax.s4
-rw-r--r--bolt/test/RISCV/reloc-branch.s2
-rw-r--r--bolt/test/RISCV/reloc-jal.s2
-rw-r--r--bolt/test/X86/dwarf5-debug-names-abstract-origin-linkage-name-only.s568
-rw-r--r--bolt/test/X86/dwarf5-debug-names-abstract-origin-specification.s829
-rw-r--r--bolt/test/X86/dwarf5-debug-names-gnu-push-tls-address.s291
-rw-r--r--bolt/test/X86/dwarf5-debug-names-union.test496
-rw-r--r--bolt/test/X86/icf-safe-icp.test148
-rw-r--r--bolt/test/X86/icf-safe-process-rela-data.test64
-rw-r--r--bolt/test/X86/icf-safe-test1-no-relocs.test20
-rw-r--r--bolt/test/X86/icf-safe-test1.test98
-rw-r--r--bolt/test/X86/icf-safe-test2GlobalConstPtrNoPic.test95
-rw-r--r--bolt/test/X86/linux-alt-instruction.s9
-rw-r--r--bolt/test/X86/linux-bug-table.s9
-rw-r--r--bolt/test/X86/linux-exceptions.s9
-rw-r--r--bolt/test/X86/linux-orc.s9
-rw-r--r--bolt/test/X86/linux-parainstructions.s9
-rw-r--r--bolt/test/X86/linux-pci-fixup.s9
-rw-r--r--bolt/test/X86/linux-smp-locks.s9
-rw-r--r--bolt/test/X86/linux-static-calls.s9
-rw-r--r--bolt/test/X86/linux-static-keys.s33
-rw-r--r--bolt/test/X86/linux-version.S53
-rw-r--r--bolt/test/binary-analysis/AArch64/Inputs/dummy.txt1
-rw-r--r--bolt/test/binary-analysis/AArch64/cmdline-args.test33
-rw-r--r--bolt/test/binary-analysis/AArch64/lit.local.cfg7
-rw-r--r--bolt/test/lit.cfg.py1
-rw-r--r--bolt/test/merge-fdata-bat-no-lbr.test20
-rw-r--r--bolt/test/merge-fdata-lbr-mode.test15
-rw-r--r--bolt/test/merge-fdata-mixed-bat-no-lbr.test16
-rw-r--r--bolt/test/merge-fdata-mixed-mode.test15
-rw-r--r--bolt/test/merge-fdata-no-lbr-mode.test18
-rw-r--r--bolt/test/unreadable-profile.test2
36 files changed, 2955 insertions, 18 deletions
diff --git a/bolt/test/AArch64/long-jmp-one-stub.s b/bolt/test/AArch64/long-jmp-one-stub.s
new file mode 100644
index 000000000000..cd9e0875a43c
--- /dev/null
+++ b/bolt/test/AArch64/long-jmp-one-stub.s
@@ -0,0 +1,32 @@
+## This test verifies that no unnecessary stubs are inserted when each DotAddress increases during a lookup.
+
+# REQUIRES: system-linux, asserts
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
+# RUN: %clang %cflags -O0 %t.o -o %t.exe -Wl,-q
+# RUN: link_fdata %s %t.o %t.fdata
+# RUN: llvm-bolt %t.exe -o %t.bolt \
+# RUN: --data %t.fdata | FileCheck %s
+
+# CHECK: BOLT-INFO: Inserted 1 stubs in the hot area and 0 stubs in the cold area.
+
+ .section .text
+ .global _start
+ .global far_away_func
+
+ .align 4
+ .global _start
+ .type _start, %function
+_start:
+# FDATA: 0 [unknown] 0 1 _start 0 0 100
+ bl far_away_func
+ bl far_away_func
+ ret
+ .space 0x8000000
+ .global far_away_func
+ .type far_away_func, %function
+far_away_func:
+ add x0, x0, #1
+ ret
+
+.reloc 0, R_AARCH64_NONE
diff --git a/bolt/test/AArch64/pad-before-funcs.s b/bolt/test/AArch64/pad-before-funcs.s
new file mode 100644
index 000000000000..3ce0ee5e3838
--- /dev/null
+++ b/bolt/test/AArch64/pad-before-funcs.s
@@ -0,0 +1,29 @@
+# Test checks that --pad-before-funcs is working as expected.
+# It should be able to introduce a configurable offset for the _start symbol.
+# It should reject requests which don't obey the code alignment requirement.
+
+# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
+# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -Wl,--section-start=.text=0x4000
+# RUN: llvm-bolt %t.exe -o %t.bolt.0 --pad-funcs-before=_start:0
+# RUN: llvm-bolt %t.exe -o %t.bolt.4 --pad-funcs-before=_start:4
+# RUN: llvm-bolt %t.exe -o %t.bolt.8 --pad-funcs-before=_start:8
+
+# RUN: not llvm-bolt %t.exe -o %t.bolt.8 --pad-funcs-before=_start:1 2>&1 | FileCheck --check-prefix=CHECK-BAD-ALIGN %s
+
+# CHECK-BAD-ALIGN: user-requested 1 padding bytes before function _start(*2) is not a multiple of the minimum function alignment (4).
+
+# RUN: llvm-objdump --section=.text --disassemble %t.bolt.0 | FileCheck --check-prefix=CHECK-0 %s
+# RUN: llvm-objdump --section=.text --disassemble %t.bolt.4 | FileCheck --check-prefix=CHECK-4 %s
+# RUN: llvm-objdump --section=.text --disassemble %t.bolt.8 | FileCheck --check-prefix=CHECK-8 %s
+
+# Trigger relocation mode in bolt.
+.reloc 0, R_AARCH64_NONE
+
+.section .text
+.globl _start
+
+# CHECK-0: 0000000000400000 <_start>
+# CHECK-4: 0000000000400004 <_start>
+# CHECK-8: 0000000000400008 <_start>
+_start:
+ ret
diff --git a/bolt/test/CMakeLists.txt b/bolt/test/CMakeLists.txt
index d468ff984840..6e18b028bddf 100644
--- a/bolt/test/CMakeLists.txt
+++ b/bolt/test/CMakeLists.txt
@@ -37,6 +37,7 @@ list(APPEND BOLT_TEST_DEPS
lld
llvm-config
llvm-bolt
+ llvm-bolt-binary-analysis
llvm-bolt-heatmap
llvm-bat-dump
llvm-dwarfdump
diff --git a/bolt/test/RISCV/call-annotations.s b/bolt/test/RISCV/call-annotations.s
index ff99e0f1dfd8..f876544e214c 100644
--- a/bolt/test/RISCV/call-annotations.s
+++ b/bolt/test/RISCV/call-annotations.s
@@ -16,13 +16,13 @@ f:
// CHECK-LABEL: Binary Function "_start" after building cfg {
// CHECK: auipc ra, f
-// CHECK-NEXT: jalr ra, -0x4(ra) # Offset: 4
-// CHECK-NEXT: jal ra, f # Offset: 8
-// CHECK-NEXT: jal zero, f # TAILCALL # Offset: 12
+// CHECK-NEXT: jalr -0x4(ra) # Offset: 4
+// CHECK-NEXT: jal f # Offset: 8
+// CHECK-NEXT: j f # TAILCALL # Offset: 12
// CHECK-LABEL: Binary Function "long_tail" after building cfg {
// CHECK: auipc t1, f
-// CHECK-NEXT: jalr zero, -0x18(t1) # TAILCALL # Offset: 8
+// CHECK-NEXT: jr -0x18(t1) # TAILCALL # Offset: 8
// CHECK-LABEL: Binary Function "compressed_tail" after building cfg {
// CHECK: jr a0 # TAILCALL # Offset: 0
diff --git a/bolt/test/RISCV/relax.s b/bolt/test/RISCV/relax.s
index ec390ea76b5c..74f049b8f8dd 100644
--- a/bolt/test/RISCV/relax.s
+++ b/bolt/test/RISCV/relax.s
@@ -5,9 +5,9 @@
// RUN: llvm-objdump -d %t.bolt | FileCheck --check-prefix=OBJDUMP %s
// CHECK: Binary Function "_start" after building cfg {
-// CHECK: jal ra, near_f
+// CHECK: jal near_f
// CHECK-NEXT: auipc ra, far_f
-// CHECK-NEXT: jalr ra, 0xc(ra)
+// CHECK-NEXT: jalr 0xc(ra)
// CHECK-NEXT: j near_f
// CHECK: Binary Function "_start" after fix-riscv-calls {
diff --git a/bolt/test/RISCV/reloc-branch.s b/bolt/test/RISCV/reloc-branch.s
index 6a8b5a28e19d..780d978f36f4 100644
--- a/bolt/test/RISCV/reloc-branch.s
+++ b/bolt/test/RISCV/reloc-branch.s
@@ -7,7 +7,7 @@
.p2align 1
// CHECK: Binary Function "_start" after building cfg {
_start:
-// CHECK: beq zero, zero, .Ltmp0
+// CHECK: beqz zero, .Ltmp0
beq zero, zero, 1f
nop
// CHECK: .Ltmp0
diff --git a/bolt/test/RISCV/reloc-jal.s b/bolt/test/RISCV/reloc-jal.s
index ce54265fac05..62a2f1dbea03 100644
--- a/bolt/test/RISCV/reloc-jal.s
+++ b/bolt/test/RISCV/reloc-jal.s
@@ -14,7 +14,7 @@ f:
.globl _start
.p2align 1
_start:
-// CHECK: jal ra, f
+// CHECK: jal f
jal ra, f
ret
.size _start, .-_start
diff --git a/bolt/test/X86/dwarf5-debug-names-abstract-origin-linkage-name-only.s b/bolt/test/X86/dwarf5-debug-names-abstract-origin-linkage-name-only.s
new file mode 100644
index 000000000000..8c9817ce91ed
--- /dev/null
+++ b/bolt/test/X86/dwarf5-debug-names-abstract-origin-linkage-name-only.s
@@ -0,0 +1,568 @@
+# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %tmain.o
+# RUN: %clang %cflags -gdwarf-5 %tmain.o -o %tmain.exe
+# RUN: llvm-bolt %tmain.exe -o %tmain.exe.bolt --update-debug-sections
+# RUN: llvm-dwarfdump --debug-names %tmain.exe.bolt > %tlog.txt
+# RUN: cat %tlog.txt | FileCheck -check-prefix=BOLT %s
+
+## Tests that bolt can correctly generate debug_names when there is an DW_TAG_inlined_subroutine
+## with DW_AT_abstract_origin that points to DW_TAG_subprogram that only has DW_AT_linkage_name.
+
+# BOLT: Name Index @ 0x0 {
+# BOLT-NEXT: Header {
+# BOLT-NEXT: Length: 0xA2
+# BOLT-NEXT: Format: DWARF32
+# BOLT-NEXT: Version: 5
+# BOLT-NEXT: CU count: 1
+# BOLT-NEXT: Local TU count: 0
+# BOLT-NEXT: Foreign TU count: 0
+# BOLT-NEXT: Bucket count: 4
+# BOLT-NEXT: Name count: 4
+# BOLT-NEXT: Abbreviations table size: 0x19
+# BOLT-NEXT: Augmentation: 'BOLT'
+# BOLT-NEXT: }
+# BOLT-NEXT: Compilation Unit offsets [
+# BOLT-NEXT: CU[0]: 0x00000000
+# BOLT-NEXT: ]
+# BOLT-NEXT: Abbreviations [
+# BOLT-NEXT: Abbreviation [[ABBREV1:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV2:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV3:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_inlined_subroutine
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_ref4
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 0 [
+# BOLT-NEXT: Name 1 {
+# BOLT-NEXT: Hash: 0xB888030
+# BOLT-NEXT: String: {{.+}} "int"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: 0x1
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x0000004a
+# BOLT-NEXT: DW_IDX_parent: <parent not indexed>
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 1 [
+# BOLT-NEXT: EMPTY
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 2 [
+# BOLT-NEXT: Name 2 {
+# BOLT-NEXT: Hash: 0x7C9A7F6A
+# BOLT-NEXT: String: {{.+}} "main"
+# BOLT-NEXT: Entry @ [[REF1:0x[0-9a-f]*]] {
+# BOLT-NEXT: Abbrev: [[ABBREV2]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x0000004e
+# BOLT-NEXT: DW_IDX_parent: <parent not indexed>
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: Name 3 {
+# BOLT-NEXT: Hash: 0xB5063CFE
+# BOLT-NEXT: String: {{.+}} "_Z3fooi"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV2]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000024
+# BOLT-NEXT: DW_IDX_parent: <parent not indexed>
+# BOLT-NEXT: }
+# BOLT-NEXT: Entry @ 0x96 {
+# BOLT-NEXT: Abbrev: [[ABBREV3]]
+# BOLT-NEXT: Tag: DW_TAG_inlined_subroutine
+# BOLT-NEXT: DW_IDX_die_offset: 0x0000007e
+# BOLT-NEXT: DW_IDX_parent: Entry @ [[REF1]]
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 3 [
+# BOLT-NEXT: Name 4 {
+# BOLT-NEXT: Hash: 0x7C952063
+# BOLT-NEXT: String: {{.+}} "char"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV1]]
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x0000009f
+# BOLT-NEXT: DW_IDX_parent: <parent not indexed>
+
+## int foo(int i) {
+## return i ++;
+## }
+## int main(int argc, char* argv[]) {
+## int i = 0;
+## [[clang::always_inline]] i = foo(argc);
+## return i;
+## }
+## Test was manually modified so that DW_TAG_subprogram only had DW_AT_linkage_name.
+
+ .text
+ .file "main.cpp"
+ .globl _Z3fooi
+ .p2align 4, 0x90
+ .type _Z3fooi,@function
+_Z3fooi:
+.Lfunc_begin0:
+ .file 0 "/abstractChain" "main.cpp" md5 0x2e29d55fc1320801a8057a4c50643ea1
+ .loc 0 1 0
+ .loc 0 2 12 prologue_end
+ .loc 0 2 3 epilogue_begin is_stmt 0
+ retq
+.Lfunc_end0:
+ .size _Z3fooi, .Lfunc_end0-_Z3fooi
+
+ .globl main
+ .p2align 4, 0x90
+ .type main,@function
+main:
+.Lfunc_begin1:
+ .loc 0 4 0 is_stmt 1
+.Ltmp2:
+ .loc 0 5 7 prologue_end
+ .loc 0 6 36
+ movl -12(%rbp), %eax
+.Ltmp3:
+ .loc 0 2 12
+.Ltmp4:
+ .loc 0 6 30
+ .loc 0 7 10
+ .loc 0 7 3 epilogue_begin is_stmt 0
+ retq
+.Ltmp5:
+.Lfunc_end1:
+ .size main, .Lfunc_end1-main
+ # -- 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 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 115 # DW_AT_addr_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 49 # DW_AT_abstract_origin
+ .byte 19 # DW_FORM_ref4
+ .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 49 # DW_AT_abstract_origin
+ .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 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 32 # DW_AT_inline
+ .byte 33 # DW_FORM_implicit_const
+ .byte 1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .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 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 8 # 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 9 # 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 10 # Abbreviation Code
+ .byte 29 # DW_TAG_inlined_subroutine
+ .byte 1 # DW_CHILDREN_yes
+ .byte 49 # DW_AT_abstract_origin
+ .byte 19 # DW_FORM_ref4
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 88 # DW_AT_call_file
+ .byte 11 # DW_FORM_data1
+ .byte 89 # DW_AT_call_line
+ .byte 11 # DW_FORM_data1
+ .byte 87 # DW_AT_call_column
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 11 # 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:0x98 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
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end1-.Lfunc_begin0 # DW_AT_high_pc
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .byte 2 # Abbrev [2] 0x23:0x15 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
+ .long 56 # DW_AT_abstract_origin
+ .byte 3 # Abbrev [3] 0x2f:0x8 DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 124
+ .long 64 # DW_AT_abstract_origin Manually Modified
+ .byte 0 # End Of Children Mark
+ .byte 4 # Abbrev [4] 0x38:0x12 DW_TAG_subprogram
+ .byte 3 # DW_AT_linkage_name
+ #.byte 4 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .long 74 # DW_AT_type
+ # DW_AT_external
+ # DW_AT_inline
+ .byte 5 # Abbrev [5] 0x41:0x8 DW_TAG_formal_parameter
+ .byte 6 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .long 74 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 6 # Abbrev [6] 0x4a: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] 0x4e:0x47 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 7 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 4 # DW_AT_decl_line
+ .long 73 # DW_AT_type Manually Modified
+ # DW_AT_external
+ .byte 8 # Abbrev [8] 0x5d:0xb DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 116
+ .byte 8 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 4 # DW_AT_decl_line
+ .long 73 # DW_AT_type Manually Modified
+ .byte 8 # Abbrev [8] 0x68:0xb DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 104
+ .byte 9 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 4 # DW_AT_decl_line
+ .long 148 # DW_AT_type Manually Modified
+ .byte 9 # Abbrev [9] 0x73:0xb DW_TAG_variable
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 100
+ .byte 6 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 5 # DW_AT_decl_line
+ .long 73 # DW_AT_type Manually Modified
+ .byte 10 # Abbrev [10] 0x7e:0x16 DW_TAG_inlined_subroutine
+ .long 56 # DW_AT_abstract_origin
+ .byte 2 # DW_AT_low_pc
+ .long .Ltmp4-.Ltmp3 # DW_AT_high_pc
+ .byte 0 # DW_AT_call_file
+ .byte 6 # DW_AT_call_line
+ .byte 32 # DW_AT_call_column
+ .byte 3 # Abbrev [3] 0x8b:0x8 DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 124
+ .long 64 # DW_AT_abstract_origin Manually Modified
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
+ .byte 11 # Abbrev [11] 0x95:0x5 DW_TAG_pointer_type
+ .long 153 # DW_AT_type Manually Modified
+ .byte 11 # Abbrev [11] 0x9a:0x5 DW_TAG_pointer_type
+ .long 158 # DW_AT_type Manually Modified
+ .byte 6 # Abbrev [6] 0x9f: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_str_offsets,"",@progbits
+ .long 48 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 20.0.0git" # string offset=0
+.Linfo_string1:
+ .asciz "main.cpp" # string offset=24
+.Linfo_string2:
+ .asciz "/abstractChain" # string offset=33
+.Linfo_string3:
+ .asciz "foo" # string offset=85
+.Linfo_string4:
+ .asciz "_Z3fooi" # string offset=89
+.Linfo_string5:
+ .asciz "int" # string offset=97
+.Linfo_string6:
+ .asciz "i" # string offset=101
+.Linfo_string7:
+ .asciz "main" # string offset=103
+.Linfo_string8:
+ .asciz "argc" # string offset=108
+.Linfo_string9:
+ .asciz "argv" # string offset=113
+.Linfo_string10:
+ .asciz "char" # string offset=118
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string4
+ .long .Linfo_string3
+ .long .Linfo_string5
+ .long .Linfo_string6
+ .long .Linfo_string7
+ .long .Linfo_string8
+ .long .Linfo_string9
+ .long .Linfo_string10
+ .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
+ .quad .Ltmp3
+.Ldebug_addr_end0:
+ .section .debug_names,"",@progbits
+ .long .Lnames_end0-.Lnames_start0 # Header: unit length
+.Lnames_start0:
+ .short 5 # Header: version
+ .short 0 # Header: padding
+ .long 1 # Header: compilation unit count
+ .long 0 # Header: local type unit count
+ .long 0 # Header: foreign type unit count
+ .long 5 # Header: bucket count
+ .long 5 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 8 # Header: augmentation string size
+ .ascii "LLVM0700" # Header: augmentation string
+ .long .Lcu_begin0 # Compilation unit 0
+ .long 0 # Bucket 0
+ .long 1 # Bucket 1
+ .long 0 # Bucket 2
+ .long 3 # Bucket 3
+ .long 4 # Bucket 4
+ .long 2090499946 # Hash in Bucket 1
+ .long -1257882370 # Hash in Bucket 1
+ .long 193495088 # Hash in Bucket 3
+ .long 193491849 # Hash in Bucket 4
+ .long 2090147939 # Hash in Bucket 4
+ .long .Linfo_string7 # String in Bucket 1: main
+ .long .Linfo_string4 # String in Bucket 1: _Z3fooi
+ .long .Linfo_string5 # String in Bucket 3: int
+ .long .Linfo_string3 # String in Bucket 4: foo
+ .long .Linfo_string10 # String in Bucket 4: char
+ .long .Lnames3-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames2-.Lnames_entries0 # Offset in Bucket 3
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 4
+ .long .Lnames4-.Lnames_entries0 # Offset in Bucket 4
+.Lnames_abbrev_start0:
+ .byte 1 # Abbrev code
+ .byte 46 # DW_TAG_subprogram
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 2 # Abbrev code
+ .byte 29 # DW_TAG_inlined_subroutine
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 3 # Abbrev code
+ .byte 36 # DW_TAG_base_type
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames3:
+.L2:
+ .byte 1 # Abbreviation code
+ .long 78 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: main
+.Lnames1:
+.L0:
+ .byte 1 # Abbreviation code
+ .long 35 # DW_IDX_die_offset
+.L3: # DW_IDX_parent
+ .byte 2 # Abbreviation code
+ .long 126 # DW_IDX_die_offset
+ .long .L2-.Lnames_entries0 # DW_IDX_parent
+ .byte 0 # End of list: _Z3fooi
+.Lnames2:
+.L1:
+ .byte 3 # Abbreviation code
+ .long 74 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: int
+.Lnames0:
+ .byte 1 # Abbreviation code
+ .long 35 # DW_IDX_die_offset
+ .byte 2 # DW_IDX_parent
+ # Abbreviation code
+ .long 126 # DW_IDX_die_offset
+ .long .L2-.Lnames_entries0 # DW_IDX_parent
+ .byte 0 # End of list: foo
+.Lnames4:
+.L4:
+ .byte 3 # Abbreviation code
+ .long 159 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: char
+ .p2align 2, 0x0
+.Lnames_end0:
+ .ident "clang version 20.0.0git"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/bolt/test/X86/dwarf5-debug-names-abstract-origin-specification.s b/bolt/test/X86/dwarf5-debug-names-abstract-origin-specification.s
new file mode 100644
index 000000000000..2075640d6761
--- /dev/null
+++ b/bolt/test/X86/dwarf5-debug-names-abstract-origin-specification.s
@@ -0,0 +1,829 @@
+# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %tmain.o
+# RUN: %clang %cflags -gdwarf-5 %tmain.o -o %tmain.exe
+# RUN: llvm-bolt %tmain.exe -o %tmain.exe.bolt --update-debug-sections
+# RUN: llvm-dwarfdump --debug-names %tmain.exe.bolt > %tlog.txt
+# RUN: cat %tlog.txt | FileCheck -check-prefix=BOLT %s
+
+## This test checks that BOLT correctly generates .debug_names section when there is transative
+## DW_AT_name/DW_AT_linkage_name resolution.
+
+# BOLT: Abbreviations [
+# BOLT-NEXT: Abbreviation [[ABBREV1:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV2:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_class_type
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV3:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_inlined_subroutine
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_ref4
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV4:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 0 [
+# BOLT-NEXT: Name 1 {
+# BOLT-NEXT: Hash: 0xD72418AA
+# BOLT-NEXT: String: {{.+}} "_ZL3fooi"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV1]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x000000ba
+# BOLT-NEXT: DW_IDX_parent: <parent not indexed>
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 1 [
+# BOLT-NEXT: Name 2 {
+# BOLT-NEXT: Hash: 0x10614A06
+# BOLT-NEXT: String: {{.+}} "State"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV2]]
+# BOLT-NEXT: Tag: DW_TAG_class_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x0000002b
+# BOLT-NEXT: DW_IDX_parent: <parent not indexed>
+# BOLT-NEXT: }
+# BOLT-NEXT: Entry @ [[REF1:0x[0-9a-f]*]] {
+# BOLT-NEXT: Abbrev: [[ABBREV1]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000089
+# BOLT-NEXT: DW_IDX_parent: <parent not indexed>
+# BOLT-NEXT: }
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV3]]
+# BOLT-NEXT: Tag: DW_TAG_inlined_subroutine
+# BOLT-NEXT: DW_IDX_die_offset: 0x000000a3
+# BOLT-NEXT: DW_IDX_parent: Entry @ [[REF1]]
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 2 [
+# BOLT-NEXT: EMPTY
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 3 [
+# BOLT-NEXT: Name 3 {
+# BOLT-NEXT: Hash: 0xB888030
+# BOLT-NEXT: String: {{.+}} "int"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV4]]
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000085
+# BOLT-NEXT: DW_IDX_parent: <parent not indexed>
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: Name 4 {
+# BOLT-NEXT: Hash: 0x7C9A7F6A
+# BOLT-NEXT: String: {{.+}} "main"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV1]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000042
+# BOLT-NEXT: DW_IDX_parent: <parent not indexed>
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 4 [
+# BOLT-NEXT: EMPTY
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 5 [
+# BOLT-NEXT: Name 5 {
+# BOLT-NEXT: Hash: 0xB887389
+# BOLT-NEXT: String: {{.+}} "foo"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV1]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x000000ba
+# BOLT-NEXT: DW_IDX_parent: <parent not indexed>
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: Name 6 {
+# BOLT-NEXT: Hash: 0x7C952063
+# BOLT-NEXT: String: {{.+}} "char"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV4]]
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x000000d9
+# BOLT-NEXT: DW_IDX_parent: <parent not indexed>
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: Name 7 {
+# BOLT-NEXT: Hash: 0xFBBDC812
+# BOLT-NEXT: String: {{.+}} "_ZN5StateC2Ev"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV1]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000089
+# BOLT-NEXT: DW_IDX_parent: <parent not indexed>
+# BOLT-NEXT: }
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV3]]
+# BOLT-NEXT: Tag: DW_TAG_inlined_subroutine
+# BOLT-NEXT: DW_IDX_die_offset: 0x000000a3
+# BOLT-NEXT: DW_IDX_parent: Entry @ [[REF1]]
+
+## static int foo(int i) {
+## return i ++;
+## }
+## class State {
+## public:
+## State() {[[clang::always_inline]] foo(3);}
+## };
+##
+## int main(int argc, char* argv[]) {
+## State S;
+## return 0;
+## }
+
+## Test manually modified to redirect DW_TAG_inlined_subroutine to DW_TAG_subprogram with DW_AT_specification.
+
+ .text
+ .file "main.cpp"
+ .file 0 "abstractChainTwo" "main.cpp" md5 0x17ad726b6a1fd49ee59559a1302da539
+ .globl main # -- Begin function main
+ .p2align 4, 0x90
+ .type main,@function
+main: # @main
+.Lfunc_begin0:
+ .loc 0 9 0 # main.cpp:9:0
+.Ltmp0:
+ .loc 0 10 9 prologue_end # main.cpp:10:9
+ callq _ZN5StateC2Ev
+ .loc 0 11 3 # main.cpp:11:3
+ .loc 0 11 3 epilogue_begin is_stmt 0 # main.cpp:11:3
+ retq
+.Ltmp1:
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
+ # -- End function
+ .section .text._ZN5StateC2Ev,"axG",@progbits,_ZN5StateC2Ev,comdat
+ .weak _ZN5StateC2Ev # -- Begin function _ZN5StateC2Ev
+ .p2align 4, 0x90
+ .type _ZN5StateC2Ev,@function
+_ZN5StateC2Ev: # @_ZN5StateC2Ev
+.Lfunc_begin1:
+ .loc 0 6 0 is_stmt 1 # main.cpp:6:0
+ .cfi_startproc
+# %bb.0:
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset %rbp, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register %rbp
+ movq %rdi, -16(%rbp)
+ movl $3, -4(%rbp)
+.Ltmp2:
+ .loc 0 2 12 prologue_end # main.cpp:2:12
+ movl -4(%rbp), %eax
+ addl $1, %eax
+ movl %eax, -4(%rbp)
+.Ltmp3:
+ .loc 0 6 44 epilogue_begin # main.cpp:6:44
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+ retq
+.Ltmp4:
+.Lfunc_end1:
+ .size _ZN5StateC2Ev, .Lfunc_end1-_ZN5StateC2Ev
+ .cfi_endproc
+ # -- End function
+ .text
+ .p2align 4, 0x90 # -- Begin function _ZL3fooi
+ .type _ZL3fooi,@function
+_ZL3fooi: # @_ZL3fooi
+.Lfunc_begin2:
+ .loc 0 1 0 # main.cpp:1:0
+ .cfi_startproc
+# %bb.0:
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset %rbp, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register %rbp
+ movl %edi, -4(%rbp)
+.Ltmp5:
+ .loc 0 2 12 prologue_end # main.cpp:2:12
+ movl -4(%rbp), %eax
+ movl %eax, %ecx
+ addl $1, %ecx
+ movl %ecx, -4(%rbp)
+ .loc 0 2 3 epilogue_begin is_stmt 0 # main.cpp:2:3
+ popq %rbp
+ .cfi_def_cfa %rsp, 8
+ retq
+.Ltmp6:
+.Lfunc_end2:
+ .size _ZL3fooi, .Lfunc_end2-_ZL3fooi
+ .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 2 # DW_TAG_class_type
+ .byte 1 # DW_CHILDREN_yes
+ .byte 54 # DW_AT_calling_convention
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .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 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .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 60 # DW_AT_declaration
+ .byte 25 # DW_FORM_flag_present
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 50 # DW_AT_accessibility
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 4 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 52 # DW_AT_artificial
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 5 # 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 6 # 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 7 # 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 8 # 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 9 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 1 # DW_CHILDREN_yes
+ .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 32 # DW_AT_inline
+ .byte 33 # DW_FORM_implicit_const
+ .byte 1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 10 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .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 11 # 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 12 # 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 100 # DW_AT_object_pointer
+ .byte 19 # DW_FORM_ref4
+ .byte 110 # DW_AT_linkage_name
+ .byte 37 # DW_FORM_strx1
+ .byte 71 # DW_AT_specification
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 13 # 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 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 52 # DW_AT_artificial
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 14 # Abbreviation Code
+ .byte 29 # DW_TAG_inlined_subroutine
+ .byte 1 # DW_CHILDREN_yes
+ .byte 49 # DW_AT_abstract_origin
+ .byte 19 # DW_FORM_ref4
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 88 # DW_AT_call_file
+ .byte 11 # DW_FORM_data1
+ .byte 89 # DW_AT_call_line
+ .byte 11 # DW_FORM_data1
+ .byte 87 # DW_AT_call_column
+ .byte 11 # DW_FORM_data1
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 15 # Abbreviation Code
+ .byte 5 # DW_TAG_formal_parameter
+ .byte 0 # DW_CHILDREN_no
+ .byte 2 # DW_AT_location
+ .byte 24 # DW_FORM_exprloc
+ .byte 49 # DW_AT_abstract_origin
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 16 # 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 49 # DW_AT_abstract_origin
+ .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:0xd7 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:0x12 DW_TAG_class_type
+ .byte 5 # DW_AT_calling_convention
+ .byte 3 # DW_AT_name
+ .byte 1 # DW_AT_byte_size
+ .byte 0 # DW_AT_decl_file
+ .byte 4 # DW_AT_decl_line
+ .byte 3 # Abbrev [3] 0x31:0xb DW_TAG_subprogram
+ .byte 3 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 6 # DW_AT_decl_line
+ # DW_AT_declaration
+ # DW_AT_external
+ .byte 1 # DW_AT_accessibility
+ # DW_ACCESS_public
+ .byte 4 # Abbrev [4] 0x36:0x5 DW_TAG_formal_parameter
+ .long 61 # DW_AT_type
+ # DW_AT_artificial
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
+ .byte 5 # Abbrev [5] 0x3d:0x5 DW_TAG_pointer_type
+ .long 43 # DW_AT_type
+ .byte 6 # Abbrev [6] 0x42:0x31 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 8 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 9 # DW_AT_decl_line
+ .long 133 # DW_AT_type
+ # DW_AT_external
+ .byte 7 # Abbrev [7] 0x51:0xb DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 120
+ .byte 10 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 9 # DW_AT_decl_line
+ .long 133 # DW_AT_type
+ .byte 7 # Abbrev [7] 0x5c:0xb DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 112
+ .byte 11 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 9 # DW_AT_decl_line
+ .long 207 # DW_AT_type
+ .byte 8 # Abbrev [8] 0x67:0xb DW_TAG_variable
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 111
+ .byte 13 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 10 # DW_AT_decl_line
+ .long 43 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 9 # Abbrev [9] 0x73:0x12 DW_TAG_subprogram
+ .byte 4 # DW_AT_linkage_name
+ .byte 5 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .long 133 # DW_AT_type
+ # DW_AT_inline
+ .byte 10 # Abbrev [10] 0x7c:0x8 DW_TAG_formal_parameter
+ .byte 7 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .long 133 # DW_AT_type
+ .byte 0 # End Of Children Mark
+ .byte 11 # Abbrev [11] 0x85:0x4 DW_TAG_base_type
+ .byte 6 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 12 # Abbrev [12] 0x89: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
+ .long 154 # DW_AT_object_pointer
+ .byte 9 # DW_AT_linkage_name
+ .long 49 # DW_AT_specification
+ .byte 13 # Abbrev [13] 0x9a:0x9 DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 112
+ .byte 14 # DW_AT_name
+ .long 221 # DW_AT_type
+ # DW_AT_artificial
+ .byte 14 # Abbrev [14] 0xa3:0x16 DW_TAG_inlined_subroutine
+ .long 137 # DW_AT_abstract_origin Manually Modified
+ .byte 2 # DW_AT_low_pc
+ .long .Ltmp3-.Ltmp2 # DW_AT_high_pc
+ .byte 0 # DW_AT_call_file
+ .byte 6 # DW_AT_call_line
+ .byte 37 # DW_AT_call_column
+ .byte 15 # Abbrev [15] 0xb0:0x8 DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 124
+ .long 124 # DW_AT_abstract_origin
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
+ .byte 16 # Abbrev [16] 0xba:0x15 DW_TAG_subprogram
+ .byte 3 # DW_AT_low_pc
+ .long .Lfunc_end2-.Lfunc_begin2 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .long 115 # DW_AT_abstract_origin
+ .byte 15 # Abbrev [15] 0xc6:0x8 DW_TAG_formal_parameter
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 124
+ .long 124 # DW_AT_abstract_origin
+ .byte 0 # End Of Children Mark
+ .byte 5 # Abbrev [5] 0xcf:0x5 DW_TAG_pointer_type
+ .long 212 # DW_AT_type
+ .byte 5 # Abbrev [5] 0xd4:0x5 DW_TAG_pointer_type
+ .long 217 # DW_AT_type
+ .byte 11 # Abbrev [11] 0xd9:0x4 DW_TAG_base_type
+ .byte 12 # DW_AT_name
+ .byte 6 # DW_AT_encoding
+ .byte 1 # DW_AT_byte_size
+ .byte 5 # Abbrev [5] 0xdd:0x5 DW_TAG_pointer_type
+ .long 43 # DW_AT_type
+ .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 1 # DW_RLE_base_addressx
+ .byte 0 # base address index
+ .byte 4 # DW_RLE_offset_pair
+ .uleb128 .Lfunc_begin0-.Lfunc_begin0 # starting offset
+ .uleb128 .Lfunc_end0-.Lfunc_begin0 # ending offset
+ .byte 4 # DW_RLE_offset_pair
+ .uleb128 .Lfunc_begin2-.Lfunc_begin0 # starting offset
+ .uleb128 .Lfunc_end2-.Lfunc_begin0 # ending offset
+ .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 64 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 20.0.0git" # string offset=0
+.Linfo_string1:
+ .asciz "main.cpp" # string offset=24
+.Linfo_string2:
+ .asciz "abstractChainTwo" # string offset=33
+.Linfo_string3:
+ .asciz "State" # string offset=88
+.Linfo_string4:
+ .asciz "main" # string offset=94
+.Linfo_string5:
+ .asciz "_ZL3fooi" # string offset=99
+.Linfo_string6:
+ .asciz "foo" # string offset=108
+.Linfo_string7:
+ .asciz "int" # string offset=112
+.Linfo_string8:
+ .asciz "i" # string offset=116
+.Linfo_string9:
+ .asciz "_ZN5StateC2Ev" # string offset=118
+.Linfo_string10:
+ .asciz "argc" # string offset=132
+.Linfo_string11:
+ .asciz "argv" # string offset=137
+.Linfo_string12:
+ .asciz "char" # string offset=142
+.Linfo_string13:
+ .asciz "S" # string offset=147
+.Linfo_string14:
+ .asciz "this" # string offset=149
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string3
+ .long .Linfo_string5
+ .long .Linfo_string6
+ .long .Linfo_string7
+ .long .Linfo_string8
+ .long .Linfo_string4
+ .long .Linfo_string9
+ .long .Linfo_string10
+ .long .Linfo_string11
+ .long .Linfo_string12
+ .long .Linfo_string13
+ .long .Linfo_string14
+ .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
+ .quad .Ltmp2
+ .quad .Lfunc_begin2
+.Ldebug_addr_end0:
+ .section .debug_names,"",@progbits
+ .long .Lnames_end0-.Lnames_start0 # Header: unit length
+.Lnames_start0:
+ .short 5 # Header: version
+ .short 0 # Header: padding
+ .long 1 # Header: compilation unit count
+ .long 0 # Header: local type unit count
+ .long 0 # Header: foreign type unit count
+ .long 7 # Header: bucket count
+ .long 7 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 8 # Header: augmentation string size
+ .ascii "LLVM0700" # Header: augmentation string
+ .long .Lcu_begin0 # Compilation unit 0
+ .long 1 # Bucket 0
+ .long 2 # Bucket 1
+ .long 0 # Bucket 2
+ .long 3 # Bucket 3
+ .long 0 # Bucket 4
+ .long 5 # Bucket 5
+ .long 0 # Bucket 6
+ .long -685500246 # Hash in Bucket 0
+ .long 274811398 # Hash in Bucket 1
+ .long 193495088 # Hash in Bucket 3
+ .long 2090499946 # Hash in Bucket 3
+ .long 193491849 # Hash in Bucket 5
+ .long 2090147939 # Hash in Bucket 5
+ .long -71448558 # Hash in Bucket 5
+ .long .Linfo_string5 # String in Bucket 0: _ZL3fooi
+ .long .Linfo_string3 # String in Bucket 1: State
+ .long .Linfo_string7 # String in Bucket 3: int
+ .long .Linfo_string4 # String in Bucket 3: main
+ .long .Linfo_string6 # String in Bucket 5: foo
+ .long .Linfo_string12 # String in Bucket 5: char
+ .long .Linfo_string9 # String in Bucket 5: _ZN5StateC2Ev
+ .long .Lnames5-.Lnames_entries0 # Offset in Bucket 0
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames2-.Lnames_entries0 # Offset in Bucket 3
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 3
+ .long .Lnames4-.Lnames_entries0 # Offset in Bucket 5
+ .long .Lnames6-.Lnames_entries0 # Offset in Bucket 5
+ .long .Lnames3-.Lnames_entries0 # Offset in Bucket 5
+.Lnames_abbrev_start0:
+ .byte 1 # Abbrev code
+ .byte 29 # DW_TAG_inlined_subroutine
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 2 # Abbrev code
+ .byte 46 # DW_TAG_subprogram
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 3 # Abbrev code
+ .byte 2 # DW_TAG_class_type
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 4 # Abbrev code
+ .byte 36 # DW_TAG_base_type
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames5:
+.L1:
+ .byte 1 # Abbreviation code
+ .long 163 # DW_IDX_die_offset
+ .long .L2-.Lnames_entries0 # DW_IDX_parent
+.L0:
+ .byte 2 # Abbreviation code
+ .long 186 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: _ZL3fooi
+.Lnames0:
+.L5:
+ .byte 3 # Abbreviation code
+ .long 43 # DW_IDX_die_offset
+.L2: # DW_IDX_parent
+ .byte 2 # Abbreviation code
+ .long 137 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: State
+.Lnames2:
+.L4:
+ .byte 4 # Abbreviation code
+ .long 133 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: int
+.Lnames1:
+.L6:
+ .byte 2 # Abbreviation code
+ .long 66 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: main
+.Lnames4:
+ .byte 1 # Abbreviation code
+ .long 163 # DW_IDX_die_offset
+ .long .L2-.Lnames_entries0 # DW_IDX_parent
+ .byte 2 # Abbreviation code
+ .long 186 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: foo
+.Lnames6:
+.L3:
+ .byte 4 # Abbreviation code
+ .long 217 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: char
+.Lnames3:
+ .byte 2 # Abbreviation code
+ .long 137 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: _ZN5StateC2Ev
+ .p2align 2, 0x0
+.Lnames_end0:
+ .ident "clang version 20.0.0git"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/bolt/test/X86/dwarf5-debug-names-gnu-push-tls-address.s b/bolt/test/X86/dwarf5-debug-names-gnu-push-tls-address.s
new file mode 100644
index 000000000000..f84d0b6654e7
--- /dev/null
+++ b/bolt/test/X86/dwarf5-debug-names-gnu-push-tls-address.s
@@ -0,0 +1,291 @@
+# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %tmain.o
+# RUN: %clang %cflags -gdwarf-5 %tmain.o -o %tmain.exe
+# RUN: llvm-bolt %tmain.exe -o %tmain.exe.bolt --update-debug-sections
+# RUN: llvm-dwarfdump --debug-names --debug-info %tmain.exe.bolt > %tlog.txt
+# RUN: cat %tlog.txt | FileCheck -check-prefix=BOLT %s
+
+## This test checks that BOLT correctly generates .debug_names section when there is DW_TAG_variable
+## with DW_OP_GNU_push_tls_address in DW_AT_location.
+
+# BOLT: [[DIEOFFSET:0x[0-9a-f]*]]: DW_TAG_variable
+# BOLT-NEXT: DW_AT_name ("x")
+# BOLT-NEXT: DW_AT_type ({{.+}} "int")
+# BOLT-NEXT: DW_AT_external (true)
+# BOLT-NEXT: DW_AT_decl_file ("gnu_tls_push/main.cpp")
+# BOLT-NEXT: DW_AT_decl_line (1)
+# BOLT-NEXT: DW_AT_location (DW_OP_const8u 0x0, DW_OP_GNU_push_tls_address)
+# BOLT: Hash: 0x2B61D
+# BOLT-NEXT: String: {{.+}} "x"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: {{.+}}
+# BOLT-NEXT: Tag: DW_TAG_variable
+# BOLT-NEXT: DW_IDX_die_offset: [[DIEOFFSET]]
+# BOLT-NEXT: DW_IDX_parent: <parent not indexed>
+
+## thread_local int x = 0;
+## int main() {
+## x = 10;
+## return x;
+## }
+ .file "main.cpp"
+ .file 0 "gnu_tls_push" "main.cpp" md5 0x551db97d5e23dc6a81abdc5ade4d9d71
+ .globl main
+ .type main,@function
+main:
+.Lfunc_begin0:
+ .loc 0 2 0
+ .loc 0 3 3 prologue_end
+ .loc 0 3 5 is_stmt 0
+ .loc 0 4 10 is_stmt 1
+ .loc 0 4 3 epilogue_begin is_stmt 0
+ retq
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
+
+ .hidden _ZTW1x
+ .weak _ZTW1x
+ .type _ZTW1x,@function
+_ZTW1x:
+.Lfunc_begin1:
+ retq
+.Lfunc_end1:
+ .size _ZTW1x, .Lfunc_end1-_ZTW1x
+
+ .type x,@object
+ .section .tbss,"awT",@nobits
+ .globl x
+x:
+ .long 0
+ .size x, 4
+
+ .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 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 52 # DW_TAG_variable
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .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 3 # 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 4 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 0 # DW_CHILDREN_no
+ .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 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:0x3e 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
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .byte 2 # Abbrev [2] 0x23:0x13 DW_TAG_variable
+ .byte 3 # DW_AT_name
+ .long 54 # DW_AT_type
+ # DW_AT_external
+ .byte 0 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .byte 10 # DW_AT_location
+ .byte 14
+ .quad x@DTPOFF
+ .byte 224
+ .byte 3 # Abbrev [3] 0x36:0x4 DW_TAG_base_type
+ .byte 4 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 4 # Abbrev [4] 0x3a:0xf 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 5 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 2 # DW_AT_decl_line
+ .long 54 # DW_AT_type
+ # DW_AT_external
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end0:
+ .section .debug_str_offsets,"",@progbits
+ .long 28 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 17.0.4" # string offset=0
+.Linfo_string1:
+ .asciz "main.cpp" # string offset=137
+.Linfo_string2:
+ .asciz "gnu_tls_push" # string offset=146
+.Linfo_string3:
+ .asciz "x" # string offset=184
+.Linfo_string4:
+ .asciz "int" # string offset=186
+.Linfo_string5:
+ .asciz "main" # string offset=190
+ .section .debug_str_offsets,"",@progbits
+ .long .Linfo_string0
+ .long .Linfo_string1
+ .long .Linfo_string2
+ .long .Linfo_string3
+ .long .Linfo_string4
+ .long .Linfo_string5
+ .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
+.Ldebug_addr_end0:
+ .section .debug_names,"",@progbits
+ .long .Lnames_end0-.Lnames_start0 # Header: unit length
+.Lnames_start0:
+ .short 5 # Header: version
+ .short 0 # Header: padding
+ .long 1 # Header: compilation unit count
+ .long 0 # Header: local type unit count
+ .long 0 # Header: foreign type unit count
+ .long 3 # Header: bucket count
+ .long 3 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 8 # Header: augmentation string size
+ .ascii "LLVM0700" # Header: augmentation string
+ .long .Lcu_begin0 # Compilation unit 0
+ .long 1 # Bucket 0
+ .long 2 # Bucket 1
+ .long 3 # Bucket 2
+ .long 177693 # Hash in Bucket 0
+ .long 2090499946 # Hash in Bucket 1
+ .long 193495088 # Hash in Bucket 2
+ .long .Linfo_string3 # String in Bucket 0: x
+ .long .Linfo_string5 # String in Bucket 1: main
+ .long .Linfo_string4 # String in Bucket 2: int
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 0
+ .long .Lnames2-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 2
+.Lnames_abbrev_start0:
+ .byte 1 # Abbrev code
+ .byte 52 # DW_TAG_variable
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 2 # Abbrev code
+ .byte 46 # DW_TAG_subprogram
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 3 # Abbrev code
+ .byte 36 # DW_TAG_base_type
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames1:
+.L2:
+ .byte 1 # Abbreviation code
+ .long 35 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: x
+.Lnames2:
+.L0:
+ .byte 2 # Abbreviation code
+ .long 58 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: main
+.Lnames0:
+.L1:
+ .byte 3 # Abbreviation code
+ .long 54 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: int
+ .p2align 2, 0x0
+.Lnames_end0:
+ .ident "clang version 17.0.4 (https://git.internal.tfbnw.net/repos/git/rw/osmeta/external/llvm-project 8d1fd9f463cb31caf429b83cf7a5baea5f67e54a)"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/bolt/test/X86/dwarf5-debug-names-union.test b/bolt/test/X86/dwarf5-debug-names-union.test
new file mode 100644
index 000000000000..c6da1db684dd
--- /dev/null
+++ b/bolt/test/X86/dwarf5-debug-names-union.test
@@ -0,0 +1,496 @@
+# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %tmain.o
+# RUN: %clang %cflags -gdwarf-5 %tmain.o -o %tmain.exe
+# RUN: llvm-bolt %tmain.exe -o %tmain.exe.bolt --update-debug-sections
+# RUN: llvm-dwarfdump --debug-names %tmain.exe.bolt > %tlog.txt
+# RUN: cat %tlog.txt | FileCheck -check-prefix=BOLT %s
+
+## This test checks that bolt correctly generates entry for DW_TAG_union_type for .debug_name section.
+
+# BOLT: Abbreviations [
+# BOLT-NEXT: Abbreviation [[ABBREV1:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV2:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV3:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_union_type
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_ref4
+# BOLT-NEXT: }
+# BOLT-NEXT: Abbreviation [[ABBREV4:0x[0-9a-f]*]] {
+# BOLT-NEXT: Tag: DW_TAG_structure_type
+# BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
+# BOLT-NEXT: DW_IDX_parent: DW_FORM_ref4
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 0 [
+# BOLT-NEXT: EMPTY
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 1 [
+# BOLT-NEXT: Name 1 {
+# BOLT-NEXT: Hash: 0x7C9A7F6A
+# BOLT-NEXT: String: {{.+}} "main"
+# BOLT-NEXT: Entry @ [[ENTRY:0x[0-9a-f]*]] {
+# BOLT-NEXT: Abbrev: [[ABBREV1]]
+# BOLT-NEXT: Tag: DW_TAG_subprogram
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000024
+# BOLT-NEXT: DW_IDX_parent: <parent not indexed>
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 2 [
+# BOLT-NEXT: EMPTY
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 3 [
+# BOLT-NEXT: Name 2 {
+# BOLT-NEXT: Hash: 0xB888030
+# BOLT-NEXT: String: {{.+}} "int"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV2]]
+# BOLT-NEXT: Tag: DW_TAG_base_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000083
+# BOLT-NEXT: DW_IDX_parent: <parent not indexed>
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: Name 3 {
+# BOLT-NEXT: Hash: 0xED0F01B4
+# BOLT-NEXT: String: {{.+}} "MyUnion"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV3]]
+# BOLT-NEXT: Tag: DW_TAG_union_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000049
+# BOLT-NEXT: DW_IDX_parent: Entry @ [[ENTRY]]
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: ]
+# BOLT-NEXT: Bucket 4 [
+# BOLT-NEXT: Name 4 {
+# BOLT-NEXT: Hash: 0x8AB681F0
+# BOLT-NEXT: String: {{.+}} "MyStruct"
+# BOLT-NEXT: Entry @ [[ENTRY2:0x[0-9a-f]*]] {
+# BOLT-NEXT: Abbrev: [[ABBREV4]]
+# BOLT-NEXT: Tag: DW_TAG_structure_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000062
+# BOLT-NEXT: DW_IDX_parent: Entry @ [[ENTRY]]
+# BOLT-NEXT: }
+# BOLT-NEXT: }
+# BOLT-NEXT: Name 5 {
+# BOLT-NEXT: Hash: 0x8EEF3866
+# BOLT-NEXT: String: {{.+}} "MyUnion2"
+# BOLT-NEXT: Entry @ {{.+}} {
+# BOLT-NEXT: Abbrev: [[ABBREV3]]
+# BOLT-NEXT: Tag: DW_TAG_union_type
+# BOLT-NEXT: DW_IDX_die_offset: 0x00000071
+# BOLT-NEXT: DW_IDX_parent: Entry @ [[ENTRY2]]
+
+
+## int main() {
+## union MyUnion {
+## int a;
+## int b;
+## };
+## struct MyStruct {
+## union MyUnion2 {
+## int a;
+## };
+## MyUnion2 myUnion2;
+## };
+## MyUnion myEnum;
+## myEnum.a = 5;
+## MyStruct myStruct;
+## return myEnum.a + myStruct.myUnion2.a;
+## }
+
+ .text
+ .file "main.cpp"
+ .globl main # -- Begin function main
+ .p2align 4, 0x90
+ .type main,@function
+main: # @main
+.Lfunc_begin0:
+ .file 0 "union" "main.cpp" md5 0xb75b2512f2daa57bbcfe0c29f56d95f4
+ .loc 0 1 0 # main.cpp:1:0
+ retq
+.Lfunc_end0:
+ .size main, .-main
+ # -- 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 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 115 # DW_AT_addr_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 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 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 4 # Abbreviation Code
+ .byte 23 # DW_TAG_union_type
+ .byte 1 # DW_CHILDREN_yes
+ .byte 54 # DW_AT_calling_convention
+ .byte 11 # DW_FORM_data1
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .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 5 # Abbreviation Code
+ .byte 13 # DW_TAG_member
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .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 6 # 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 37 # DW_FORM_strx1
+ .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 7 # 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 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:0x7b 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
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .byte 2 # Abbrev [2] 0x23:0x5f 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_name
+ .byte 0 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .long 130 # DW_AT_type
+ # DW_AT_external
+ .byte 3 # Abbrev [3] 0x32:0xb DW_TAG_variable
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 120
+ .byte 5 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 12 # DW_AT_decl_line
+ .long 72 # DW_AT_type
+ .byte 3 # Abbrev [3] 0x3d:0xb DW_TAG_variable
+ .byte 2 # DW_AT_location
+ .byte 145
+ .byte 116
+ .byte 9 # DW_AT_name
+ .byte 0 # DW_AT_decl_file
+ .byte 14 # DW_AT_decl_line
+ .long 97 # DW_AT_type
+ .byte 4 # Abbrev [4] 0x48:0x19 DW_TAG_union_type
+ .byte 5 # DW_AT_calling_convention
+ .byte 8 # DW_AT_name
+ .byte 4 # DW_AT_byte_size
+ .byte 0 # DW_AT_decl_file
+ .byte 2 # DW_AT_decl_line
+ .byte 5 # Abbrev [5] 0x4e:0x9 DW_TAG_member
+ .byte 6 # DW_AT_name
+ .long 130 # DW_AT_type
+ .byte 0 # DW_AT_decl_file
+ .byte 3 # DW_AT_decl_line
+ .byte 0 # DW_AT_data_member_location
+ .byte 5 # Abbrev [5] 0x57:0x9 DW_TAG_member
+ .byte 7 # DW_AT_name
+ .long 130 # DW_AT_type
+ .byte 0 # DW_AT_decl_file
+ .byte 4 # DW_AT_decl_line
+ .byte 0 # DW_AT_data_member_location
+ .byte 0 # End Of Children Mark
+ .byte 6 # Abbrev [6] 0x61:0x20 DW_TAG_structure_type
+ .byte 5 # DW_AT_calling_convention
+ .byte 12 # DW_AT_name
+ .byte 4 # DW_AT_byte_size
+ .byte 0 # DW_AT_decl_file
+ .byte 6 # DW_AT_decl_line
+ .byte 5 # Abbrev [5] 0x67:0x9 DW_TAG_member
+ .byte 10 # DW_AT_name
+ .long 112 # DW_AT_type
+ .byte 0 # DW_AT_decl_file
+ .byte 10 # DW_AT_decl_line
+ .byte 0 # DW_AT_data_member_location
+ .byte 4 # Abbrev [4] 0x70:0x10 DW_TAG_union_type
+ .byte 5 # DW_AT_calling_convention
+ .byte 11 # DW_AT_name
+ .byte 4 # DW_AT_byte_size
+ .byte 0 # DW_AT_decl_file
+ .byte 7 # DW_AT_decl_line
+ .byte 5 # Abbrev [5] 0x76:0x9 DW_TAG_member
+ .byte 6 # DW_AT_name
+ .long 130 # DW_AT_type
+ .byte 0 # DW_AT_decl_file
+ .byte 8 # DW_AT_decl_line
+ .byte 0 # DW_AT_data_member_location
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
+ .byte 0 # End Of Children Mark
+ .byte 7 # Abbrev [7] 0x82:0x4 DW_TAG_base_type
+ .byte 4 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 0 # End Of Children Mark
+.Ldebug_info_end0:
+ .section .debug_str_offsets,"",@progbits
+ .long 56 # Length of String Offsets Set
+ .short 5
+ .short 0
+.Lstr_offsets_base0:
+ .section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "clang version 20.0.0git" # string offset=0
+.Linfo_string1:
+ .asciz "main.cpp" # string offset=24
+.Linfo_string2:
+ .asciz "union" # string offset=33
+.Linfo_string3:
+ .asciz "main" # string offset=77
+.Linfo_string4:
+ .asciz "int" # string offset=82
+.Linfo_string5:
+ .asciz "myEnum" # string offset=86
+.Linfo_string6:
+ .asciz "MyUnion" # string offset=93
+.Linfo_string7:
+ .asciz "a" # string offset=101
+.Linfo_string8:
+ .asciz "b" # string offset=103
+.Linfo_string9:
+ .asciz "myStruct" # string offset=105
+.Linfo_string10:
+ .asciz "MyStruct" # string offset=114
+.Linfo_string11:
+ .asciz "myUnion2" # string offset=123
+.Linfo_string12:
+ .asciz "MyUnion2" # string offset=132
+ .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_string7
+ .long .Linfo_string8
+ .long .Linfo_string6
+ .long .Linfo_string9
+ .long .Linfo_string11
+ .long .Linfo_string12
+ .long .Linfo_string10
+ .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
+.Ldebug_addr_end0:
+ .section .debug_names,"",@progbits
+ .long .Lnames_end0-.Lnames_start0 # Header: unit length
+.Lnames_start0:
+ .short 5 # Header: version
+ .short 0 # Header: padding
+ .long 1 # Header: compilation unit count
+ .long 0 # Header: local type unit count
+ .long 0 # Header: foreign type unit count
+ .long 5 # Header: bucket count
+ .long 5 # Header: name count
+ .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+ .long 8 # Header: augmentation string size
+ .ascii "LLVM0700" # Header: augmentation string
+ .long .Lcu_begin0 # Compilation unit 0
+ .long 0 # Bucket 0
+ .long 1 # Bucket 1
+ .long 0 # Bucket 2
+ .long 2 # Bucket 3
+ .long 4 # Bucket 4
+ .long 2090499946 # Hash in Bucket 1
+ .long 193495088 # Hash in Bucket 3
+ .long -317783628 # Hash in Bucket 3
+ .long -1967750672 # Hash in Bucket 4
+ .long -1896925082 # Hash in Bucket 4
+ .long .Linfo_string3 # String in Bucket 1: main
+ .long .Linfo_string4 # String in Bucket 3: int
+ .long .Linfo_string6 # String in Bucket 3: MyUnion
+ .long .Linfo_string10 # String in Bucket 4: MyStruct
+ .long .Linfo_string12 # String in Bucket 4: MyUnion2
+ .long .Lnames0-.Lnames_entries0 # Offset in Bucket 1
+ .long .Lnames1-.Lnames_entries0 # Offset in Bucket 3
+ .long .Lnames2-.Lnames_entries0 # Offset in Bucket 3
+ .long .Lnames3-.Lnames_entries0 # Offset in Bucket 4
+ .long .Lnames4-.Lnames_entries0 # Offset in Bucket 4
+.Lnames_abbrev_start0:
+ .byte 1 # Abbrev code
+ .byte 46 # DW_TAG_subprogram
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 2 # Abbrev code
+ .byte 36 # DW_TAG_base_type
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 3 # Abbrev code
+ .byte 23 # DW_TAG_union_type
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 4 # Abbrev code
+ .byte 19 # DW_TAG_structure_type
+ .byte 3 # DW_IDX_die_offset
+ .byte 19 # DW_FORM_ref4
+ .byte 4 # DW_IDX_parent
+ .byte 19 # DW_FORM_ref4
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev
+ .byte 0 # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames0:
+.L3:
+ .byte 1 # Abbreviation code
+ .long 35 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: main
+.Lnames1:
+.L1:
+ .byte 2 # Abbreviation code
+ .long 130 # DW_IDX_die_offset
+ .byte 0 # DW_IDX_parent
+ # End of list: int
+.Lnames2:
+.L4:
+ .byte 3 # Abbreviation code
+ .long 72 # DW_IDX_die_offset
+ .long .L3-.Lnames_entries0 # DW_IDX_parent
+ .byte 0 # End of list: MyUnion
+.Lnames3:
+.L2:
+ .byte 4 # Abbreviation code
+ .long 97 # DW_IDX_die_offset
+ .long .L3-.Lnames_entries0 # DW_IDX_parent
+ .byte 0 # End of list: MyStruct
+.Lnames4:
+.L0:
+ .byte 3 # Abbreviation code
+ .long 112 # DW_IDX_die_offset
+ .long .L2-.Lnames_entries0 # DW_IDX_parent
+ .byte 0 # End of list: MyUnion2
+ .p2align 2, 0x0
+.Lnames_end0:
+ .ident "clang version 20.0.0git"
+ .section ".note.GNU-stack","",@progbits
+ .addrsig
+ .section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/bolt/test/X86/icf-safe-icp.test b/bolt/test/X86/icf-safe-icp.test
new file mode 100644
index 000000000000..a9227d311edc
--- /dev/null
+++ b/bolt/test/X86/icf-safe-icp.test
@@ -0,0 +1,148 @@
+## Check that BOLT handles correctly folding functions with --icf=safe
+## that can be referenced through a non control flow instruction when ICP optimization is enabled.
+## This tests also checks that destructors are folded.
+
+# REQUIRES: system-linux, asserts
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o
+# RUN: %clang %cflags %t1.o -o %t.exe -Wl,-q
+# RUN: llvm-bolt --no-threads %t.exe --icf -debug-only=bolt-icf -o %t.bolt 2>&1 | FileCheck --check-prefix=ICFCHECK %s
+# RUN: llvm-bolt --no-threads %t.exe --icf=safe -debug-only=bolt-icf -o %t.bolt 2>&1 | FileCheck --check-prefix=SAFEICFCHECK %s
+
+# ICFCHECK: ICF iteration 1
+# ICFCHECK-NEXT: folding Derived3Destructor into Derived2Destructor
+# ICFCHECK-NEXT: folding Derived3Func into Derived2Func
+
+# SAFEICFCHECK: skipping function with reference taken Derived3Func
+# SAFEICFCHECK-NEXT: ICF iteration 1
+# SAFEICFCHECK-NEXT: folding Derived3Destructor into Derived2Destructor
+# SAFEICFCHECK-NEXT: ===---------
+
+
+## generate profile
+## clang++ -O2 -fprofile-generate=. main.cpp -c -o mainProf.o
+## PROF=test.profdata
+## clang++ -m64 -fprofile-use=$PROF \
+## -mllvm -disable-icp=true -mllvm -print-after-all \
+## -g0 -flto=thin -fwhole-program-vtables -fno-split-lto-unit -O2 \
+## -fdebug-types-section \
+## main.cpp -c -o mainProfLTO.bc
+## PASS='pgo-icall-prom'
+## clang++ -m64 -fprofile-use=$PROF \
+## -O3 -Rpass=$PASS \
+## -mllvm -print-before=$PASS \
+## -mllvm -print-after=$PASS \
+## -mllvm -filter-print-funcs=main \
+## -mllvm -debug-only=$PASS \
+## -x ir \
+## mainProfLTO.bc -c -o mainProfFinal.o
+
+## class Base {
+## public:
+## virtual int func(int a, int b) const = 0;
+##
+## virtual ~Base() {};
+## };
+##
+## class Derived2 : public Base {
+## int c = 5;
+## public:
+## __attribute__((noinline)) int func(int a, int b)const override { return a * (a - b) + this->c; }
+##
+## ~Derived2() {}
+## };
+##
+## class Derived3 : public Base {
+## int c = 500;
+## public:
+## __attribute__((noinline)) int func(int a, int b) const override { return a * (a - b) + this->c; }
+## ~Derived3() {}
+## };
+##
+## __attribute__((noinline)) Base *createType(int a) {
+## Base *base = nullptr;
+## if (a == 4)
+## base = new Derived2();
+## else
+## base = new Derived3();
+## return base;
+## }
+##
+## extern int returnFive();
+## extern int returnFourOrFive(int val);
+## int main(int argc, char **argv) {
+## int sum = 0;
+## int a = returnFourOrFive(argc);
+## int b = returnFive();
+## Base *ptr = createType(a);
+## Base *ptr2 = createType(b);
+## sum += ptr->func(b, a) + ptr2->func(b, a);
+## return 0;
+## }
+## clang++ -c helper.cpp -o helper.o
+## int FooVar = 1;
+## int BarVar = 2;
+##
+## int fooGlobalFuncHelper(int a, int b) {
+## return 5;
+## }
+## Manually modified to remove "extra" assembly.
+ .globl main
+ .type main,@function
+main:
+ leaq Derived3Func(%rip), %rcx
+ callq Derived3Func
+ .size main, .-main
+
+ .weak Derived2Func
+ .type Derived2Func,@function
+Derived2Func:
+ imull %esi, %eax
+ retq
+ .size Derived2Func, .-Derived2Func
+
+ .weak Derived2Destructor
+ .type Derived2Destructor,@function
+Derived2Destructor:
+ jmp _ZdlPvm@PLT
+ .size Derived2Destructor, .-Derived2Destructor
+
+ .weak Derived3Func
+ .type Derived3Func,@function
+Derived3Func:
+ imull %esi, %eax
+ retq
+ .size Derived3Func, .-Derived3Func
+
+ .weak _ZN4BaseD2Ev
+ .type _ZN4BaseD2Ev,@function
+_ZN4BaseD2Ev:
+ retq
+ .size _ZN4BaseD2Ev, .-_ZN4BaseD2Ev
+
+ .weak Derived3Destructor
+ .type Derived3Destructor,@function
+Derived3Destructor:
+ jmp _ZdlPvm@PLT
+ .size Derived3Destructor, .-Derived3Destructor
+
+ .type _ZTV8Derived2,@object
+ .section .data.rel.ro._ZTV8Derived2,"awG",@progbits,_ZTV8Derived2,comdat
+ .weak _ZTV8Derived2
+_ZTV8Derived2:
+ .quad 0
+ .quad _ZTI8Derived2
+ .quad Derived2Func
+ .quad _ZN4BaseD2Ev
+ .quad Derived2Destructor
+ .size _ZTV8Derived2, 40
+
+ .type _ZTV8Derived3,@object
+ .section .data.rel.ro._ZTV8Derived3,"awG",@progbits,_ZTV8Derived3,comdat
+ .weak _ZTV8Derived3
+_ZTV8Derived3:
+ .quad 0
+ .quad _ZTI8Derived3
+ .quad Derived3Func
+ .quad _ZN4BaseD2Ev
+ .quad Derived3Destructor
+ .size _ZTV8Derived3, 40
diff --git a/bolt/test/X86/icf-safe-process-rela-data.test b/bolt/test/X86/icf-safe-process-rela-data.test
new file mode 100644
index 000000000000..cf71f5525777
--- /dev/null
+++ b/bolt/test/X86/icf-safe-process-rela-data.test
@@ -0,0 +1,64 @@
+## Check that BOLT handles correctly folding functions with --icf=safe that are only referenced from a .rela.data section.
+
+# REQUIRES: system-linux, asserts
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o
+# RUN: %clang %cflags %t1.o -o %t.exe -Wl,-q -no-pie
+# RUN: llvm-bolt --no-threads %t.exe --icf -debug-only=bolt-icf -o %t.bolt 2>&1 | FileCheck --check-prefix=ICFCHECK %s
+# RUN: llvm-bolt --no-threads %t.exe --icf=safe -debug-only=bolt-icf -o %t.bolt 2>&1 | FileCheck --check-prefix=SAFEICFCHECK %s
+
+# ICFCHECK: ICF iteration 1
+# ICFCHECK-NEXT: folding barAddFunc into fooAddFunc
+
+# SAFEICFCHECK: skipping function with reference taken fooAddFunc
+# SAFEICFCHECK-NEXT: skipping function with reference taken barAddFunc
+# SAFEICFCHECK-NEXT: ICF iteration 1
+# SAFEICFCHECK-NEXT: ===---------
+
+## clang++ main.cpp
+## Other functions removed for brevity.
+## int main(int argc, char **argv) {
+## const static int (*const funcGlobalBarAdd)(int, int) = barAddHdlper;
+## const int (* const funcGlobalBarMul)(int, int) = fooGlobalFuncHelper;
+## helper2(funcGlobalBarAdd, funcGlobalFooAdd, 3, 4)
+## }
+## Extra assembly removed.
+
+ .globl fooAddFunc
+ .type fooAddFunc,@function
+fooAddFunc:
+ addl -8(%rbp), %eax
+ retq
+ .size fooAddFunc, .-fooAddFunc
+
+ .globl barAddFunc
+ .type barAddFunc,@function
+barAddFunc:
+ addl -8(%rbp), %eax
+ retq
+ .size barAddFunc, .-barAddFunc
+
+ .globl helperFunc
+ .type helperFunc,@function
+helperFunc:
+ retq
+ .size helperFunc, .-helperFunc
+
+ .globl main
+ .type main,@function
+main:
+ movq localStaticVarBarAdd, %rdi
+ movq localStaticVarFooAdd, %rsi
+ callq helperFunc
+ retq
+ .size main, .-main
+
+ .type localStaticVarBarAdd,@object # @localStaticVarBarAdd
+ .data
+localStaticVarBarAdd:
+ .quad barAddFunc
+ .size localStaticVarBarAdd, 8
+
+ .type localStaticVarFooAdd,@object # @localStaticVarFooAdd
+localStaticVarFooAdd:
+ .quad fooAddFunc
+ .size localStaticVarFooAdd, 8
diff --git a/bolt/test/X86/icf-safe-test1-no-relocs.test b/bolt/test/X86/icf-safe-test1-no-relocs.test
new file mode 100644
index 000000000000..b4e55a6d5504
--- /dev/null
+++ b/bolt/test/X86/icf-safe-test1-no-relocs.test
@@ -0,0 +1,20 @@
+## Check that BOLT reports an error for a binary with no relocations with the --icf=safe option.
+
+# REQUIRES: system-linux, asserts
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o
+# RUN: %clang %cflags %t1.o -o %t.exe
+# RUN: not llvm-bolt --no-threads %t.exe --icf=safe -o %t.bolt 2>&1 | FileCheck --check-prefix=SAFEICFCHECK %s
+
+# SAFEICFCHECK: BOLT-ERROR: binary built without relocations. Safe ICF is not supported
+
+## int main(int argc, char **argv) {
+## return temp;
+## }
+ .globl main
+ .type main,@function
+main:
+ .cfi_startproc
+ retq
+.Lfunc_end8:
+ .size main, .-main
+ .cfi_endproc
diff --git a/bolt/test/X86/icf-safe-test1.test b/bolt/test/X86/icf-safe-test1.test
new file mode 100644
index 000000000000..8a8e5ccf38e7
--- /dev/null
+++ b/bolt/test/X86/icf-safe-test1.test
@@ -0,0 +1,98 @@
+## Check that BOLT handles correctly folding functions with --icf=safe that can be referenced by non-control flow instructions.
+## It invokes BOLT twice first testing CFG path, and second when functions have to be disassembled.
+
+# REQUIRES: system-linux, asserts
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o
+# RUN: %clang %cflags %t1.o -o %t.exe -Wl,-q
+# RUN: llvm-bolt --no-threads %t.exe --icf -debug-only=bolt-icf \
+# RUN: -o %t.bolt 2>&1 | FileCheck --check-prefix=ICFCHECK %s
+# RUN: llvm-bolt --no-threads %t.exe --icf=safe -debug-only=bolt-icf \
+# RUN: -o %t.bolt 2>&1 | FileCheck --check-prefix=SAFEICFCHECK %s
+# RUN: llvm-bolt --no-threads %t.exe --icf=safe -debug-only=bolt-icf \
+# RUN: --skip-funcs=helper1Func,main -o %t.bolt 2>&1 | FileCheck --check-prefix=SAFEICFCHECKNOCFG %s
+
+# ICFCHECK: ICF iteration 1
+# ICFCHECK-NEXT: folding barAddFunc into fooAddFunc
+# ICFCHECK-NEXT: folding barSubFunc into fooSubFunc
+
+# SAFEICFCHECK: skipping function with reference taken barAddFunc
+# SAFEICFCHECK-NEXT: ICF iteration 1
+# SAFEICFCHECK-NEXT: folding barSubFunc into fooSubFunc
+# SAFEICFCHECK-NEXT: ===---------
+
+# SAFEICFCHECKNOCFG: skipping function with reference taken barAddFunc
+# SAFEICFCHECKNOCFG-NEXT: ICF iteration 1
+# SAFEICFCHECKNOCFG-NEXT: folding barSubFunc into fooSubFunc
+# SAFEICFCHECKNOCFG-NEXT: ===---------
+
+## clang++ -c main.cpp -o main.o
+## extern int FooVar;
+## extern int BarVar;
+## [[clang::noinline]]
+## int fooSub(int a, int b) {
+## return a - b;
+## }
+## [[clang::noinline]]
+## int barSub(int a, int b) {
+## return a - b;
+## }
+## [[clang::noinline]]
+## int fooAdd(int a, int b) {
+## return a + b;
+## }
+## [[clang::noinline]]
+## int barAdd(int a, int b) {
+## return a + b;
+## }
+## int main(int argc, char **argv) {
+## int temp = helper1(barAdd, FooVar, BarVar) +
+## fooSub(FooVar, BarVar) +
+## barSub(FooVar, BarVar) + fooAdd(FooVar, BarVar);
+## return temp;
+## }
+ .globl fooSubFunc
+ .type fooSubFunc,@function
+fooSubFunc:
+ subl -8(%rbp), %eax
+ retq
+ .size fooSubFunc, .-fooSubFunc
+
+ .globl barSubFunc
+ .type barSubFunc,@function
+barSubFunc:
+ subl -8(%rbp), %eax
+ retq
+ .size barSubFunc, .-barSubFunc
+
+ .globl fooAddFunc
+ .type fooAddFunc,@function
+fooAddFunc:
+ addl -8(%rbp), %eax
+ retq
+ .size fooAddFunc, .-fooAddFunc
+
+ .globl barAddFunc
+ .type barAddFunc,@function
+barAddFunc:
+ addl -8(%rbp), %eax
+ retq
+ .size barAddFunc, .-barAddFunc
+
+ .globl helper1Func
+ .type helper1Func,@function
+helper1Func:
+ leaq barAddFunc(%rip), %rax
+ cmpq %rax, -16(%rbp)
+ retq
+ .size helper1Func, .-helper1Func
+
+ .globl main
+ .type main,@function
+main:
+ leaq barAddFunc(%rip), %rdi
+ callq helper1Func
+ callq fooSubFunc
+ callq barSubFunc
+ callq fooAddFunc
+ retq
+ .size main, .-main
diff --git a/bolt/test/X86/icf-safe-test2GlobalConstPtrNoPic.test b/bolt/test/X86/icf-safe-test2GlobalConstPtrNoPic.test
new file mode 100644
index 000000000000..ea2d8a5f11e0
--- /dev/null
+++ b/bolt/test/X86/icf-safe-test2GlobalConstPtrNoPic.test
@@ -0,0 +1,95 @@
+## Check that BOLT handles correctly folding functions with --icf=safe that can be referenced by non-control flow instructions,
+## when binary is built with -fno-PIC/-fno-PIE.
+
+# REQUIRES: system-linux, asserts
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o
+# RUN: %clang %cflags %t1.o -o %t.exe -Wl,-q -no-pie
+# RUN: llvm-bolt --no-threads %t.exe --icf -debug-only=bolt-icf -o %t.bolt 2>&1 | FileCheck --check-prefix=ICFCHECK %s
+# RUN: llvm-bolt --no-threads %t.exe --icf=safe -debug-only=bolt-icf -o %t.bolt 2>&1 | FileCheck --check-prefix=SAFEICFCHECK %s
+
+# ICFCHECK: ICF iteration 1
+# ICFCHECK-NEXT: folding barAddFunc into fooAddFunc
+# ICFCHECK-NEXT: folding barMulFunc into fooMulFunc
+
+# SAFEICFCHECK: skipping function with reference taken fooMulFunc
+# SAFEICFCHECK-NEXT: skipping function with reference taken barMulFunc
+# SAFEICFCHECK-NEXT: skipping function with reference taken barAddFunc
+# SAFEICFCHECK-NEXT: ICF iteration 1
+# SAFEICFCHECK-NEXT: ===---------
+
+## clang++ main.cpp -c -o -fno-PIC
+## Similar code gets generated for external reference function.
+## Other functions removed for brevity.
+## const static int (*const funcGlobalBarAdd)(int, int) = barAdd;
+## const int (*const funcGlobalBarMul)(int, int) = barMul;
+## int main(int argc, char **argv) {
+## int temp = helper1(funcGlobalBarAdd, FooVar, BarVar)
+## return temp;
+## }
+## Manually modified to remove "extra" assembly.
+ .globl fooMulFunc
+ .type fooMulFunc,@function
+fooMulFunc:
+ imull -8(%rbp), %eax
+ retq
+ .size fooMulFunc, .-fooMulFunc
+
+ .globl barMulFunc
+ .type barMulFunc,@function
+barMulFunc:
+ imull -8(%rbp), %eax
+ retq
+ .size barMulFunc, .-barMulFunc
+
+ .globl fooAddFunc
+ .type fooAddFunc,@function
+fooAddFunc:
+ addl -8(%rbp), %eax
+ retq
+ .size fooAddFunc, .-fooAddFunc
+
+ .globl barAddFunc
+ .type barAddFunc,@function
+barAddFunc:
+ addl -8(%rbp), %eax
+ retq
+ .size barAddFunc, .-barAddFunc
+
+ .globl helperFunc
+ .type helperFunc,@function
+helperFunc:
+ movabsq $barAddFunc, %rax
+ cmpq %rax, -16(%rbp)
+ retq
+ .size helperFunc, .-helperFunc
+
+ .globl main
+ .type main,@function
+main:
+ movl FooVar, %esi
+ movl BarVar, %edx
+ movabsq $barAddFunc, %rdi
+ callq helperFunc
+ movabsq $fooMulFunc, %rdi
+ movabsq $barMulFunc, %rsi
+ retq
+ .size main, .-main
+
+ .type FooVar,@object
+ .data
+ .globl FooVar
+FooVar:
+ .long 1
+ .size FooVar, 4
+
+ .type BarVar,@object
+ .globl BarVar
+BarVar:
+ .long 2
+ .size BarVar, 4
+
+ .type .L.str,@object
+ .section .rodata.str1.1,"aMS",@progbits,1
+.L.str:
+ .asciz "val: %d\n"
+ .size .L.str, 9
diff --git a/bolt/test/X86/linux-alt-instruction.s b/bolt/test/X86/linux-alt-instruction.s
index fe3abbfc2b4c..83d2cd0634d0 100644
--- a/bolt/test/X86/linux-alt-instruction.s
+++ b/bolt/test/X86/linux-alt-instruction.s
@@ -142,6 +142,15 @@ _start:
.section .orc_unwind_ip
.long .L0 + 2 - .
+## Linux kernel version
+ .rodata
+ .align 16
+ .globl linux_banner
+ .type linux_banner, @object
+linux_banner:
+ .string "Linux version 6.6.61\n"
+ .size linux_banner, . - linux_banner
+
## Fake Linux Kernel sections.
.section __ksymtab,"a",@progbits
.section __ksymtab_gpl,"a",@progbits
diff --git a/bolt/test/X86/linux-bug-table.s b/bolt/test/X86/linux-bug-table.s
index 07a4729ade73..2965daab2b26 100644
--- a/bolt/test/X86/linux-bug-table.s
+++ b/bolt/test/X86/linux-bug-table.s
@@ -56,6 +56,15 @@ _start:
.long .L1 - . # instruction
.org 2b + 12
+## Linux kernel version
+ .rodata
+ .align 16
+ .globl linux_banner
+ .type linux_banner, @object
+linux_banner:
+ .string "Linux version 6.6.61\n"
+ .size linux_banner, . - linux_banner
+
## Fake Linux Kernel sections.
.section __ksymtab,"a",@progbits
.section __ksymtab_gpl,"a",@progbits
diff --git a/bolt/test/X86/linux-exceptions.s b/bolt/test/X86/linux-exceptions.s
index 20b8c965f853..b0e7641af1cd 100644
--- a/bolt/test/X86/linux-exceptions.s
+++ b/bolt/test/X86/linux-exceptions.s
@@ -59,6 +59,15 @@ foo:
.long .LF0 - . # fixup
.long 0 # data
+## Linux kernel version
+ .rodata
+ .align 16
+ .globl linux_banner
+ .type linux_banner, @object
+linux_banner:
+ .string "Linux version 6.6.61\n"
+ .size linux_banner, . - linux_banner
+
## Fake Linux Kernel sections.
.section __ksymtab,"a",@progbits
.section __ksymtab_gpl,"a",@progbits
diff --git a/bolt/test/X86/linux-orc.s b/bolt/test/X86/linux-orc.s
index 1b0e681b1dbf..133b0df690e6 100644
--- a/bolt/test/X86/linux-orc.s
+++ b/bolt/test/X86/linux-orc.s
@@ -157,6 +157,15 @@ bar:
.section .orc_unwind_ip
.long .L4 - .
+## Linux kernel version
+ .rodata
+ .align 16
+ .globl linux_banner
+ .type linux_banner, @object
+linux_banner:
+ .string "Linux version 6.6.61\n"
+ .size linux_banner, . - linux_banner
+
## Fake Linux Kernel sections.
.section __ksymtab,"a",@progbits
.section __ksymtab_gpl,"a",@progbits
diff --git a/bolt/test/X86/linux-parainstructions.s b/bolt/test/X86/linux-parainstructions.s
index 07fca6bbedaf..facfcb168b16 100644
--- a/bolt/test/X86/linux-parainstructions.s
+++ b/bolt/test/X86/linux-parainstructions.s
@@ -49,6 +49,15 @@ _start:
.byte 1 # type
.byte 7 # length
+## Linux kernel version
+ .rodata
+ .align 16
+ .globl linux_banner
+ .type linux_banner, @object
+linux_banner:
+ .string "Linux version 6.6.61\n"
+ .size linux_banner, . - linux_banner
+
## Fake Linux Kernel sections.
.section __ksymtab,"a",@progbits
.section __ksymtab_gpl,"a",@progbits
diff --git a/bolt/test/X86/linux-pci-fixup.s b/bolt/test/X86/linux-pci-fixup.s
index 42504c108d33..d8df91a4e9bc 100644
--- a/bolt/test/X86/linux-pci-fixup.s
+++ b/bolt/test/X86/linux-pci-fixup.s
@@ -36,6 +36,15 @@ _start:
.long 0x0 # class shift
.long .L0 - . # fixup
+## Linux kernel version
+ .rodata
+ .align 16
+ .globl linux_banner
+ .type linux_banner, @object
+linux_banner:
+ .string "Linux version 6.6.61\n"
+ .size linux_banner, . - linux_banner
+
## Fake Linux Kernel sections.
.section __ksymtab,"a",@progbits
.section __ksymtab_gpl,"a",@progbits
diff --git a/bolt/test/X86/linux-smp-locks.s b/bolt/test/X86/linux-smp-locks.s
index 50d9e632b117..2fc136fd78cd 100644
--- a/bolt/test/X86/linux-smp-locks.s
+++ b/bolt/test/X86/linux-smp-locks.s
@@ -35,6 +35,15 @@ _start:
.long .L0 - .
.long .L1 - .
+## Linux kernel version
+ .rodata
+ .align 16
+ .globl linux_banner
+ .type linux_banner, @object
+linux_banner:
+ .string "Linux version 6.6.61\n"
+ .size linux_banner, . - linux_banner
+
## Fake Linux Kernel sections.
.section __ksymtab,"a",@progbits
.section __ksymtab_gpl,"a",@progbits
diff --git a/bolt/test/X86/linux-static-calls.s b/bolt/test/X86/linux-static-calls.s
index ce90f4bb79c0..758e1395d884 100644
--- a/bolt/test/X86/linux-static-calls.s
+++ b/bolt/test/X86/linux-static-calls.s
@@ -54,6 +54,15 @@ __start_static_call_sites:
.type __stop_static_call_sites, %object
__stop_static_call_sites:
+## Linux kernel version
+ .rodata
+ .align 16
+ .globl linux_banner
+ .type linux_banner, @object
+linux_banner:
+ .string "Linux version 6.6.61\n"
+ .size linux_banner, . - linux_banner
+
## Fake Linux Kernel sections.
.section __ksymtab,"a",@progbits
.section __ksymtab_gpl,"a",@progbits
diff --git a/bolt/test/X86/linux-static-keys.s b/bolt/test/X86/linux-static-keys.s
index 0bd17a375d88..2e4457e4df9f 100644
--- a/bolt/test/X86/linux-static-keys.s
+++ b/bolt/test/X86/linux-static-keys.s
@@ -35,13 +35,13 @@ _start:
.L0:
jmp L1
# CHECK: jit
-# CHECK-SAME: # ID: 1 {{.*}} # Likely: 0 # InitValue: 1
+# CHECK-SAME: # ID: 1 {{.*}} # Likely: 1 # InitValue: 0
nop
L1:
.nops 5
- jmp .L0
# CHECK: jit
-# CHECK-SAME: # ID: 2 {{.*}} # Likely: 1 # InitValue: 1
+# CHECK-SAME: # ID: 2 {{.*}} # Likely: 0 # InitValue: 0
+ jmp .L0
## Check that a branch profile associated with a NOP is handled properly when
## dynamic branch is created.
@@ -67,18 +67,33 @@ foo:
.type __start___jump_table, %object
__start___jump_table:
- .long .L0 - . # Jump address
- .long L1 - . # Target address
- .quad 1 # Key address
+ .long .L0 - . # Jump address
+ .long L1 - . # Target address
+ .quad fake_static_key + 1 - . # Key address; LSB = 1 : likely
- .long L1 - . # Jump address
- .long L2 - . # Target address
- .quad 0 # Key address
+ .long L1 - . # Jump address
+ .long L2 - . # Target address
+ .quad fake_static_key -. # Key address; LSB = 0 : unlikely
.globl __stop___jump_table
.type __stop___jump_table, %object
__stop___jump_table:
+## Staic keys (we just use the label ignoring the format of the keys).
+ .data
+ .align 8
+fake_static_key:
+ .quad 0
+
+## Linux kernel version
+ .rodata
+ .align 16
+ .globl linux_banner
+ .type linux_banner, @object
+linux_banner:
+ .string "Linux version 6.6.61\n"
+ .size linux_banner, . - linux_banner
+
## Fake Linux Kernel sections.
.section __ksymtab,"a",@progbits
.section __ksymtab_gpl,"a",@progbits
diff --git a/bolt/test/X86/linux-version.S b/bolt/test/X86/linux-version.S
new file mode 100644
index 000000000000..e680d0d64a21
--- /dev/null
+++ b/bolt/test/X86/linux-version.S
@@ -0,0 +1,53 @@
+# REQUIRES: system-linux
+
+## Check that BOLT correctly detects the Linux kernel version
+
+# RUN: %clang -DA -target x86_64-unknown-unknown \
+# RUN: %cflags -nostdlib %s -o %t.exe \
+# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr
+# RUN: llvm-bolt %t.exe -o %t.out 2>&1 | FileCheck --check-prefix=CHECK-A %s
+
+# RUN: %clang -DB -target x86_64-unknown-unknown \
+# RUN: %cflags -nostdlib %s -o %t.exe \
+# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr
+# RUN: llvm-bolt %t.exe -o %t.out 2>&1 | FileCheck --check-prefix=CHECK-B %s
+
+# RUN: %clang -DC -target x86_64-unknown-unknown \
+# RUN: %cflags -nostdlib %s -o %t.exe \
+# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr
+# RUN: llvm-bolt %t.exe -o %t.out 2>&1 | FileCheck --check-prefix=CHECK-C %s
+
+ .text
+ .globl foo
+ .type foo, %function
+foo:
+ ret
+ .size foo, .-foo
+
+## Linux kernel version
+ .rodata
+ .align 16
+ .globl linux_banner
+ .type linux_banner, @object
+linux_banner:
+
+#ifdef A
+ .string "Linux version 6.6.61\n"
+#endif
+# CHECK-A: BOLT-INFO: Linux kernel version is 6.6.61
+
+#ifdef B
+ .string "Linux version 6.6.50-rc4\n"
+#endif
+# CHECK-B: BOLT-INFO: Linux kernel version is 6.6.50
+
+#ifdef C
+ .string "Linux version 6.6\n"
+#endif
+# CHECK-C: BOLT-INFO: Linux kernel version is 6.6
+
+ .size linux_banner, . - linux_banner
+
+## Fake Linux Kernel sections.
+ .section __ksymtab,"a",@progbits
+ .section __ksymtab_gpl,"a",@progbits
diff --git a/bolt/test/binary-analysis/AArch64/Inputs/dummy.txt b/bolt/test/binary-analysis/AArch64/Inputs/dummy.txt
new file mode 100644
index 000000000000..2995a4d0e749
--- /dev/null
+++ b/bolt/test/binary-analysis/AArch64/Inputs/dummy.txt
@@ -0,0 +1 @@
+dummy \ No newline at end of file
diff --git a/bolt/test/binary-analysis/AArch64/cmdline-args.test b/bolt/test/binary-analysis/AArch64/cmdline-args.test
new file mode 100644
index 000000000000..e414818644a3
--- /dev/null
+++ b/bolt/test/binary-analysis/AArch64/cmdline-args.test
@@ -0,0 +1,33 @@
+# This file tests error messages produced on invalid command line arguments.
+# It also checks that help messages are generated as expected.
+
+# Verify that an error message is provided if an input file is missing or incorrect
+
+RUN: not llvm-bolt-binary-analysis 2>&1 | FileCheck -check-prefix=NOFILEARG %s
+NOFILEARG: llvm-bolt-binary-analysis: Not enough positional command line arguments specified!
+NOFILEARG-NEXT: Must specify at least 1 positional argument: See: {{.*}}llvm-bolt-binary-analysis --help
+
+RUN: not llvm-bolt-binary-analysis non-existing-file 2>&1 | FileCheck -check-prefix=NONEXISTINGFILEARG %s
+NONEXISTINGFILEARG: llvm-bolt-binary-analysis: 'non-existing-file': No such file or directory.
+
+RUN: not llvm-bolt-binary-analysis %p/Inputs/dummy.txt 2>&1 | FileCheck -check-prefix=NOELFFILEARG %s
+NOELFFILEARG: llvm-bolt-binary-analysis: '{{.*}}/Inputs/dummy.txt': The file was not recognized as a valid object file.
+
+RUN: %clang %cflags %p/../../Inputs/asm_foo.s %p/../../Inputs/asm_main.c -o %t.exe
+RUN: llvm-bolt-binary-analysis %t.exe 2>&1 | FileCheck -check-prefix=VALIDELFFILEARG --allow-empty %s
+# Check that there are no BOLT-WARNING or BOLT-ERROR output lines
+VALIDELFFILEARG: BOLT-INFO:
+VALIDELFFILEARG-NOT: BOLT-WARNING:
+VALIDELFFILEARG-NOT: BOLT-ERROR:
+
+# Check --help output
+
+RUN: llvm-bolt-binary-analysis --help 2>&1 | FileCheck -check-prefix=HELP %s
+
+HELP: OVERVIEW: BinaryAnalysis
+HELP-EMPTY:
+HELP-NEXT: USAGE: llvm-bolt-binary-analysis [options] <executable>
+HELP-EMPTY:
+HELP-NEXT: OPTIONS:
+HELP-EMPTY:
+HELP-NEXT: Generic Options:
diff --git a/bolt/test/binary-analysis/AArch64/lit.local.cfg b/bolt/test/binary-analysis/AArch64/lit.local.cfg
new file mode 100644
index 000000000000..6f247dd52e82
--- /dev/null
+++ b/bolt/test/binary-analysis/AArch64/lit.local.cfg
@@ -0,0 +1,7 @@
+if "AArch64" not in config.root.targets:
+ config.unsupported = True
+
+flags = "--target=aarch64-linux-gnu -nostartfiles -nostdlib -ffreestanding -Wl,--emit-relocs"
+
+config.substitutions.insert(0, ("%cflags", f"%cflags {flags}"))
+config.substitutions.insert(0, ("%cxxflags", f"%cxxflags {flags}"))
diff --git a/bolt/test/lit.cfg.py b/bolt/test/lit.cfg.py
index da3ae34ba3bd..0d05229be2bf 100644
--- a/bolt/test/lit.cfg.py
+++ b/bolt/test/lit.cfg.py
@@ -110,6 +110,7 @@ tools = [
),
ToolSubst("llvm-boltdiff", unresolved="fatal"),
ToolSubst("llvm-bolt-heatmap", unresolved="fatal"),
+ ToolSubst("llvm-bolt-binary-analysis", unresolved="fatal"),
ToolSubst("llvm-bat-dump", unresolved="fatal"),
ToolSubst("perf2bolt", unresolved="fatal"),
ToolSubst("yaml2obj", unresolved="fatal"),
diff --git a/bolt/test/merge-fdata-bat-no-lbr.test b/bolt/test/merge-fdata-bat-no-lbr.test
new file mode 100644
index 000000000000..fd5cd1626335
--- /dev/null
+++ b/bolt/test/merge-fdata-bat-no-lbr.test
@@ -0,0 +1,20 @@
+## Check that merge-fdata correctly handles merging two fdata files with both boltedcollection and no_lbr tags.
+
+# REQUIRES: system-linux
+
+# RUN: split-file %s %t
+# RUN: merge-fdata %t/a.fdata %t/b.fdata -o %t/merged.fdata
+# RUN: FileCheck %s --input-file %t/merged.fdata
+
+# CHECK: boltedcollection
+# CHECK: no_lbr
+# CHECK: main 2
+
+#--- a.fdata
+boltedcollection
+no_lbr
+main 1
+#--- b.fdata
+boltedcollection
+no_lbr
+main 1
diff --git a/bolt/test/merge-fdata-lbr-mode.test b/bolt/test/merge-fdata-lbr-mode.test
new file mode 100644
index 000000000000..2cd385319428
--- /dev/null
+++ b/bolt/test/merge-fdata-lbr-mode.test
@@ -0,0 +1,15 @@
+## Check that merge-fdata tool doesn't falsely print no_lbr when not in no-lbr mode
+
+# REQUIRES: system-linux
+
+# RUN: split-file %s %t
+# RUN: merge-fdata %t/a.fdata %t/b.fdata -o %t/merged.fdata
+# RUN: FileCheck %s --input-file %t/merged.fdata
+
+# CHECK-NOT: no_lbr
+# CHECK: 1 main 0 1 main 2 1 3
+
+#--- a.fdata
+1 main 0 1 main 2 0 1
+#--- b.fdata
+1 main 0 1 main 2 1 2
diff --git a/bolt/test/merge-fdata-mixed-bat-no-lbr.test b/bolt/test/merge-fdata-mixed-bat-no-lbr.test
new file mode 100644
index 000000000000..eeb3a0e23b0c
--- /dev/null
+++ b/bolt/test/merge-fdata-mixed-bat-no-lbr.test
@@ -0,0 +1,16 @@
+## Check that merge-fdata doesn't incorrectly merge two fdata files with boltedcollection and no_lbr tags.
+
+# REQUIRES: system-linux
+
+# RUN: split-file %s %t
+# RUN: not merge-fdata %t/a.fdata %t/b.fdata 2>&1 | FileCheck %s
+
+# CHECK: cannot mix profile with and without boltedcollection
+
+#--- a.fdata
+boltedcollection
+no_lbr
+main 1
+#--- b.fdata
+no_lbr
+main 1
diff --git a/bolt/test/merge-fdata-mixed-mode.test b/bolt/test/merge-fdata-mixed-mode.test
new file mode 100644
index 000000000000..f897fec5d9db
--- /dev/null
+++ b/bolt/test/merge-fdata-mixed-mode.test
@@ -0,0 +1,15 @@
+## Check that merge-fdata tool correctly reports error message
+## when trying to merge 'no-lbr' and 'lbr' profiles
+
+# REQUIRES: system-linux
+
+# RUN: split-file %s %t
+# RUN: not merge-fdata %t/a.fdata %t/b.fdata 2>&1 | FileCheck %s
+
+# CHECK: cannot mix profile with and without no_lbr
+
+#--- a.fdata
+no_lbr
+main 1
+#--- b.fdata
+main 1
diff --git a/bolt/test/merge-fdata-no-lbr-mode.test b/bolt/test/merge-fdata-no-lbr-mode.test
new file mode 100644
index 000000000000..9dfad99f7999
--- /dev/null
+++ b/bolt/test/merge-fdata-no-lbr-mode.test
@@ -0,0 +1,18 @@
+## Check that merge-fdata tool correctly processes fdata files with header
+## string produced by no-lbr mode (no_lbr)
+
+# REQUIRES: system-linux
+
+# RUN: split-file %s %t
+# RUN: merge-fdata %t/a.fdata %t/b.fdata -o %t/merged.fdata
+# RUN: FileCheck %s --input-file %t/merged.fdata
+
+# CHECK: no_lbr
+# CHECK: main 2
+
+#--- a.fdata
+no_lbr
+main 1
+#--- b.fdata
+no_lbr
+main 1
diff --git a/bolt/test/unreadable-profile.test b/bolt/test/unreadable-profile.test
index fe1ca93f3221..4c1cd8af0a62 100644
--- a/bolt/test/unreadable-profile.test
+++ b/bolt/test/unreadable-profile.test
@@ -1,4 +1,4 @@
-REQUIRES: system-linux
+REQUIRES: system-linux, non-root-user
RUN: touch %t.profile && chmod 000 %t.profile
RUN: %clang %S/Inputs/hello.c -o %t