-
Notifications
You must be signed in to change notification settings - Fork 15k
Description
In Clang, in addition to __builtin_trap, there is a "debugtrap" builtin, which is not considered no-return by LLVM codegen. In BOLT, on the other hand, brk instructions corresponding to both builtins are handled the same way, as if they are no-return. This issue was originally discussed in #137975 (comment).
For example, by compiling the following source
int test_trap(void) {
__builtin_trap();
return 42;
}
int test_debugtrap(void) {
__builtin_debugtrap();
return 42;
}
int main() {
return 0;
}with
./bin/clang -target aarch64-linux-gnu -O1 /tmp/debugtrap.c -o /tmp/debugtrap.o -c
./bin/clang -target aarch64-linux-gnu -Wl,--emit-relocs /tmp/debugtrap.o -o /tmp/debugtrap
we get the following instructions:
/tmp/debugtrap.o: file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <test_debugtrap>:
0: d43e0000 brk #0xf000
4: 52800540 mov w0, #0x2a // =42
8: d65f03c0 ret
000000000000000c <main>:
c: 2a1f03e0 mov w0, wzr
10: d65f03c0 ret
Disassembly of section .text.unlikely.:
0000000000000000 <test_trap>:
0: d4200020 brk #0x1
That is, test_debugtrap function is compiled as if there is, for example, a SIGTRAP handler which can handle the breakpoint and continue program execution.
Here are CFGs reconstructed by BOLT for test_trap and test_debugtrap functions (call_weak_fn is kept as an example of the expected output):
Output of `./bin/llvm-bolt-binary-analysis --print-cfg /tmp/debugtrap`
// ...
Binary Function "test_trap" after building cfg {
Number : 2
State : CFG constructed
Address : 0x5c0
Size : 0x4
MaxSize : 0x40
Offset : 0x5c0
Section : .text
Orc Section : .local.text.test_trap
LSDA : 0x0
IsSimple : 1
IsMultiEntry: 0
IsSplit : 0
BB Count : 1
Hash : 5e8022319bedc45e
BB Layout : .LBB01
}
.LBB01 (1 instructions, align : 1)
Entry Point
CFI State : 0
00000000: brk #0x1
CFI State: 0
DWARF CFI Instructions:
<empty>
End of Function "test_trap"
// ...
Binary Function "call_weak_fn/1(*2)" after building cfg {
All names : call_weak_fn/1
call_weak_fn/crti.o/1
Number : 4
State : CFG constructed
Address : 0x634
Size : 0x14
MaxSize : 0x2c
Offset : 0x634
Section : .text
Orc Section : .local.text.call_weak_fn/1
LSDA : 0x0
IsSimple : 1
IsMultiEntry: 0
IsSplit : 0
BB Count : 3
Hash : 3f2b02f13366beca
BB Layout : .LBB03, .LFT3, .Ltmp0
}
.LBB03 (3 instructions, align : 1)
Entry Point
00000000: adrp x0, __BOLT_got_zero+126976
00000004: ldr x0, [x0, :lo12:__BOLT_got_zero+4048]
00000008: cbz x0, .Ltmp0
Successors: .Ltmp0, .LFT3
.LFT3 (1 instructions, align : 1)
Predecessors: .LBB03
0000000c: b __gmon_start__@PLT # TAILCALL
.Ltmp0 (1 instructions, align : 1)
Predecessors: .LBB03
00000010: ret
DWARF CFI Instructions:
<empty>
End of Function "call_weak_fn/1(*2)"
// ...
Binary Function "test_debugtrap" after building cfg {
Number : 9
State : CFG constructed
Address : 0x728
Size : 0xc
MaxSize : 0xc
Offset : 0x728
Section : .text
Orc Section : .local.text.test_debugtrap
LSDA : 0x0
IsSimple : 1
IsMultiEntry: 0
IsSplit : 0
BB Count : 2
Hash : 3a14616afcf1f0f2
BB Layout : .LBB08, .LFT2
}
.LBB08 (1 instructions, align : 1)
Entry Point
CFI State : 0
00000000: brk #0xf000
CFI State: 0
.LFT2 (2 instructions, align : 1)
CFI State : 0
00000004: mov w0, #0x2a
00000008: ret
CFI State: 0
DWARF CFI Instructions:
<empty>
End of Function "test_debugtrap"
In both cases there is no Successors: field in the basic blocks ending with brk instruction.