public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Bruno Larsen <blarsen@redhat.com>
To: Abdul Basit Ijaz <abdul.b.ijaz@intel.com>, gdb-patches@sourceware.org
Cc: JiniSusan.George@amd.com, tom@tromey.com, eliz@gnu.org,
	Nils-Christian Kempke <nils-christian.kempke@intel.com>
Subject: Re: [PATCH v3 1/4] gdb, dwarf: add support for DW_AT_trampoline in DWARF reader
Date: Thu, 27 Jul 2023 11:09:48 +0200	[thread overview]
Message-ID: <27931c60-cdee-e430-13bf-37cbbcc926aa@redhat.com> (raw)
In-Reply-To: <20230710225643.32280-2-abdul.b.ijaz@intel.com>

On 11/07/2023 00:56, Abdul Basit Ijaz via Gdb-patches wrote:
> From: Nils-Christian Kempke <nils-christian.kempke@intel.com>
>
> 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.

Sorry for jumping in late for the review. If I say something that's been 
previously agreed upon, feel free to ignore me :)

Thanks for working on this! Some comments and nits inlined.

> 2023-07-10 Nils-Christian Kempke <nils-christian.kempke@intel.com>
> ---
>   gdb/dwarf2/read.c |  45 +++++++++++++++++++-
>   gdb/gdbtypes.c    |  35 +++++++++++++++-
>   gdb/gdbtypes.h    | 103 +++++++++++++++++++++++++++++++++++++++++++---
>   3 files changed, 176 insertions(+), 7 deletions(-)
>
> diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
> index 3508f2c29ee..1cfa8178d94 100644
> --- a/gdb/dwarf2/read.c
> +++ b/gdb/dwarf2/read.c
> @@ -14657,6 +14657,49 @@ 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_physname
> +	  (attr->as_string ());
> +      else if (attr->form_is_ref ())
> +	{
> +	  die_info *target_die;
> +	  dwarf2_cu *target_cu = cu;
> +
> +	  target_die = follow_die_ref (die, attr, &target_cu);
> +	  const char *target_name = dwarf2_name (target_die, target_cu);
As was mentioned in v1 of this patch, this bit gets the "regular" name 
of the function. This could be a problem if there are 2 functions with 
the same in different contexts (say in and out of a namespace).  I would 
suggest that you first attempt to take the linkage_name and only if that 
doesn't exist do you take the name of the function. This way, if GDB 
misidentifies a function it would probably be a compiler error, not 
adding the linkage name.
> +	  if (target_name == nullptr)
> +	    {
> +	      complaint (_("DW_AT_trampoline target DIE has no name for"
> +			 "referencing DIE %s [in module %s]"),
> +			 sect_offset_str (die->sect_off),
> +			 objfile_name (objfile));
> +	    }
> +	  TYPE_TRAMPOLINE_TARGET (ftype)->set_target_physname (target_name);
> +	}
> +      else if (attr->form_is_unsigned ())
> +	TYPE_TRAMPOLINE_TARGET (ftype)->set_target_flag (attr->as_boolean ());
> +      else
> +	{
> +	  unrelocated_addr target_addr_reloc = attr->as_address ();
> +	  CORE_ADDR target_addr
> +	    = cu->per_objfile->relocate (target_addr_reloc);
> +	  target_addr = gdbarch_adjust_dwarf2_addr (objfile->arch (),
> +						    target_addr);
> +	  TYPE_TRAMPOLINE_TARGET (ftype)->set_target_physaddr (target_addr);
> +	}
> +    }
> +
>     /* 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.  */
> @@ -14674,7 +14717,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 c5272979cb9..7355317f7db 100644
> --- a/gdb/gdbtypes.c
> +++ b/gdb/gdbtypes.c
> @@ -5091,6 +5091,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_PHYSADDR:
> +      gdb_printf ("%*starget physaddr: 0x%s\n", spaces + 2, "",
> +		  print_core_address (type->arch_owner (),
> +				      TYPE_TRAMPOLINE_TARGET (type)
> +				      ->target_physaddr ()));
> +      break;
> +    case TRAMPOLINE_TARGET_PHYSNAME:
> +      gdb_printf ("%*starget physname: %s\n", spaces + 2, "",
> +		  TYPE_TRAMPOLINE_TARGET (type)->target_physname ());
> +      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.  */
> @@ -5417,6 +5444,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 %u\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:
> @@ -5633,8 +5664,10 @@ copy_type_recursive (struct type *type, htab_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_NO_RETURN (type);
>         TYPE_TAIL_CALL_LIST (new_type) = NULL;
> +      TYPE_FUNC_FLAGS (new_type) |= TYPE_IS_TRAMPOLINE (type);

Why not just have

    TYPE_FUNC_FLAGS (new_type) = TYPE_FUNC_FLAGS (type);

?

> +      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 aedaf53cd5d..a1789223cd5 100644
> --- a/gdb/gdbtypes.h
> +++ b/gdb/gdbtypes.h
> @@ -106,6 +106,21 @@ enum type_instance_flag_value : unsigned
>   
>   DEF_ENUM_FLAGS_TYPE (enum type_instance_flag_value, type_instance_flags);
>   
> +/* * 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);
> +
>   /* * Not textual.  By default, GDB treats all single byte integers as
>      characters (or elements of strings) unless this flag is set.  */
>   
> @@ -1730,11 +1745,9 @@ struct func_type
>   
>       ENUM_BITFIELD (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
> @@ -1749,6 +1762,78 @@ struct func_type
>          contains the method.  */
>   
>       struct type *self_type;
> +
> +    struct trampoline_target *self_trampoline_target;

This member should have a comment describing it.

Also, why did you call it self_trampoline_target instead of 
trampoline_target? The only other member prefixed with self_ in this 
struct is self_type, and that has it because when a method wants to know 
the type pointed at by the "self" or "this" variable, it will check that 
pointer, not due to self referencing stuff, if I understood it correctly.

> +  };
> +
> +/* The kind of location held by this call site target.  */
> +enum trampoline_target_kind
> +  {
> +    /* An address.  */
> +    TRAMPOLINE_TARGET_PHYSADDR,
> +    /* A (mangled) name.  */
> +    TRAMPOLINE_TARGET_PHYSNAME,

After some time looking into how GDB calculates names and what not, I 
don't think calling this "physname" is a good idea, I think it would be 
better to call it TRAMPOLINE_TARGET_MANGLED_NAME.

My reasoning for that is that physname is not some well defined thing, 
it is a name that a GDB developer came up with to call what happens when 
GDB needs to calculate mangled names ourselves because the compiler 
didn't add a linkage name, as far as I understood it. Since the struct 
trampoline_target doesn't care about how a mangled name was calculated, 
and mangled name is a well defined thing while physname is not, I think 
its better to use the latter.

> +    /* An flag (target is unknown).  */
s/An/A
> +    TRAMPOLINE_TARGET_FLAG,
> +  };
> +
> +struct trampoline_target
The struct and all methods in it should also have comments.
> +  {
> +    trampoline_target_kind target_kind () const
> +    {
> +      return m_target_kind;
> +    }
> +
> +    void set_target_physaddr (CORE_ADDR physaddr)
> +    {
> +      m_target_kind = TRAMPOLINE_TARGET_PHYSADDR;
> +      m_trampoline_target.physaddr = physaddr;
> +    }
> +
> +    CORE_ADDR target_physaddr () const
> +    {
> +      gdb_assert (m_target_kind == TRAMPOLINE_TARGET_PHYSADDR);
> +      return m_trampoline_target.physaddr;
> +    }
> +
> +    void set_target_physname (const char *physname)
> +    {
> +      m_target_kind = TRAMPOLINE_TARGET_PHYSNAME;
> +      m_trampoline_target.physname = physname;
> +    }
> +
> +    const char *target_physname () const
> +    {
> +      gdb_assert (m_target_kind == TRAMPOLINE_TARGET_PHYSNAME);
> +      return m_trampoline_target.physname;
> +    }
> +
> +    void set_target_flag (bool flag)
> +    {
> +      m_target_kind = TRAMPOLINE_TARGET_FLAG;
> +      m_trampoline_target.flag = flag;
> +    }
> +
> +    bool target_flag () const
> +    {
> +      gdb_assert (m_target_kind == TRAMPOLINE_TARGET_FLAG);
> +      return m_trampoline_target.flag;
> +    }
> +
> +  private:
> +
> +    union
> +    {
> +      /* Address.  */
> +      CORE_ADDR physaddr;
> +      /* Mangled name.  */
> +      const char *physname;
> +      /* 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.  */
> @@ -1891,8 +1976,16 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
>   #define TYPE_GNAT_SPECIFIC(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.gnat_stuff
>   #define TYPE_DESCRIPTIVE_TYPE(thistype) TYPE_GNAT_SPECIFIC(thistype)->descriptive_type
>   #define TYPE_CALLING_CONVENTION(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.func_stuff->calling_convention
> -#define TYPE_NO_RETURN(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.func_stuff->is_noreturn
> +#define TYPE_FUNC_FLAGS(thistype) \
> +  TYPE_MAIN_TYPE(thistype)->type_specific.func_stuff->flags
> +#define TYPE_NO_RETURN(thistype) \
> +  (TYPE_MAIN_TYPE(thistype)->type_specific.func_stuff->flags \
> +   & FUNC_TYPE_NO_RETURN)
>   #define TYPE_TAIL_CALL_LIST(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.func_stuff->tail_call_list
> +#define TYPE_IS_TRAMPOLINE(thistype) \
> +  (TYPE_MAIN_TYPE(thistype)->type_specific.func_stuff->flags \
> +   & FUNC_TYPE_TRAMPOLINE)
Minor nit, but I'd move this up above type_tail_call_list, just to keep 
all func_flag stuff together.
> +#define TYPE_TRAMPOLINE_TARGET(thistype) TYPE_MAIN_TYPE(thistype)->type_specific.func_stuff->self_trampoline_target
>   #define TYPE_BASECLASS(thistype,index) ((thistype)->field (index).type ())
>   #define TYPE_N_BASECLASSES(thistype) TYPE_CPLUS_SPECIFIC(thistype)->n_baseclasses
>   #define TYPE_BASECLASS_NAME(thistype,index) (thistype->field (index).name ())


-- 
Cheers,
Bruno


  reply	other threads:[~2023-07-27  9:09 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-07-10 22:56 [PATCH v3 0/4] GDB support for DW_AT_trampoline Abdul Basit Ijaz
2023-07-10 22:56 ` [PATCH v3 1/4] gdb, dwarf: add support for DW_AT_trampoline in DWARF reader Abdul Basit Ijaz
2023-07-27  9:09   ` Bruno Larsen [this message]
2023-07-29 11:36     ` Ijaz, Abdul B
2023-07-31  7:16       ` Bruno Larsen
2023-07-10 22:56 ` [PATCH v3 2/4] gdb/symtab: add lookup for trampoline functions Abdul Basit Ijaz
2023-07-10 22:56 ` [PATCH v3 3/4] gdb/infrun: handle stepping through functions with DW_AT_trampoline Abdul Basit Ijaz
2023-07-11 11:21   ` Eli Zaretskii
2023-07-27 11:46   ` Bruno Larsen
2023-07-29 11:03     ` Ijaz, Abdul B
2023-07-10 22:56 ` [PATCH v3 4/4] gdb: Skip trampoline frames in the stack for printing or finish command Abdul Basit Ijaz
2023-07-11 11:23   ` Eli Zaretskii

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=27931c60-cdee-e430-13bf-37cbbcc926aa@redhat.com \
    --to=blarsen@redhat.com \
    --cc=JiniSusan.George@amd.com \
    --cc=abdul.b.ijaz@intel.com \
    --cc=eliz@gnu.org \
    --cc=gdb-patches@sourceware.org \
    --cc=nils-christian.kempke@intel.com \
    --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;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).