diff --git a/gdb/testsuite/gdb.base/backtrace-through-cu-nodebug-caller.c b/gdb/testsuite/gdb.base/backtrace-through-cu-nodebug-caller.c new file mode 100644 index 00000000000..9d49f5c3610 --- /dev/null +++ b/gdb/testsuite/gdb.base/backtrace-through-cu-nodebug-caller.c @@ -0,0 +1,28 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2005-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 . */ + +typedef int (*callback_t) (void); + +int +caller (callback_t callback) +{ + /* Ensure some frame content to push away the return address. */ + volatile const long one = 1; + + /* Modify the return value to prevent any tail-call optimization. */ + return (*callback) () - one; +} diff --git a/gdb/testsuite/gdb.base/backtrace-through-cu-nodebug-main.c b/gdb/testsuite/gdb.base/backtrace-through-cu-nodebug-main.c new file mode 100644 index 00000000000..b4e0d9eef06 --- /dev/null +++ b/gdb/testsuite/gdb.base/backtrace-through-cu-nodebug-main.c @@ -0,0 +1,32 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2005-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 . */ + +typedef int (*callback_t) (void); + +extern int caller (callback_t callback); + +int +callback (void) +{ + return 1; +} + +int +main (void) +{ + return caller (callback); +} diff --git a/gdb/testsuite/gdb.base/backtrace-through-cu-nodebug.exp b/gdb/testsuite/gdb.base/backtrace-through-cu-nodebug.exp new file mode 100644 index 00000000000..d6e686539c9 --- /dev/null +++ b/gdb/testsuite/gdb.base/backtrace-through-cu-nodebug.exp @@ -0,0 +1,94 @@ +# Copyright 2010-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 . + +# Test that GDB can generate accurate backtraces even if some of the stack +# trace goes through a function with no debug information. + +standard_testfile -caller.c -main.c +set objmainfile ${testfile}-main.o +set objcallerfile ${testfile}-caller.o + +# Recompile the inferior with or without CFI information, then run the +# inferior until the point where the important test starts. +# Returns FALSE on an ERROR. +proc prepare_test {has_cfi} { + global srcdir subdir srcfile srcfile2 objmainfile objcallerfile binfile + if {$has_cfi} { + set extension "cfi" + if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" \ + "${srcdir}/${subdir}/${objcallerfile}" \ + object [list {additional_flags=-fomit-frame-pointer \ + -funwind-tables -fasynchronous-unwind-tables}]] != "" } { + untested "couldn't compile with cfi" + return false + } + } else { + set extension "no-cfi" + if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" \ + "${srcdir}/${subdir}/${objcallerfile}" \ + object [list {additional_flags=-fomit-frame-pointer \ + -fno-unwind-tables \ + -fno-asynchronous-unwind-tables}]] != "" } { + untested "couldn't compile without cfi" + return false + } + } + if {[gdb_compile [list "${srcdir}/${subdir}/${objmainfile}" \ + "${srcdir}/${subdir}/${objcallerfile}"] \ + "${binfile}-${extension}" binfile {}] != ""} { + untested "couldn't link object files" + return false + } + + clean_restart "$binfile-${extension}" + + with_test_prefix "${extension}" { + + if ![runto callback] then { + fail "has_cfi=$has_cfi: Can't run to callback" + return false + } + gdb_test_no_output "maint frame-unwinder disable ARCH" + return true + } +} + +if {[gdb_compile "${srcdir}/${subdir}/${srcfile2}" \ + "${srcdir}/${subdir}/${objmainfile}" \ + object {debug}] != "" } { + untested "couldn't compile main file" + return +} + +if { [prepare_test false] } { + gdb_test "bt" \ + [multi_line \ + "\[^\r\n\]+Required frame unwinder may have been disabled, \[^\r\n\]+" \ + "#0\\s+callback \\(\\) \[^\r\n\]+"] \ + "verify unwind fail without CFI" +} + +if { [prepare_test true] } { + if { [istarget "arm*-*-*"] } { + setup_kfail backtrace/31950 *-*-* + } + set text {[^\r\n]+} + # #0 callback () at ... + # #1 0x00000000004004e9 in caller () + # #2 0x00000000004004cd in main () at ... + gdb_test "bt" \ + "#0 +callback $text\r\n#1 $text in caller $text\r\n#2 $text in main $text" \ + "Verify unwinding works based only on CFI information" +}