[PATCH v11 01/10] gdb, dwarf: add support for DW_AT_trampoline in DWARF reader

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

DW_AT_trampoline can be used to describe compiler generated functions
that serve some intermediary purpose on making a call to another
function.  A compiler can emit this tag in order to help a debugger hide
the trampolines from a user.

The attribute is only applicable to DW_TAG_subroutine and
DW_TAG_inlined_subroutine tags.  It contains information about the
trampoline target either as a reference to its DIE, as its address or
its name.  DW_AT_trampoline can also be a flag indicating that the DIE
is a trampoline or not without specifying the target (e.g. if it is
unknown).

This patch adds support to GDB for reading the DW_AT_trampoline
attribute.  It stores the attribute and its value in the type_specific
part of a GDB type.  This patch is implemented in preparation of the
following patches, which will add a mechanism to hide DW_AT_trampoline
subroutines from the user.
---
 gdb/dwarf2/read.c |  39 +++++++++++++++-
 gdb/gdbtypes.c    |  34 +++++++++++++-
 gdb/gdbtypes.h    | 113 ++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 179 insertions(+), 7 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index ca475f53745..71f4838a402 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -12430,6 +12430,43 @@ read_subroutine_type (struct die_info *die, struct dwarf2_cu *cu)
   if (prototyped_function_p (die, cu))
     ftype->set_is_prototyped (true);
 
+  /* If this is a trampoline function store it and its target here.  */
+  attr = dwarf2_attr (die, DW_AT_trampoline, cu);
+  if (attr != nullptr)
+    {
+      TYPE_FUNC_FLAGS (ftype) |= FUNC_TYPE_TRAMPOLINE;
+      TYPE_TRAMPOLINE_TARGET (ftype)
+	= (trampoline_target *) TYPE_ZALLOC (ftype,
+					     sizeof (trampoline_target));
+
+      /* A DW_AT_trampoline can be either an address, a flag, a reference or a
+	 string.  */
+      if (attr->form_is_string ())
+	TYPE_TRAMPOLINE_TARGET (ftype)->set_target_name
+	  (attr->as_string ());
+      else if (attr->form_is_ref ())
+	{
+	  die_info *target_die;
+	  dwarf2_cu *target_cu = cu;
+	  unrelocated_addr lowpc;
+
+	  target_die = follow_die_ref (die, attr, &target_cu);
+
+	  if (dwarf2_get_pc_bounds (target_die, &lowpc, NULL, target_cu,
+				    nullptr, nullptr) <= PC_BOUNDS_INVALID)
+	    complaint (_("DW_AT_trampoline target DIE has invalid "
+			 "low pc, for referencing DIE %s[in module %s]"),
+			 sect_offset_str (die->sect_off),
+			 objfile_name (objfile));
+	  else
+	    TYPE_TRAMPOLINE_TARGET (ftype)->set_target_addr (lowpc);
+	}
+      else if (attr->form_is_unsigned ())
+	TYPE_TRAMPOLINE_TARGET (ftype)->set_target_flag (attr->as_boolean ());
+      else
+	TYPE_TRAMPOLINE_TARGET (ftype)->set_target_addr (attr->as_address ());
+    }
+
   /* Store the calling convention in the type if it's available in
      the subroutine die.  Otherwise set the calling convention to
      the default value DW_CC_normal.  */
@@ -12451,7 +12488,7 @@ read_subroutine_type (struct die_info *die, struct dwarf2_cu *cu)
      if the DWARF producer set that information.  */
   attr = dwarf2_attr (die, DW_AT_noreturn, cu);
   if (attr && attr->as_boolean ())
-    TYPE_NO_RETURN (ftype) = 1;
+    TYPE_FUNC_FLAGS (ftype) |= FUNC_TYPE_NO_RETURN;
 
   /* We need to add the subroutine type to the die immediately so
      we don't infinitely recurse when dealing with parameters
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 9098727959e..76af0a911e5 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -4919,6 +4919,33 @@ print_fixed_point_type_info (struct type *type, int spaces)
 	      type->fixed_point_scaling_factor ().str ().c_str ());
 }
 
+/* Print the contents of the TYPE's self_trampoline_target, assuming that its
+   type-specific kind is TYPE_SPECIFIC_FUNC and is_trampoline is not 0.  */
+static void
+print_trampoline_target_info (struct type *type, int spaces)
+{
+  switch (TYPE_TRAMPOLINE_TARGET (type)->target_kind ())
+    {
+    case TRAMPOLINE_TARGET_ADDR:
+      gdb_printf ("%*starget addr: 0x%s\n", spaces + 2, "",
+		  print_core_address (type->arch_owner (),
+				      (CORE_ADDR) TYPE_TRAMPOLINE_TARGET (type)
+				      ->target_addr ()));
+      break;
+    case TRAMPOLINE_TARGET_NAME:
+      gdb_printf ("%*starget name: %s\n", spaces + 2, "",
+		  TYPE_TRAMPOLINE_TARGET (type)->target_name ());
+      break;
+    case TRAMPOLINE_TARGET_FLAG:
+      gdb_printf ("%*starget flag: %d\n", spaces + 2, "",
+		  TYPE_TRAMPOLINE_TARGET (type)->target_flag ());
+      break;
+    default:
+      gdb_assert_not_reached ("unhandled trampoline target kind");
+      break;
+    }
+}
+
 static struct obstack dont_print_type_obstack;
 
 /* Print the dynamic_prop PROP.  */
@@ -5149,6 +5176,10 @@ recursive_dump_type (struct type *type, int spaces)
       gdb_printf ("%*scalling_convention %d\n", spaces, "",
 		  TYPE_CALLING_CONVENTION (type));
       /* tail_call_list is not printed.  */
+      gdb_printf ("%*sfunc_type_flags 0x%x\n", spaces, "",
+		  (unsigned int) TYPE_FUNC_FLAGS (type));
+      if (TYPE_IS_TRAMPOLINE (type))
+	print_trampoline_target_info (type, spaces);
       break;
 
     case TYPE_SPECIFIC_SELF_TYPE:
@@ -5320,8 +5351,9 @@ copy_type_recursive (struct type *type, copied_types_hash_t &copied_types)
     case TYPE_SPECIFIC_FUNC:
       INIT_FUNC_SPECIFIC (new_type);
       TYPE_CALLING_CONVENTION (new_type) = TYPE_CALLING_CONVENTION (type);
-      TYPE_NO_RETURN (new_type) = TYPE_NO_RETURN (type);
+      TYPE_FUNC_FLAGS (new_type) = TYPE_FUNC_FLAGS (type);
       TYPE_TAIL_CALL_LIST (new_type) = NULL;
+      TYPE_TRAMPOLINE_TARGET (new_type) = TYPE_TRAMPOLINE_TARGET (type);
       break;
     case TYPE_SPECIFIC_FLOATFORMAT:
       TYPE_FLOATFORMAT (new_type) = TYPE_FLOATFORMAT (type);
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index eda09641248..c65d71fc761 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -99,6 +99,21 @@ enum harvard_address_space
   HARVARD_ASPACE_DATA = 2,
 };
 
+/* * Define flags for function types.  */
+enum func_type_flag_value : unsigned
+{
+  /* * Flag indicates, whether this function normally returns to its
+     caller.  It is set from the DW_AT_noreturn attribute if set on
+     the DW_TAG_subprogram.  */
+  FUNC_TYPE_NO_RETURN = (1 << 0),
+
+  /* * Flag is used for functions marked with DW_AT_trampoline.  These
+     are compiler generated wrappers that should be hidden from the user.  */
+  FUNC_TYPE_TRAMPOLINE = (1 << 1)
+};
+
+DEF_ENUM_FLAGS_TYPE (enum func_type_flag_value, func_type_flags);
+
 /* A type's instance_flags.  */
 
 struct type_instance_flags
@@ -1891,11 +1906,9 @@ struct func_type
 
     dwarf_calling_convention calling_convention : 8;
 
-    /* Whether this function normally returns to its caller.  It is
-       set from the DW_AT_noreturn attribute if set on the
-       DW_TAG_subprogram.  */
+    /* * For storing function types defined in eunm func_type_flag_value.  */
 
-    unsigned int is_noreturn : 1;
+    func_type_flags flags;
 
     /* Only those DW_TAG_call_site's in this function that have
        DW_AT_call_tail_call set are linked in this list.  Function
@@ -1910,6 +1923,87 @@ struct func_type
        contains the method.  */
 
     struct type *self_type;
+
+    struct trampoline_target *self_trampoline_target;
+  };
+
+/* The kind of location held by this call site target.  */
+enum trampoline_target_kind
+  {
+    /* An address.  */
+    TRAMPOLINE_TARGET_ADDR,
+    /* A (mangled) name.  */
+    TRAMPOLINE_TARGET_NAME,
+    /* A flag (target is unknown).  */
+    TRAMPOLINE_TARGET_FLAG,
+  };
+
+/* Target information for trampoline functions.  */
+
+struct trampoline_target
+  {
+    /* Returns what kind of target the trampoline points to.  */
+    trampoline_target_kind target_kind () const
+    {
+      return m_target_kind;
+    }
+
+    /* Set the address for trampoline target.  */
+    void set_target_addr (unrelocated_addr unreloc_addr)
+    {
+      m_target_kind = TRAMPOLINE_TARGET_ADDR;
+      m_trampoline_target.unreloc_addr = unreloc_addr;
+    }
+
+    /* Return the address of the trampoline target.  */
+    unrelocated_addr target_addr () const
+    {
+      gdb_assert (m_target_kind == TRAMPOLINE_TARGET_ADDR);
+      return m_trampoline_target.unreloc_addr;
+    }
+
+    /* Set the name of the trampoline target.  */
+    void set_target_name (const char *name)
+    {
+      m_target_kind = TRAMPOLINE_TARGET_NAME;
+      m_trampoline_target.name = name;
+    }
+
+    /* Return the name of the trampoline target.  */
+    const char *target_name () const
+    {
+      gdb_assert (m_target_kind == TRAMPOLINE_TARGET_NAME);
+      return m_trampoline_target.name;
+    }
+
+    /* Set the flag for trampoline target subroutine.  */
+    void set_target_flag (bool flag)
+    {
+      m_target_kind = TRAMPOLINE_TARGET_FLAG;
+      m_trampoline_target.flag = flag;
+    }
+
+    /* Return the flag for trampoline target.  */
+    bool target_flag () const
+    {
+      gdb_assert (m_target_kind == TRAMPOLINE_TARGET_FLAG);
+      return m_trampoline_target.flag;
+    }
+
+  private:
+
+    union
+    {
+      /* Address.  */
+      unrelocated_addr unreloc_addr;
+      /* Mangled name.  */
+      const char *name;
+      /* Flag.  */
+      bool flag;
+    } m_trampoline_target;
+
+    /* * Discriminant for union m_trampoline_target.  */
+    ENUM_BITFIELD (trampoline_target_kind) m_target_kind : 2;
   };
 
 /* The type-specific info for TYPE_CODE_FIXED_POINT types.  */
@@ -2022,7 +2116,16 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
 #define TYPE_GNAT_SPECIFIC(thistype) (thistype)->main_type->type_specific.gnat_stuff
 #define TYPE_DESCRIPTIVE_TYPE(thistype) TYPE_GNAT_SPECIFIC(thistype)->descriptive_type
 #define TYPE_CALLING_CONVENTION(thistype) (thistype)->main_type->type_specific.func_stuff->calling_convention
-#define TYPE_NO_RETURN(thistype) (thistype)->main_type->type_specific.func_stuff->is_noreturn
+#define TYPE_FUNC_FLAGS(thistype) \
+  (thistype)->main_type->type_specific.func_stuff->flags
+#define TYPE_NO_RETURN(thistype) \
+  ((thistype)->main_type->type_specific.func_stuff->flags \
+   & FUNC_TYPE_NO_RETURN)
+#define TYPE_IS_TRAMPOLINE(thistype) \
+  ((thistype)->main_type->type_specific.func_stuff->flags \
+   & FUNC_TYPE_TRAMPOLINE)
+#define TYPE_TRAMPOLINE_TARGET(thistype) \
+  (thistype)->main_type->type_specific.func_stuff->self_trampoline_target
 #define TYPE_TAIL_CALL_LIST(thistype) (thistype)->main_type->type_specific.func_stuff->tail_call_list
 #define TYPE_BASECLASS(thistype,index) ((thistype)->field (index).type ())
 #define TYPE_N_BASECLASSES(thistype) TYPE_CPLUS_SPECIFIC(thistype)->n_baseclasses
-- 
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.