From: "Ijaz, Abdul B" <abdul.b.ijaz@intel.com>
This change skips trampoline functions for the '-stack-list-frames' command
when the option 'skip-trampoline-functions' is set to 'on'. Before this
change, GDB prints the frames indicated by the compiler with DIE
"DW_AT_trampoline" in the backtrace for mi command stack-list-frames, but
for better user experience, all such frames can be hidden from the user.
In this example the IFX compiler emits "DW_AT_trampoline" tag for the 'first'
and 'second' trampoline functions like following:
function second (x, y) result(z)
integer, intent(in) :: x, y
integer :: z
z = x * y ! breakpt-backtrace
end function second
function first (num1, num2) result(total)
integer, intent(in) :: num1, num2
integer :: total
total = second (num1 + 4, num2 * 3) ! first-breakpt
total = total + 30
end function first
Related Dwarf:
0x0000013f: DW_TAG_subprogram
DW_AT_low_pc (0x0000000000404350)
DW_AT_high_pc (0x000000000040435f)
DW_AT_frame_base (DW_OP_reg6 RBP)
DW_AT_linkage_name ("second_.t74p.t75p")
DW_AT_name ("second_.t74p.t75p")
DW_AT_trampoline ("second_")
0x0000015a: DW_TAG_subprogram
DW_AT_low_pc (0x00000000004044a0)
DW_AT_high_pc (0x00000000004044af)
DW_AT_frame_base (DW_OP_reg6 RBP)
DW_AT_linkage_name ("first_.t104p.t105p")
DW_AT_name ("first_.t104p.t105p")
DW_AT_trampoline ("first_")
Before this change, the '-stack-list-frames' command output looks like:
'''
(gdb) -stack-list-frames
-stack-list-frames
^done,
stack=[
frame={level="0",addr="0x0000000000405194",func="second",
file="test.f90",fullname="/home/test.f90",line="4",
arch="i386:x86-64"},
frame={level="1",addr="0x0000000000405209",
func="second_.t74p.t75p",
file="test.f90",fullname="/home/test.f90",line="12",
arch="i386:x86-64"},
frame={level="2",addr="0x00000000004051e3",func="first",
file="test.f90",fullname="/home/test.f90",line="10",
arch="i386:x86-64"},
frame={level="3",addr="0x0000000000405309",
func="first_.t95p.t96p",file="test.f90",
fullname="/home/test.f90",line="21",arch="i386:x86-64"},
frame={level="4",addr="0x0000000000405234",
func="func_trampoline",file="test.f90",
fullname="/home/test.f90",line="17",arch="i386:x86-64"}]
'''
After this change:
'''
(gdb) -stack-list-frames
-stack-list-frames
^done,
stack=[frame={level="0",addr="0x0000000000405194",func="second",
file="test.f90",fullname="/home/test.f90",line="4",
arch="i386:x86-64"},
frame={level="2",addr="0x00000000004051e3",func="first",
file="test.f90",fullname="/home/test.f90",line="10",
arch="i386:x86-64"},
frame={level="4",addr="0x0000000000405234",
func="func_trampoline",file="test.f90",fullname="/home/test.f90",
line="17",arch="i386:x86-64"}]
'''
New test gdb.mi/mi-func-trampoline.exp is added for testing the change.
2024-11-24 Ijaz, Abdul B <abdul.b.ijaz@intel.com>
---
gdb/doc/gdb.texinfo | 4 +-
gdb/mi/mi-cmd-stack.c | 7 +++
gdb/testsuite/gdb.mi/mi-func-trampoline.exp | 68 +++++++++++++++++++++
3 files changed, 78 insertions(+), 1 deletion(-)
create mode 100644 gdb/testsuite/gdb.mi/mi-func-trampoline.exp
@@ -34920,7 +34920,9 @@ an error if @var{low-frame} is larger than the actual number of
frames. On the other hand, @var{high-frame} may be larger than the
actual number of frames, in which case only existing frames will be
returned. If the option @code{--no-frame-filters} is supplied, then
-Python frame filters will not be executed.
+Python frame filters will not be executed. If the option
+@code{skip-trampoline-functions} is set, @value{GDBN} will skip the trampoline
+frames while printing a backtrace.
@subsubheading @value{GDBN} Command
@@ -178,6 +178,13 @@ mi_cmd_stack_list_frames (const char *command, const char *const *argv,
i++, fi = get_prev_frame (fi))
{
QUIT;
+ if (skip_trampoline_functions)
+ {
+ for (int j = 0; (SAFE_TRAMPOLINE_CHAIN (j, fi)
+ && in_trampoline_frame (fi)); ++j)
+ fi = get_prev_frame (fi);
+ }
+
/* Print the location and the address always, even for level 0.
If args is 0, don't print the arguments. */
print_frame_info (user_frame_print_options,
new file mode 100644
@@ -0,0 +1,68 @@
+# Copyright 2024 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/> .
+
+# Test -stack-list-frames command for functions with trampoline
+# calls. Also checks if trampoline frames are filtered while printing
+# stack.
+
+require allow_fortran_tests
+
+if {![test_compiler_info {ifx-*} f90]} {
+ untested "This test is only applicable for IFX, which emits the\
+ trampoline DIE in Dwarf."
+ return -1
+}
+
+load_lib fortran.exp
+load_lib mi-support.exp
+
+set MIFLAGS "-i=mi"
+
+if {[mi_clean_restart]} {
+ return
+}
+
+set testfile mi-func-trampoline
+set srcfile "${srcdir}/gdb.fortran/func-trampoline.f90"
+set binfile [standard_output_file $testfile]
+
+if { [gdb_compile "${srcfile}" "${binfile}" executable \
+ {debug f90} ] != "" } {
+ untested "failed to compile"
+ return -1
+}
+
+mi_delete_breakpoints
+mi_gdb_reinitialize_dir $srcdir/$subdir
+mi_gdb_load ${binfile}
+
+set inner_loc [gdb_get_line_number "second-breakpt"]
+set fill "\[^\r\n\]*"
+
+set frame1_regx "\{level=\"0\",addr=\"$hex\",func=\"second\",file=\".*func-trampoline.f90\",fullname=\"${fullname_syntax}func-trampoline.f90\",line=\"$inner_loc\",arch=\".*\"\}"
+set frame2_regx "\{level=\"2\",addr=\"$hex\",func=\"first\",.*\}"
+set frame3_regx "\{level=\"4\",addr=\"$hex\",func=\"func_trampoline\",.*\}"
+
+# Set breakpoint inside the innermost function 'second'.
+mi_create_breakpoint "-t $srcfile:$inner_loc" \
+ "insert breakpoint at line $inner_loc " \
+ -number 1 -disp del -func second ".*trampoline.f90" $inner_loc $hex
+mi_run_cmd
+mi_expect_stop \
+ "breakpoint-hit" "second" ".*" ".*trampoline.f90" "\[0-9\]+" { "" "disp=\"del\"" } \
+ "run to breakpoint at line $inner_loc"
+
+mi_gdb_test "100-stack-list-frames" \
+ "100\\^done,stack=\\\[frame=${frame1_regx},frame=${frame2_regx},frame=${frame3_regx}\\\]"