[PATCH v11 02/10] gdb/symtab: add lookup for trampoline functions

Abdul Basit Ijaz <[email protected]> Mon, 3 Aug 2026 21:34:41 +0200
Newsgroups gmane.comp.gdb.patches
Message-ID <[email protected]>
From: Nils-Christian Kempke <[email protected]>

In order to query information about the DW_AT_trampoline tag for
subroutines and inlined subroutines, three functions were added to symtab.

First, in_trampoline_code() a routine for querying whether the given
pc belongs to a block that is associated with a function (maybe inlined)
marked DW_AT_trampoline.  Used inside trampoline code (inline or concrete)
that was stepped into and continues stepping through it.  This function
uses find_symbol_for_pc_sect_maybe_inline() which calls containing_function
to detect inline trampolines as well as concrete ones.

Second, in_trampoline_function() a routine to check concrete trampoline
(non-inline) functions and attempt target resolution upfront.  Used in
forward stepping and for frame navigation commands.  This function uses
find_symbol_for_pc_sect() which calls block->linkage_function to skip
inlined blocks and return only the concrete function at the PC.

Third, find_function_trampoline_target() a routine for querying a trampoline
function's target.  Subroutines and inlined subroutines marked with
DW_AT_trampoline usually contain information about the target subroutine
they are 'wrapping'/ passing control to.

These lookup functions will be used in the follow up commits for the
trampoline handling in different GDB commands.

Co-Authored-By: Abdul Basit Ijaz <[email protected]>
---
 gdb/symtab.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/symtab.h |  24 ++++++++++++
 2 files changed, 132 insertions(+)

diff --git a/gdb/symtab.c b/gdb/symtab.c
index 5d5076f2e77..e5464551807 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -74,6 +74,7 @@
 #include "gdbsupport/common-utils.h"
 #include <optional>
 #include "gdbsupport/unordered_set.h"
+#include "gdbsupport/symbol.h"
 
 /* Forward declarations for local functions.  */
 
@@ -4103,6 +4104,113 @@ find_function_alias_target (bound_minimal_symbol msymbol)
   return NULL;
 }
 
+/* See symtab.h.  */
+
+bool
+in_trampoline_code (CORE_ADDR pc)
+{
+  /* Find the innermost function containing pc, which might be an inlined
+     function.  This is used by stepping logic to detect when execution is
+     within ANY trampoline code (inline or concrete) and continue stepping
+     through it.
+
+     Unlike in_trampoline_function(), this uses containing_function() by
+     calling find_symbol_for_pc_sect_maybe_inline to detect inline trampolines as
+     well as concrete ones.  */
+  symbol *sym = find_symbol_for_pc_sect_maybe_inline (pc,
+						  find_pc_mapped_section (pc));
+  return sym != nullptr && TYPE_IS_TRAMPOLINE (sym->type ());
+}
+
+/* See symtab.h.  */
+
+bool
+in_trampoline_function (CORE_ADDR pc)
+{
+  /* Find the concrete non-inlined function at pc, skipping inlined blocks.
+     The find_symbol_for_pc_sect calls block->linkage_function which skips
+     inlined blocks to return the concrete function at the PC.  This ensures
+     we check the concrete function's trampoline flag, not the flag from an
+     abstract inline origin that might be marked as a trampoline.
+
+     This is used by forward stepping to determine if about to step into a
+     concrete trampoline function and by frame navigation commands to skip
+     trampoline frames.
+
+     For O2 optimization, the compiler may create trampoline wrappers with
+     both DW_AT_trampoline + DW_AT_inline.  At a given PC, inlined code from
+     such abstract trampolines may exist, but the concrete function at that
+     PC is the user's real function (not a trampoline).  Using linkage_function
+     by calling find_symbol_for_pc_sect avoids incorrectly checking the inline
+     trampoline's abstract origin.  */
+  symbol *sym = find_symbol_for_pc_sect (pc, find_pc_mapped_section (pc));
+  return sym != nullptr && TYPE_IS_TRAMPOLINE (sym->type ());
+}
+
+/* See symtab.h.  */
+
+CORE_ADDR
+find_function_trampoline_target (CORE_ADDR pc)
+{
+  /* Find the innermost function containing pc.  This might be an inlined
+     function.  */
+  symbol *sym
+    = find_symbol_for_pc_sect_maybe_inline (pc, find_pc_mapped_section (pc));
+  CORE_ADDR target_address = 0;
+
+  if (sym != nullptr && TYPE_IS_TRAMPOLINE (sym->type ()))
+    {
+      trampoline_target *trampoline = TYPE_TRAMPOLINE_TARGET (sym->type ());
+
+      /* DW_AT_trampoline can be given as an address, name, or flag here (die
+	 references have been resolved as names at this point.  In the case
+	 where DW_AT_trampoline contains a flag we do not know the target
+	 address and return 0.  */
+      if (trampoline->target_kind () == TRAMPOLINE_TARGET_NAME)
+	{
+	  /* Handle both the mangled and demangled PHYSNAME.  */
+	  const char *physname = trampoline->target_name ();
+
+	  /* First, check whether there exists a symbol matching the
+	     physname.  If we cannot find one also check for minimal
+	     symbols.  */
+	  const block *blk = block_for_pc (pc);
+	  block_symbol bs
+	    = lookup_symbol (physname, blk, SEARCH_VAR_DOMAIN, 0);
+	  if (bs.symbol != nullptr)
+	    {
+	      const block *block = bs.symbol->value_block ();
+	      gdb_assert (block != nullptr);
+	      target_address = block->start ();
+	    }
+	  else
+	    {
+	      /* We normally expect the target symbol to be located in one
+		 objfile only.  However, a JIT compiler may have generated
+		 a duplicated symbol that most likely resides in the same
+		 objfile with the trampoline symbol.  Give priority to that
+		 objfile in the search.  If not found, try all objfiles.
+		 This is a heuristic.  */
+	      if ((find_minimal_symbol_address (physname, &target_address,
+						sym->objfile ()) != 0)
+		  && (find_minimal_symbol_address (physname, &target_address,
+						   nullptr) != 0))
+		target_address = 0;
+	    }
+	}
+      else if (trampoline->target_kind () == TRAMPOLINE_TARGET_ADDR)
+	{
+	  /* If the function symbol containing this trampoline target has
+	     been relocated we assume the target_address also needs relocation.
+	     If it has not been relocated the offset should be zero.  */
+	  target_address = \
+	    ( (CORE_ADDR) trampoline->target_addr ()
+	       + sym->objfile ()->section_offsets[sym->section_index ()]);
+	}
+    }
+
+  return target_address;
+}
 
 /* If P is of the form "operator[ \t]+..." where `...' is
    some legitimate operator text, return a pointer to the
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 6443216fd7f..10f64548f58 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2362,6 +2362,30 @@ extern const struct gnu_ifunc_fns *gnu_ifunc_fns_p;
 
 extern CORE_ADDR find_solib_trampoline_target (const frame_info_ptr &, CORE_ADDR);
 
+/* Return whether the current pc is within a block that belongs to a
+   function that is marked as a trampoline by the compiler.  This checks
+   only the concrete (non-inline) function at the PC.  Used by forward stepping
+   to check if about to step into a concrete trampoline function and attempt
+   to resolve its target.  Also used for frame navigation commands.  */
+
+extern bool in_trampoline_function (CORE_ADDR pc);
+
+/* Return whether the current pc is within any trampoline code
+   (inline or concrete).  Used to detect when execution stepped into ANY
+   trampoline code (inline or concrete) and continue stepping through it.
+   Also used for reverse stepping logic.  */
+
+extern bool in_trampoline_code (CORE_ADDR pc);
+
+/* 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
+   is given as a flag, the target is unknown and the function will still return
+   0.  One has to additionally query in_trampoline_function to cover this
+   case.  */
+
+extern CORE_ADDR find_function_trampoline_target (CORE_ADDR pc);
+
 struct symtab_and_line
 {
   /* The program space of this sal.  */
-- 
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.