From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp00.avonet.cz (smtp00.avonet.cz [217.112.162.55]) by sourceware.org (Postfix) with ESMTP id D2B6A3858CDA for ; Tue, 10 Jan 2023 16:33:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D2B6A3858CDA Authentication-Results: sourceware.org; dmarc=fail (p=none dis=none) header.from=fbl.cz Authentication-Results: sourceware.org; spf=fail smtp.mailfrom=fbl.cz Received: from ktus.lan (217-115-245-101.cust.avonet.cz [217.115.245.101]) by smtp00.avonet.cz (Postfix) with ESMTP id 4NrxG66cfJz1xqY for ; Tue, 10 Jan 2023 17:33:50 +0100 (CET) Received: by ktus.lan (Postfix, from userid 209) id CCCD231BEC0; Tue, 10 Jan 2023 17:33:50 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-Spam-Level: X-Spam-Status: No, score=-5.3 required=5.0 tests=BAYES_00,BODY_8BITS,KAM_DMARC_NONE,KAM_DMARC_STATUS,NICE_REPLY_A,SPF_HELO_NONE,TXREP,T_SPF_PERMERROR autolearn=no autolearn_force=no version=3.4.6 Received: from [192.168.33.9] (217-115-245-101.cust.avonet.cz [217.115.245.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: vanekt) by ktus.lan (Postfix) with ESMTPSA id 83F8131BEBC; Tue, 10 Jan 2023 17:33:43 +0100 (CET) Message-ID: Date: Tue, 10 Jan 2023 17:33:42 +0100 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Thunderbird/91.13.1 Subject: Re: [PATCH v2] gdb: Modify until_break_command to act correctly on SIGTRAMP_FRAME Content-Language: en-GB To: Simon Marchi , gdb-patches@sourceware.org References: <1666353538-15846-1-git-send-email-vanekt@fbl.cz> From: Tomas Vanek In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit List-Id: On 10/01/2023 16:31, Simon Marchi wrote: > > 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 > Hi Tomas, > > In order to better understand if this is the right fix, can you describe > what the different frames are in this situation, starting with the > current frame? I'd like to see what the frame ids and frame types are. > > Is there any chance this could be reproduced using the GDB simulator (or maybe > qemu), so I could tinker with it? > > Simon Hi Simon, I'm not familiar with GDB sim nor qemu and have no idea if their Cortex-M profile implementation is precise enough to get the same behaviour. I'll give it a try... Please see gdb debug output, I marked compute_frame_id results. This is a real Cortex-M device (this time STM32H7A3) right after reset, OpenOCD used as gdb server: (gdb) maintenance flush register-cache Register cache flushed. (gdb) set debug frame 1 (gdb) bt -past-entry [frame] get_prev_frame_always_1: enter   [frame] get_prev_frame_always_1: this_frame=-1   [frame] get_prev_frame_always_1:   -> {level=0,type=,unwinder=,pc=0x800609c,id=,func=} // cached [frame] get_prev_frame_always_1: exit [frame] get_prev_frame_always_1: enter   [frame] get_prev_frame_always_1: this_frame=-1   [frame] get_prev_frame_always_1:   -> {level=0,type=,unwinder=,pc=0x800609c,id=,func=} // cached [frame] get_prev_frame_always_1: exit [frame] compute_frame_id: enter   [frame] compute_frame_id: fi=0   [frame] frame_unwind_find_by_frame: enter     [frame] frame_unwind_find_by_frame: this_frame=0     [frame] frame_unwind_try_unwinder: trying unwinder "dummy"     [frame] frame_unwind_try_unwinder: no     [frame] frame_unwind_try_unwinder: trying unwinder "dwarf2 tailcall"     [frame] frame_unwind_try_unwinder: no     [frame] frame_unwind_try_unwinder: trying unwinder "inline"     [frame] frame_unwind_try_unwinder: no     [frame] frame_unwind_try_unwinder: trying unwinder "jit"     [frame] frame_unwind_try_unwinder: no     [frame] frame_unwind_try_unwinder: trying unwinder "arm m exception lockup sec_fnc"     [frame] frame_unwind_try_unwinder: no     [frame] frame_unwind_try_unwinder: trying unwinder "arm stub"     [frame] frame_unwind_try_unwinder: no     [frame] frame_unwind_try_unwinder: trying unwinder "dwarf2"     [frame] frame_unwind_try_unwinder: no     [frame] frame_unwind_try_unwinder: trying unwinder "dwarf2 signal"     [frame] frame_unwind_try_unwinder: no     [frame] frame_unwind_try_unwinder: trying unwinder "arm exidx"     [frame] frame_unwind_try_unwinder: no     [frame] frame_unwind_try_unwinder: trying unwinder "arm epilogue"     [frame] frame_unwind_register_value: enter       [frame] frame_unwind_register_value: frame=-1, regnum=25(xPSR)       [frame] frame_unwind_register_value:   -> register=25 bytes=[00000001]     [frame] frame_unwind_register_value: exit     [frame] frame_unwind_try_unwinder: no     [frame] frame_unwind_try_unwinder: trying unwinder "arm prologue"     [frame] frame_unwind_try_unwinder: yes   [frame] frame_unwind_find_by_frame: exit   [frame] frame_unwind_register_value: enter     [frame] frame_unwind_register_value: frame=-1, regnum=13(sp)     [frame] frame_unwind_register_value:   -> register=13 bytes=[00000220]   [frame] frame_unwind_register_value: exit   [frame] frame_unwind_register_value: enter     [frame] frame_unwind_register_value: frame=-1, regnum=91(msp)     [frame] frame_unwind_register_value:   -> register=91 bytes=[00000220]   [frame] frame_unwind_register_value: exit   [frame] frame_unwind_register_value: enter     [frame] frame_unwind_register_value: frame=-1, regnum=92(psp)     [frame] frame_unwind_register_value:   -> register=92 bytes=[00000000]   [frame] frame_unwind_register_value: exit   [frame] frame_unwind_register_value: enter     [frame] frame_unwind_register_value: frame=-1, regnum=25(xPSR)     [frame] frame_unwind_register_value:   -> register=25 bytes=[00000001]   [frame] frame_unwind_register_value: exit   [frame] frame_unwind_register_value: enter     [frame] frame_unwind_register_value: frame=-1, regnum=13(sp)     [frame] frame_unwind_register_value:   -> register=13 bytes=[00000220]   [frame] frame_unwind_register_value: exit   [frame] get_frame_func_if_available: this_frame=0 -> 0x800609c   [frame] frame_id_p: l={stack=0x20020000,code=0x000000000800609c,!special} -> 1   [frame] compute_frame_id:   -> {stack=0x20020000,code=0x000000000800609c,!special} <------- *current frame* [frame] compute_frame_id: exit #0  Reset_Handler ([frame] frame_id_p: l={!stack,!code,!special} -> 0 ) at startup_stm32h7a3xx.s:62 [frame] operator==: l={stack=0x20020000,code=0x000000000800609c,!special}, r={!stack,!code,!special} -> 0 [frame] get_prev_frame: enter   [frame] get_prev_frame_always_1: enter     [frame] get_prev_frame_always_1: this_frame=0     [frame] get_prev_frame_raw:   -> {level=1,type=,unwinder=,pc=,id=,func=}     [frame] compute_frame_id: enter       [frame] compute_frame_id: fi=1       [frame] frame_unwind_find_by_frame: enter         [frame] frame_unwind_find_by_frame: this_frame=1         [frame] frame_unwind_arch: next_frame=0 -> armv7e-m         [frame] frame_unwind_try_unwinder: trying unwinder "dummy"         [frame] frame_unwind_try_unwinder: no         [frame] frame_unwind_try_unwinder: trying unwinder "dwarf2 tailcall"         [frame] frame_unwind_try_unwinder: no         [frame] frame_unwind_try_unwinder: trying unwinder "inline"         [frame] frame_unwind_register_value: enter           [frame] frame_unwind_register_value: frame=0, regnum=15(pc)           [frame] frame_unwind_register_value: enter             [frame] frame_unwind_register_value: frame=0, regnum=14(lr)             [frame] frame_id_p: l={stack=,!code,special=0x0000000000000000} -> 1             [frame] frame_id_p: l={stack=,!code,special=0x0000000000000000} -> 1             [frame] operator==: l={stack=,!code,special=0x0000000000000000}, r={stack=,!code,special=0x0000000000000000} -> 1             [frame] frame_unwind_register_value: enter               [frame] frame_unwind_register_value: frame=-1, regnum=14(lr)               [frame] frame_unwind_register_value:   -> register=14 bytes=[ffffffff]             [frame] frame_unwind_register_value: exit             [frame] frame_id_p: l={stack=,!code,special=0x0000000000000000} -> 1             [frame] operator==: l={stack=,!code,special=0x0000000000000000}, r={stack=,!code,special=0x0000000000000000} -> 1             [frame] get_prev_frame_always_1: enter               [frame] get_prev_frame_always_1: this_frame=-1               [frame] get_prev_frame_always_1:   -> {level=0,type=NORMAL_FRAME,unwinder="arm prologue",pc=0x800609c,id={stack=0x20020000,code=0x000000000800609c,!special},func=0x800609c} //  cached             [frame] get_prev_frame_always_1: exit             [frame] value_fetch_lazy_register: (frame=0, regnum=14(lr), ...) -> register=14 bytes=[ffffffff]             [frame] frame_unwind_register_value:   -> register=14 bytes=[ffffffff]           [frame] frame_unwind_register_value: exit           [frame] frame_unwind_register_value:   -> computed bytes=[ffffffff]         [frame] frame_unwind_register_value: exit         [frame] frame_unwind_pc: this_frame=0 -> 0xffffffff         [frame] frame_unwind_try_unwinder: no         [frame] frame_unwind_try_unwinder: trying unwinder "jit"         [frame] frame_unwind_try_unwinder: no         [frame] frame_unwind_try_unwinder: trying unwinder "arm m exception lockup sec_fnc"         [frame] frame_unwind_try_unwinder: yes       [frame] frame_unwind_find_by_frame: exit       [frame] frame_unwind_register_value: enter         [frame] frame_unwind_register_value: frame=0, regnum=13(sp)         [frame] frame_unwind_register_value:   -> computed bytes=[00000220]       [frame] frame_unwind_register_value: exit       [frame] frame_unwind_register_value: enter         [frame] frame_unwind_register_value: frame=0, regnum=91(msp)         [frame] frame_unwind_register_value:   -> computed bytes=[00000220]       [frame] frame_unwind_register_value: exit       [frame] frame_unwind_register_value: enter         [frame] frame_unwind_register_value: frame=0, regnum=92(psp)         [frame] frame_unwind_register_value:   -> computed bytes=[00000000]       [frame] frame_unwind_register_value: exit       [frame] frame_id_p: l={stack=0x0,code=0x00000000ffffffff,!special} -> 1       [frame] compute_frame_id:   -> {stack=0x0,code=0x00000000ffffffff,!special}        <----- *magic value 0xffffffff in LR indicates there is no caller*     [frame] compute_frame_id: exit   [frame] get_prev_frame_always_1: exit [frame] get_prev_frame: exit #1  [frame] operator==: l={stack=0x0,code=0x00000000ffffffff,!special}, r={!stack,!code,!special} -> 0 [frame] get_prev_frame: enter   [frame] get_prev_frame_always_1: enter     [frame] get_prev_frame_always_1: this_frame=1     [frame] get_prev_frame_always_1:   -> nullptr // UNWIND_OUTERMOST   [frame] get_prev_frame_always_1: exit [frame] get_prev_frame: exit [frame] get_prev_frame_always_1: enter   [frame] get_prev_frame_always_1: this_frame=1   [frame] get_prev_frame_always_1:   -> nullptr // UNWIND_OUTERMOST // cached [frame] get_prev_frame_always_1: exit [frame] get_prev_frame_always_1: enter   [frame] get_prev_frame_always_1: this_frame=-1   [frame] get_prev_frame_always_1:   -> {level=0,type=NORMAL_FRAME,unwinder="arm prologue",pc=0x800609c,id={stack=0x20020000,code=0x000000000800609c,!special},func=0x800609c} // cached [frame] get_prev_frame_always_1: exit The situation when stopped in an ISR is similar, just the magic value differs e.g. 0xfffffff1 and other frames follows.