diff options
author | Pawel Kupczak <pawel.kupczak@intel.com> | 2025-08-28 11:50:13 +0000 |
---|---|---|
committer | Christina Schimpe <christina.schimpe@intel.com> | 2025-09-04 20:44:48 +0000 |
commit | f9aa48dc545ef511e19f4dfab88a196b820fd2da (patch) | |
tree | e9c8208fc40ae0c9007260804dc84b7247b60f9c | |
parent | 55fc9233a835a87d1a9020a8c71c473b03fc4f72 (diff) | |
download | binutils-f9aa48dc545ef511e19f4dfab88a196b820fd2da.zip binutils-f9aa48dc545ef511e19f4dfab88a196b820fd2da.tar.gz binutils-f9aa48dc545ef511e19f4dfab88a196b820fd2da.tar.bz2 |
gdb, amd64: extend the amd64 prologue analyzer to skip register pushes
A typical function's prologue can consist of setting up a frame pointer,
pushing registers onto the stack and allocating space on the stack.
Current amd64 prologue analyzer would stop after the frame setup.
This patch allows GDB to skip past register pushes, while also improving
unwinding pushed registers, for functions with a frame pointer, without
debug info and .cfi directives found in .eh_frame section that are used
for unwinding. Skipping register pushes was also present for i386
targets before - the proposed changes are based on i386 implementation.
It also improves the unwinding even if .cfi directives are present,
because GDB can only unwind a register if it has reached a corresponding
.cfi directive, which won't be there before the pushes.
Additionally, at least gcc 11.4 and later by default doesn't emit
necessary debug info, which GDB would try to use to find prologue's end.
In that case, extended prologue analyzer would take effect.
Using C source listed below as an example, compiled with gcc 11.4.0:
```
int __attribute__ ((noinline))
bar (int a)
{
return a + a;
}
int __attribute__ ((noinline))
foo (int a, int b, int c, int d, int e)
{
int x = bar (a) + bar (b) + bar (c) + bar (d) + bar (e);
return x;
}
int
main (int argc, char **argv)
{
return foo (1, 2, 3, 4, 5);
}
```
Compiling with "gcc -O1 -fno-omit-frame-pointer
-fno-asynchronous-unwind-tables", we get:
```
(gdb) b foo
Breakpoint 1 at 0x1139
(gdb) r
...
Breakpoint 1, 0x0000555555555139 in foo ()
(gdb) disassemble
Dump of assembler code for function foo:
0x0000555555555131 <+0>: endbr64
0x0000555555555135 <+4>: push %rbp
0x0000555555555136 <+5>: mov %rsp,%rbp
=> 0x0000555555555139 <+8>: push %r15
0x000055555555513b <+10>: push %r14
0x000055555555513d <+12>: push %r13
0x000055555555513f <+14>: push %r12
0x0000555555555141 <+16>: push %rbx
0x0000555555555142 <+17>: sub $0x8,%rsp
0x0000555555555146 <+21>: mov %esi,%r15d
...
(gdb) ni
0x000055555555513b in foo ()
(gdb) p $r15
$1 = 140737354125376
(gdb) p $r15=1234
$2 = 1234
(gdb) p $r15
$3 = 1234
(gdb) up
#1 0x00005555555551b7 in main ()
(gdb) p $r15
$4 = 1234
```
With the proposed changes, breakpoint gets past those register pushes:
```
(gdb) b foo
Breakpoint 1 at 0x1142
(gdb) r
...
Breakpoint 1, 0x0000555555555142 in foo ()
(gdb) disassemble
Dump of assembler code for function foo:
0x0000555555555131 <+0>: endbr64
0x0000555555555135 <+4>: push %rbp
0x0000555555555136 <+5>: mov %rsp,%rbp
0x0000555555555139 <+8>: push %r15
0x000055555555513b <+10>: push %r14
0x000055555555513d <+12>: push %r13
0x000055555555513f <+14>: push %r12
0x0000555555555141 <+16>: push %rbx
=> 0x0000555555555142 <+17>: sub $0x8,%rsp
0x0000555555555146 <+21>: mov %esi,%r15d
...
```
Also, unwinding pushed registers now works:
```
...
Breakpoint 1, 0x0000555555555142 in foo ()
(gdb) disassemble
Dump of assembler code for function foo:
0x0000555555555131 <+0>: endbr64
0x0000555555555135 <+4>: push %rbp
0x0000555555555136 <+5>: mov %rsp,%rbp
0x0000555555555139 <+8>: push %r15
0x0000555555555139 <+8>: push %r15
0x000055555555513b <+10>: push %r14
0x000055555555513d <+12>: push %r13
0x000055555555513f <+14>: push %r12
0x0000555555555141 <+16>: push %rbx
=> 0x0000555555555142 <+17>: sub $0x8,%rsp
0x0000555555555146 <+21>: mov %esi,%r15d
...
(gdb) p $r15
$1 = 140737354125376
(gdb) p $r15=1234
$2 = 1234
(gdb) p $r15
$3 = 1234
(gdb) up
#1 0x00005555555551b7 in main ()
(gdb) p $r15
$4 = 140737354125376
```
Additionally a new test was added to verify this behavior.
Reviewed-By: Guinevere Larsen <guinevere@redhat.com>
Approved-By: Andrew Burgess <aburgess@redhat.com>
-rwxr-xr-x[-rw-r--r--] | gdb/amd64-tdep.c | 56 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis-no-cfi.S | 93 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis-offset.S | 90 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis.S | 116 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis.c | 49 | ||||
-rw-r--r-- | gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis.exp | 204 |
6 files changed, 607 insertions, 1 deletions
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c index 9160834..47eb2ec 100644..100755 --- a/gdb/amd64-tdep.c +++ b/gdb/amd64-tdep.c @@ -2586,6 +2586,59 @@ amd64_analyze_frame_setup (gdbarch *gdbarch, CORE_ADDR pc, return pc; } +/* Check whether PC points at code pushing registers onto the stack. If so, + update CACHE and return pc after those pushes or CURRENT_PC, whichever is + smaller. Otherwise, return PC passed to this function. + + In AMD64 prologue, we only expect GPRs being pushed onto the stack. */ + +static CORE_ADDR +amd64_analyze_register_saves (CORE_ADDR pc, CORE_ADDR current_pc, + amd64_frame_cache *cache) +{ + gdb_byte op; + + /* Limit iterating to 16 GPRs available. */ + for (int i = 0; i < 16 && pc < current_pc; i++) + { + int reg = 0; + int pc_offset = 0; + + if (target_read_code (pc, &op, 1) == -1) + return pc; + + /* push %r8 - %r15 REX prefix. We expect only REX.B to be set, but + because, for example, REX.R would be "unused" if it were there, + we mask opcode with 0xF1 in case compilers don't get rid of it + "because it doesn't matter anyway". */ + if ((op & 0xF1) == 0x41) + { + reg += 8; + pc_offset = 1; + + if (target_read_code (pc + 1, &op, 1) == -1) + return pc; + } + + /* push %rax|%rcx|%rdx|%rbx|%rsp|%rbp|%rsi|%rdi + + or with 0x41 prefix: + push %r8|%r9|%r10|%r11|%r12|%r13|%r14|%r15. */ + if (op < 0x50 || op > 0x57) + break; + + reg += op - 0x50; + + int regnum = amd64_arch_reg_to_regnum (reg); + cache->sp_offset += 8; + cache->saved_regs[regnum] = -cache->sp_offset; + + pc += 1 + pc_offset; + } + + return pc; +} + /* Do a limited analysis of the prologue at PC and update CACHE accordingly. Bail out early if CURRENT_PC is reached. Return the address where the analysis stopped. @@ -2627,7 +2680,8 @@ amd64_analyze_prologue (gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR current_pc, if (current_pc <= pc) return current_pc; - return amd64_analyze_frame_setup (gdbarch, pc, current_pc, cache); + pc = amd64_analyze_frame_setup (gdbarch, pc, current_pc, cache); + return amd64_analyze_register_saves (pc, current_pc, cache); } /* Work around false termination of prologue - GCC PR debug/48827. diff --git a/gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis-no-cfi.S b/gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis-no-cfi.S new file mode 100644 index 0000000..bcebfe8 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis-no-cfi.S @@ -0,0 +1,93 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2025 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* This file is compiled from gdb.arch/amd64-extended-prologue-analysis.c + using gcc 11.4.0 with flags: -g0 -O1 -S -fno-omit-frame-pointer + -fno-asynchronous-unwind-tables. */ + + .file "amd64-extended-prologue-analysis.c" + .text + .globl bar + .type bar, @function +bar: + endbr64 + leal (%rdi,%rdi), %eax + ret + .size bar, .-bar + .globl foo + .type foo, @function +foo: + endbr64 + pushq %rbp + movq %rsp, %rbp + pushq %r14 + pushq %r13 + pushq %r12 + pushq %rbx + movl %edi, %r12d + movl %esi, %r14d + movl %edx, %r13d + call bar + movl %eax, %ebx + movl %r14d, %edi + call bar + addl %eax, %ebx + movl %r13d, %edi + call bar + addl %ebx, %eax + addl %r12d, %eax + popq %rbx + popq %r12 + popq %r13 + popq %r14 + popq %rbp + ret + .size foo, .-foo + .globl main + .type main, @function +main: + endbr64 + pushq %rbp + movq %rsp, %rbp + subq $16, %rsp + leal (%rdi,%rdi), %ecx + leal 2(%rdi), %edx + leal 1(%rdi), %esi + call foo + movl %eax, -4(%rbp) + movl -4(%rbp), %eax + leave + ret + .size main, .-main + .ident "GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0" + .section .note.GNU-stack,"",@progbits + .section .note.gnu.property,"a" + .align 8 + .long 1f - 0f + .long 4f - 1f + .long 5 +0: + .string "GNU" +1: + .align 8 + .long 0xc0000002 + .long 3f - 2f +2: + .long 0x3 +3: + .align 8 +4: diff --git a/gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis-offset.S b/gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis-offset.S new file mode 100644 index 0000000..783ec33 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis-offset.S @@ -0,0 +1,90 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2025 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* This file is compiled from gdb.arch/amd64-extended-prologue-analysis.c + using gcc 11.4.0 with flags: -g0 -O1 -S -fomit-frame-pointer + -fno-asynchronous-unwind-tables. */ + + .file "amd64-extended-prologue-analysis.c" + .text + .globl bar + .type bar, @function +bar: + endbr64 + leal (%rdi,%rdi), %eax + ret + .size bar, .-bar + .globl foo + .type foo, @function +foo: + endbr64 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %rbp + pushq %rbx + movl %edi, %ebp + movl %esi, %r13d + movl %edx, %r12d + call bar + movl %eax, %ebx + movl %r13d, %edi + call bar + addl %eax, %ebx + movl %r12d, %edi + call bar + addl %ebx, %eax + addl %ebp, %eax + popq %rbx + popq %rbp + popq %r12 + popq %r13 + popq %r14 + ret + .size foo, .-foo + .globl main + .type main, @function +main: + endbr64 + subq $16, %rsp + leal (%rdi,%rdi), %ecx + leal 2(%rdi), %edx + leal 1(%rdi), %esi + call foo + movl %eax, 12(%rsp) + movl 12(%rsp), %eax + addq $16, %rsp + ret + .size main, .-main + .ident "GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0" + .section .note.GNU-stack,"",@progbits + .section .note.gnu.property,"a" + .align 8 + .long 1f - 0f + .long 4f - 1f + .long 5 +0: + .string "GNU" +1: + .align 8 + .long 0xc0000002 + .long 3f - 2f +2: + .long 0x3 +3: + .align 8 +4: diff --git a/gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis.S b/gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis.S new file mode 100644 index 0000000..c5ef4f6 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis.S @@ -0,0 +1,116 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2025 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* This file is compiled from gdb.arch/amd64-extended-prologue-analysis.c + using gcc 11.4.0 with flags: -g0 -O1 -S -fno-omit-frame-pointer. */ + + .file "amd64-extended-prologue-analysis.c" + .text + .globl bar + .type bar, @function +bar: +.LFB0: + .cfi_startproc + endbr64 + leal (%rdi,%rdi), %eax + ret + .cfi_endproc +.LFE0: + .size bar, .-bar + .globl foo + .type foo, @function +foo: +.LFB1: + .cfi_startproc + endbr64 + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset 6, -16 + movq %rsp, %rbp + .cfi_def_cfa_register 6 + pushq %r14 + pushq %r13 + pushq %r12 + pushq %rbx + .cfi_offset 14, -24 + .cfi_offset 13, -32 + .cfi_offset 12, -40 + .cfi_offset 3, -48 + movl %edi, %r12d + movl %esi, %r14d + movl %edx, %r13d + call bar + movl %eax, %ebx + movl %r14d, %edi + call bar + addl %eax, %ebx + movl %r13d, %edi + call bar + addl %ebx, %eax + addl %r12d, %eax + popq %rbx + popq %r12 + popq %r13 + popq %r14 + popq %rbp + .cfi_def_cfa 7, 8 + ret + .cfi_endproc +.LFE1: + .size foo, .-foo + .globl main + .type main, @function +main: +.LFB2: + .cfi_startproc + endbr64 + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset 6, -16 + movq %rsp, %rbp + .cfi_def_cfa_register 6 + subq $16, %rsp + leal (%rdi,%rdi), %ecx + leal 2(%rdi), %edx + leal 1(%rdi), %esi + call foo + movl %eax, -4(%rbp) + movl -4(%rbp), %eax + leave + .cfi_def_cfa 7, 8 + ret + .cfi_endproc +.LFE2: + .size main, .-main + .ident "GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0" + .section .note.GNU-stack,"",@progbits + .section .note.gnu.property,"a" + .align 8 + .long 1f - 0f + .long 4f - 1f + .long 5 +0: + .string "GNU" +1: + .align 8 + .long 0xc0000002 + .long 3f - 2f +2: + .long 0x3 +3: + .align 8 +4: diff --git a/gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis.c b/gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis.c new file mode 100644 index 0000000..1ce30b1 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis.c @@ -0,0 +1,49 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2025 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +int __attribute__ ((noinline)) +bar (int x) +{ + return x + x; +} + +/* This function should generate a prologue in shape of: + push %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + mov %rsp, %rbp + .cfi_def_cfa_register %rbp + push %reg1 + push %reg2 + .cfi_offset %reg2, 32 + .cfi_offset %reg1, 24 + + So to be able to unwind a register, GDB needs to skip prologue past + register pushes (to access .cfi directives). */ +int __attribute__ ((noinline)) +foo (int a, int b, int c, int d) +{ + a += bar (a) + bar (b) + bar (c); + return a; +} + +int +main (int argc, char **argv) +{ + volatile int a = foo (argc, argc + 1, argc + 2, argc * 2); + return a; +} diff --git a/gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis.exp b/gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis.exp new file mode 100644 index 0000000..7ad0c60 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-extended-prologue-analysis.exp @@ -0,0 +1,204 @@ +# Copyright 2025 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# This test verifies that when placing a breakpoint on a function with a frame +# pointer, instructions that push callee-saved registers in the prologue are +# skipped, without debug info. When stopped on such breakpoint, the pushed +# registers should be able to be immediately unwound. With debug info present, +# GDB would try to use prologue-end markers found in the line table to +# determine where the prologue ends. +# +# It is also tested both with and without .eh_frame's .cfi directives - with +# them, GDB can only unwind a register once stopped after .cfi directive for +# that register's push. + +require is_x86_64_m64_target +standard_testfile .c -no-cfi.S .S -offset.S + +proc test_run {} { + gdb_breakpoint "foo" + gdb_continue_to_breakpoint "Continue to foo" + + gdb_test "backtrace" "#0\[^\r\n\]+in foo\[^s\]+#1\[^\r\n\]+in main\[^s\]+" \ + "Verify backtrace output in foo" + + set main_r12 [get_integer_valueof "\$r12" "null"] + gdb_assert { $main_r12 ne "null" } + + set foo_r12 [expr "$main_r12 + 2"] + gdb_test "print \$r12=$foo_r12" "$foo_r12" "Set foo's %r12=$foo_r12" + gdb_test "up" ".*main.*" "Go up a frame from foo" + gdb_test "print \$r12" "$main_r12" "foo's %r12 unwound" + gdb_test "down" ".*foo.*" "Go back down a frame to foo" + gdb_test "print \$r12" "$foo_r12" "foo's %r12 unwound back" +} + +proc offset_test_run {} { + gdb_breakpoint "*foo" + gdb_continue_to_breakpoint "Continue to entry of foo" + + set old_reg_val [get_integer_valueof "\$r12" "null"] + gdb_assert { $old_reg_val ne "null" } + + set new_reg_val [expr "$old_reg_val + 3"] + gdb_test "print \$r14=$new_reg_val" "$new_reg_val" "Set %r14=$new_reg_val" + gdb_test "print \$r13=$new_reg_val" "$new_reg_val" "Set %r13=$new_reg_val" + gdb_test "print \$r12=$new_reg_val" "$new_reg_val" "Set %r12=$new_reg_val" + + set addr_past_prologue "null" + gdb_test_multiple "disassemble" "Disassemble foo" -lbl { + -re "($::hex) <\\+($::decimal)>:\\s*mov.*" { + set addr_past_prologue $expect_out(1,string) + pass $gdb_test_name + } + } + + gdb_assert { $addr_past_prologue ne "null" } + + gdb_breakpoint "*$addr_past_prologue" + gdb_continue_to_breakpoint "Continue past foo's prologue" + + gdb_test "up" ".*main.*" "Go up a frame from foo" + gdb_test "print \$r14" "$new_reg_val" "Verify %r14 value" + gdb_test "print \$r13" "$new_reg_val" "Verify %r13 value" + gdb_test "print \$r12" "$new_reg_val" "Verify %r12 value" +} + +# Tests are done for two versions (not counting with and w/o .cfi): +# - binary compiled from C source, which verifies we actually test against +# the code that compilers produce and we expect +# - binary compiled from ASM source, which verifies that we properly analyze +# prologue sequences even when compiler introduces a sudden change in how +# it generates assembly +# +# With those 2 versions, we can easily distinguish GDB breaking analyzer and +# compilers behaving differently, if there ever is an impactful change in how +# they generate prologues. +with_test_prefix "w/o .cfi directives" { + with_test_prefix "compiler gen" { + # -fno-asynchronous-unwind-tables is needed to get rid of .cfi + # directives in .eh_frame section. + if { [gdb_can_simple_compile fno-asynchronous-unwind-tables \ + { void foo () { } } object -fno-asynchronous-unwind-tables] == 0 } { + unsupported \ + "compiler doesn't support -fno-asynchronous-unwind-tables flag" + } else { + # For at least gcc 11.4/clang 14.0.0 and later, -O1 makes them more + # eager to use registers in the prologue. + # + # At least gcc 11.4 and later by default does not generate full + # debug info, "nodebug" is there for other compilers. + if { [prepare_for_testing "failed to prepare" "$testfile-no-cfi-C" \ + $srcfile { optimize=-O1 nodebug + additional_flags=-fno-asynchronous-unwind-tables + additional_flags=-fno-omit-frame-pointer}] } { + return + } + + if { ![runto_main] } { + untested "unable to run to main" + return + } + + test_run + } + } + + with_test_prefix "ASM source" { + if { [prepare_for_testing "failed to prepare" "$testfile-no-cfi-S" \ + $srcfile2 nodebug ] } { + return + } + + if { ![runto_main] } { + untested "unable to run to main" + return + } + + test_run + } +} + +with_test_prefix "with .cfi directives" { + with_test_prefix "compiler gen" { + if { [prepare_for_testing "failed to prepare" "$testfile-cfi-C" \ + $srcfile { optimize=-O1 + nodebug additional_flags=-fno-omit-frame-pointer}] } { + return + } + + if { ![runto_main] } { + untested "unable to run to main" + return + } + + test_run + } + + with_test_prefix "ASM source" { + if { [prepare_for_testing "failed to prepare" "$testfile-cfi-S" \ + $srcfile3 nodebug ] } { + return + } + + if { ![runto_main] } { + untested "unable to run to main" + return + } + + test_run + } +} + +# This section exists to verify that we properly assign offsets for functions +# w/o a frame pointer, for registers when they're pushed. If they were assigned +# in a wrong way, we might end up unwinding improper register values. +with_test_prefix "offset initialization" { + with_test_prefix "compiler gen" { + if { [gdb_can_simple_compile fno-asynchronous-unwind-tables \ + { void foo () { } } object -fno-asynchronous-unwind-tables] == 0 } { + unsupported \ + "compiler doesn't support -fno-asynchronous-unwind-tables flag" + } else { + if { [prepare_for_testing "failed to prepare" "$testfile-offset-C" \ + $srcfile { optimize=-O1 nodebug + additional_flags=-fno-asynchronous-unwind-tables + additional_flags=-fomit-frame-pointer}] } { + return + } + + if { ![runto_main] } { + untested "unable to run to main" + return + } + + offset_test_run + } + } + + with_test_prefix "ASM source" { + if { [prepare_for_testing "failed to prepare" "$testfile-offset-S" \ + $srcfile4 nodebug ] } { + return + } + + if { ![runto_main] } { + untested "unable to run to main" + return + } + + offset_test_run + } +} |