From patchwork Mon Aug 3 19:34:40 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Ijaz, Abdul B" X-Patchwork-Id: 140533 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 9A1974BB24C3 for ; Mon, 3 Aug 2026 19:36:48 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9A1974BB24C3 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=UrkSUf23 X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.16]) by sourceware.org (Postfix) with ESMTPS id B303E4BA23E6 for ; Mon, 3 Aug 2026 19:35:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B303E4BA23E6 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org B303E4BA23E6 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=192.198.163.16 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785723; cv=none; b=f0ItzbWE4/vWljIZSVQXwJGKFHGlQF7PyAiso6YLkhKWxtYLXuDyw5w7dbFbcWiFENpcviyUMg3ks876Zpgs7FX306dPvuzR5b85Ipke/Lqmv+T5zumMmA5u1ydPAYCpCcXuRLq/gtmGFSlbbJTWiqmSkT4CC9OH0lMHPdgAJ2o= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785723; c=relaxed/simple; bh=7U0JDtLgvMKdQPuQ3vZ0BnbUIPI06pKSeEYhYezdgkY=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=DnyAvxDUbHMu9QmJLNxQApJb5wqkyri8qITRULWzahhB7vzFtCg3rzasIygeERhZ3A7PcpnImZe0M3RcQ1FUpihZXAAycyKxOH3HbTQYHKKFaMqOnCM5A5DQKKc3XLWol6jPuyC82t/phIuBg3zpTCIuvLBj4zxT6XbgkS5sZcg= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=UrkSUf23 DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B303E4BA23E6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1785785723; x=1817321723; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=7U0JDtLgvMKdQPuQ3vZ0BnbUIPI06pKSeEYhYezdgkY=; b=UrkSUf23g+kf1VsjA9M8ZfrIbhZbaNvcpAXqHGVuyRCTFT8PmjpeG3/H yFZWM0+MsVkAmKXVKqBUqOecaRlEditoViXj49EzLb/cHMrrjanZVxccz 4KhwuHWHpMbvin49kZRV5ATNhhjTT2/JtR/2OPeZhe1s6ySnHBaNmyYd7 y7F6xyTgMvbS4cxLa6wxXBVJUBBhYMks3uJKadUx9SWAMrRqAnU5UE6b3 aKQksqtDOW4yPptBLj1vHjvpQF5A5Uw8G3q554TV8047G5w9qOM1rE0lQ LCy5SvaQ+Ghus2xrS1QAG3o+apE7HROYmCmPgCGA67AuNoGYXGf2HBPLD g==; X-CSE-ConnectionGUID: XdowaMcYQrqGb24/yxydpA== X-CSE-MsgGUID: hmP1oe6HROGaM54OVrZVXw== X-IronPort-AV: E=McAfee;i="6800,10657,11864"; a="73867986" X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="73867986" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by fmvoesa110.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:35:21 -0700 X-CSE-ConnectionGUID: dHGai7o1Q8C5xmMDhdre0A== X-CSE-MsgGUID: ArKKZvPzTzymJDtUmMogOw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="299528810" Received: from fdaddami-mobl1.amr.corp.intel.com (HELO localhost) ([10.245.115.173]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:35:20 -0700 From: Abdul Basit Ijaz To: gdb-patches@sourceware.org Cc: abdul.b.ijaz@intel.com, JiniSusan.George@amd.com, tom@tromey.com, eliz@gnu.org, Nils-Christian Kempke Subject: [PATCH v11 01/10] gdb, dwarf: add support for DW_AT_trampoline in DWARF reader Date: Mon, 3 Aug 2026 21:34:40 +0200 Message-Id: <20260803193449.33375-2-abdul.b.ijaz@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260803193449.33375-1-abdul.b.ijaz@intel.com> References: <20260803193449.33375-1-abdul.b.ijaz@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, TXREP, T_SPF_TEMPERROR shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org 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. --- 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 From patchwork Mon Aug 3 19:34:41 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Ijaz, Abdul B" X-Patchwork-Id: 140530 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id ECA964BB24FA for ; Mon, 3 Aug 2026 19:35:43 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.16]) by sourceware.org (Postfix) with ESMTPS id 39B4E4BB24C4 for ; Mon, 3 Aug 2026 19:35:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 39B4E4BB24C4 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 39B4E4BB24C4 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=192.198.163.16 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785729; cv=none; b=aL3O4bbtFyu50nqj9MGyy+t9F4f2JZ/5aRRu5d0rpIUR+umorl6GrFrI5fxF7utzKTqDwWvg1kab2YYPe3/khxvI3ZgalmVlJqomerEMOiZlh6rGdPCeNPDEdv6c8WvtN0ppt0XcVCYR1wzjnB44yUuZaWQlWTo6GQ3DOhMUKQw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785729; c=relaxed/simple; bh=URSmbjxx017C+ZyD/ByiISpCMESWUIR3J4bPrAocxT4=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=WIhMtcnvdJgnwhRPKpZZ4OhRpew3nmOYdw8qwWI3gIwnVtUe62XVrpiVCY/xZumHwFR5RuBLsnuKJ1xA5HgcsMvpCPjcTYiJYnHQOdbzE6IVNL8QITnkFTZ8NWoDLDsnkqfux6w8ei+HeCzyHiqfyN4DfVar7Zd3hHymBIrnnro= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=Czvo/E9V DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 39B4E4BB24C4 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=Czvo/E9V DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1785785729; x=1817321729; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=URSmbjxx017C+ZyD/ByiISpCMESWUIR3J4bPrAocxT4=; b=Czvo/E9VP1NQ762X+b0FerbVlincQRNEzH3AronzurC/O5iCfyhwNOk9 b7sMPUFTr14ESJjDR8FaLFGxdvduFX9Z6ROY9oiytMfVyG6mXD07JzkE7 LOhOUspqNCvUegmtJiZ8g9hniXbKVRdITHCwmFhy83E7LJw+xPdUMoUUy nkZRpFYyTs1LyC+KaNecAfltx5QjnNkzCkQVleeTo4m3sIp9qR+XxZikd govg/OKBLeZ+3rTu8fPlxmr/aENLUTy1H82+jp8wgF9RaQ5rLULmIyT4W zTmh77+/6Zq6Oi5VIXmU8sXK5TDe0X8L+/vJLtMFqpJlfp887/Pm5m32U w==; X-CSE-ConnectionGUID: 9zJKltTGTK2mLnWkM6B66A== X-CSE-MsgGUID: xXkp7wXqTQefRfTp0Yzl4A== X-IronPort-AV: E=McAfee;i="6800,10657,11864"; a="73867996" X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="73867996" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by fmvoesa110.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:35:29 -0700 X-CSE-ConnectionGUID: 6G6UTNDhQVOPzFqR11rLiA== X-CSE-MsgGUID: wC11obBWTqqaliA2GcYZJA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="299528821" Received: from fdaddami-mobl1.amr.corp.intel.com (HELO localhost) ([10.245.115.173]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:35:27 -0700 From: Abdul Basit Ijaz To: gdb-patches@sourceware.org Cc: abdul.b.ijaz@intel.com, JiniSusan.George@amd.com, tom@tromey.com, eliz@gnu.org, Nils-Christian Kempke Subject: [PATCH v11 02/10] gdb/symtab: add lookup for trampoline functions Date: Mon, 3 Aug 2026 21:34:41 +0200 Message-Id: <20260803193449.33375-3-abdul.b.ijaz@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260803193449.33375-1-abdul.b.ijaz@intel.com> References: <20260803193449.33375-1-abdul.b.ijaz@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, TXREP, T_SPF_TEMPERROR shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org From: Nils-Christian Kempke 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 --- 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 #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. */ From patchwork Mon Aug 3 19:34:42 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Ijaz, Abdul B" X-Patchwork-Id: 140531 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7D1BA4BB24F0 for ; Mon, 3 Aug 2026 19:36:40 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7D1BA4BB24F0 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=hFduvtOY X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.16]) by sourceware.org (Postfix) with ESMTPS id 1C8394BB24E6 for ; Mon, 3 Aug 2026 19:35:35 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1C8394BB24E6 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 1C8394BB24E6 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=192.198.163.16 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785736; cv=none; b=m4CmzLPj3dIVSxjLZGbXlVb44t/zY9KZli9igdHernHSkLtwKQQ8QM17v9uHnaH0dZEcJLBo98XLKTiDoG4SzxoGUojg3ZIMihT9W420pEP1hHpFp+p/K1164BJbkgiYl+9ErNIOARUVHdrt4YsWKKogjtFANIjGgKiGnsbS5CU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785736; c=relaxed/simple; bh=yU7Wq3y/K/5YEBS76IQY7tKStF/b0OVbicPfnjS9FaY=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=hzg2cKMvXDerg/MLWSRujW4+Xdwf59tD4DE6vzZeguJEw7lcC6lDJJg9w6HGpBVubU1OmfBe7nO8lcb9b/5Kdj2ZFTsjkGqfHlGO3w+qatkIB8u0DONgF5BMVh0EnCXadj6X9y5aSomHkuklJH4G0Lkb3h9zwMkFHUcQUMgdbwo= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=hFduvtOY DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1C8394BB24E6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1785785736; x=1817321736; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=yU7Wq3y/K/5YEBS76IQY7tKStF/b0OVbicPfnjS9FaY=; b=hFduvtOYDTAQ3RuzffUmFD6wHf5nMX1GrumaovbmXur02+bxOx+tmTKQ CtLsGD38RGaKNnbcBBlhUF5x33fdcihCTv8X4qxhlSmnTYk86AwxNdsW2 +XpyovciG+zaZiJf5GJ4hB3Cmqb3uS1Dv5+Z2r4o6VNPgI+EHMzrni09+ MDNPgTr7T/d97sWsaTeK1c89qn/6RZniDTgguSUKVpX79FoHslRt3qBgR qQGWnUlI8bgJa0kVkqbFFDA8zs07mWsvtUvy6Cvrg4q3caxzq6P/707T/ pvFEmD8HMk+HiBl16A+KsD85SdWXbmDP+G4+jINOri203g0fpx3YYS4Gs g==; X-CSE-ConnectionGUID: ahfbZm3kTT6k/iu/C4WtrA== X-CSE-MsgGUID: NMmCHLj/StqbA2OsJat2hA== X-IronPort-AV: E=McAfee;i="6800,10657,11864"; a="73868008" X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="73868008" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by fmvoesa110.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:35:36 -0700 X-CSE-ConnectionGUID: K/yWwCtDTimnnZsU4/X6XA== X-CSE-MsgGUID: NoWfxhNqQK2bF+hQEsnBxA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="299528837" Received: from fdaddami-mobl1.amr.corp.intel.com (HELO localhost) ([10.245.115.173]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:35:34 -0700 From: Abdul Basit Ijaz To: gdb-patches@sourceware.org Cc: abdul.b.ijaz@intel.com, JiniSusan.George@amd.com, tom@tromey.com, eliz@gnu.org, Nils-Christian Kempke Subject: [PATCH v11 03/10] gdb: handle stepping through functions with DW_AT_trampoline Date: Mon, 3 Aug 2026 21:34:42 +0200 Message-Id: <20260803193449.33375-4-abdul.b.ijaz@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260803193449.33375-1-abdul.b.ijaz@intel.com> References: <20260803193449.33375-1-abdul.b.ijaz@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, TXREP, T_SPF_TEMPERROR shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org From: Nils-Christian Kempke This patch makes infrun continue stepping into and through trampoline functions marked via the DW_AT_trampoline in DWARF. The attribute can be emitted by the compiler for certain subroutines/inlined subroutines that are compiler generated and should be hidden from a user. Mainly, infrun is modified in 3 ways. First, GDB will now attempt to step through trampoline functions. Whenever we issued a step command that would make GDB step into a function that is marked trampoline, GDB will try to step directly towards the trampoline's 'target' instead and, e.g., not stop at the first instruction of the trampoline. The target can be specified by the compiler by the value of DW_AT_trampoline if its form is either an address, a name, or a DIE reference. DW_AT_trampoline is also allowed to be specified as a flag (containing true or false), in which case the target is assumed to be unknown. If GDB successfully finds a target, so if the value of DW_AT_trampoline was not a flag and could be resolved successfully, GDB steps directly towards the target and through the trampoline, hiding the trampoline from the user. If GDB cannot, however deduce a target, most likely because the DW_AT_trampoline was given as a flag or because of broken debug info, it will instead continue inside execution in the trampoline function until it reaches an instruction that is not associated with a trampoline function, which is usually the target function. It will then stop and give control back to the user. It should be noted, that there might be the cases, where trampolines call functions other than the target before the actual target call. If, in such a situation, GDB fails to resolve the target, it would resume execution until stepping into this other function call, and hand back control to the user, without actually having reached the target. A second step would have to be issued by the user to arrive a the target (by resuming in the trampoline and then until leaving it a second time). As this is a rather pathological case and no real instance of this is known, I think the current behavior here is good enough and seems to be the best GDB can do in such a situation. Secondly, as trampoline functions normally do not have any real source code correlation, it is likely that they mostly appear without line info. Normally, GDB would skip completely over a function call to a function that has no source line information, so we would never get to the aforementioned stepping through a trampoline and target resolution. To remedy this, for debug info trampolines, GDB now attempts to step through them regardless of them having source line information or not. So issuing a step at a function call wrapped by a trampoline without source line information will no longer skip the whole function call, but now step through the trampoline and attempt to resolve the trampoline target as described above (so usually, a single step at the call site will step through the trampoline and towards the target, even if the trampoline had not source line info). Last, in all other cases when GDB is about to stop at a location that is included in a trampoline region (e.g. after a step from the target back into the trampoline) GDB will instead continue until the trampoline region is left again and only then give control back to the user. This change serves the purpose of allowing stepping back from a target call through the trampoline without the user noticing the artificial function call inbetween call site and target. Together, these changes attempt to hide the trampoline function from the user while stepping. Additionally, the skip-trampoline-functions option has been introduced in infrun. It is set by default, and, when turned off, GDB will return to its 'normal' stepping behavior and ignore any possible DW_AT_trampoline. As currently only ifx emits the DW_AT_trampoline tag, a test has been added to gdb.dwarf2 that artificially creates a set of trampoline functions. --- gdb/NEWS | 11 + gdb/doc/gdb.texinfo | 35 +++ gdb/infrun.c | 94 ++++++- gdb/infrun.h | 5 + .../gdb.dwarf2/dw2-function-trampolines.c | 80 ++++++ .../gdb.dwarf2/dw2-function-trampolines.exp | 244 ++++++++++++++++++ 6 files changed, 465 insertions(+), 4 deletions(-) create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.c create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.exp diff --git a/gdb/NEWS b/gdb/NEWS index 8f40ca5cb11..5c618c0d38d 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -1768,6 +1768,17 @@ platform. * New commands +set skip-trampoline-functions on|off +show skip-trampoline-functions + This setting is 'on' by default. When 'on' it controls whether GDB will + recognize function calls that have been marked as trampolines in the debug + info. It improves stepping behavior in that it steps over the trampoline + code and hides it from the user. Currently, only DWARF trampolines are + supported. + + If this is turned off, GDB will handle @dfn{trampoline functions} the same + as any other function. + maint set backtrace-on-fatal-signal on|off maint show backtrace-on-fatal-signal This setting is 'on' by default. When 'on' GDB will print a limited diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 0030698dcee..f8dd7d8ec4e 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -6742,6 +6742,41 @@ debug information. This is the default. Show whether @value{GDBN} will stop in or step over functions without source line debug information. +@kindex set skip-trampoline-functions +@item set skip-trampoline-functions +@cindex trampoline functions +@cindex stepping through trampoline functions +@itemx set skip-trampoline-functions on +When calling a function in any language, some compilers might generate +so-called @dfn{trampoline functions}, which wrap the actual function call (the +target of the trampoline). The compiler might mark such a trampoline in +its debug information. + +The default is @code{on} and it will cause @value{GDBN} to treat these +trampolines differently. + +When issuing a @code{step} at the call site of a trampoline function if +@code{skip-trampoline-functions} is set @value{GDBN} will attempt to determine +the target of the trampoline and then step through the trampoline stopping at +the target. If the target could not be found or was not given in the debug +info, @value{GDBN} will simply continue execution until it leaves the +trampoline code, even if the trampoline has no line info associated with it. +When returning from a target function call and stepping back into the +trampoline, @value{GDBN} will step over the trampoline towards the call site. +Additionally, even if stopped in a trampoline function with source +line information, issuing a @code{step} will prompt @value{GDBN} to resume +execution until leaving the trampoline region. The @code{stepi} command +is not affected by the setting which is enabled by default. Currently, only +DWARF trampolines marked via DW_AT_trampoline are supported by this. + +@item set skip-trampoline-functions off +Causes @value{GDBN} to completely ignore any trampoline information a compiler +might have emitted in its debug info. Trampolines will be treated like any +other normal function. + +@item show skip-trampoline-functions +Show whether @value{GDBN} tries to skip trampolines or not. + @kindex finish @kindex fin @r{(@code{finish})} @item finish diff --git a/gdb/infrun.c b/gdb/infrun.c index c0767e7f764..0b032ce94c0 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -190,6 +190,12 @@ get_previous_thread () static bool detach_fork = true; +/* If set (default) GDB will step through functions/inlined subroutines marked + DW_AT_trampoline by the compiler. If false, GDB will ignore the + attribute. */ + +static bool skip_trampoline_functions = true; + bool debug_infrun = false; static void show_debug_infrun (struct ui_file *file, int from_tty, @@ -7979,7 +7985,6 @@ process_event_stop_test (struct execution_control_state *ecs) || !ecs->event_thread->control.in_step_start_function (frame)))) { CORE_ADDR stop_pc = ecs->event_thread->stop_pc (); - CORE_ADDR real_stop_pc; infrun_debug_printf ("stepped into subroutine"); @@ -8051,8 +8056,47 @@ process_event_stop_test (struct execution_control_state *ecs) calling routine and the real function), locate the real function. That's what tells us (a) whether we want to step into it at all, and (b) what prologue we want to run to the - end of, if we do step into it. */ - real_stop_pc = skip_language_trampoline (frame, stop_pc); + end of, if we do step into it. For functions marked as + trampoline functions we try to find their target and step + towards it (if skip_trampoline_functions is not set to false by the + user). If no target can be determined we just step into the + trampoline and hand control back to the user. */ + CORE_ADDR real_stop_pc = 0; + bool in_trampoline = skip_trampoline_functions + && in_trampoline_function (stop_pc); + + if (in_trampoline) + { + if (execution_direction == EXEC_REVERSE) + { + keep_going (ecs); + return; + } + + real_stop_pc = find_function_trampoline_target (stop_pc); + + for (int i = 0; i < MAX_TRAMPOLINE_CHAIN_SIZE + && in_trampoline_function (real_stop_pc); ++i) + { + real_stop_pc = find_function_trampoline_target (real_stop_pc); + /* Exit if find_function_trampoline_target failed to find the + trampoline target. Do not try to resolve the trampolines + in this case. */ + if (real_stop_pc == 0x0) + break; + } + + /* If we failed to find a target we will just single step in the + hope of leaving the trampoline again soon. */ + if (real_stop_pc == 0x0) + { + keep_going (ecs); + return; + } + } + + if (real_stop_pc == 0) + real_stop_pc = skip_language_trampoline (frame, stop_pc); if (real_stop_pc == 0) real_stop_pc = gdbarch_skip_trampoline_code (gdbarch, frame, stop_pc); if (real_stop_pc != 0) @@ -8073,6 +8117,8 @@ process_event_stop_test (struct execution_control_state *ecs) /* If we have line number information for the function we are thinking of stepping into and the function isn't on the skip list, step into it. + If we are about to step into a function marked trampoline with no + line number information, we still want to enter it here. If there are several symtabs at that PC (e.g. with include files), just want to know whether *any* of them have line @@ -8081,7 +8127,9 @@ process_event_stop_test (struct execution_control_state *ecs) struct symtab_and_line tmp_sal; tmp_sal = find_sal_for_pc (ecs->stop_func_start, 0); - if (tmp_sal.line != 0 + if ((tmp_sal.line != 0 + || (skip_trampoline_functions + && in_trampoline_function (ecs->stop_func_start))) && !function_name_is_marked_for_skip (ecs->stop_func_name, tmp_sal) && !inline_frame_is_marked_for_skip (true, ecs->event_thread)) @@ -8234,6 +8282,26 @@ process_event_stop_test (struct execution_control_state *ecs) return; } + /* If we ended up in a function trampoline without stepping into a new + function we are either in some inlined trampoline or returning through a + trampoline function. In either case we continue to single step until we + are out of the trampoline code again. This check has to be done before + stop_pc_sal.line == 0 below, as trampolines usually don't have source + line information associated with them. + The in_trampoline_code() is used here (which detects both inline and + concrete trampolines). Because this is already mid-step and need to + detect ANY trampoline code (inline or concrete) to properly step through + it. This handles cases where compilers emit DW_AT_trampoline + + DW_AT_inline (e.g., O2 optimizations), where inlined trampoline code + may exist at the current PC even though the concrete function is not a + trampoline. */ + if (skip_trampoline_functions && in_trampoline_code (stop_pc_sal.pc)) + { + infrun_debug_printf ("stepped into trampoline code"); + keep_going (ecs); + return; + } + if (stop_pc_sal.line == 0) { /* We have no line number information. That means to stop @@ -10608,6 +10676,14 @@ show_exec_direction_func (struct ui_file *out, int from_tty, } } +static void +show_skip_trampoline_functions (ui_file *file, int from_tty, + cmd_list_element *c, + const char *value) +{ + gdb_printf (file, _("Skipping trampoline functions is %s.\n"), value); +} + static void show_schedule_multiple (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -10951,6 +11027,16 @@ Options are 'forward' or 'reverse'."), set_exec_direction_func, show_exec_direction_func, &setlist, &showlist); + add_setshow_boolean_cmd ("skip-trampoline-functions", class_run, + &skip_trampoline_functions, _("\ +Set whether gdb attempts to hide trampolines marked in the debug info."), _("\ +Show whether gdb attempts to hide trampolines marked in the debug info."), _("\ +If on, while stepping gdb will skip through functions and inlined functions\n\ +marked as trampolines by the compiler. If off, gdb will treat trampolines as\n\ +normal functions."), + nullptr, show_skip_trampoline_functions, &setlist, + &showlist); + /* Set/show detach-on-fork: user-settable mode. */ add_setshow_boolean_cmd ("detach-on-fork", class_run, &detach_fork, _("\ diff --git a/gdb/infrun.h b/gdb/infrun.h index cbc603b74ed..135d1fc350b 100644 --- a/gdb/infrun.h +++ b/gdb/infrun.h @@ -75,6 +75,11 @@ infrun_debug_show_threads (const char *title, ThreadRange threads) } +/* Maximum size of trampoline chain to process while resolving + trampolines. This avoids infinite loops for malformed debug + information. */ +#define MAX_TRAMPOLINE_CHAIN_SIZE 10 + /* Nonzero if we want to give control to the user when we're notified of shared library events by the dynamic linker. */ extern int stop_on_solib_events; diff --git a/gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.c b/gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.c new file mode 100644 index 00000000000..9629b753e7d --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.c @@ -0,0 +1,80 @@ +/* Copyright 2026 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* This test relies on inlined_trampoline being inlined into main and the other + functions not. All functions except target will be marked via + DW_AT_trampoline in the debug info and we'll check whether one can step + through the trampolines towards target. */ +volatile int global_var; + +int __attribute__ ((noinline)) +target () /* target decl line */ +{ /* target prologue */ + asm ("target_label: .globl target_label"); + ++global_var; /* target add */ + asm ("target_label2: .globl target_label2"); + return 9 + 10; /* target return */ +} /* target end */ + +int __attribute__ ((noinline)) +trampoline () +{ /* trampoline prologue */ + asm ("trampoline_label: .globl trampoline_label"); + ++global_var; + return target (); /* trampoline target call */ +} /* trampoline end */ + +static inline int __attribute__ ((always_inline)) +inlined_trampoline () +{ /* inlined_trampoline prologue */ + asm ("inlined_trampoline_label: .globl inlined_trampoline_label"); + ++global_var; /* inlined_trampoline add */ + asm ("inlined_trampoline_label2: .globl inlined_trampoline_label2"); + return target (); /* inlined_trampoline target call */ +} /* inlined_trampoline end */ + +int __attribute__ ((noinline)) +chained_trampoline () +{ /* chained_trampoline prologue */ + asm ("chained_trampoline_label: .globl chained_trampoline_label"); + ++global_var; + return trampoline (); /* chained_trampoline trampoline call */ +} /* chained_trampoline end */ + +int __attribute__ ((noinline)) +doubly_chained_trampoline () +{ /* doubly_chained_trampoline prologue */ + asm ("doubly_chained_trampoline_label: .globl doubly_chained_trampoline_label"); + ++global_var; + return chained_trampoline (); /* doubly_chained_trampoline chained_trampoline call */ +} /* doubly_chained_trampoline end */ + +int +main () /* main decl line */ +{ /* main prologue */ + int ans; + asm ("main_label: .globl main_label"); + global_var = 0; /* main set global_var */ + asm ("main_label2: .globl main_label2"); + ans = inlined_trampoline (); /* main call inlined_trampoline */ + asm ("main_label3: .globl main_label3"); + ans = trampoline (); /* main call trampoline */ + asm ("main_label4: .globl main_label4"); + ans = chained_trampoline (); /* main call chained_trampoline */ + asm ("main_label5: .globl main_label5"); + ans = doubly_chained_trampoline (); /* main call doubly_chained_trampoline */ + asm ("main_label6: .globl main_label6"); + return ans; /* main call return */ +} /* main end */ diff --git a/gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.exp b/gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.exp new file mode 100644 index 00000000000..f2aa43e27c9 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-function-trampolines.exp @@ -0,0 +1,244 @@ +# Copyright 2026 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This test checks GDB's handling of functions/inlined functions marked +# DW_AT_trampoline by the compiler. A function marked as trampoline should +# generally be hidden from the user. We check whether we can step through +# trampolines. Every trampoline is defined using a different type for its +# target: a string, an address, a DIE reference or a flag. +# Setting skip-trampoline-functions to false inside GDB should make it return +# to its 'normal' behavior, ignore the DW_AT_trampoline, and skip all of the +# non-inlined trampoline calls (as their DIEs don't have any source +# information). + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return +} + +standard_testfile .c .S + +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + declare_labels lines_label trampoline_label + + get_func_info target + get_func_info trampoline + get_func_info chained_trampoline + get_func_info doubly_chained_trampoline + get_func_info main + + set target_decl_line [gdb_get_line_number "target decl line"] + set main_decl_line [gdb_get_line_number "main decl line"] + set main_call_inlined_trampoline_line [gdb_get_line_number "main call inlined_trampoline"] + + cu {} { + compile_unit { + DW_AT_language @DW_LANG_C + DW_AT_name dw2-function-trampolines.c + DW_AT_low_pc 0 addr + DW_AT_stmt_list ${lines_label} DW_FORM_sec_offset + } { + subprogram { + DW_AT_name target + DW_AT_low_pc $target_start addr + DW_AT_high_pc "$target_start + $target_len" addr + DW_AT_decl_file 1 data1 + DW_AT_decl_line $target_decl_line data1 + } + # The 'trampoline' subprogram declares its target by name. + trampoline_label: subprogram { + DW_AT_name trampoline + DW_AT_low_pc $trampoline_start addr + DW_AT_high_pc "$trampoline_start + $trampoline_len" addr + DW_AT_trampoline target string + } + # The 'chained_trampoline' subprogram declares its target as die + # reference. + subprogram { + DW_AT_name chained_trampoline + DW_AT_low_pc $chained_trampoline_start addr + DW_AT_high_pc "$chained_trampoline_start + $chained_trampoline_len" addr + DW_AT_trampoline %$trampoline_label + } + # The 'doubly_chained_trampoline' subprogram declares no target. + # Its DW_AT_trampoline is a flag set to true. + subprogram { + DW_AT_name doubly_chained_trampoline + DW_AT_low_pc $doubly_chained_trampoline_start addr + DW_AT_high_pc "$doubly_chained_trampoline_start + $doubly_chained_trampoline_len" addr + DW_AT_trampoline 1 flag + } + subprogram { + DW_AT_external 1 flag + DW_AT_name main + DW_AT_main_subprogram 1 flag + DW_AT_low_pc $main_start addr + DW_AT_high_pc "$main_start + $main_len" addr + DW_AT_decl_file 1 data1 + DW_AT_decl_line $main_decl_line data1 + } { + # The 'inlined_trampoline' subroutine declares its target as + # an address. + inlined_subroutine { + DW_AT_name inlined_trampoline + DW_AT_low_pc main_label2 addr + DW_AT_high_pc main_label3 addr + DW_AT_trampoline $target_start addr + DW_AT_call_file 1 data1 + DW_AT_call_line $main_call_inlined_trampoline_line data1 + } + } + } + } + + lines {version 2} lines_label { + include_dir "$::srcdir/$::subdir" + file_name "$::srcfile" 1 + + program { + DW_LNE_set_address $main_start + line [gdb_get_line_number "main set global_var"] + DW_LNS_copy + DW_LNE_set_address main_label + line [gdb_get_line_number "main set global_var"] + DW_LNS_copy + DW_LNE_set_address main_label2 + line [gdb_get_line_number "main call inlined_trampoline"] + DW_LNS_copy + DW_LNE_set_address inlined_trampoline_label + line [gdb_get_line_number "inlined_trampoline add"] + DW_LNS_copy + DW_LNE_set_address inlined_trampoline_label2 + line [gdb_get_line_number "inlined_trampoline target call"] + DW_LNS_copy + DW_LNE_set_address main_label3 + line [gdb_get_line_number "main call trampoline"] + DW_LNS_copy + DW_LNE_set_address main_label4 + line [gdb_get_line_number "main call chained_trampoline"] + DW_LNS_copy + DW_LNE_set_address main_label5 + line [gdb_get_line_number "main call doubly_chained_trampoline"] + DW_LNS_copy + DW_LNE_set_address main_label6 + line [gdb_get_line_number "main call return"] + DW_LNS_copy + DW_LNE_set_address $main_end + DW_LNE_end_sequence + + DW_LNE_set_address $target_start + line [gdb_get_line_number "target prologue"] + DW_LNS_negate_stmt + DW_LNS_copy + DW_LNE_set_address target_label + line [gdb_get_line_number "target add"] + DW_LNS_negate_stmt + DW_LNS_copy + DW_LNE_set_address target_label2 + line [gdb_get_line_number "target return"] + DW_LNS_copy + DW_LNE_set_address $target_end + DW_LNE_end_sequence + } + } +} + +if {[prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] {nodebug additional_flags=-O0}]} { + return +} + +set target_first_line_pattern ".*target add.*" +set target_second_line_pattern ".*target return.*" + +if {![runto_main]} { + return +} + +gdb_test "show skip-trampoline-functions" \ + "Skipping trampoline functions is on\." \ + "check skip-trampoline-functions is enabled" + +with_test_prefix "with trampoline handling" { + foreach {trampoline return_line} { "inlined_trampoline" "trampoline" \ + "trampoline" "chained_trampoline" \ + "chained_trampoline" "doubly_chained_trampoline" } { + + gdb_test "s" "$target_first_line_pattern" "step through $trampoline" + gdb_test "s" "$target_second_line_pattern" \ + "step target second line from $trampoline" + gdb_test "s" ".*main call $return_line.*" \ + "step back through $trampoline" + } + + # The doubly_chained_trampoline has only been marked as trampoline but no + # target was given. In this case GDB steps into the trampoline and then + # continues until the trampoline section is left again. + + # When compiled with gcc 7.5 (and possibly others) on a 32 bit system, the + # trampoline function contains a call to __x86.get_pc_thunk.ax before the + # actual target call. So, we end up in __x86.get_pc_thunk.ax. Issuing a + # second step command will return from the function call back into the + # trampoline and go on inside the trampoline towards the actual target call. + # On other targets we step directly towards the target call. + gdb_test_multiple "s" "step through double_chained_trampoline" { + -re -wrap "$target_first_line_pattern" { + pass $gdb_test_name + } + -re -wrap ".*__x86.get_pc_thunk.ax.*" { + gdb_test "s" "$target_first_line_pattern" \ + "step through double_chained_trampoline 2nd try" + } + } + gdb_test "s" "$target_second_line_pattern" \ + "step target second line fromdoubly_chained_trampoline" + gdb_test "s" ".*main call return.*" \ + "step back through doubly_chained_trampoline" +} + +clean_restart ${testfile} + +if {![runto_main]} { + return +} + +gdb_test_no_output "set skip-trampoline-functions off" \ + "disable trampoline handling" +gdb_test "show skip-trampoline-functions" \ + "Skipping trampoline functions is off." \ + "check skip-trampoline-functions is disabled" + +with_test_prefix "without trampoline handling" { + gdb_test "s" ".*main call inlined_trampoline.*" + gdb_test "s" ".*inlined_trampoline add.*" \ + "step into inlined_trampoline with skip-trampoline off" + gdb_test "s" ".*inlined_trampoline target call.*" \ + "step in inlined_trampoline with skip-trampoline off" + gdb_test "s" "$target_first_line_pattern" \ + "step into target with skip-trampoline off" + gdb_test "s" "$target_second_line_pattern" \ + "step second line in target with skip-trampoline off" + gdb_test "s" ".*main call trampoline.*" \ + "step brack from target with skip-trampoline off" + gdb_test "s" ".*main call chained_trampoline.*" \ + "skip trampoline call with no line info" + gdb_test "s" ".*main call doubly_chained_trampoline.*" \ + "skip chained_trampoline call with no line info" + gdb_test "s" ".*main call return.*" \ + "skip doubly_chained_trampoline call with no line info" +} From patchwork Mon Aug 3 19:34:43 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Ijaz, Abdul B" X-Patchwork-Id: 140532 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 529164BB24C5 for ; Mon, 3 Aug 2026 19:36:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 529164BB24C5 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=L6WAee7m X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.16]) by sourceware.org (Postfix) with ESMTPS id 394D04BB24F1 for ; Mon, 3 Aug 2026 19:35:42 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 394D04BB24F1 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 394D04BB24F1 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=192.198.163.16 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785742; cv=none; b=JYLA4YteFMbWyGnzw3cJMDACqChQmQryxX2jTLFFsKdfZlUEeEGflHaMK715o0gi3DQQ3GetGJY7iq/nBOkZza1iVNQmmQgqmBMb1WQ/uqB36h5KDqGGXhZukcKnXQVA3VKtx/njlYhVBSUEeO7/WCXTYyjwZNrmzhhJSmZEZXY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785742; c=relaxed/simple; bh=r6xv2pZHnXktINGaO48gorWvyTLhNRFWbqjO+zCR150=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=YJYzP9JcAzgYyoCSaKFT1w58YZ+iQWrox50JQaqfJl6vVAsv3mIk9GX3QhaoXrOe7HUU40ZmaACUmWCZqUfQsx6bCr6x0WPynfkI3INmlT7PvytFCBIs6/D8vAzEMmCdBknfCh+FMhohwvMO5vBEFFYh8yxqYcpUsP3h90Pm4Lc= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=L6WAee7m DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 394D04BB24F1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1785785742; x=1817321742; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=r6xv2pZHnXktINGaO48gorWvyTLhNRFWbqjO+zCR150=; b=L6WAee7mDF9pqnAsP5jocUhSP6xJxodunvqhZrsRgePqWOkHhnsg+E6i dXXWD4aYbHQOZi/pktdUUd1BwmHJAV0VfHp28K1FfivyTzdCYjs9QmrUe XuJ435l6CDaWl8IyzlnjHoSoUUSiO9UCVvlU5CymXpTkXrrSIy8yp3uS1 KG45TNXKay8NKBjuQNvj5Mi399/7ijfHYv/hH460QtmWP67Q8/oE0JEZ4 zgKS0oopPibixUDuw+C7xEy3s1J9DWkhdbt7rDjHcNoxNjfuM7taY5eZ7 oepEAcEBmAJyTnFcYmqMaoAYnIA3F3h6xBahToBwO238XzFTaRb7KlNs1 A==; X-CSE-ConnectionGUID: TtDbqC8CR4Op5qawkin1UQ== X-CSE-MsgGUID: vBdjGY/SSAa9LbnkMDlgWA== X-IronPort-AV: E=McAfee;i="6800,10657,11864"; a="73868016" X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="73868016" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by fmvoesa110.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:35:42 -0700 X-CSE-ConnectionGUID: A3zebQN/QZuNDvIeOstSgQ== X-CSE-MsgGUID: hmSoROCDQLahdVr9t19Ntg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="299528844" Received: from fdaddami-mobl1.amr.corp.intel.com (HELO localhost) ([10.245.115.173]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:35:41 -0700 From: Abdul Basit Ijaz To: gdb-patches@sourceware.org Cc: abdul.b.ijaz@intel.com, JiniSusan.George@amd.com, tom@tromey.com, eliz@gnu.org Subject: [PATCH v11 04/10] gdb: Skip trampoline frames for the backtrace command. Date: Mon, 3 Aug 2026 21:34:43 +0200 Message-Id: <20260803193449.33375-5-abdul.b.ijaz@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260803193449.33375-1-abdul.b.ijaz@intel.com> References: <20260803193449.33375-1-abdul.b.ijaz@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, TXREP, T_SPF_TEMPERROR shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This change filters trampoline functions when the option 'skip-trampoline-functions' is set to 'on' for the backtrace command. Before the change, GDB prints the frames indicated by the compiler with DIE "DW_AT_trampoline" in the backtrace, but for better user experience, all such frames can be hidden from the user. For O2 optimized code where inlined trampoline wrappers are inlined into regular functions. Check the frame's function directly for inline frames instead of looking up by PC, which would incorrectly return the caller's function. The test 'gdb.fortran/mixed-lang-stack' test used to fail for the IFX compiler because of extra trampoline frames in the backtrace. After the commit, those trampoline frames are filtered and test is updated accordingly. Extra trampoline frames: bt -frame-arguments all ''' \#8 0x0000000000405535 in mixed_func_1b_.t86p.t87p.t88p.t89p.t90p.t91p.t3v () \#10 0x0000000000405439 in mixed_func_1a_.void () at mixed-lang-stack.f90:33 ''' (gdb) FAIL: gdb.fortran/mixed-lang-stack.exp: lang=auto: bt -frame-arguments all In this example the IFX compiler emits "DW_AT_trampoline" tag for the 'first' and 'second' trampoline functions like following: function second (x, y) result(z) integer, intent(in) :: x, y integer :: z z = x * y ! breakpt-backtrace end function second function first (num1, num2) result(total) integer, intent(in) :: num1, num2 integer :: total total = second (num1 + 4, num2 * 3) ! first-breakpt total = total + 30 end function first Related Dwarf: 0x0000013f: DW_TAG_subprogram DW_AT_low_pc (0x0000000000404350) DW_AT_high_pc (0x000000000040435f) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("second_.t74p.t75p") DW_AT_name ("second_.t74p.t75p") DW_AT_trampoline ("second_") 0x0000015a: DW_TAG_subprogram DW_AT_low_pc (0x00000000004044a0) DW_AT_high_pc (0x00000000004044af) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("first_.t104p.t105p") DW_AT_name ("first_.t104p.t105p") DW_AT_trampoline ("first_") Before this change, the backtrace command output looks like: ''' (gdb) backtrace 3 \#0 second (x=20, y=9) at test.f90:4 \#1 0x0000000000405209 in second_.t74p.t75p () at test.f90:12 \#2 0x00000000004051e3 in first (num1=16, num2=3) at test.f90:10 (gdb) backtrace -3 \#2 0x00000000004051e3 in first (num1=16, num2=3) at test.f90:10 \#3 0x0000000000405309 in first_.t95p.t96p () at test.f90:21 \#4 0x0000000000405234 in func_trampoline () at test.f90:17 ''' After the change: ''' (gdb) backtrace 3 \#0 second (x=20, y=9) at test.f90:4 \#2 0x00000000004051e3 in first (num1=16, num2=3) at test.f90:10 \#4 0x0000000000405234 in func_trampoline () at test.f90:17 (gdb) backtrace -3 \#2 0x00000000004051e3 in first (num1=16, num2=3) at test.f90:10 \#4 0x0000000000405234 in func_trampoline () at test.f90:17 ''' The test gdb.fortran/func-trampoline.exp is added for testing the change using O0 and O2 optimization level. --- gdb/NEWS | 5 +- gdb/doc/gdb.texinfo | 6 ++ gdb/infrun.c | 6 +- gdb/infrun.h | 6 ++ gdb/stack.c | 8 ++ gdb/symtab.c | 31 +++++++ gdb/symtab.h | 5 ++ gdb/testsuite/gdb.fortran/func-trampoline.exp | 87 +++++++++++++++++++ gdb/testsuite/gdb.fortran/func-trampoline.f90 | 40 +++++++++ .../gdb.fortran/mixed-lang-stack.exp | 8 +- 10 files changed, 195 insertions(+), 7 deletions(-) create mode 100644 gdb/testsuite/gdb.fortran/func-trampoline.exp create mode 100644 gdb/testsuite/gdb.fortran/func-trampoline.f90 diff --git a/gdb/NEWS b/gdb/NEWS index 5c618c0d38d..8100f7cd7b4 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -1773,8 +1773,9 @@ show skip-trampoline-functions This setting is 'on' by default. When 'on' it controls whether GDB will recognize function calls that have been marked as trampolines in the debug info. It improves stepping behavior in that it steps over the trampoline - code and hides it from the user. Currently, only DWARF trampolines are - supported. + code and hides it from the user. It improves the printing of the stack by + hiding trampoline functions from the backtrace. Currently, only DWARF + trampolines are supported. If this is turned off, GDB will handle @dfn{trampoline functions} the same as any other function. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index f8dd7d8ec4e..af57610ddc3 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -6769,6 +6769,12 @@ execution until leaving the trampoline region. The @code{stepi} command is not affected by the setting which is enabled by default. Currently, only DWARF trampolines marked via DW_AT_trampoline are supported by this. +When issuing a @code{backtrace}, if @code{skip-trampoline-functions} is set, +@value{GDBN} will skip trampoline frames while printing the stack. + +Currently, only DWARF trampolines marked via DW_AT_trampoline are supported by +this. + @item set skip-trampoline-functions off Causes @value{GDBN} to completely ignore any trampoline information a compiler might have emitted in its debug info. Trampolines will be treated like any diff --git a/gdb/infrun.c b/gdb/infrun.c index 0b032ce94c0..9d1b85e9d1f 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -194,7 +194,7 @@ static bool detach_fork = true; DW_AT_trampoline by the compiler. If false, GDB will ignore the attribute. */ -static bool skip_trampoline_functions = true; +bool skip_trampoline_functions = true; bool debug_infrun = false; static void @@ -11031,8 +11031,8 @@ Options are 'forward' or 'reverse'."), &skip_trampoline_functions, _("\ Set whether gdb attempts to hide trampolines marked in the debug info."), _("\ Show whether gdb attempts to hide trampolines marked in the debug info."), _("\ -If on, while stepping gdb will skip through functions and inlined functions\n\ -marked as trampolines by the compiler. If off, gdb will treat trampolines as\n\ +If on, gdb will skip through functions and inlined functions marked as\n\ +trampolines by the compiler. If off, gdb will treat trampolines as\n\ normal functions."), nullptr, show_skip_trampoline_functions, &setlist, &showlist); diff --git a/gdb/infrun.h b/gdb/infrun.h index 135d1fc350b..a5c6f317193 100644 --- a/gdb/infrun.h +++ b/gdb/infrun.h @@ -106,6 +106,12 @@ extern bool non_stop; starting an inferior. */ extern bool disable_randomization; +/* If set (default) GDB will step through functions/inlined subroutines marked + DW_AT_trampoline by the compiler. If false, GDB will ignore the + attribute. */ + +extern bool skip_trampoline_functions; + /* Returns a unique identifier for the current stop. This can be used to tell whether a command has proceeded the inferior past the current location. */ diff --git a/gdb/stack.c b/gdb/stack.c index f41f818cebb..fa217ae9f6f 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -1978,6 +1978,14 @@ backtrace_command_1 (const frame_print_options &fp_opts, { QUIT; + if (skip_trampoline_functions && in_trampoline_frame (fi)) + { + /* Trampoline frames are not printed so they are not counted in + the backtrace limit. */ + count++; + continue; + } + /* Don't use print_stack_frame; if an error() occurs it probably means further attempts to backtrace would fail (on the other hand, perhaps the code does or could be fixed to make sure diff --git a/gdb/symtab.c b/gdb/symtab.c index e5464551807..8931f50775c 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -4149,6 +4149,37 @@ in_trampoline_function (CORE_ADDR pc) /* See symtab.h. */ +bool +in_trampoline_frame (frame_info_ptr fi) +{ + /* For inline frames, they share the PC of their caller. We need to check + the frame's function directly, not look up the function at the PC. + Looking up by PC would return the caller's function not the inline + function itself. + + For O2 optimized code, the compiler may inline trampoline wrappers into + regular functions. In such cases, looking up by PC would point to the + concrete regular function and incorrectly return false (not a trampoline). + By checking the inline frame's function directly via get_frame_function(), + we correctly identify when the inline frame itself is a trampoline. */ + if (get_frame_type (fi) == INLINE_FRAME) + { + symbol *func = get_frame_function (fi); + return func != nullptr && TYPE_IS_TRAMPOLINE (func->type ()); + } + + /* For non-inline frames, use in_trampoline_function() which looks up only + the concrete function at the PC, ensuring we check the actual frame's + function and not any inlined code within it. */ + std::optional pc; + if ((pc = get_frame_pc_if_available (fi))) + return in_trampoline_function (pc.value ()); + + return false; +} + +/* See symtab.h. */ + CORE_ADDR find_function_trampoline_target (CORE_ADDR pc) { diff --git a/gdb/symtab.h b/gdb/symtab.h index 10f64548f58..8a8d9f3f85f 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -2377,6 +2377,11 @@ extern bool in_trampoline_function (CORE_ADDR pc); extern bool in_trampoline_code (CORE_ADDR pc); +/* Return whether or not the pc of the current frame is within a block that + belongs to a function that is marked as a trampoline by the compiler. */ + +extern bool in_trampoline_frame (frame_info_ptr); + /* 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 diff --git a/gdb/testsuite/gdb.fortran/func-trampoline.exp b/gdb/testsuite/gdb.fortran/func-trampoline.exp new file mode 100644 index 00000000000..5216de25a45 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/func-trampoline.exp @@ -0,0 +1,87 @@ +# Copyright 2026 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Test "backtrace" and "backtrace -n" commands for functions with trampoline +# calls. + +require allow_fortran_tests + +if {![test_compiler_info {ifx-*} f90]} { + untested "This test is only applicable for IFX, which emits the\ + trampoline DIE in Dwarf." + return +} + +standard_testfile ".f90" +load_lib fortran.exp + +# Initialize the test by running the program to the innermost +# function name "second". + +proc init_test {opt_level} { + clean_restart ${::testfile}_${opt_level} + if {![fortran_runto_main]} { + return + } + + # Set breakpoint inside the innermost function 'second'. + gdb_breakpoint "$::srcfile:$::inner_loc" + gdb_continue_to_breakpoint "innermost-body" ".*$::srcfile:$::inner_loc.*" +} + +set inner_loc [gdb_get_line_number "second-breakpt"] +set middle_loc [gdb_get_line_number "first-breakpt"] +set outer_loc [gdb_get_line_number "main-outer-loc"] +set fill "\[^\r\n\]*" + +# Test both O0 and O2 to verify trampoline handling works correctly +# with and without optimization. +foreach_with_prefix opt_level {O0 O2} { + if {[build_executable "failed to prepare" ${testfile}_${opt_level} ${srcfile} \ + [list debug f90 "optimize=-${opt_level}"]]} { + continue + } + + set binfile "${testfile}_${opt_level}" + + if {[string match -nocase "O2" $opt_level]} { + # At O2, parameters may be optimized out + set inner_desc "second \\(.*\\) at ${fill}$srcfile:$inner_loc" + set middle_desc "first \\(.*\\) at ${fill}$srcfile:$middle_loc" + } else { + set inner_desc "second \\(x=20, y=9\\) at ${fill}$srcfile:$inner_loc" + set middle_desc "first \\(num1=16, num2=3\\) at ${fill}$srcfile:$middle_loc" + } + set outer_desc ".* at .*$srcfile:$outer_loc" + + with_test_prefix "backtrace" { + init_test $opt_level + + # Limit the backtrace to 3 frames and ensure both frames for first + # and second function are shown only and trampoline frames are filtered. + gdb_test "backtrace 3" [multi_line \ + "#$decimal.* $inner_desc" \ + "#$decimal.* $middle_desc" \ + "#$decimal.* $outer_desc.*"] + } + + with_test_prefix "backtrace outerframes" { + init_test $opt_level + + gdb_test "backtrace -3" [multi_line \ + "#$decimal.* $middle_desc" \ + "#$decimal.* $outer_desc.*"] + } +} diff --git a/gdb/testsuite/gdb.fortran/func-trampoline.f90 b/gdb/testsuite/gdb.fortran/func-trampoline.f90 new file mode 100644 index 00000000000..bb9ce7f3491 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/func-trampoline.f90 @@ -0,0 +1,40 @@ +! Copyright 2026 Free Software Foundation, Inc. +! +! This program is free software; you can redistribute it and/or modify +! it under the terms of the GNU General Public License as published by +! the Free Software Foundation; either version 3 of the License, or +! (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, +! but WITHOUT ANY WARRANTY; without even the implied warranty of +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +! GNU General Public License for more details. +! +! You should have received a copy of the GNU General Public License +! along with this program. If not, see . + +! Source code for func-trampoline.exp. + +!DIR$ ATTRIBUTES NOINLINE :: second +integer(kind=4) function second(x, y) + integer(kind=4), intent(in) :: x + integer(kind=4), intent(in) :: y + + second = x * y ! second-breakpt +end function + +integer(kind=4) function first(num1, num2) + integer(kind=4), intent(in) :: num1 + integer(kind=4), intent(in) :: num2 + + first = second (num1 + 4, num2 * 3) ! first-breakpt +end function + +program func_trampoline + integer(kind=4) :: total + + total = first(16, 3) ! main-outer-loc + + write(*,*) "Result is ", total, "\n" + ! Expected: 180 +end program func_trampoline diff --git a/gdb/testsuite/gdb.fortran/mixed-lang-stack.exp b/gdb/testsuite/gdb.fortran/mixed-lang-stack.exp index 43f77d3eb66..b470554988e 100644 --- a/gdb/testsuite/gdb.fortran/mixed-lang-stack.exp +++ b/gdb/testsuite/gdb.fortran/mixed-lang-stack.exp @@ -63,6 +63,10 @@ proc run_tests { lang } { set e_arg "\['\"\]abcdef\['\"\]" set 1b_args "\[^\r\n\]+$e_arg\[^\r\n\]+" set 1g_args "obj=\[^\r\n\]+" + # Generic decimal number is checked in regex for Frame #8 and #9 to + # handle filtered trampoline frames. Since Frame#8 and Frame#10 are + # set to trampoline in DWARF by Intel® Fortran Compiler (ifx), they + # are not shown by the backtrace command. set bt_stack \ [multi_line \ "#0\\s+breakpt \\(\\) at \[^\r\n\]+" \ @@ -73,8 +77,8 @@ proc run_tests { lang } { "#5\\s+$hex in mixed_func_1d \\(\[^\r\n\]+\\) at \[^\r\n\]+" \ "#6\\s+$hex in mixed_func_1c \\(\[^\r\n\]+\\) at \[^\r\n\]+" \ "#7\\s+$hex in mixed_func_1b \\($1b_args\\) at \[^\r\n\]+" \ - "#8\\s+$hex in mixed_func_1a \\(\\) at \[^\r\n\]+" \ - "#9\\s+$hex in mixed_stack_main \\(\\) at \[^\r\n\]+" ] + "#$::decimal\\s+$hex in mixed_func_1a \\(\\) at \[^\r\n\]+" \ + "#$::decimal\\s+$hex in mixed_stack_main \\(\\) at \[^\r\n\]+" ] set main_args "argc=1, argv=${hex}( \[^\r\n\]+)?" set bt_stack_kfail \ [multi_line \ From patchwork Mon Aug 3 19:34:44 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Ijaz, Abdul B" X-Patchwork-Id: 140536 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 591D84BB588F for ; Mon, 3 Aug 2026 19:37:16 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) by sourceware.org (Postfix) with ESMTPS id 067094BB1C35 for ; Mon, 3 Aug 2026 19:35:52 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 067094BB1C35 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 067094BB1C35 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785753; cv=none; b=uhF8RLo70SGS3hTZj9+jE7arJZmxi3xVm2NFaIcY71VAmaicdJn2QFR9pNYjxdTUf+iC+B56jqDcgf++yNAE8j/T1EAL3TSTWpLMnBEsu2xTo2Gko6dVolTUotiBSRglzTC8pYcUUrP4jH38uwWjv/yGFfnG6KrSWv7hB5oqY74= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785753; c=relaxed/simple; bh=0PbwzrTc7pJKRjfglYsfG38PIukh4IY487cePyAWk+c=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=mBQRTAZwNhanfiYjH1GAtvk0CNw2DQ9nw/wmsQVV/6Ff7XBabrn58h3xeCQHtoD3hP60VTItWy+V1JgADimXra3vTFp3BGq++UQIabp01ubNIQhhVgqoUVwWcQj3Z+g6qq32Rp0THofBtvX6LClVar/62J2eD3He0tfdG983Kgk= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=VtU5GoBc DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 067094BB1C35 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=VtU5GoBc DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1785785753; x=1817321753; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=0PbwzrTc7pJKRjfglYsfG38PIukh4IY487cePyAWk+c=; b=VtU5GoBcVMHJIY+xHNHHG4vk1XmXWZ6TQqg1UihrVxs1Tb1h7MtL8MjA XCyTrBK6UiOz06edLcTdINmwhhOl6Jh1IC1Unj3Icjf/j0teOvXVE8MJb KdE8XLl2zdPqPB0cVI8VoBUsHyji5kCI1DtHCdRgDXvTVEiq0r7dqF21w I5XJSKnymgxXjNZtHZabKjK7mWjIESK6KXtWXuEeJmCDRnzN87oDcISac nD5KD9nU96UVrxdbNR0lpU8fl5pu/y+2a0wWxngJMp3ck3BkJ15BO1MZE 5/ICiG/LDXP9yLx/st4qwekbKYPev+TLqqHA+aUo1is+T85Em3ChA7/ef w==; X-CSE-ConnectionGUID: sH4mN1IvRCai042hR13obA== X-CSE-MsgGUID: MB+9cTZqT3aO8yB+NAGdBQ== X-IronPort-AV: E=McAfee;i="6800,10657,11864"; a="85462647" X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="85462647" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:35:47 -0700 X-CSE-ConnectionGUID: cPgbcL00TceiRV3gtkdVmw== X-CSE-MsgGUID: XCPGfm/sQ9+YJIx+OrNa+w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="265139722" Received: from fdaddami-mobl1.amr.corp.intel.com (HELO localhost) ([10.245.115.173]) by orviesa004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:35:46 -0700 From: Abdul Basit Ijaz To: gdb-patches@sourceware.org Cc: abdul.b.ijaz@intel.com, JiniSusan.George@amd.com, tom@tromey.com, eliz@gnu.org Subject: [PATCH v11 05/10] gdb: Skip trampoline functions for the finish and reverse-finish commands. Date: Mon, 3 Aug 2026 21:34:44 +0200 Message-Id: <20260803193449.33375-6-abdul.b.ijaz@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260803193449.33375-1-abdul.b.ijaz@intel.com> References: <20260803193449.33375-1-abdul.b.ijaz@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, TXREP, T_SPF_TEMPERROR shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This change skips trampoline functions when the option 'skip-trampoline-functions' is set to 'on' for the finish or reverse-finish command. Before this change, for these commands GDB returns to the trampoline function indicated by the compiler with DIE "DW_AT_trampoline". For better user experience, all such frames can be hidden from the user. In this example the IFX compiler emits "DW_AT_trampoline" tag for the 'first' and 'second' trampoline functions like following: function second (x, y) result(z) integer, intent(in) :: x, y integer :: z z = x * y ! breakpt-finish end function second function first (num1, num2) result(total) integer, intent(in) :: num1, num2 integer :: total total = second (num1 + 4, num2 * 3) ! first-breakpt total = total + 30 end function first Related Dwarf: 0x0000013f: DW_TAG_subprogram DW_AT_low_pc (0x0000000000404350) DW_AT_high_pc (0x000000000040435f) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("second_.t74p.t75p") DW_AT_name ("second_.t74p.t75p") DW_AT_trampoline ("second_") 0x0000015a: DW_TAG_subprogram DW_AT_low_pc (0x00000000004044a0) DW_AT_high_pc (0x00000000004044af) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("first_.t104p.t105p") DW_AT_name ("first_.t104p.t105p") DW_AT_trampoline ("first_") Before this change, the finish command output looks like: ''' (gdb) finish Run till exit from #0 second (x=20, y=9) at test.f90:4 0x0000000000405209 in second_.t74p.t75p () at test.f90:12 12 end function first Value returned is $1 = 180 ''' The reverse-finish command output in this test before the change: ''' (gdb) reverse-finish Run back to call of #0 second (x=20, y=9) at test.f90:4 0x0000000000405204 in second_.t74p.t75p () at test.f90:12 12 end function first ''' After this change: ''' (gdb) finish Run till exit from #0 second (x=20, y=9) at test.f90:4 0x00000000004051e3 in first (num1=16, num2=3) at test.f90:10 10 total = second (num1 + 4, num2 * 3) ! first-breakpt Value returned is $1 = 180 (gdb) reverse-finish Run back to call of #0 second (x=20, y=9) at test.f90:4 0x00000000004051de in first (num1=16, num2=3) at test.f90:10 10 total = second (num1 + 4, num2 * 3) ! first-breakpt ''' The test gdb.fortran/func-trampoline.exp is updated for testing the finish command. The test gdb.reverse/finish-reverse-trampoline.exp is added for testing the reverse-finish command. --- gdb/NEWS | 5 +- gdb/doc/gdb.texinfo | 4 ++ gdb/infcmd.c | 12 ++++ gdb/infrun.c | 9 +++ gdb/infrun.h | 5 ++ gdb/testsuite/gdb.fortran/func-trampoline.exp | 17 +++++- .../gdb.reverse/finish-reverse-trampoline.exp | 56 +++++++++++++++++++ 7 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 gdb/testsuite/gdb.reverse/finish-reverse-trampoline.exp diff --git a/gdb/NEWS b/gdb/NEWS index 8100f7cd7b4..ed035f25303 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -1774,8 +1774,9 @@ show skip-trampoline-functions recognize function calls that have been marked as trampolines in the debug info. It improves stepping behavior in that it steps over the trampoline code and hides it from the user. It improves the printing of the stack by - hiding trampoline functions from the backtrace. Currently, only DWARF - trampolines are supported. + hiding the trampoline frames from the backtrace and skips trampoline + functions while returning from the target function of a trampoline call. + Currently, only DWARF trampolines are supported. If this is turned off, GDB will handle @dfn{trampoline functions} the same as any other function. diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index af57610ddc3..b9dd6c14809 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -6772,6 +6772,10 @@ DWARF trampolines marked via DW_AT_trampoline are supported by this. When issuing a @code{backtrace}, if @code{skip-trampoline-functions} is set, @value{GDBN} will skip trampoline frames while printing the stack. +When issuing a @code{finish} or @code{reverse-finish}, if +@code{skip-trampoline-functions} is set, @value{GDBN} will skip trampoline +frames while returning from the target function. + Currently, only DWARF trampolines marked via DW_AT_trampoline are supported by this. diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 3e943123519..451777e3087 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -1952,6 +1952,18 @@ finish_command (const char *arg, int from_tty) error (_("\"%ps\" not meaningful in the outermost frame."), styled_string (command_style.style (), "finish")); + if (skip_trampoline_functions) + { + for (int i = 0; (SAFE_TRAMPOLINE_CHAIN (i, frame) + && in_trampoline_frame (frame)); ++i) + frame = get_prev_frame (frame); + + if (frame == nullptr) + error (_("\"finish\" not meaningful in the outermost non-trampoline \ +frame. Consider running \"set skip-trampoline-functions off\", to stop in \ +trampoline frames for the \"finish\" command.")); + } + clear_proceed_status (0); tp = inferior_thread (); diff --git a/gdb/infrun.c b/gdb/infrun.c index 9d1b85e9d1f..024bf30aced 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -8211,6 +8211,15 @@ process_event_stop_test (struct execution_control_state *ecs) keep_going (ecs); return; } + else if (skip_trampoline_functions && in_trampoline_code (stop_pc)) + { + /* While reverse stepping if we are in trampoline code + we will just continue single step in the hope of leaving the + trampoline again soon. Uses in_trampoline_code() to detect + both inline and concrete trampolines. */ + keep_going (ecs); + return; + } } /* This always returns the sal for the inner-most frame when we are in a diff --git a/gdb/infrun.h b/gdb/infrun.h index a5c6f317193..019ea86c43f 100644 --- a/gdb/infrun.h +++ b/gdb/infrun.h @@ -80,6 +80,11 @@ infrun_debug_show_threads (const char *title, ThreadRange threads) information. */ #define MAX_TRAMPOLINE_CHAIN_SIZE 10 +/* True if the trampoline index "i" is less then the maximum allowed size + of a trampoline chain. */ +#define SAFE_TRAMPOLINE_CHAIN(i, frame) \ + (i < MAX_TRAMPOLINE_CHAIN_SIZE && (frame != nullptr)) + /* Nonzero if we want to give control to the user when we're notified of shared library events by the dynamic linker. */ extern int stop_on_solib_events; diff --git a/gdb/testsuite/gdb.fortran/func-trampoline.exp b/gdb/testsuite/gdb.fortran/func-trampoline.exp index 5216de25a45..f330ac54ef2 100644 --- a/gdb/testsuite/gdb.fortran/func-trampoline.exp +++ b/gdb/testsuite/gdb.fortran/func-trampoline.exp @@ -13,8 +13,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Test "backtrace" and "backtrace -n" commands for functions with trampoline -# calls. +# Test "backtrace", "backtrace -n" and "finish" commands for functions with +# trampoline calls. require allow_fortran_tests @@ -84,4 +84,17 @@ foreach_with_prefix opt_level {O0 O2} { "#$decimal.* $middle_desc" \ "#$decimal.* $outer_desc.*"] } + + if {[string match -nocase "O2" $opt_level]} { + continue + } + + with_test_prefix "finish" { + init_test $opt_level + + gdb_test "finish" [multi_line \ + "Run till exit from #0 $fill second \\(x=20, y=9\\) $fill" \ + "${fill}first \\(num1=16, num2=3\\)${fill}" \ + "${fill}(\r\nValue returned is $valnum_re = 180)"] + } } diff --git a/gdb/testsuite/gdb.reverse/finish-reverse-trampoline.exp b/gdb/testsuite/gdb.reverse/finish-reverse-trampoline.exp new file mode 100644 index 00000000000..fb342eca030 --- /dev/null +++ b/gdb/testsuite/gdb.reverse/finish-reverse-trampoline.exp @@ -0,0 +1,56 @@ +# Copyright 2026 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Test "reverse-finish" command for functions with trampoline. + +require supports_reverse allow_fortran_tests + +if {![test_compiler_info {ifx-*} f90]} { + untested "This test is only applicable for IFX, which emits the\ + trampoline DIE in Dwarf." + return +} + +load_lib fortran.exp + +set testfile finish-reverse-trampoline +set srcfile "${srcdir}/gdb.fortran/func-trampoline.f90" +set binfile [standard_output_file $testfile] + +if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \ + {debug f90}]} { + return +} + +if {![fortran_runto_main]} { + return +} + +set inner_loc [gdb_get_line_number "second-breakpt"] + +if [supports_process_record] { + # Activate process record/replay + gdb_test_no_output "record" "turn on process record" +} + +# Set breakpoint inside the innermost function 'second'. +gdb_breakpoint "$srcfile:$inner_loc" +gdb_continue_to_breakpoint "innermost-body" ".*$srcfile:$inner_loc.*" + +gdb_test "reverse-finish" [multi_line \ + "Run back to call of #0 second \\(x=20, y=9\\).*" \ + ".*in first \\(num1=16, num2=3\\).*"] + +gdb_test "frame" "#0.*first.*" "Frame 0 shows first function" From patchwork Mon Aug 3 19:34:45 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Ijaz, Abdul B" X-Patchwork-Id: 140538 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 733B24BB24C6 for ; Mon, 3 Aug 2026 19:37:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 733B24BB24C6 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=D7k6CluI X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) by sourceware.org (Postfix) with ESMTPS id 33BA44BB24D2 for ; Mon, 3 Aug 2026 19:35:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 33BA44BB24D2 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 33BA44BB24D2 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785755; cv=none; b=iBjQDHxegSk9WdohRE52LagMmQeXLysACNKMWq6B7hwJ9uJGElAK1NuaTMXpzrzK8Wpyhk1d+lKVymUARqosFABqKHhiaALEGap5AETxvDUeBxfgg79CP6NHrWSzU0EGiWzdjNigTUT5gjP9q5Oz+Nam6qPm86ZN1KDn4WeuMwk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785755; c=relaxed/simple; bh=oJsCtRAGsN02CtnpC5DSegi/dh6DLzI+FP4s4wnQv0g=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=FNIv5Yg7f5XHqU/YvuMkf2751DtVxmSe78FjiqbGCCHiZQh+8qkpJ6QKTpzrcVvTWeFUFe2ZBbD7u/1uyjYhgTgugx2e6swAE0fHDyirXiFH3sg5nYWOnXmlCXRbk32icu6vY62G/AH3tDLnNXL61aABftZQVhxyIDfCFByyyAU= ARC-Authentication-Results: i=1; sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1785785755; x=1817321755; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=oJsCtRAGsN02CtnpC5DSegi/dh6DLzI+FP4s4wnQv0g=; b=D7k6CluIYL2vw8N//M/9yoeOzZ6ROKBLjAHFC6ogxDJhZ+yXVwPKrxWk eYojNJARko7hFj/zNDjWPC4ORS2fSKDakTgAVQ37j4JWKmrslqk9a2skr DUB0zB2XZDAtOdVWUl3mTabpdanr8BbB9iXvtdYNfgsY6ocTLieGASeFz Z6uIfZgkbzD1L2whbjRjS8ilvC/d3XztQqFbw8Em1+vCgMakOyDx3zE6Q qMCiH2rYLjXaJKjvcFQoiLyvOKpWoBvVapqtESNLv7DdJDOHeRFnzODzD nGOyjSHGnvGpzCMDzgsYPwsDNkRWur/KuEhbHAJlTWEy8ivw0uULkDnWZ g==; X-CSE-ConnectionGUID: TZxLW1vIR7GiV2WLozDKYg== X-CSE-MsgGUID: OU+5n1qzRNG+zWWgEmIpGQ== X-IronPort-AV: E=McAfee;i="6800,10657,11864"; a="85462666" X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="85462666" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:35:53 -0700 X-CSE-ConnectionGUID: tjCJWUtOQzSuV+4QyvIV2g== X-CSE-MsgGUID: yhCM2DA1SF+JXa5/JiG/eQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="265139738" Received: from fdaddami-mobl1.amr.corp.intel.com (HELO localhost) ([10.245.115.173]) by orviesa004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:35:52 -0700 From: Abdul Basit Ijaz To: gdb-patches@sourceware.org Cc: abdul.b.ijaz@intel.com, JiniSusan.George@amd.com, tom@tromey.com, eliz@gnu.org Subject: [PATCH v11 06/10] gdb: Skip trampoline functions for the up command. Date: Mon, 3 Aug 2026 21:34:45 +0200 Message-Id: <20260803193449.33375-7-abdul.b.ijaz@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260803193449.33375-1-abdul.b.ijaz@intel.com> References: <20260803193449.33375-1-abdul.b.ijaz@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, TXREP, T_SPF_TEMPERROR shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This change skips trampoline functions when the option 'skip-trampoline-functions' is set to 'on' for the up command. Before this change, GDB processes trampoline functions indicated by the compiler with DIE "DW_AT_trampoline" and stops at the trampoline function for the 'up' command. For better user experience, all such frames can be skipped and hidden from the user. In this example the IFX compiler emits "DW_AT_trampoline" tag for the 'first' and 'second' trampoline functions like following: function second (x, y) result(z) integer, intent(in) :: x, y integer :: z z = x * y ! breakpt-up end function second function first (num1, num2) result(total) integer, intent(in) :: num1, num2 integer :: total total = second (num1 + 4, num2 * 3) ! first-breakpt total = total + 30 end function first Related Dwarf: 0x0000013f: DW_TAG_subprogram DW_AT_low_pc (0x0000000000404350) DW_AT_high_pc (0x000000000040435f) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("second_.t74p.t75p") DW_AT_name ("second_.t74p.t75p") DW_AT_trampoline ("second_") 0x0000015a: DW_TAG_subprogram DW_AT_low_pc (0x00000000004044a0) DW_AT_high_pc (0x00000000004044af) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("first_.t104p.t105p") DW_AT_name ("first_.t104p.t105p") DW_AT_trampoline ("first_") Before this change, the 'up' command output looks like: ''' (gdb) up \#1 0x0000000000405209 in second_.t74p.t75p () at test.f90:12 12 end function first ''' After this change: ''' (gdb) up \#2 0x00000000004051e3 in first (num1=16, num2=3) at test.f90:10 10 total = second (num1 + 4, num2 * 3) ! first-breakpt ''' The test gdb.fortran/func-trampoline.exp is updated for testing this change. --- gdb/doc/gdb.texinfo | 2 +- gdb/stack.c | 7 +++++++ gdb/testsuite/gdb.fortran/func-trampoline.exp | 12 ++++++++++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index b9dd6c14809..ee94ad09fd9 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -6772,7 +6772,7 @@ DWARF trampolines marked via DW_AT_trampoline are supported by this. When issuing a @code{backtrace}, if @code{skip-trampoline-functions} is set, @value{GDBN} will skip trampoline frames while printing the stack. -When issuing a @code{finish} or @code{reverse-finish}, if +When issuing a @code{finish}, @code{reverse-finish} or @code{up}, if @code{skip-trampoline-functions} is set, @value{GDBN} will skip trampoline frames while returning from the target function. diff --git a/gdb/stack.c b/gdb/stack.c index fa217ae9f6f..8b1644ddb6e 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -2636,6 +2636,13 @@ up_silently_base (const char *count_exp) frame = find_relative_frame (get_selected_frame ("No stack."), &count); if (count != 0 && count_exp == NULL) error (_("Initial frame selected; you cannot go up.")); + + if (skip_trampoline_functions) + { + for (int i = 0; (SAFE_TRAMPOLINE_CHAIN (i, frame) + && in_trampoline_frame (frame)); ++i) + frame = get_prev_frame (frame); + } select_frame (frame); } diff --git a/gdb/testsuite/gdb.fortran/func-trampoline.exp b/gdb/testsuite/gdb.fortran/func-trampoline.exp index f330ac54ef2..ce9f14160aa 100644 --- a/gdb/testsuite/gdb.fortran/func-trampoline.exp +++ b/gdb/testsuite/gdb.fortran/func-trampoline.exp @@ -13,8 +13,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Test "backtrace", "backtrace -n" and "finish" commands for functions with -# trampoline calls. +# Test "backtrace", "backtrace -n", "finish" and "up" commands for +# functions with trampoline calls. require allow_fortran_tests @@ -97,4 +97,12 @@ foreach_with_prefix opt_level {O0 O2} { "${fill}first \\(num1=16, num2=3\\)${fill}" \ "${fill}(\r\nValue returned is $valnum_re = 180)"] } + + with_test_prefix "up" { + init_test $opt_level + + gdb_test "up" [multi_line \ + "#$decimal.* $middle_desc" \ + "${fill}first = second \\(num1 \\+ 4, num2 \\* 3\\).*${fill}"] + } } From patchwork Mon Aug 3 19:34:46 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Ijaz, Abdul B" X-Patchwork-Id: 140534 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6D8144BB3BD8 for ; Mon, 3 Aug 2026 19:37:09 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) by sourceware.org (Postfix) with ESMTPS id 3CE5D4BB24DB for ; Mon, 3 Aug 2026 19:36:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3CE5D4BB24DB Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 3CE5D4BB24DB Authentication-Results: sourceware.org; arc=none smtp.remote-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785790; cv=none; b=tWNdkFUqcbj2j6aAx3ps0E2Y9/Pfh6eHFDVMLtP1b6ZcUqtHp0Nr+uZdRrTnZ/9o65K2ssocd/YpxmjYKFQmXb+H45GP+haFD8R2cmCWium06LzkUKGKTgHFijLzxGq5mXaxIT5JKtRSbfBaXjECg/fLygRTUr82WdX2AHeAHGA= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785790; c=relaxed/simple; bh=CpeGd7VbW0RUECbdG4SnmMo7G7c4Cn+AHcOd9ucM1s8=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=ANAZXVuYRruRlhYge05F90TwXn2VglyEjW5Sh9gc0v/hsuzphOmFlosFITWowsmvnVEfBQMlWxQF0MRW3KDLH+6g5AOZxJgOIZ1+DS772xdul2An7kzoinYW1K7jYBaIjY1RK4CUycUt6aLmM6oyjvSoawHxK5AWQxQCYP7grT0= ARC-Authentication-Results: i=1; sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1785785790; x=1817321790; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=CpeGd7VbW0RUECbdG4SnmMo7G7c4Cn+AHcOd9ucM1s8=; b=DedW9h2ga4KIbhzC1vurXneUNGTRCdDMMpYMTFBxczAjP7NlcRQ5o2KL UHie/MCfGte/bmoHMto5LY1iuwefnQcvlaf3mtQMezmxIqgxA+28r4t9o RzNfXGOqgED2qougHZC0bs6srLwQ4qXkbRKjMgrm87WdtviFlhT/ckImu nakZWRzwuDxFeVpIE4fmtq3tjB0v7+ylf/KI5cUkBC+9aC8tjWStA3frx rWLDJJelqUoH7sy6pOL5tjzc15rCg1kf1Dbj4/ElGbykXRlJukbjFipYB bqKkySfmCdCT7mZxscqiWAVvKz/SgXIJcn23O676CMa/S5Jbd0niJVQqx A==; X-CSE-ConnectionGUID: 476At66zRIeZD6snT/x3Yw== X-CSE-MsgGUID: 7A9Dt7eQTU2WlwBcUQGHcA== X-IronPort-AV: E=McAfee;i="6800,10657,11864"; a="85462685" X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="85462685" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:36:04 -0700 X-CSE-ConnectionGUID: Dz96ryExQIKA4AJDEhqKWA== X-CSE-MsgGUID: K7+NFDaFTgi2LK0dQ+EGgA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="265139796" Received: from fdaddami-mobl1.amr.corp.intel.com (HELO localhost) ([10.245.115.173]) by orviesa004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:36:03 -0700 From: Abdul Basit Ijaz To: gdb-patches@sourceware.org Cc: abdul.b.ijaz@intel.com, JiniSusan.George@amd.com, tom@tromey.com, eliz@gnu.org Subject: [PATCH v11 07/10] gdb: Skip trampoline functions for the return command. Date: Mon, 3 Aug 2026 21:34:46 +0200 Message-Id: <20260803193449.33375-8-abdul.b.ijaz@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260803193449.33375-1-abdul.b.ijaz@intel.com> References: <20260803193449.33375-1-abdul.b.ijaz@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, TXREP, T_SPF_TEMPERROR shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This change skips trampoline functions for the return command when the option 'skip-trampoline-functions' is set to 'on'. Before this change, GDB processes trampoline functions indicated by the compiler with DIE "DW_AT_trampoline" for the return command and stops at the trampoline functions. For better user experience, all such frames can be skipped and hidden from the user. In this example the IFX compiler emits "DW_AT_trampoline" tag for the 'first' and 'second' trampoline functions like following: function second (x, y) result(z) integer, intent(in) :: x, y integer :: z z = x * y ! breakpt-return end function second function first (num1, num2) result(total) integer, intent(in) :: num1, num2 integer :: total total = second (num1 + 4, num2 * 3) ! first-breakpt total = total + 30 end function first Related Dwarf: 0x0000013f: DW_TAG_subprogram DW_AT_low_pc (0x0000000000404350) DW_AT_high_pc (0x000000000040435f) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("second_.t74p.t75p") DW_AT_name ("second_.t74p.t75p") DW_AT_trampoline ("second_") 0x0000015a: DW_TAG_subprogram DW_AT_low_pc (0x00000000004044a0) DW_AT_high_pc (0x00000000004044af) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("first_.t104p.t105p") DW_AT_name ("first_.t104p.t105p") DW_AT_trampoline ("first_") Before this change, the return command output looks like: ''' (gdb) return Make second return now? (y or n) y \#0 0x0000000000405209 in second_.t74p.t75p () at test.f90:12 12 end function first ''' After this change: ''' (gdb) return Make second return now? (y or n) y \#0 0x00000000004051e3 in first (num1=16, num2=3) at test.f90:10 10 total = second (num1 + 4, num2 * 3) ! first-breakpt ''' The test gdb.fortran/func-trampoline.exp is updated for testing this change. --- gdb/doc/gdb.texinfo | 6 +++--- gdb/stack.c | 11 +++++++++++ gdb/testsuite/gdb.fortran/func-trampoline.exp | 10 +++++++++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index ee94ad09fd9..b73cdf8b430 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -6772,9 +6772,9 @@ DWARF trampolines marked via DW_AT_trampoline are supported by this. When issuing a @code{backtrace}, if @code{skip-trampoline-functions} is set, @value{GDBN} will skip trampoline frames while printing the stack. -When issuing a @code{finish}, @code{reverse-finish} or @code{up}, if -@code{skip-trampoline-functions} is set, @value{GDBN} will skip trampoline -frames while returning from the target function. +When issuing a @code{finish}, @code{reverse-finish}, @code{up} or +@code{return}, if @code{skip-trampoline-functions} is set, @value{GDBN} will +skip trampoline frames while returning from the target function. Currently, only DWARF trampolines marked via DW_AT_trampoline are supported by this. diff --git a/gdb/stack.c b/gdb/stack.c index 8b1644ddb6e..90d6fef6824 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -2839,6 +2839,17 @@ return_command (const char *retval_exp, int from_tty) if (get_frame_type (get_current_frame ()) == DUMMY_FRAME) frame_pop (get_current_frame ()); + if (skip_trampoline_functions) + { + frame_info_ptr ret_frame = get_current_frame (); + for (int i = 0; (SAFE_TRAMPOLINE_CHAIN (i, ret_frame) + && in_trampoline_frame (ret_frame)); ++i) + { + frame_pop (ret_frame); + ret_frame = get_current_frame (); + } + } + select_frame (get_current_frame ()); /* If interactive, print the frame that is now current. */ if (from_tty) diff --git a/gdb/testsuite/gdb.fortran/func-trampoline.exp b/gdb/testsuite/gdb.fortran/func-trampoline.exp index ce9f14160aa..4f91aa17860 100644 --- a/gdb/testsuite/gdb.fortran/func-trampoline.exp +++ b/gdb/testsuite/gdb.fortran/func-trampoline.exp @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Test "backtrace", "backtrace -n", "finish" and "up" commands for +# Test "backtrace", "backtrace -n", "finish", "up" and "return" commands for # functions with trampoline calls. require allow_fortran_tests @@ -105,4 +105,12 @@ foreach_with_prefix opt_level {O0 O2} { "#$decimal.* $middle_desc" \ "${fill}first = second \\(num1 \\+ 4, num2 \\* 3\\).*${fill}"] } + + with_test_prefix "return" { + init_test $opt_level + + gdb_test "return" \ + ".*first = second \\(num1 \\+ 4, num2 \\* 3\\) \\! first-breakpt" \ + "" "Make second return now.*y or n. $" "y" + } } From patchwork Mon Aug 3 19:34:47 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Ijaz, Abdul B" X-Patchwork-Id: 140539 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A25DE4BB24CB for ; Mon, 3 Aug 2026 19:38:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A25DE4BB24CB Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=KeRvTmKE X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) by sourceware.org (Postfix) with ESMTPS id 3AE754BB24DC for ; Mon, 3 Aug 2026 19:36:33 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3AE754BB24DC Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 3AE754BB24DC Authentication-Results: sourceware.org; arc=none smtp.remote-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785793; cv=none; b=W5/YirVksCfFrmoBDD7zhClYv9/NNlMVPKcbi/7yf8VjsjdmI4iQ6FYZoRYZsQaUiliC3AhS/NFAMD9EpOI2xuF1bXAiTp0UgbZNYw6/zuHLKe8sw8yalR4opvaYg6GQw9nIAeSXNCWJ20uPwKuPiyjsm7fYv6JWcadgFe+b9yE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785793; c=relaxed/simple; bh=QZ/O7jdkTjjlhwKVy1x6TA3vWCedvq5HOKtQkNCHsMs=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=v6JqHyLJl9ejK6enUn1Ldv+1LS5Q4SwJLj4hJo/hNhhff0sWdxsOXTsnHMMYOQaqbrbAjYoSPUggZpHlMO/1SCHj36fbE2sLktb1d+4MuP34S9VOLc08Lwzg/18cjY6wGshmJi3X34KllqzoIczbQySSaUgRVWTksTRkFzTmeDc= ARC-Authentication-Results: i=1; sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1785785793; x=1817321793; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=QZ/O7jdkTjjlhwKVy1x6TA3vWCedvq5HOKtQkNCHsMs=; b=KeRvTmKEGZ/mzSvR0mrNrSxX+K530YWlUarEpMxqQv7LmZZDcNbV327O BDcCE2n7wKfg5utZM79sRxPrsIESGXOSloa+X7vpM90uXk6MwPKeVdvfZ IzkfpSLfr74VDCksukZAywNH9oHxvPWYfmep4bhZJoo2+Xty4V3tsfJiU iTbK/79B2PBFGLxk1qrWvtszCMhdu8KCkBll34YipxOMqQhM0bo675qUK TAvyPNxpnoVaCTqw0lXI9QfkwUEFK8JZMYNCR8e0tAia3sLoRa0xJ2x7s D3XZ4SsKqxtccZ1Hhi34dCiEZwbp0b/kpq9eTf25wTyF+s/xG78H/ToyV Q==; X-CSE-ConnectionGUID: rvaRcpZ4RDWMlfNgoCLU0Q== X-CSE-MsgGUID: rP2dYunkTjawjhMq6EETBw== X-IronPort-AV: E=McAfee;i="6800,10657,11864"; a="85462703" X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="85462703" Received: from orviesa004.jf.intel.com ([10.64.159.144]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:36:14 -0700 X-CSE-ConnectionGUID: vz3qmQFGTiqXJH5g1P5dYQ== X-CSE-MsgGUID: 02lBiUziQfOVWcpEVzrVow== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="265139811" Received: from fdaddami-mobl1.amr.corp.intel.com (HELO localhost) ([10.245.115.173]) by orviesa004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:36:12 -0700 From: Abdul Basit Ijaz To: gdb-patches@sourceware.org Cc: abdul.b.ijaz@intel.com, JiniSusan.George@amd.com, tom@tromey.com, eliz@gnu.org Subject: [PATCH v11 08/10] gdb, mi: Skip trampoline functions for the -stack-list-frames command. Date: Mon, 3 Aug 2026 21:34:47 +0200 Message-Id: <20260803193449.33375-9-abdul.b.ijaz@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260803193449.33375-1-abdul.b.ijaz@intel.com> References: <20260803193449.33375-1-abdul.b.ijaz@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, TXREP, T_SPF_TEMPERROR shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This change skips trampoline functions for the '-stack-list-frames' command when the option 'skip-trampoline-functions' is set to 'on'. Before this change, GDB prints the frames indicated by the compiler with DIE "DW_AT_trampoline" in the backtrace for mi command stack-list-frames, but for better user experience, all such frames can be hidden from the user. In this example the IFX compiler emits "DW_AT_trampoline" tag for the 'first' and 'second' trampoline functions like following: function second (x, y) result(z) integer, intent(in) :: x, y integer :: z z = x * y ! breakpt-backtrace end function second function first (num1, num2) result(total) integer, intent(in) :: num1, num2 integer :: total total = second (num1 + 4, num2 * 3) ! first-breakpt total = total + 30 end function first Related Dwarf: 0x0000013f: DW_TAG_subprogram DW_AT_low_pc (0x0000000000404350) DW_AT_high_pc (0x000000000040435f) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("second_.t74p.t75p") DW_AT_name ("second_.t74p.t75p") DW_AT_trampoline ("second_") 0x0000015a: DW_TAG_subprogram DW_AT_low_pc (0x00000000004044a0) DW_AT_high_pc (0x00000000004044af) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("first_.t104p.t105p") DW_AT_name ("first_.t104p.t105p") DW_AT_trampoline ("first_") Before this change, the '-stack-list-frames' command output looks like: ''' (gdb) -stack-list-frames -stack-list-frames ^done, stack=[ frame={level="0",addr="0x0000000000405194",func="second", file="test.f90",fullname="/home/test.f90",line="4", arch="i386:x86-64"}, frame={level="1",addr="0x0000000000405209", func="second_.t74p.t75p", file="test.f90",fullname="/home/test.f90",line="12", arch="i386:x86-64"}, frame={level="2",addr="0x00000000004051e3",func="first", file="test.f90",fullname="/home/test.f90",line="10", arch="i386:x86-64"}, frame={level="3",addr="0x0000000000405309", func="first_.t95p.t96p",file="test.f90", fullname="/home/test.f90",line="21",arch="i386:x86-64"}, frame={level="4",addr="0x0000000000405234", func="func_trampoline",file="test.f90", fullname="/home/test.f90",line="17",arch="i386:x86-64"}] ''' After this change: ''' (gdb) -stack-list-frames -stack-list-frames ^done, stack=[frame={level="0",addr="0x0000000000405194",func="second", file="test.f90",fullname="/home/test.f90",line="4", arch="i386:x86-64"}, frame={level="2",addr="0x00000000004051e3",func="first", file="test.f90",fullname="/home/test.f90",line="10", arch="i386:x86-64"}, frame={level="4",addr="0x0000000000405234", func="func_trampoline",file="test.f90",fullname="/home/test.f90", line="17",arch="i386:x86-64"}] ''' New test gdb.mi/mi-func-trampoline.exp is added for testing the change. --- gdb/doc/gdb.texinfo | 4 +- gdb/mi/mi-cmd-stack.c | 7 +++ gdb/testsuite/gdb.mi/mi-func-trampoline.exp | 69 +++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 gdb/testsuite/gdb.mi/mi-func-trampoline.exp diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index b73cdf8b430..684716a869e 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -35476,7 +35476,9 @@ an error if @var{low-frame} is larger than the actual number of frames. On the other hand, @var{high-frame} may be larger than the actual number of frames, in which case only existing frames will be returned. If the option @code{--no-frame-filters} is supplied, then -Python frame filters will not be executed. +Python frame filters will not be executed. If the option +@code{skip-trampoline-functions} is set, @value{GDBN} will skip the trampoline +frames while printing a backtrace. @subsubheading @value{GDBN} Command diff --git a/gdb/mi/mi-cmd-stack.c b/gdb/mi/mi-cmd-stack.c index 37a470701af..1f66c02f8b4 100644 --- a/gdb/mi/mi-cmd-stack.c +++ b/gdb/mi/mi-cmd-stack.c @@ -174,6 +174,13 @@ mi_cmd_stack_list_frames (const char *command, const char *const *argv, i++, fi = get_prev_frame (fi)) { QUIT; + if (skip_trampoline_functions) + { + for (int j = 0; (SAFE_TRAMPOLINE_CHAIN (j, fi) + && in_trampoline_frame (fi)); ++j) + fi = get_prev_frame (fi); + } + /* Print the location and the address always, even for level 0. If args is 0, don't print the arguments. */ print_frame_info (user_frame_print_options, diff --git a/gdb/testsuite/gdb.mi/mi-func-trampoline.exp b/gdb/testsuite/gdb.mi/mi-func-trampoline.exp new file mode 100644 index 00000000000..f40a9722f91 --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi-func-trampoline.exp @@ -0,0 +1,69 @@ +# Copyright 2026 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Test -stack-list-frames command for functions with trampoline +# calls. Also checks if trampoline frames are filtered while printing +# stack. + +require allow_fortran_tests + +if {![test_compiler_info {ifx-*} f90]} { + untested "This test is only applicable for IFX, which emits the\ + trampoline DIE in Dwarf." + return +} + +load_lib fortran.exp +load_lib mi-support.exp + +set MIFLAGS "-i=mi" + +if {[mi_clean_restart]} { + return +} + +set testfile mi-func-trampoline +set srcfile "${srcdir}/gdb.fortran/func-trampoline.f90" +set binfile [standard_output_file $testfile] + +if { [gdb_compile "${srcfile}" "${binfile}" executable \ + {debug f90} ] != "" } { + untested "failed to compile" + return +} + +mi_delete_breakpoints +mi_gdb_reinitialize_dir $srcdir/$subdir +mi_gdb_load ${binfile} + +set inner_loc [gdb_get_line_number "second-breakpt"] +set fill "\[^\r\n\]*" + +set frame1_regx "\{level=\"0\",addr=\"$hex\",func=\"second\",file=\".*func-trampoline.f90\",fullname=\"${fullname_syntax}func-trampoline.f90\",line=\"$inner_loc\",arch=\".*\"\}" +set frame2_regx "\{level=\"2\",addr=\"$hex\",func=\"first\",.*\}" +set frame3_regx "\{level=\"4\",addr=\"$hex\",func=\"func_trampoline\",.*\}" + +# Set breakpoint inside the innermost function 'second'. +mi_create_breakpoint "-t $srcfile:$inner_loc" \ + "insert breakpoint at line $inner_loc " \ + -number 1 -disp del -func second -file ".*trampoline.f90" \ + -line $inner_loc -addr $hex +mi_run_cmd +mi_expect_stop \ + "breakpoint-hit" "second" ".*" ".*trampoline.f90" "\[0-9\]+" { "" "disp=\"del\"" } \ + "run to breakpoint at line $inner_loc" + +mi_gdb_test "100-stack-list-frames" \ + "100\\^done,stack=\\\[frame=${frame1_regx},frame=${frame2_regx},frame=${frame3_regx}\\\]" From patchwork Mon Aug 3 19:34:48 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Ijaz, Abdul B" X-Patchwork-Id: 140535 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5F62C4BB3BF1 for ; Mon, 3 Aug 2026 19:37:12 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.14]) by sourceware.org (Postfix) with ESMTPS id 4F0524BB1C3D for ; Mon, 3 Aug 2026 19:37:00 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4F0524BB1C3D Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 4F0524BB1C3D Authentication-Results: sourceware.org; arc=none smtp.remote-ip=198.175.65.14 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785820; cv=none; b=YH/yJjp5fjhqfNugenRO2+Xt1n/L9d9Hab73lUy6grlq2xZyW237eHh4sHbTHkD91zNrEoF513SQ+zgeKyIesplNC/iaP0Caayb6FmOHxydX5ISnLABq1uINEnrBaDSrC2d4nle95k0lDeWz38rkzZsBWEAjeXUkEdkN8JCJROo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785820; c=relaxed/simple; bh=7XJAvTrFrkqfMet6bw2cauptG7DW2U1pRUDrdVAixhQ=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=gbzZHBKg9futOpTRPx8tKGiO5ufCQ27fUSZjm4JECPmS0N3R+cNT+uVWuApdm0Fn/0QdykD8L7L8FFOjqQvbLKnn/NndlS/Z39+PAwxhvWltlPyrohUHBH5dswSHsxGGiYJtxUKDx/+ar8Q2A8r9c2x+yzLW0hgAIETr9uEu0Cw= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=d7coDj/i DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4F0524BB1C3D Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=d7coDj/i DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1785785820; x=1817321820; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=7XJAvTrFrkqfMet6bw2cauptG7DW2U1pRUDrdVAixhQ=; b=d7coDj/ig4oL/8hkKX6OA9+B+vxd8kZFdtI5S6JStTVvpHm7nRjJ2r3S UGg8iwkU4ukOa+EN/Z4LpuOnfEMEnv+j0Yx/qDd3kdmB9NwAxeQ/1CT5k Qz3FZZDYHvPWTIICY68dYwAPopUTrpsTRf7LWArh5ANMMSMz3VGUgs0KB O1Q0jkXAXcrir8gV+jCpQskysCDAoWIDAkuu0XD/q2UvW/IpViWrD7xbw UnVGW0p+TPFCLd1SgaFG681ZmwHxvYv/l08e6h/FZyWbVxcLMMujwzAwv 9iVUlVnFAalfgA5Ad3vpZxNQDWwJHyqih8BcwDO+OXY0MKCDsYjFJk0ri Q==; X-CSE-ConnectionGUID: hlphv9u3RQyOiRPE9ZpVHA== X-CSE-MsgGUID: whv39AtsTkOHq0+9FHOWBg== X-IronPort-AV: E=McAfee;i="6800,10657,11864"; a="90218589" X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="90218589" Received: from fmviesa005.fm.intel.com ([10.60.135.145]) by orvoesa106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:36:36 -0700 X-CSE-ConnectionGUID: LX2WkBS+TUi5VABEmaZ+Dg== X-CSE-MsgGUID: jZl06nHDQa+mVIwdmLAJnw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="266425978" Received: from fdaddami-mobl1.amr.corp.intel.com (HELO localhost) ([10.245.115.173]) by fmviesa005-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:36:18 -0700 From: Abdul Basit Ijaz To: gdb-patches@sourceware.org Cc: abdul.b.ijaz@intel.com, JiniSusan.George@amd.com, tom@tromey.com, eliz@gnu.org Subject: [PATCH v11 09/10] gdb, mi: Skip trampoline functions for the -stack-list-arguments command. Date: Mon, 3 Aug 2026 21:34:48 +0200 Message-Id: <20260803193449.33375-10-abdul.b.ijaz@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260803193449.33375-1-abdul.b.ijaz@intel.com> References: <20260803193449.33375-1-abdul.b.ijaz@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, TXREP, T_SPF_TEMPERROR shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This change skips trampoline functions for the '-stack-list-arguments' command when the option 'skip-trampoline-functions' is set to 'on'. Before this change, GDB prints the arguments of frames indicated by the compiler with DIE "DW_AT_trampoline" in the backtrace for the mi command stack-list-arguments, but for better user experience, all such frames can be hidden from the user. In this example the IFX compiler emits "DW_AT_trampoline" tag for the 'first' and 'second' trampoline functions like following: function second (x, y) result(z) integer, intent(in) :: x, y integer :: z z = x * y ! breakpt-args end function second function first (num1, num2) result(total) integer, intent(in) :: num1, num2 integer :: total total = second (num1 + 4, num2 * 3) ! first-breakpt total = total + 30 end function first Related Dwarf: 0x0000013f: DW_TAG_subprogram DW_AT_low_pc (0x0000000000404350) DW_AT_high_pc (0x000000000040435f) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("second_.t74p.t75p") DW_AT_name ("second_.t74p.t75p") DW_AT_trampoline ("second_") 0x0000015a: DW_TAG_subprogram DW_AT_low_pc (0x00000000004044a0) DW_AT_high_pc (0x00000000004044af) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("first_.t104p.t105p") DW_AT_name ("first_.t104p.t105p") DW_AT_trampoline ("first_") Before this change, the -stack-list-arguments' command output looks like: ''' (gdb) -stack-list-arguments 0 ^done, stack-args=[ frame={level="0",args=[name="x",name="y"]}, frame={level="1",args=[]}, frame={level="2",args=[name="num1",name="num2"]}, frame={level="3",args=[]}, frame={level="4",args=[]}] ''' After change: ''' (gdb) -stack-list-arguments 0 ^done, stack-args=[ frame={level="0",args=[name="x",name="y"]}, frame={level="1",args=[name="num1",name="num2"]}, frame={level="2",args=[]}] ''' The test gdb.mi/mi-func-treampoline is updated for testing the change. --- gdb/doc/gdb.texinfo | 3 +++ gdb/mi/mi-cmd-stack.c | 7 +++++++ gdb/testsuite/gdb.mi/mi-func-trampoline.exp | 13 ++++++++++--- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 684716a869e..99909984241 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -35815,6 +35815,9 @@ variable object is updated, @value{GDBN} makes sure that the thread/frame combination the variable object is bound to still exists, and re-evaluates the variable object in context of that thread/frame. +If the option @code{skip-trampoline-functions} is set, @value{GDBN} will +not show trampoline functions in the stack. + The following is the complete set of @sc{gdb/mi} operations defined to access this functionality: diff --git a/gdb/mi/mi-cmd-stack.c b/gdb/mi/mi-cmd-stack.c index 1f66c02f8b4..66c758bd44e 100644 --- a/gdb/mi/mi-cmd-stack.c +++ b/gdb/mi/mi-cmd-stack.c @@ -401,6 +401,13 @@ mi_cmd_stack_list_args (const char *command, const char *const *argv, int argc) i++, fi = get_prev_frame (fi)) { QUIT; + if (skip_trampoline_functions) + { + for (int j = 0; (SAFE_TRAMPOLINE_CHAIN (j, fi) + && in_trampoline_frame (fi)); ++j) + fi = get_prev_frame (fi); + } + ui_out_emit_tuple tuple_emitter (uiout, "frame"); uiout->field_signed ("level", i); list_args_or_locals (user_frame_print_options, diff --git a/gdb/testsuite/gdb.mi/mi-func-trampoline.exp b/gdb/testsuite/gdb.mi/mi-func-trampoline.exp index f40a9722f91..4e0c3922eb6 100644 --- a/gdb/testsuite/gdb.mi/mi-func-trampoline.exp +++ b/gdb/testsuite/gdb.mi/mi-func-trampoline.exp @@ -13,9 +13,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Test -stack-list-frames command for functions with trampoline -# calls. Also checks if trampoline frames are filtered while printing -# stack. +# Test -stack-list-frames and -stack-list-arguments command for functions +# with trampoline calls. Also checks if trampoline frames are filtered +# while printing stack. require allow_fortran_tests @@ -55,6 +55,10 @@ set frame1_regx "\{level=\"0\",addr=\"$hex\",func=\"second\",file=\".*func-tramp set frame2_regx "\{level=\"2\",addr=\"$hex\",func=\"first\",.*\}" set frame3_regx "\{level=\"4\",addr=\"$hex\",func=\"func_trampoline\",.*\}" +set arg1_regx "\{level=\"0\",args=\\\[name=\"x\",name=\"y\"\\\]\}" +set arg2_regx "\{level=\"1\",args=\\\[name=\"num1\",name=\"num2\"\\\]\}" +set arg3_regx "\{level=\"2\",args=\\\[\\\]\}" + # Set breakpoint inside the innermost function 'second'. mi_create_breakpoint "-t $srcfile:$inner_loc" \ "insert breakpoint at line $inner_loc " \ @@ -67,3 +71,6 @@ mi_expect_stop \ mi_gdb_test "100-stack-list-frames" \ "100\\^done,stack=\\\[frame=${frame1_regx},frame=${frame2_regx},frame=${frame3_regx}\\\]" + +mi_gdb_test "200-stack-list-arguments 0" \ + "200\\^done,stack-args=\\\[frame=${arg1_regx},frame=${arg2_regx},frame=${arg3_regx}\\\]" From patchwork Mon Aug 3 19:34:49 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Ijaz, Abdul B" X-Patchwork-Id: 140537 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E43454BB24DB for ; Mon, 3 Aug 2026 19:37:32 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E43454BB24DB Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=lYEKOxBm X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.19]) by sourceware.org (Postfix) with ESMTPS id 6911D4BA23E6 for ; Mon, 3 Aug 2026 19:36:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6911D4BA23E6 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 6911D4BA23E6 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=192.198.163.19 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785819; cv=none; b=ECNndDdjtXUlWgRG3bEjAndf2ORkoKjMK1Yp+0wIZe4o5WrxNbyksg2e5z96me1qqy0A0YQrPYvTQTTEJwZPVHteAHpflpSQB7hB2179fRrR/DKbOUzAB7usR869uiQkjY981rFcqooP6kyNr1//Ucyt13wa093oai6IkV/qeX4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1785785819; c=relaxed/simple; bh=kjFOYUHhhlyOnYE1LEUCqgm9k+u4EJg6IzdJRBKQhKc=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=GiKKdjm4Zy1Brvb4rmPxw/buSugb6GoNlt943B2BVbUtgKZ0GWJZk6y2QRLOEFaqu1Tjz9XXEi5M0MSR1T61463XrPIV38ktE8NjuAbgwisDw4zXEikRLNucUe4SVYNCKr8tGJ+upz9TRl5EqxAE8a0FRlxxDyC3Lr8Dob4WBjU= ARC-Authentication-Results: i=1; sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1785785819; x=1817321819; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=kjFOYUHhhlyOnYE1LEUCqgm9k+u4EJg6IzdJRBKQhKc=; b=lYEKOxBmNgaTf/Cy3eOhy/WP+6217vqxaREGFyRMsDfeheLOviMGMVB6 mk23nw1pyEEkAge5jAivv/LlIjttncFMnvBUBzl+XFUpDgoTomgY7PsZ5 P8/6fXgNvewfQ09FPgBRntJpujcFLXOqfMC0iQTE2GH6cE7ZK/1N00IyH pPothFMq/1LgD5raslXSy68LB4HJl+w7g8EvEdGqq/ScuUYZq53f/iINP C723D2ew6HP4Rv5r/BEMnowZa1O4YTacos85DOpii6Ium5KsRk8Wfyfzp kncrrhCvIwONY2DL6o6HyjJGOUByrYzK0yI357C9sFw+L5cnsU5NCa3/r g==; X-CSE-ConnectionGUID: 2Bb3g2y1QNy8y1uG8Ou2hA== X-CSE-MsgGUID: k92WBOPuTCWptnQZfzHmSw== X-IronPort-AV: E=McAfee;i="6800,10657,11864"; a="85309496" X-IronPort-AV: E=Sophos;i="6.25,203,1779174000"; d="scan'208";a="85309496" Received: from fmviesa003.fm.intel.com ([10.60.135.143]) by fmvoesa113.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:36:27 -0700 X-CSE-ConnectionGUID: p8cr1+iNRk2jP8STdDiOsQ== X-CSE-MsgGUID: CZ+QBnepTkOZpBgigK0lOw== X-ExtLoop1: 1 Received: from fdaddami-mobl1.amr.corp.intel.com (HELO localhost) ([10.245.115.173]) by fmviesa003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2026 12:36:25 -0700 From: Abdul Basit Ijaz To: gdb-patches@sourceware.org Cc: abdul.b.ijaz@intel.com, JiniSusan.George@amd.com, tom@tromey.com, eliz@gnu.org Subject: [PATCH v11 10/10] gdb: Filter trampoline frames in backtrace when using Python frame-filters. Date: Mon, 3 Aug 2026 21:34:49 +0200 Message-Id: <20260803193449.33375-11-abdul.b.ijaz@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260803193449.33375-1-abdul.b.ijaz@intel.com> References: <20260803193449.33375-1-abdul.b.ijaz@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, TXREP, T_SPF_TEMPERROR shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org In case of the Python frame-filters, this change filters trampoline functions when the option 'skip-trampoline-functions' is set to 'on'. GDB recently added the option to hide frames that are marked by the compiler with "DW_AT_trampoline", see commit 'Skip trampoline frames for the backtrace command'. This implements the same functionality when python frame filters are in use. In this example the IFX compiler emits "DW_AT_trampoline" tag for the 'first' and 'second' trampoline functions like following: function second (x, y) result(z) integer, intent(in) :: x, y integer :: z z = x * y ! breakpt-framefilter end function second function first (num1, num2) result(total) integer, intent(in) :: num1, num2 integer :: total total = second (num1 + 4, num2 * 3) ! first-breakpt total = total + 30 end function first Related Dwarf: 0x0000013f: DW_TAG_subprogram DW_AT_low_pc (0x0000000000404350) DW_AT_high_pc (0x000000000040435f) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("second_.t74p.t75p") DW_AT_name ("second_.t74p.t75p") DW_AT_trampoline ("second_") 0x0000015a: DW_TAG_subprogram DW_AT_low_pc (0x00000000004044a0) DW_AT_high_pc (0x00000000004044af) DW_AT_frame_base (DW_OP_reg6 RBP) DW_AT_linkage_name ("first_.t104p.t105p") DW_AT_name ("first_.t104p.t105p") DW_AT_trampoline ("first_") Once frame filters are enabled the backtrace command output before this change looks like: ''' (gdb) info frame-filter global frame-filters: Priority Enabled Name 100 Yes TestTrampolineFrameFilter (gdb) backtrace 3 \#0 second (x=20, y=9) at test.f90:4 \#1 0x0000000000405209 in second_.t74p.t75p () at test.f90:12 \#2 0x00000000004051e3 in first (num1=16, num2=3) at test.f90:10 (gdb) backtrace -3 \#2 0x00000000004051e3 in first (num1=16, num2=3) at test.f90:10 \#3 0x0000000000405309 in first_.t95p.t96p () at test.f90:21 \#4 0x0000000000405234 in func_trampoline () at test.f90:17 ''' After this change: ''' (gdb) info frame-filter global frame-filters: Priority Enabled Name 100 Yes TestTrampolineFrameFilter (gdb) backtrace 3 \#0 second (x=20, y=9) at test.f90:4 \#2 0x00000000004051e3 in first (num1=16, num2=3) at test.f90:10 \#4 0x0000000000405234 in func_trampoline () at test.f90:17 (gdb) backtrace -3 \#2 0x00000000004051e3 in first (num1=16, num2=3) at test.f90:10 \#4 0x0000000000405234 in func_trampoline () at test.f90:17 ''' New test gdb.python/py-framefilter-trampoline.exp is added to test this change. --- gdb/python/py-frame.c | 11 +++ .../gdb.python/py-framefilter-trampoline.exp | 77 +++++++++++++++++++ .../gdb.python/py-framefilter-trampoline.py | 31 ++++++++ 3 files changed, 119 insertions(+) create mode 100644 gdb/testsuite/gdb.python/py-framefilter-trampoline.exp create mode 100644 gdb/testsuite/gdb.python/py-framefilter-trampoline.py diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c index afa89f0d112..098b37230e1 100644 --- a/gdb/python/py-frame.c +++ b/gdb/python/py-frame.c @@ -59,6 +59,17 @@ frame_object_to_frame_info (PyObject *obj) if (frame == NULL) return NULL; + if (skip_trampoline_functions) + { + for (int i = 0; (SAFE_TRAMPOLINE_CHAIN (i, frame) + && in_trampoline_frame (frame)); ++i) + { + frame = get_prev_frame (frame); + if (frame == nullptr) + return nullptr; + } + } + return frame; } diff --git a/gdb/testsuite/gdb.python/py-framefilter-trampoline.exp b/gdb/testsuite/gdb.python/py-framefilter-trampoline.exp new file mode 100644 index 00000000000..23fd22164ef --- /dev/null +++ b/gdb/testsuite/gdb.python/py-framefilter-trampoline.exp @@ -0,0 +1,77 @@ +# Copyright (C) 2026 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is part of the GDB testsuite. It tests skipping of trampolines +# in the backtrace command in case Python-based frame-filters are enabled. + +load_lib gdb-python.exp + +require allow_python_tests allow_fortran_tests + +if {![test_compiler_info {ifx-*} f90]} { + untested "This test is only applicable for IFX, which emits the\ + trampoline DIE in Dwarf." + return +} + +load_lib fortran.exp + +set testfile py-framefilter-trampoline +set srcfile "${srcdir}/gdb.fortran/func-trampoline.f90" +set binfile [standard_output_file $testfile] + +if {[build_executable $testfile.exp $testfile $srcfile {debug f90}] == -1} { + return +} + +# Start with a fresh gdb. +gdb_exit +gdb_start + +gdb_test "info frame-filter" \ + "No frame filters\\." \ + "info frame filter before loading filters" + +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if {![runto_main]} { + return +} +gdb_test_no_output "set python print-stack full" \ + "set python print-stack to full" + +# Load frame-filters +set remote_python_file [gdb_remote_download host \ + ${srcdir}/${subdir}/${testfile}.py] +gdb_test_no_output "source ${remote_python_file}" "load python file" + +set inner_loc [gdb_get_line_number "second-breakpt"] +set middle_loc [gdb_get_line_number "first-breakpt"] +set outer_loc [gdb_get_line_number "main-outer-loc"] +set fill "\[^\r\n\]*" + +set inner_desc "second \\(x=20, y=9\\) at ${fill}$srcfile:$inner_loc" +set middle_desc "first \\(num1=16, num2=3\\) at ${fill}$srcfile:$middle_loc" +set outer_desc ".* at .*$srcfile:$outer_loc" + +# Set breakpoint inside the innermost function 'second'. +gdb_breakpoint "$srcfile:$inner_loc" +gdb_continue_to_breakpoint "innermost-body" ".*$srcfile:$inner_loc.*" + +# Test with frame filter. +gdb_test "bt" [multi_line \ + "#$decimal.* $middle_desc" \ + "#$decimal.* $outer_desc.*"] diff --git a/gdb/testsuite/gdb.python/py-framefilter-trampoline.py b/gdb/testsuite/gdb.python/py-framefilter-trampoline.py new file mode 100644 index 00000000000..0cdaf7bb4de --- /dev/null +++ b/gdb/testsuite/gdb.python/py-framefilter-trampoline.py @@ -0,0 +1,31 @@ +# Copyright (C) 2026 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is part of the GDB testsuite. It tests if trampolines are +# skipped when Python-based frame-filters are enabled. + +import gdb + +class TestTrampolineFrameFilter(): + def __init__(self): + self.name = "TestTrampolineFrameFilter" + self.priority = 100 + self.enabled = True + gdb.frame_filters[self.name] = self + + def filter(self, frame_iter): + return frame_iter + +TestTrampolineFrameFilter()