From patchwork Mon Jun 5 11:04:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abdul Basit Ijaz X-Patchwork-Id: 70596 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 79B66384646F for ; Mon, 5 Jun 2023 11:05:09 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 79B66384646F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1685963109; bh=+Dyw+7X/TrDv5fI9nHAnBh8pJw+GTKMZVOjC1M6L5qE=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=ALZd3hpixP/unCnZPLprH+6MHwhrcxEsKyEL38hrUuS5haVYNaF0nBY5mqe8wBQZH 7igQJ+iRXHnpn2ulh0I7wgaPVsjUvwZ9DRLETnHI21rAFZaPKa0WwFh77Hy5xFiOlu b+Vme/9RvinSf4xA1VRo3TzJAqHhHqRw/DSglSAA= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by sourceware.org (Postfix) with ESMTPS id 089DB384A86E for ; Mon, 5 Jun 2023 11:04:42 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 089DB384A86E X-IronPort-AV: E=McAfee;i="6600,9927,10731"; a="335957674" X-IronPort-AV: E=Sophos;i="6.00,217,1681196400"; d="scan'208";a="335957674" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jun 2023 04:04:41 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10731"; a="821147385" X-IronPort-AV: E=Sophos;i="6.00,217,1681196400"; d="scan'208";a="821147385" Received: from labpc2030.iul.intel.com (HELO localhost) ([172.28.48.46]) by fmsmga002-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Jun 2023 04:04:39 -0700 To: gdb-patches@sourceware.org Cc: abdul.b.ijaz@intel.com, JiniSusan.George@amd.com, tom@tromey.com, Nils-Christian Kempke Subject: [PATCH v2 1/4] gdb, dwarf: add support for DW_AT_trampoline in DWARF reader Date: Mon, 5 Jun 2023 13:04:07 +0200 Message-Id: <20230605110410.3078-2-abdul.b.ijaz@intel.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230605110410.3078-1-abdul.b.ijaz@intel.com> References: <20230605110410.3078-1-abdul.b.ijaz@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-9.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_PASS, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Abdul Basit Ijaz via Gdb-patches From: Abdul Basit Ijaz Reply-To: Abdul Basit Ijaz Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" From: Nils-Christian Kempke 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. 2023-06-05 Nils-Christian Kempke --- gdb/dwarf2/read.c | 43 ++++++++++++++++++- gdb/gdbtypes.c | 35 +++++++++++++++- gdb/gdbtypes.h | 103 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 174 insertions(+), 7 deletions(-) diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 44b54f77de9..38eab809a66 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -16599,6 +16599,47 @@ 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); + 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 + { + CORE_ADDR target_addr = attr->as_address (); + 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. */ @@ -16616,7 +16657,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 6a4c5976f18..fc18fc9ce3f 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -5206,6 +5206,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. */ @@ -5532,6 +5559,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: @@ -5748,8 +5779,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); + 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 a9abb0d8071..38379aced37 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -123,6 +123,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; + }; + +/* 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, + /* An flag (target is unknown). */ + TRAMPOLINE_TARGET_FLAG, + }; + +struct trampoline_target + { + 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; }; /* struct call_site_parameter can be referenced in callees by several ways. */ @@ -2102,8 +2187,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) +#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 ())