From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id KdhlOjnLy2mzwQAAWB0awg (envelope-from ) for ; Tue, 31 Mar 2026 09:25:13 -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=SCXAJZNg; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=zio/+jbG; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=SCXAJZNg; dkim=neutral header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=zio/+jbG; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id E9FE11E04F; Tue, 31 Mar 2026 09:25:13 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-2.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,RCVD_IN_MSPIKE_H2,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.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 E04401E04F for ; Tue, 31 Mar 2026 09:25:12 -0400 (EDT) Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 70B4F4BB58AE for ; Tue, 31 Mar 2026 13:25:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 70B4F4BB58AE 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=SCXAJZNg; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=zio/+jbG; dkim=pass (1024-bit key) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=SCXAJZNg; dkim=neutral header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=zio/+jbG Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.223.131]) by sourceware.org (Postfix) with ESMTPS id 2E54D4B920B5 for ; Tue, 31 Mar 2026 13:23:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2E54D4B920B5 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 2E54D4B920B5 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=195.135.223.131 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774963429; cv=none; b=M/ixpj7nrRwzj+YQhI7h43uVjM+Ud1QvAzpLFpDgTBYVn4c8/JFZbkvKFqkAtIcVBmqaIHddvcOxQLFwCEkuG6DjL3/VoWTjMP3dWPZjFCduqOpaaLoYDWe84JJJpa9laudeGWGzNjV9Qh9E6NF4d4UNB03/ExPcDXrwRQ7p2BI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774963429; c=relaxed/simple; bh=kPtlHpscjONW+zZKnCDiCIXHENGd04tu1sc3axCQx7w=; h=DKIM-Signature:DKIM-Signature:DKIM-Signature:DKIM-Signature:From: To:Subject:Date:Message-ID:MIME-Version; b=X+zpzkLveIbNLQlKeWyDnN5d6xx1uJoxBkbzTXZQK9hHgEGigvKf/vKsbx3KSWk0Qy6JEUaLyWEaJQxtRdLGAYpLSswuGf5yXUcZ2p1bP/VSgx6G2NZbUIsefu1mf6k7VtjrfB+aAdPbE2PSp9zNKhdaoCt1/G91GHW1qlKQNUk= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2E54D4B920B5 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 D7F095BDCF for ; Tue, 31 Mar 2026 13:23:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1774963422; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fOn5HYquKKC1V4wz1aZxbz+YgiWv//Jlm9m0sWzVx8o=; b=SCXAJZNguCyaNt+VyEK+YdLVcmswuhNjUY21hKHcezguEGRBzHI2xhawQmyE6/QX2dOf+S hLaoJaZ4BJL+uQ1JXwveNqToBRUUaQI9EBushRnsi5GIPFwL0DE0tC5WHVjtROAbwKQn77 pNhAkNv8NLIijBffsIswDJqUp4BkVbs= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1774963422; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fOn5HYquKKC1V4wz1aZxbz+YgiWv//Jlm9m0sWzVx8o=; b=zio/+jbGs51JjDzoLSvXvvID8R/WcwiygHKpKGVkWBN7l8sB2OoMU8cKHlKtxEgO/jZxdB +1YNAtUm9sUV1iAg== Authentication-Results: smtp-out2.suse.de; none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1774963422; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fOn5HYquKKC1V4wz1aZxbz+YgiWv//Jlm9m0sWzVx8o=; b=SCXAJZNguCyaNt+VyEK+YdLVcmswuhNjUY21hKHcezguEGRBzHI2xhawQmyE6/QX2dOf+S hLaoJaZ4BJL+uQ1JXwveNqToBRUUaQI9EBushRnsi5GIPFwL0DE0tC5WHVjtROAbwKQn77 pNhAkNv8NLIijBffsIswDJqUp4BkVbs= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1774963422; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fOn5HYquKKC1V4wz1aZxbz+YgiWv//Jlm9m0sWzVx8o=; b=zio/+jbGs51JjDzoLSvXvvID8R/WcwiygHKpKGVkWBN7l8sB2OoMU8cKHlKtxEgO/jZxdB +1YNAtUm9sUV1iAg== 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 C340E4A0B2 for ; Tue, 31 Mar 2026 13:23:42 +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 4GKELt7Ky2moUwAAD6G6ig (envelope-from ) for ; Tue, 31 Mar 2026 13:23:42 +0000 From: Tom de Vries To: gdb-patches@sourceware.org Subject: [RFC v2 3/3] [gdb] Fix missing print frame when stepping out of function Date: Tue, 31 Mar 2026 15:23:42 +0200 Message-ID: <20260331132342.1050954-4-tdevries@suse.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260331132342.1050954-1-tdevries@suse.de> References: <20260331132342.1050954-1-tdevries@suse.de> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spamd-Result: default: False [-2.80 / 50.00]; BAYES_HAM(-3.00)[100.00%]; MID_CONTAINS_FROM(1.00)[]; NEURAL_HAM_LONG(-1.00)[-1.000]; R_MISSING_CHARSET(0.50)[]; NEURAL_HAM_SHORT(-0.20)[-0.996]; MIME_GOOD(-0.10)[text/plain]; TO_DN_NONE(0.00)[]; DKIM_SIGNED(0.00)[suse.de:s=susede2_rsa,suse.de:s=susede2_ed25519]; FUZZY_RATELIMITED(0.00)[rspamd.com]; ARC_NA(0.00)[]; RCPT_COUNT_ONE(0.00)[1]; TO_MATCH_ENVRCPT_ALL(0.00)[]; RCVD_COUNT_TWO(0.00)[2]; FROM_HAS_DN(0.00)[]; RCVD_TLS_ALL(0.00)[]; PREVIOUSLY_DELIVERED(0.00)[gdb-patches@sourceware.org]; FROM_EQ_ENVFROM(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[]; MIME_TRACE(0.00)[0:+]; DBL_BLOCKED_OPENRESOLVER(0.00)[imap1.dmz-prg2.suse.org:helo, suse.de:mid, sourceware.org:url] 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 [ This is an RFC. The patch fixes one problem, but introduces another problem. The point of the RFC is the analysis of the second problem. ] Consider test-case gdb.dwarf2/dw2-extend-inline-block.exp, specifically the "contiguous block" prefix part, which can be stepped through like this: ... $ gdb -q outputs/gdb.dwarf2/dw2-extend-inline-block/dw2-extend-inline-block-5 Reading symbols from dw2-extend-inline-block-5... (gdb) start ... Temporary breakpoint 1, main () at dw2-extend-inline-block.c:35 35 /* main:2 */ (gdb) s 36 /* main:3 */ foo (); /* foo call line */ (gdb) foo () at dw2-extend-inline-block.c:26 26 /* foo:1 */ (gdb) s 27 /* foo:2 */ (gdb) s 28 /* foo:3 */ (gdb) s main () at dw2-extend-inline-block.c:37 37 /* main:4 */ (gdb) ... If we slightly modify the line program: ... DW_LNE_set_address main_4 + DW_LNS_advance_line 1 DW_LNS_copy DW_LNE_set_address main_5 - DW_LNS_advance_line 1 DW_LNS_negate_stmt DW_LNS_copy ... we change the 36/0x401165 entry into a 37/0x401165 entry: ... File name Line number Starting address View Stmt dw2-extend-inline-block.c 34 0x401116 x dw2-extend-inline-block.c 35 0x401129 x dw2-extend-inline-block.c 26 0x401138 x dw2-extend-inline-block.c 27 0x401147 x dw2-extend-inline-block.c 28 0x401156 x dw2-extend-inline-block.c 36 0x401156 -dw2-extend-inline-block.c 36 0x401165 +dw2-extend-inline-block.c 37 0x401165 dw2-extend-inline-block.c 37 0x401174 x dw2-extend-inline-block.c 38 0x401183 x dw2-extend-inline-block.c 39 0x401192 x dw2-extend-inline-block.c 40 0x4011a1 x dw2-extend-inline-block.c - 0x4011b7 ... As it happens, the fix to extend truncated inlined function blocks doesn't work in this case. This is PR33930. We can work around this by making sure that the inlined function block isn't truncated in the first place: ... - DW_AT_high_pc main_3 addr + DW_AT_high_pc main_4 addr ... But then we still run into PR33981: the problem that gdb doesn't notify us when stepping out of foo: ... (gdb) step^M 28 /* foo:3 */^M (gdb) step^M 37 /* main:4 */^M (gdb) ... What happens is that the slightly different line program triggers a different stepping path, which includes a case of "stepped to a different frame, but it's not the start of a statement", which refreshes the stepping info and consequently updates tp->control.step_frame_id to the frame id of main. So by the time we're stopped at line 37, and are trying to figure out what to print in print_stop_location, this condition evaluates to true: ... if (tp->control.stop_step && (tp->control.step_frame_id == get_frame_id (get_current_frame ())) && (tp->control.step_start_function == find_symbol_for_pc (tp->stop_pc ()))) ... and we get: ... /* Finished step in same frame and same file, just print source line. */ source_flag = SRC_LINE; ... It's good to realize here that because foo is inlined into main, tp->control.step_start_function is not foo but main, so consequently the step_start_function check (which checks if we are still in the same function) also passes, even though we actually stepped from foo into main. Fix this by using find_symbol_for_pc_maybe_inline instead of find_symbol_for_pc in set_step_start_function and in_step_start_function. Doing so however regresses gdb.opt/inline-cmds.exp. To understand that regression, let's first investigate the behavior without this patch. We step from function main (lines 64/66) into function func1 (35): ... $ gdb -q outputs/gdb.opt/inline-cmds/inline-cmds -ex "tbreak 64" -ex run ... Temporary breakpoint 1, main () at inline-cmds.c:64 64 y = 8; /* set mi break here */ (gdb) step 66 result = func1 (); (gdb) step func1 () at inline-cmds.c:35 35 bar (); (gdb) ... This seems trivial, but it's not. If we list the effects of the two steps in terms of line number and pc, we get: - 64/0x401124 - step - 66/0x40112e - step - 35/0x40112e We're initially stopped at pc 0x401124, and after the first step stopped at pc 0x40112e. Effectively we've entered the inlined function func1 at this point, both according to the line number info (where 0x40112e maps to line 35): ... Line number Starting address View Stmt 60 0x401116 x 63 0x40111a x 64 0x401124 x 35 0x40112e x 36 0x401133 x ... and to the debug info: ... <2><395>: Abbrev Number: 1 (DW_TAG_inlined_subroutine) <396> DW_AT_abstract_origin: <0x4b7> <39a> DW_AT_low_pc : 0x40112e <3a2> DW_AT_high_pc : 0x14 <3aa> DW_AT_call_file : 1 <3aa> DW_AT_call_line : 66 <3ab> DW_AT_call_column : 12 <1><4b7>: Abbrev Number: 5 (DW_TAG_subprogram) <4b8> DW_AT_external : 1 <4b8> DW_AT_name : func1 <4bc> DW_AT_decl_file : 1 <4bc> DW_AT_decl_line : 33 <4bd> DW_AT_decl_column : 17 <4bd> DW_AT_prototyped : 1 <4bd> DW_AT_type : <0x30b> <4c1> DW_AT_inline : 3 (declared as inline and inlined) ... However, we're going to pretend that we're still in main at the call site at line 66, and require another step to land at line 35. This works as follows. When stopping at pc 0x40112e, find_frame_sal is called, where this code: ... if (frame_inlined_callees (frame) > 0) { const symbol *sym; /* If the current frame has some inlined callees, and we have a next frame, then that frame must be an inlined frame. In this case this frame's sal is the "call site" of the next frame's inlined function, which can not be inferred from get_frame_pc. */ next_frame = get_next_frame (frame); if (next_frame) sym = get_frame_function (next_frame); else sym = inline_skipped_symbol (inferior_thread ()); ... selects the line number for the call site, 66. Then we're going to decide what to print in print_stop_location, and decide that since the step started in main, and stopped in main, there no need to print anything else than the line, and so we get: ... (gdb) step 66 result = func1 (); (gdb) ... When executing the second step, prepare_one_step is called, which hits this clause: ... /* Step at an inlined function behaves like "down". */ if (!sm->skip_subroutines && inline_skipped_frames (tp)) { ... /* Pretend that we've ran. */ ... and consequently the pc stays the same. Instead, step_into_inline_frames make a change in the "inline frame state" of the thread, so the next time find_frame_sal is called, the "frame_inlined_callees (frame) > 0" condition no longer triggers, and line 35 is selected. Then when deciding what to print in print_stop_location, the comparison of the frame ids fails, so SRC_AND_LOC is selected and we get: ... (gdb) step func1 () at inline-cmds.c:35 35 bar (); (gdb) ... Now with this patch, instead we get: ... $ gdb -q outputs/gdb.opt/inline-cmds/inline-cmds -ex "tbreak 64" -ex run ... Temporary breakpoint 1, main () at inline-cmds.c:64 64 y = 8; /* set mi break here */ (gdb) s main () at inline-cmds.c:66 66 result = func1 (); (gdb) s func1 () at inline-cmds.c:35 35 bar (); (gdb) ... The problem is that when stepping from line 64 to 66, we seem to be entering main, while that's not the case, because we were already in main. So how does that happen? This time, when deciding what to print in print_stop_location, we observe that we started the step in main, but are stopped in func1 (without the patch, we would have observed that we're stopped in main): ... (gdb) p m_step_start_function.m_name $12 = 0x33cc351 "main" (gdb) p find_symbol_for_pc_maybe_inline (pc).m_name $13 = 0x33cc2e1 "func1" (gdb) ... so we get SRC_AND_LOC. Then when doing the actual printing, the infrastructure does look at the "inline frame state" and concludes that we're actually in main, and so we get: ... (gdb) s main () at inline-cmds.c:66 66 result = func1 (); (gdb) ... In short, AFAIU the problem is that our proposed fix doesn't take the "inline frame state" into account. I hope that doing so will be easy, but I thought it would be a good idea to record the current state using an RFC. Tested on x86_64-linux. Co-Authored-By: Andrew Burgess Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33981 --- gdb/gdbthread.h | 4 +- .../gdb.dwarf2/dw2-extend-inline-block.exp | 45 +++++++++++++++++-- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h index c0a828409a4..6b2d0ba0801 100644 --- a/gdb/gdbthread.h +++ b/gdb/gdbthread.h @@ -129,7 +129,7 @@ struct thread_control_state /* Set step_start_function according to PC. */ void set_step_start_function (CORE_ADDR pc) { - m_step_start_function = find_symbol_for_pc (pc); + m_step_start_function = find_symbol_for_pc_maybe_inline (pc); } /* Reset step_start_function. */ @@ -141,7 +141,7 @@ struct thread_control_state /* Return true if PC is in step_start_function. */ bool in_step_start_function (CORE_ADDR pc) { - return m_step_start_function == find_symbol_for_pc (pc); + return m_step_start_function == find_symbol_for_pc_maybe_inline (pc); } /* Return true if step_start_function is set. */ diff --git a/gdb/testsuite/gdb.dwarf2/dw2-extend-inline-block.exp b/gdb/testsuite/gdb.dwarf2/dw2-extend-inline-block.exp index 9e4798b53f3..3f92c1965d8 100644 --- a/gdb/testsuite/gdb.dwarf2/dw2-extend-inline-block.exp +++ b/gdb/testsuite/gdb.dwarf2/dw2-extend-inline-block.exp @@ -52,8 +52,11 @@ get_func_info main # Create DWARF for the test. In this case, inline function 'foo' is created # with a contiguous address range that needs extending. -proc build_dwarf_for_contiguous_block { asm_file } { +proc build_dwarf_for_contiguous_block { asm_file {range_correct 0} {variant 0}} { Dwarf::assemble $asm_file { + upvar range_correct range_correct + upvar variant variant + declare_labels lines_table inline_func cu { } { @@ -83,7 +86,11 @@ proc build_dwarf_for_contiguous_block { asm_file } { DW_AT_call_file 1 data1 DW_AT_call_line $::foo_call_line data1 DW_AT_low_pc main_1 addr - DW_AT_high_pc main_3 addr + if {$range_correct} { + DW_AT_high_pc main_4 addr + } else { + DW_AT_high_pc main_3 addr + } } } } @@ -120,10 +127,15 @@ proc build_dwarf_for_contiguous_block { asm_file } { DW_LNS_copy DW_LNE_set_address main_4 + if {$variant == 1} { + DW_LNS_advance_line 1 + } DW_LNS_copy DW_LNE_set_address main_5 - DW_LNS_advance_line 1 + if {$variant == 0} { + DW_LNS_advance_line 1 + } DW_LNS_negate_stmt DW_LNS_copy @@ -146,6 +158,22 @@ proc build_dwarf_for_contiguous_block { asm_file } { } } +# Like build_dwarf_for_contiguous_block, but use a slightly different line +# info by setting variant == 1. +# Use range_correct 1, so we're not testing the fix for PR33930. + +proc build_dwarf_for_contiguous_block_2 { asm_file } { + return [build_dwarf_for_contiguous_block $asm_file 1 1] +} + +# Like build_dwarf_for_contiguous_block, but use a slightly different line +# info by setting variant == 1. +# Use range_correct 0, so we're testing the fix for PR33930. + +proc build_dwarf_for_contiguous_block_3 { asm_file } { + return [build_dwarf_for_contiguous_block $asm_file 0 1] +} + # Assuming GDB is stopped at the entry $pc for 'foo', use 'maint info # blocks' to check the block for 'foo' is correct. This function checks # 'foo' created by 'build_dwarf_for_contiguous_block'. @@ -555,6 +583,12 @@ set test_list \ [list "contiguous block" \ build_dwarf_for_contiguous_block \ check_contiguous_block] \ + [list "contiguous block 2" \ + build_dwarf_for_contiguous_block_2 \ + check_contiguous_block] \ + [list "contiguous block 3" \ + build_dwarf_for_contiguous_block_3 \ + check_contiguous_block] \ ] # Run all the tests. @@ -566,6 +600,11 @@ foreach test_spec $test_list { set build_dwarf_func [lindex $test_spec 1] set check_block_func [lindex $test_spec 2] + if {$build_dwarf_func == "build_dwarf_for_contiguous_block_3"} { + # Work around PR33930. + continue + } + with_test_prefix $prefix { set asm_file [standard_output_file ${testfile}-${suffix}.S] $build_dwarf_func $asm_file -- 2.51.0