From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id P8OPH9pLNWqiZw8AWB0awg (envelope-from ) for ; Fri, 19 Jun 2026 10:02:02 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=V1YHmWTe; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=P2xcQAML; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=V1YHmWTe; dkim=neutral header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=P2xcQAML; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 6F49B1E024; Fri, 19 Jun 2026 10:02:02 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-5.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [IPv6:2620:52:6:3111::32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id D90801E024 for ; Fri, 19 Jun 2026 10:02:00 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A19C64BAE7D4 for ; Fri, 19 Jun 2026 14:01:59 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A19C64BAE7D4 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=V1YHmWTe; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=P2xcQAML; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=V1YHmWTe; dkim=neutral header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=P2xcQAML Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2a07:de40:b251:101:10:150:64:2]) by sourceware.org (Postfix) with ESMTPS id 8779A4BA799B for ; Fri, 19 Jun 2026 14:01:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8779A4BA799B Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=suse.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=suse.de ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 8779A4BA799B Authentication-Results: sourceware.org; arc=none smtp.remote-ip=2a07:de40:b251:101:10:150:64:2 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1781877690; cv=none; b=gzoq8UFtBt2gBATuMx0tIGgWFEeAcxUU+guBULNkTUUFP3W6+2l5sJzeBI53DXvkarolur+XeWDMemWPm+sbFGD2Ry9lceQE7lDQynJIFmsAzTuDRGBkbwCvCGg6vd4+FsgM6x64DVHRgrIxpJ7Q8+YD9xSjeCnflz+Rd4Rf75M= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1781877690; c=relaxed/simple; bh=gzfh150Q9PYLO+1TyPIJOBsFTJeLwTk/ogr1PgKmmyo=; h=DKIM-Signature:DKIM-Signature:DKIM-Signature:DKIM-Signature: Message-ID:Date:MIME-Version:Subject:To:From; b=cku2bIF0A15FRNcuRMPd1U4RlGj8AKTTIdon4XJe620o9n6fxc/J+XP8Q2lq1T1WtRcKnFzu99ksBPEn+gia1A+unUCICSDL/UEfaO0JDKjwMU6cXQ6AC556FORP7L15j5MRwWpfEFLfV4GmSAluEjG1Cm79s2a6X9xhBm/j9Jc= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=V1YHmWTe; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=P2xcQAML; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=V1YHmWTe; dkim=neutral header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=P2xcQAML DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8779A4BA799B Received: from imap1.dmz-prg2.suse.org (unknown [10.150.64.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 7F57A75D80; Fri, 19 Jun 2026 14:01:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1781877689; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0fBBIrgr5PZTiIyRVH3NokkFVrdNUD4926hZD7d7678=; b=V1YHmWTezYGD+H4vHTVDe10pPXmRFD0BUKsZmcRnaiewpxotBVVnTnHw1unsJ/SMfOEhJ1 WNsnagF1AgDJql7wL7CdtL87M6FSqIplGOcOdYRCDP5KUeUsj1PvGnFbDRXbZlbg/fBIi2 yITZFQTMYRIVC/KCQZgAqg1ptXSQVtU= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1781877689; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0fBBIrgr5PZTiIyRVH3NokkFVrdNUD4926hZD7d7678=; b=P2xcQAMLnas32gV/ZJexbBE7ZoMjSLq5MaTCQ5uHDxF/j6zKIGwgq7fIXQdbn/qPq8L6t4 doWHHpJv0hb58lDA== Authentication-Results: smtp-out2.suse.de; none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1781877689; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0fBBIrgr5PZTiIyRVH3NokkFVrdNUD4926hZD7d7678=; b=V1YHmWTezYGD+H4vHTVDe10pPXmRFD0BUKsZmcRnaiewpxotBVVnTnHw1unsJ/SMfOEhJ1 WNsnagF1AgDJql7wL7CdtL87M6FSqIplGOcOdYRCDP5KUeUsj1PvGnFbDRXbZlbg/fBIi2 yITZFQTMYRIVC/KCQZgAqg1ptXSQVtU= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1781877689; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0fBBIrgr5PZTiIyRVH3NokkFVrdNUD4926hZD7d7678=; b=P2xcQAMLnas32gV/ZJexbBE7ZoMjSLq5MaTCQ5uHDxF/j6zKIGwgq7fIXQdbn/qPq8L6t4 doWHHpJv0hb58lDA== Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id 68719779A8; Fri, 19 Jun 2026 14:01:29 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id Eh8SGLlLNWoRAwAAD6G6ig (envelope-from ); Fri, 19 Jun 2026 14:01:29 +0000 Message-ID: <290cb329-f501-412b-8830-81b43de86c8d@suse.de> Date: Fri, 19 Jun 2026 16:01:29 +0200 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH] Handle nested Ada functions with gnat-llvm To: Tom Tromey , gdb-patches@sourceware.org References: <20260423191041.2665677-1-tromey@adacore.com> Content-Language: en-US From: Tom de Vries In-Reply-To: <20260423191041.2665677-1-tromey@adacore.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spamd-Result: default: False [-4.30 / 50.00]; BAYES_HAM(-3.00)[100.00%]; NEURAL_HAM_LONG(-1.00)[-1.000]; NEURAL_HAM_SHORT(-0.20)[-0.997]; MIME_GOOD(-0.10)[text/plain]; RCVD_VIA_SMTP_AUTH(0.00)[]; FUZZY_RATELIMITED(0.00)[rspamd.com]; ARC_NA(0.00)[]; MIME_TRACE(0.00)[0:+]; MID_RHS_MATCH_FROM(0.00)[]; RCPT_COUNT_TWO(0.00)[2]; RCVD_TLS_ALL(0.00)[]; DKIM_SIGNED(0.00)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; FROM_HAS_DN(0.00)[]; TO_DN_SOME(0.00)[]; FROM_EQ_ENVFROM(0.00)[]; TO_MATCH_ENVRCPT_ALL(0.00)[]; RCVD_COUNT_TWO(0.00)[2]; DBL_BLOCKED_OPENRESOLVER(0.00)[imap1.dmz-prg2.suse.org:helo, suse.de:email, suse.de:mid] 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~public-inbox=simark.ca@sourceware.org On 4/23/26 9:10 PM, Tom Tromey wrote: > In Ada, a nested function can refer to variables in lexically > enclosing outer scopes. Ordinarily this is implemented in DWARF using > DW_AT_static_link, so that the correct outer function invocation can > be found from the nested function. > > However, LLVM does not implement the DWARF DW_AT_static_link feature, > so this approach isn't possible. > > gnat-llvm, though, implements "unnesting" manually, passing an > activation record parameter to nested functions. This activation > record can be used to find the correct outer frame. > > This patch adds a new language method to enable this. A new test case > is included; this test will fail if the static link or some similar > feature is not implemented (i.e., a naive unwind looking for the next > instance of the outer function will fail). This looks fine to me. Reviewed-By: Tom de Vries Thanks, - Tom > --- > gdb/ada-lang.c | 83 +++++++++++++++++++ > gdb/frame.c | 6 +- > gdb/language.c | 8 ++ > gdb/language.h | 12 +++ > gdb/testsuite/gdb.ada/nested-confounding.exp | 35 ++++++++ > .../gdb.ada/nested-confounding/nested.adb | 52 ++++++++++++ > 6 files changed, 195 insertions(+), 1 deletion(-) > create mode 100644 gdb/testsuite/gdb.ada/nested-confounding.exp > create mode 100644 gdb/testsuite/gdb.ada/nested-confounding/nested.adb > > diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c > index 71a338ce17e..2f2c0227322 100644 > --- a/gdb/ada-lang.c > +++ b/gdb/ada-lang.c > @@ -14038,6 +14038,11 @@ class ada_language : public language_defn > const struct lang_varobj_ops *varobj_ops () const override > { return &ada_varobj_ops; } > > + /* See language.h. */ > + > + frame_info_ptr follow_static_link (const frame_info_ptr &frame) const > + override; > + > protected: > /* See language.h. */ > > @@ -14048,6 +14053,84 @@ class ada_language : public language_defn > } > }; > > +frame_info_ptr > +ada_language::follow_static_link (const frame_info_ptr &frame) const > +{ > + const block *frame_block = get_frame_block (frame, nullptr); > + if (frame_block == nullptr) > + return {}; > + frame_block = frame_block->function_block (); > + > + /* LLVM doesn't implement DW_AT_static_link, but for Ada we can > + search for the pointer to the activation record. Then, we can go > + up the stack and find the frame where this activation record is > + defined. Note that we don't use the activation record directly, > + because that is type-erased and just holds pointers. */ > + symbol *arec = nullptr; > + for (symbol *iter : block_iterator_range (frame_block)) > + { > + /* The activation record argument is an artificial argument > + whose name starts with "AREC". */ > + if (iter->is_argument () && iter->is_artificial () > + && startswith (iter->linkage_name (), "AREC")) > + { > + arec = iter; > + break; > + } > + } > + > + if (arec == nullptr) > + return {}; > + > + /* We aren't interested in ordinary (non-quit) exceptions that might > + occur here -- we just want to return an empty frame if something > + goes wrong. */ > + try > + { > + value *val = read_var_value (arec, frame_block, frame); > + CORE_ADDR arec_address = value_as_address (val); > + > + for (frame_info_ptr frame_iter = get_prev_frame (frame); > + frame_iter != nullptr; > + frame_iter = get_prev_frame (frame_iter)) > + { > + /* Stacks can be quite deep: give the user a chance to stop > + this. */ > + QUIT; > + > + frame_block = get_frame_block (frame_iter, nullptr); > + if (frame_block == nullptr) > + continue; > + frame_block = frame_block->function_block (); > + > + for (symbol *iter : block_iterator_range (frame_block)) > + { > + /* The activation record itself is an artificial > + non-argument of record type, whose name starts with > + "AREC", and that has the same address as the argument > + passed down to the callee. */ > + if (!iter->is_argument () && iter->is_artificial () > + && startswith (iter->linkage_name (), "AREC") > + && iter->type ()->code () == TYPE_CODE_STRUCT) > + { > + value *outer = read_var_value (iter, frame_block, > + frame_iter); > + CORE_ADDR outer_address = outer->address (); > + if (outer_address == arec_address) > + return frame_iter; > + } > + } > + } > + } > + catch (const gdb_exception_error &ex) > + { > + /* Ignore. */ > + } > + > + return {}; > +} > + > + > /* Single instance of the Ada language class. */ > > static ada_language ada_language_defn; > diff --git a/gdb/frame.c b/gdb/frame.c > index 7a83f5e61c0..06f604a8683 100644 > --- a/gdb/frame.c > +++ b/gdb/frame.c > @@ -3245,7 +3245,11 @@ frame_follow_static_link (const frame_info_ptr &initial_frame) > > const struct dynamic_prop *static_link = frame_block->static_link (); > if (static_link == nullptr) > - return {}; > + { > + const language_defn *lang > + = language_def (get_frame_language (initial_frame)); > + return lang->follow_static_link (initial_frame); > + } > > CORE_ADDR upper_frame_base; > > diff --git a/gdb/language.c b/gdb/language.c > index 439ef293622..4e1dc5682f0 100644 > --- a/gdb/language.c > +++ b/gdb/language.c > @@ -917,6 +917,14 @@ language_defn::value_string (struct gdbarch *gdbarch, > > /* See language.h. */ > > +frame_info_ptr > +language_defn::follow_static_link (const frame_info_ptr &frame) const > +{ > + return {}; > +} > + > +/* See language.h. */ > + > struct type * > language_bool_type (const struct language_defn *la, > struct gdbarch *gdbarch) > diff --git a/gdb/language.h b/gdb/language.h > index b43dae66107..75154d9c591 100644 > --- a/gdb/language.h > +++ b/gdb/language.h > @@ -638,6 +638,18 @@ struct language_defn > > virtual const struct lang_varobj_ops *varobj_ops () const; > > + /* Normally a "static link" (a reference to an outer frame) is > + represented by DW_AT_static_link in DWARF. However, some > + compilers do not emit this -- but do provide some > + language-specific way to find the correct outer frame. If the > + ordinary search for a static link fails for a given frame, then > + this method will be called for that frame's language. It should > + either return the correct outer instance, if one exists, or a > + null frame if no such frame exists. */ > + > + virtual frame_info_ptr follow_static_link (const frame_info_ptr &frame) > + const; > + > protected: > > /* This is the overridable part of the GET_SYMBOL_NAME_MATCHER method. > diff --git a/gdb/testsuite/gdb.ada/nested-confounding.exp b/gdb/testsuite/gdb.ada/nested-confounding.exp > new file mode 100644 > index 00000000000..79cf10b3d58 > --- /dev/null > +++ b/gdb/testsuite/gdb.ada/nested-confounding.exp > @@ -0,0 +1,35 @@ > +# 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 . > + > +# A test case for a nested function that requires a static link. > + > +load_lib "ada.exp" > + > +require allow_ada_tests > + > +standard_ada_testfile nested > + > +if {[gdb_compile_ada "${srcfile}" "${binfile}" executable {debug}] != ""} { > + return > +} > + > +clean_restart ${testfile} > +set bp_location [gdb_get_line_number "BREAK" "${testdir}/nested.adb"] > +runto "nested.adb:$bp_location" > + > +# In the innermost call, the passed id and the reference to the outer > +# id are different. > +gdb_test "print id" [quotemeta {$@DECIMAL = 28}] > +gdb_test "print outer_id" [quotemeta {$@DECIMAL = 23}] > diff --git a/gdb/testsuite/gdb.ada/nested-confounding/nested.adb b/gdb/testsuite/gdb.ada/nested-confounding/nested.adb > new file mode 100644 > index 00000000000..44f7c7866fe > --- /dev/null > +++ b/gdb/testsuite/gdb.ada/nested-confounding/nested.adb > @@ -0,0 +1,52 @@ > +-- 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 . > + > +procedure Nested is > + type Proc_Access is access procedure (Id: Integer); > + > + procedure Parent (My_Id : Integer; Call : access procedure (Id: Integer)); > + > + procedure Do_Nothing (Id : Boolean); > + > + procedure Do_Nothing (Id : Boolean) is > + begin > + null; > + end Do_Nothing; > + > + procedure Parent (My_Id : Integer; Call : access procedure (Id: Integer)) is > + procedure Inner (Id : Integer); > + > + Outer_Id : Integer := My_Id; > + > + procedure Inner (Id : Integer) is > + begin > + Do_Nothing (Id = Outer_Id); -- BREAK > + end Inner; > + > + begin > + > + -- This setup ensures that when Inner is reached, the most > + -- recent invocation of Parent will not be the correct one for > + -- the purposes of finding "Outer_Id". > + if Call = null then > + Parent (My_Id + 5, Inner'Access); > + else > + Call (Outer_Id); > + end if; > + end Parent; > + > +begin > + Parent (23, null); > +end Nested; > > base-commit: f797b25fdc7ca4a48c09802082426b71e56898aa