From: Abdul Basit Ijaz <abdul.b.ijaz@intel.com>
To: gdb-patches@sourceware.org
Cc: abdul.b.ijaz@intel.com, JiniSusan.George@amd.com, tom@tromey.com,
eliz@gnu.org
Subject: [PATCH v11 04/10] gdb: Skip trampoline frames for the backtrace command.
Date: Mon, 3 Aug 2026 21:34:43 +0200 [thread overview]
Message-ID: <20260803193449.33375-5-abdul.b.ijaz@intel.com> (raw)
In-Reply-To: <20260803193449.33375-1-abdul.b.ijaz@intel.com>
This change filters trampoline functions when the option
'skip-trampoline-functions' is set to 'on' for the backtrace command.
Before the change, GDB prints the frames indicated by the compiler with
DIE "DW_AT_trampoline" in the backtrace, but for better user experience,
all such frames can be hidden from the user.
For O2 optimized code where inlined trampoline wrappers are inlined into
regular functions. Check the frame's function directly for inline frames
instead of looking up by PC, which would incorrectly return the caller's
function.
The test 'gdb.fortran/mixed-lang-stack' test used to fail for the IFX
compiler because of extra trampoline frames in the backtrace. After the
commit, those trampoline frames are filtered and test is updated accordingly.
Extra trampoline frames:
bt -frame-arguments all
'''
\#8 0x0000000000405535 in mixed_func_1b_.t86p.t87p.t88p.t89p.t90p.t91p.t3v ()
\#10 0x0000000000405439 in mixed_func_1a_.void () at mixed-lang-stack.f90:33
'''
(gdb) FAIL: gdb.fortran/mixed-lang-stack.exp: lang=auto: bt -frame-arguments all
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 backtrace command output looks like:
'''
(gdb) backtrace 3
\#0 second (x=20, y=9) at test.f90:4
\#1 0x0000000000405209 in second_.t74p.t75p () at test.f90:12
\#2 0x00000000004051e3 in first (num1=16, num2=3) at test.f90:10
(gdb) backtrace -3
\#2 0x00000000004051e3 in first (num1=16, num2=3) at test.f90:10
\#3 0x0000000000405309 in first_.t95p.t96p () at test.f90:21
\#4 0x0000000000405234 in func_trampoline () at test.f90:17
'''
After the change:
'''
(gdb) backtrace 3
\#0 second (x=20, y=9) at test.f90:4
\#2 0x00000000004051e3 in first (num1=16, num2=3) at test.f90:10
\#4 0x0000000000405234 in func_trampoline () at test.f90:17
(gdb) backtrace -3
\#2 0x00000000004051e3 in first (num1=16, num2=3) at test.f90:10
\#4 0x0000000000405234 in func_trampoline () at test.f90:17
'''
The test gdb.fortran/func-trampoline.exp is added for testing the change
using O0 and O2 optimization level.
---
gdb/NEWS | 5 +-
gdb/doc/gdb.texinfo | 6 ++
gdb/infrun.c | 6 +-
gdb/infrun.h | 6 ++
gdb/stack.c | 8 ++
gdb/symtab.c | 31 +++++++
gdb/symtab.h | 5 ++
gdb/testsuite/gdb.fortran/func-trampoline.exp | 87 +++++++++++++++++++
gdb/testsuite/gdb.fortran/func-trampoline.f90 | 40 +++++++++
.../gdb.fortran/mixed-lang-stack.exp | 8 +-
10 files changed, 195 insertions(+), 7 deletions(-)
create mode 100644 gdb/testsuite/gdb.fortran/func-trampoline.exp
create mode 100644 gdb/testsuite/gdb.fortran/func-trampoline.f90
diff --git a/gdb/NEWS b/gdb/NEWS
index 5c618c0d38d..8100f7cd7b4 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -1773,8 +1773,9 @@ show skip-trampoline-functions
This setting is 'on' by default. When 'on' it controls whether GDB will
recognize function calls that have been marked as trampolines in the debug
info. It improves stepping behavior in that it steps over the trampoline
- code and hides it from the user. Currently, only DWARF trampolines are
- supported.
+ code and hides it from the user. It improves the printing of the stack by
+ hiding trampoline functions from the backtrace. Currently, only DWARF
+ trampolines are supported.
If this is turned off, GDB will handle @dfn{trampoline functions} the same
as any other function.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index f8dd7d8ec4e..af57610ddc3 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6769,6 +6769,12 @@ execution until leaving the trampoline region. The @code{stepi} command
is not affected by the setting which is enabled by default. Currently, only
DWARF trampolines marked via DW_AT_trampoline are supported by this.
+When issuing a @code{backtrace}, if @code{skip-trampoline-functions} is set,
+@value{GDBN} will skip trampoline frames while printing the stack.
+
+Currently, only DWARF trampolines marked via DW_AT_trampoline are supported by
+this.
+
@item set skip-trampoline-functions off
Causes @value{GDBN} to completely ignore any trampoline information a compiler
might have emitted in its debug info. Trampolines will be treated like any
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 0b032ce94c0..9d1b85e9d1f 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -194,7 +194,7 @@ static bool detach_fork = true;
DW_AT_trampoline by the compiler. If false, GDB will ignore the
attribute. */
-static bool skip_trampoline_functions = true;
+bool skip_trampoline_functions = true;
bool debug_infrun = false;
static void
@@ -11031,8 +11031,8 @@ Options are 'forward' or 'reverse'."),
&skip_trampoline_functions, _("\
Set whether gdb attempts to hide trampolines marked in the debug info."), _("\
Show whether gdb attempts to hide trampolines marked in the debug info."), _("\
-If on, while stepping gdb will skip through functions and inlined functions\n\
-marked as trampolines by the compiler. If off, gdb will treat trampolines as\n\
+If on, gdb will skip through functions and inlined functions marked as\n\
+trampolines by the compiler. If off, gdb will treat trampolines as\n\
normal functions."),
nullptr, show_skip_trampoline_functions, &setlist,
&showlist);
diff --git a/gdb/infrun.h b/gdb/infrun.h
index 135d1fc350b..a5c6f317193 100644
--- a/gdb/infrun.h
+++ b/gdb/infrun.h
@@ -106,6 +106,12 @@ extern bool non_stop;
starting an inferior. */
extern bool disable_randomization;
+/* If set (default) GDB will step through functions/inlined subroutines marked
+ DW_AT_trampoline by the compiler. If false, GDB will ignore the
+ attribute. */
+
+extern bool skip_trampoline_functions;
+
/* Returns a unique identifier for the current stop. This can be used
to tell whether a command has proceeded the inferior past the
current location. */
diff --git a/gdb/stack.c b/gdb/stack.c
index f41f818cebb..fa217ae9f6f 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1978,6 +1978,14 @@ backtrace_command_1 (const frame_print_options &fp_opts,
{
QUIT;
+ if (skip_trampoline_functions && in_trampoline_frame (fi))
+ {
+ /* Trampoline frames are not printed so they are not counted in
+ the backtrace limit. */
+ count++;
+ continue;
+ }
+
/* Don't use print_stack_frame; if an error() occurs it probably
means further attempts to backtrace would fail (on the other
hand, perhaps the code does or could be fixed to make sure
diff --git a/gdb/symtab.c b/gdb/symtab.c
index e5464551807..8931f50775c 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4149,6 +4149,37 @@ in_trampoline_function (CORE_ADDR pc)
/* See symtab.h. */
+bool
+in_trampoline_frame (frame_info_ptr fi)
+{
+ /* For inline frames, they share the PC of their caller. We need to check
+ the frame's function directly, not look up the function at the PC.
+ Looking up by PC would return the caller's function not the inline
+ function itself.
+
+ For O2 optimized code, the compiler may inline trampoline wrappers into
+ regular functions. In such cases, looking up by PC would point to the
+ concrete regular function and incorrectly return false (not a trampoline).
+ By checking the inline frame's function directly via get_frame_function(),
+ we correctly identify when the inline frame itself is a trampoline. */
+ if (get_frame_type (fi) == INLINE_FRAME)
+ {
+ symbol *func = get_frame_function (fi);
+ return func != nullptr && TYPE_IS_TRAMPOLINE (func->type ());
+ }
+
+ /* For non-inline frames, use in_trampoline_function() which looks up only
+ the concrete function at the PC, ensuring we check the actual frame's
+ function and not any inlined code within it. */
+ std::optional<CORE_ADDR> pc;
+ if ((pc = get_frame_pc_if_available (fi)))
+ return in_trampoline_function (pc.value ());
+
+ return false;
+}
+
+/* See symtab.h. */
+
CORE_ADDR
find_function_trampoline_target (CORE_ADDR pc)
{
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 10f64548f58..8a8d9f3f85f 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2377,6 +2377,11 @@ extern bool in_trampoline_function (CORE_ADDR pc);
extern bool in_trampoline_code (CORE_ADDR pc);
+/* Return whether or not the pc of the current frame is within a block that
+ belongs to a function that is marked as a trampoline by the compiler. */
+
+extern bool in_trampoline_frame (frame_info_ptr);
+
/* Find the target of a trampoline function marked via the DW_AT_trampoline
attribute and return its address. Returns 0 if the pc is not contained
in a trampoline function (inlined or not). If DW_AT_trampoline
diff --git a/gdb/testsuite/gdb.fortran/func-trampoline.exp b/gdb/testsuite/gdb.fortran/func-trampoline.exp
new file mode 100644
index 00000000000..5216de25a45
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/func-trampoline.exp
@@ -0,0 +1,87 @@
+# Copyright 2026 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 "backtrace" and "backtrace -n" commands for functions with trampoline
+# calls.
+
+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
+}
+
+standard_testfile ".f90"
+load_lib fortran.exp
+
+# Initialize the test by running the program to the innermost
+# function name "second".
+
+proc init_test {opt_level} {
+ clean_restart ${::testfile}_${opt_level}
+ if {![fortran_runto_main]} {
+ return
+ }
+
+ # Set breakpoint inside the innermost function 'second'.
+ gdb_breakpoint "$::srcfile:$::inner_loc"
+ gdb_continue_to_breakpoint "innermost-body" ".*$::srcfile:$::inner_loc.*"
+}
+
+set inner_loc [gdb_get_line_number "second-breakpt"]
+set middle_loc [gdb_get_line_number "first-breakpt"]
+set outer_loc [gdb_get_line_number "main-outer-loc"]
+set fill "\[^\r\n\]*"
+
+# Test both O0 and O2 to verify trampoline handling works correctly
+# with and without optimization.
+foreach_with_prefix opt_level {O0 O2} {
+ if {[build_executable "failed to prepare" ${testfile}_${opt_level} ${srcfile} \
+ [list debug f90 "optimize=-${opt_level}"]]} {
+ continue
+ }
+
+ set binfile "${testfile}_${opt_level}"
+
+ if {[string match -nocase "O2" $opt_level]} {
+ # At O2, parameters may be optimized out
+ set inner_desc "second \\(.*\\) at ${fill}$srcfile:$inner_loc"
+ set middle_desc "first \\(.*\\) at ${fill}$srcfile:$middle_loc"
+ } else {
+ set inner_desc "second \\(x=20, y=9\\) at ${fill}$srcfile:$inner_loc"
+ set middle_desc "first \\(num1=16, num2=3\\) at ${fill}$srcfile:$middle_loc"
+ }
+ set outer_desc ".* at .*$srcfile:$outer_loc"
+
+ with_test_prefix "backtrace" {
+ init_test $opt_level
+
+ # Limit the backtrace to 3 frames and ensure both frames for first
+ # and second function are shown only and trampoline frames are filtered.
+ gdb_test "backtrace 3" [multi_line \
+ "#$decimal.* $inner_desc" \
+ "#$decimal.* $middle_desc" \
+ "#$decimal.* $outer_desc.*"]
+ }
+
+ with_test_prefix "backtrace outerframes" {
+ init_test $opt_level
+
+ gdb_test "backtrace -3" [multi_line \
+ "#$decimal.* $middle_desc" \
+ "#$decimal.* $outer_desc.*"]
+ }
+}
diff --git a/gdb/testsuite/gdb.fortran/func-trampoline.f90 b/gdb/testsuite/gdb.fortran/func-trampoline.f90
new file mode 100644
index 00000000000..bb9ce7f3491
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/func-trampoline.f90
@@ -0,0 +1,40 @@
+! Copyright 2026 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/> .
+
+! Source code for func-trampoline.exp.
+
+!DIR$ ATTRIBUTES NOINLINE :: second
+integer(kind=4) function second(x, y)
+ integer(kind=4), intent(in) :: x
+ integer(kind=4), intent(in) :: y
+
+ second = x * y ! second-breakpt
+end function
+
+integer(kind=4) function first(num1, num2)
+ integer(kind=4), intent(in) :: num1
+ integer(kind=4), intent(in) :: num2
+
+ first = second (num1 + 4, num2 * 3) ! first-breakpt
+end function
+
+program func_trampoline
+ integer(kind=4) :: total
+
+ total = first(16, 3) ! main-outer-loc
+
+ write(*,*) "Result is ", total, "\n"
+ ! Expected: 180
+end program func_trampoline
diff --git a/gdb/testsuite/gdb.fortran/mixed-lang-stack.exp b/gdb/testsuite/gdb.fortran/mixed-lang-stack.exp
index 43f77d3eb66..b470554988e 100644
--- a/gdb/testsuite/gdb.fortran/mixed-lang-stack.exp
+++ b/gdb/testsuite/gdb.fortran/mixed-lang-stack.exp
@@ -63,6 +63,10 @@ proc run_tests { lang } {
set e_arg "\['\"\]abcdef\['\"\]"
set 1b_args "\[^\r\n\]+$e_arg\[^\r\n\]+"
set 1g_args "obj=\[^\r\n\]+"
+ # Generic decimal number is checked in regex for Frame #8 and #9 to
+ # handle filtered trampoline frames. Since Frame#8 and Frame#10 are
+ # set to trampoline in DWARF by Intel® Fortran Compiler (ifx), they
+ # are not shown by the backtrace command.
set bt_stack \
[multi_line \
"#0\\s+breakpt \\(\\) at \[^\r\n\]+" \
@@ -73,8 +77,8 @@ proc run_tests { lang } {
"#5\\s+$hex in mixed_func_1d \\(\[^\r\n\]+\\) at \[^\r\n\]+" \
"#6\\s+$hex in mixed_func_1c \\(\[^\r\n\]+\\) at \[^\r\n\]+" \
"#7\\s+$hex in mixed_func_1b \\($1b_args\\) at \[^\r\n\]+" \
- "#8\\s+$hex in mixed_func_1a \\(\\) at \[^\r\n\]+" \
- "#9\\s+$hex in mixed_stack_main \\(\\) at \[^\r\n\]+" ]
+ "#$::decimal\\s+$hex in mixed_func_1a \\(\\) at \[^\r\n\]+" \
+ "#$::decimal\\s+$hex in mixed_stack_main \\(\\) at \[^\r\n\]+" ]
set main_args "argc=1, argv=${hex}( \[^\r\n\]+)?"
set bt_stack_kfail \
[multi_line \
--
2.34.1
________________________________________
Intel Deutschland GmbH
Registered Address: Dornacher Strasse 1, 85622 Feldkirchen, Germany
Tel: +49 (89) 99143-0
www.intel.de
Managing Directors: Candice Moore, Jeffrey Schneiderman, Ramachandran Sitaraman
Chairperson of the Supervisory Board: Sonja Pierer
Registered Seat: Munich Commercial Register B: Amtsgericht Munich HRB 186928
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
next prev parent reply other threads:[~2026-08-03 19:36 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-03 19:34 [PATCH v11 00/10] GDB support for DW_AT_trampoline Abdul Basit Ijaz
2026-08-03 19:34 ` [PATCH v11 01/10] gdb, dwarf: add support for DW_AT_trampoline in DWARF reader Abdul Basit Ijaz
2026-08-03 19:34 ` [PATCH v11 02/10] gdb/symtab: add lookup for trampoline functions Abdul Basit Ijaz
2026-08-03 19:34 ` [PATCH v11 03/10] gdb: handle stepping through functions with DW_AT_trampoline Abdul Basit Ijaz
2026-08-03 19:34 ` Abdul Basit Ijaz [this message]
2026-08-03 19:34 ` [PATCH v11 05/10] gdb: Skip trampoline functions for the finish and reverse-finish commands Abdul Basit Ijaz
2026-08-03 19:34 ` [PATCH v11 06/10] gdb: Skip trampoline functions for the up command Abdul Basit Ijaz
2026-08-03 19:34 ` [PATCH v11 07/10] gdb: Skip trampoline functions for the return command Abdul Basit Ijaz
2026-08-03 19:34 ` [PATCH v11 08/10] gdb, mi: Skip trampoline functions for the -stack-list-frames command Abdul Basit Ijaz
2026-08-03 19:34 ` [PATCH v11 09/10] gdb, mi: Skip trampoline functions for the -stack-list-arguments command Abdul Basit Ijaz
2026-08-03 19:34 ` [PATCH v11 10/10] gdb: Filter trampoline frames in backtrace when using Python frame-filters Abdul Basit Ijaz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260803193449.33375-5-abdul.b.ijaz@intel.com \
--to=abdul.b.ijaz@intel.com \
--cc=JiniSusan.George@amd.com \
--cc=eliz@gnu.org \
--cc=gdb-patches@sourceware.org \
--cc=tom@tromey.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox