Skip to content

[BOLT] __builtin_debugtrap is handled as no-return when reconstructing CFG on AArch64 #155232

@atrosinenko

Description

@atrosinenko

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions