From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca (simark.ca [158.69.221.121]) by sourceware.org (Postfix) with ESMTPS id 1BA893858CDA for ; Tue, 10 Jan 2023 17:48:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1BA893858CDA Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=simark.ca Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=simark.ca Received: from [10.0.0.11] (unknown [217.28.27.60]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPSA id D09DD1E0D3; Tue, 10 Jan 2023 12:48:03 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=simark.ca; s=mail; t=1673372883; bh=KuMt73yxbgu+JJ6lsEfK0KmNzrmYiepl0sCASxg1pLg=; h=Date:Subject:To:References:From:In-Reply-To:From; b=Gvxc3iRB4vIsmWVUmshHqfI+sngH06uYsjsccuRWUSdwqvOitXwMoGSqy75ewG77z aAcwvGScMSzA/5lx0BEC+CpR1ag7XM0RPEAozGxM7YOP0/q9rbWgC2OyiZ4o6hFXrE iTPexd9o3PyXB04FcGj3Q9rlelxXESE7XkbiSqKc= Message-ID: Date: Tue, 10 Jan 2023 12:48:03 -0500 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.6.1 Subject: Re: [PATCH v2] gdb: Modify until_break_command to act correctly on SIGTRAMP_FRAME Content-Language: en-US To: Tomas Vanek , gdb-patches@sourceware.org References: <1666353538-15846-1-git-send-email-vanekt@fbl.cz> From: Simon Marchi In-Reply-To: <1666353538-15846-1-git-send-email-vanekt@fbl.cz> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,NICE_REPLY_A,SPF_HELO_PASS,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On 10/21/22 07:58, Tomas Vanek wrote: > This patch partially depends on > gdb/arm: Terminate frame unwinding in M-profile lockup state > (without it lockup state is unwound as if it were a normal > stack frame). > > The commands 'advance' and 'until' try to set a breakpoint > on the bogus return address derived from Arm M-profile magic > address (actually EXC_RETURN or a PC value indicating lockup). > > The offending breakpoint should be set at the return address in > the caller. The magic value 0xffffffff in LR indicates > there is no caller (return to this address would lock up the CPU). > > Similar behaviour of 'advance' and 'until' is observed in > an exception handler routine. In this case LR contains e.g. > 0xfffffff1 (EXC_RETURN) and GDB tries to set a breakpoint at > 0xfffffff0. It should use a return value stacked by the exception > instead. > > Testbench setup: > STM32G474, a Cortex-M4 device. Any Cortex-M device can be used. > A test application (an ordinary blink) with a standard startup > is loaded to the device flash. > > Steps to reproduce the problem: > > start GDB server > $ openocd -f interface/cmsis-dap.cfg -f target/stm32g4x.cfg > > start GDB in second terminal > $ arm-none-eabi-gdb blink.elf > > (gdb) target extended-remote localhost:3333 > > Reset the device and halt it: > (gdb) monitor reset halt > target halted due to debug-request, current mode: Thread > xPSR: 0x01000000 pc: 0x08000e14 msp: 0x20020000 > > Step by one instruction to re-read GDB register cache: > (gdb) stepi > > Check registers, LR should be 0xffffffff after reset: > (gdb) info registers > ... > sp 0x20020000 0x20020000 > lr 0xffffffff -1 > pc 0x8000e16 0x8000e16 > xPSR 0x1000000 16777216 > ... > > (gdb) set debug remote > > Issue 'advance' command: > (gdb) advance main > [remote] Sending packet: $mfffffffe,2#fa > [remote] Packet received: 0000 > [remote] Sending packet: $mfffffffe,2#fa > [remote] Packet received: 0000 > [remote] Sending packet: $m8000526,2#30 > [remote] Packet received: 2046 > [remote] Sending packet: $Z1,8000526,2#7a > [remote] Packet received: OK > [remote] packet_ok: Packet Z1 (hardware-breakpoint) is supported > [remote] Sending packet: $Z0,fffffffe,2#43 > [remote] Packet received: E0E > [remote] packet_ok: Packet Z0 (software-breakpoint) is supported > Warning: > Cannot insert breakpoint 0. > Cannot access memory at address 0xfffffffe > > Command aborted. > (gdb) > > Relevant messages from OpenOCD: > Error: Failed to read memory at 0xfffff000 > Error: can't add breakpoint: unknown reason > > This patch adds skipping over frames that are not suitable for > guarding with a breakpoint inspired by 'finish' command. > If no suitable frame is found, a momentary breakpoint is not set. > > v2: Comment fixes, bug reference. > > Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28683 > Signed-off-by: Tomas Vanek > --- > gdb/breakpoint.c | 22 +++++++++++++++++----- > 1 file changed, 17 insertions(+), 5 deletions(-) > > diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c > index f6591d4..bb85342 100644 > --- a/gdb/breakpoint.c > +++ b/gdb/breakpoint.c > @@ -10467,6 +10467,7 @@ enum async_reply_reason > until_break_command (const char *arg, int from_tty, int anywhere) > { > frame_info_ptr frame; > + frame_info_ptr caller_frame; > struct gdbarch *frame_gdbarch; > struct frame_id stack_frame_id; > struct frame_id caller_frame_id; > @@ -10505,7 +10506,17 @@ enum async_reply_reason > frame = get_selected_frame (NULL); > frame_gdbarch = get_frame_arch (frame); > stack_frame_id = get_stack_frame_id (frame); > - caller_frame_id = frame_unwind_caller_id (frame); > + > + caller_frame = get_prev_frame_always (frame); > + > + while (caller_frame) > + { > + if (get_frame_type (caller_frame) != TAILCALL_FRAME > + && gdbarch_code_of_frame_writable (get_frame_arch (caller_frame), caller_frame)) > + break; > + > + caller_frame = get_prev_frame_always (caller_frame); > + } frame_unwind_caller_id does skip inline frames (through skip_artificial_frames), whereas your version does not, is that correct? I'm wondering if we should make frame_unwind_caller_id / skip_artificial_frames handle it instead. In other words, would other callers of frame_unwind_caller_id / skip_artificial_frames need to skip such frames, and benefit from it. If we do that, frame_unwind_caller_id would return null_frame_id in your case, and I think that until_break_command would not need to be modified. Looking at watch_command_1, for instance, there seems to be the same situation, where we create a temporary breakpoint to detect when we get out of scope: https://gitlab.com/gnutools/binutils-gdb/-/blob/8ec0b0b5df0ebe28c32900afc7ae8ff22b21f381/gdb/breakpoint.c#L10215 I guess if you try to create a watchpoint in that special frame, you'll hit the same problem? >From what I understand, in the ARM case, the sigtramp frame does not represent any code, and has no real PC. When the normal frame #0 returns, control goes back directly to the frame above the sigtramp frame. It does not go execute instructions in the sigtramp frame. Is that right? With Linux on amd64, after returning from the normal frame, control goes to some instructions that will call the sigreturn syscall, so the sigtramp frame does have a real pc. If so, I think that's the distinction we are dealing with here. We want to know what's the first instruction that is going to be executed after leaving the current frame. And it may sometimes be the sigtramp frame, or it may sometimes be the frame above that. Simon