[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.