From: Alan Hayward <Alan.Hayward@arm.com>
To: Fredrik Hederstierna <fredrik.hederstierna@verisure.com>
Cc: "gdb-patches\\@sourceware.org" <gdb-patches@sourceware.org>,
nd <nd@arm.com>,
James-Adam Renquinha Henri <arenquinha@cimeq.qc.ca>
Subject: Re: [PATCH] Fix exception stack unwinding for ARM Cortex-M
Date: Wed, 2 Sep 2020 13:24:01 +0000 [thread overview]
Message-ID: <04F0F9D3-6A7D-4F6E-8AE7-93F360CEEA91@arm.com> (raw)
In-Reply-To: <AM6PR10MB21507E7084C758828FC11B1BEF530@AM6PR10MB2150.EURPRD10.PROD.OUTLOOK.COM>
> On 29 Aug 2020, at 09:35, Fredrik Hederstierna <fredrik.hederstierna@verisure.com> wrote:
>
> For Cortex-M targets using floating-point, eg the Cortex-M4F, its not possible to get any call-stack backtrace if setting a breakpoint in ISR.
>
> The exception stack unwinder for Cortex-M does not consider if floating-point registers was stacked or not,
> further the Cortex-M has two stack pointers: MSP (Main Stack Pointer) and PSP (Process Stack Pointer).
> This is not handled when GDB tries to backtrace in the exception stack unwinder.
>
> This patch fixes this, and gives a correct call-stack backtrace from breakpoints set in a handler or ISR.
Thanks for doing this fix. This mostly looks fine, but comments inlined below.
How easy is it to compile a binary that exhibits this behaviour? If so then a
test in testsuite/gdb.arch/ would be nice. For reference, aarch64-sighandler-regs.exp
is a similar test but for AArch64.
>
> Best Regards,
> Fredrik Hederstierna
Have you signed the copyright assignment?
https://sourceware.org/gdb/wiki/ContributionChecklist#FSF_copyright_Assignment
>
> Senior Software Developer
> Verisure Innovation Centre
> Malmoe Sweden
> <gdb-cortex-m-exception-unwind-fix.patch>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 1ff47c3355..1d80e8cfc8 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,9 @@
> +2020-08-29 Fredrik Hederstierna <fredrik.hederstierna@verisure.com>
> + Adam Renquinha <arenquinha@cimeq.qc.ca>
> +
> + * arm-tdep.c (arm_m_exception_cache): Try use correct stack
> + pointer and stack frame offset when unwinding.
> +
Ideally this part should be left separate from the patch as to prevent
merge issues.
> 2020-08-29 Pedro Alves <pedro@palves.net>
>
> * progspace.c (print_program_space): Use all_inferiors. Switch to
> diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
> index 074eedb480..ed7d4b1d37 100644
> --- a/gdb/arm-tdep.c
> +++ b/gdb/arm-tdep.c
> @@ -2923,14 +2923,59 @@ arm_m_exception_cache (struct frame_info *this_frame)
> struct gdbarch *gdbarch = get_frame_arch (this_frame);
> enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> struct arm_prologue_cache *cache;
> + CORE_ADDR lr;
> + CORE_ADDR sp;
> CORE_ADDR unwound_sp;
> LONGEST xpsr;
> + uint32_t main_stack_used;
> + uint32_t extended_frame_used;
>
> cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
> cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
>
> - unwound_sp = get_frame_register_unsigned (this_frame,
> - ARM_SP_REGNUM);
> + /* ARMv7-M Architecture Reference "B1.5.6 Exception entry behavior"
> + describes which bits in LR that define which stack was used prior
> + to the exception and if FPU is used (causing extended stack frame). */
> +
> + lr = get_frame_register_unsigned (this_frame, ARM_LR_REGNUM);
> + sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
> +
> + /* Check if main stack was used. */
> + main_stack_used = ((lr & 0xf) != 0xd);
This took me a while to confirm. Could you mention that you are checking for
SPSEL in the comment. Also, I wonder if it’s worth checking the other bits in lr.
Yes they should be all ones in either case. But I’d rather be a little cautious.
Only go into the else case if all the bits are correct.
> + if (main_stack_used)
> + {
> + /* Main stack used, use MSP as SP. */
> + unwound_sp = sp;
> + }
> + else
> + {
> + /* Thread (process) stack used.
> + Potentially this could be other register defined by target, but PSP
> + can be considered a standard name for the "Process Stack Pointer".
> + To be fully aware of system registers like MSP and PSP, these could
> + be added to a separate XML arm-m-system-profile that is valid for
> + ARMv6-M and ARMv7-M architectures. Also to be able to debug eg a
> + corefile off-line, then these registers must be defined by GDB,
> + and also be included in the corefile regsets. */
> +
> + int psp_regnum = user_reg_map_name_to_regnum (gdbarch, "psp", -1);
> + if (psp_regnum == -1)
> + {
> + /* Thread (process) stack could not be fetched,
> + give warning and exit. */
> +
> + warning (_("no PSP thread stack unwinding supported, exiting."));
I don’t think you mean exit. Maybe just remove “exiting” from the string.
> +
> + /* Terminate any further stack unwinding by refer to self. */
> + cache->prev_sp = sp;
> + return cache;
> + }
> + else
> + {
> + /* Thread (process) stack used, use PSP as SP. */
> + unwound_sp = get_frame_register_unsigned (this_frame, psp_regnum);
> + }
> + }
>
> /* The hardware saves eight 32-bit words, comprising xPSR,
> ReturnAddress, LR (R14), R12, R3, R2, R1, R0. See details in
> @@ -2940,15 +2985,47 @@ arm_m_exception_cache (struct frame_info *this_frame)
> cache->saved_regs[1].addr = unwound_sp + 4;
> cache->saved_regs[2].addr = unwound_sp + 8;
> cache->saved_regs[3].addr = unwound_sp + 12;
> - cache->saved_regs[12].addr = unwound_sp + 16;
> - cache->saved_regs[14].addr = unwound_sp + 20;
> - cache->saved_regs[15].addr = unwound_sp + 24;
> + cache->saved_regs[ARM_IP_REGNUM].addr = unwound_sp + 16;
> + cache->saved_regs[ARM_LR_REGNUM].addr = unwound_sp + 20;
> + cache->saved_regs[ARM_PC_REGNUM].addr = unwound_sp + 24;
> cache->saved_regs[ARM_PS_REGNUM].addr = unwound_sp + 28;
Thanks for switching this to use the enums.
>
> + /* Check if extended stack frame (FPU regs stored) was used. */
> + extended_frame_used = ((lr & (1 << 4)) == 0);
> + if (extended_frame_used)
> + {
> + int i;
> + int fpu_regs_stack_offset;
> +
> + /* This code does not take into account the lazy stacking, see "Lazy
> + context save of FP state", in B1.5.7, also ARM AN298, supported
> + by Cortex-M4F architecture. Give a warning and try do best effort.
> + To fully handle this the FPCCR register (Floating-point Context
> + Control Register) needs to be read out and the bits ASPEN and LSPEN
> + could be checked to setup correct lazy stacked FP registers. */
> +
> + warning (_("no FPU lazy stack unwinding supported, check FPCCR."));
This means that we will always get a warning if the extended frame is used.
I’d rather that didn’t happen.
How easy would be be to check the FPCCR register and then give a warning only if
lazy stacking is being used?
> +
> + fpu_regs_stack_offset = unwound_sp + 0x20;
> + for (i = 0; i < 16; i++)
> + {
> + cache->saved_regs[ARM_D0_REGNUM + i].addr = fpu_regs_stack_offset;
> + fpu_regs_stack_offset += 4;
> + }
> + cache->saved_regs[ARM_FPSCR_REGNUM].addr = unwound_sp + 0x60;
> +
> + /* Offset 0x64 is reserved. */
> + cache->prev_sp = unwound_sp + 0x68;
> + }
> + else
> + {
> + /* Basic frame type used. */
> + cache->prev_sp = unwound_sp + 32;
The mix of hex and decimal in the function is a little glaring.
Could you switch this one to 0x20.
> + }
> +
> /* If bit 9 of the saved xPSR is set, then there is a four-byte
> aligner between the top of the 32-byte stack frame and the
> previous context's stack pointer. */
> - cache->prev_sp = unwound_sp + 32;
> if (safe_read_memory_integer (unwound_sp + 28, 4, byte_order, &xpsr)
> && (xpsr & (1 << 9)) != 0)
> cache->prev_sp += 4;
Thanks,
Alan.
next prev parent reply other threads:[~2020-09-02 13:24 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <AM4PR1001MB0948AC4D9CB635F5A9A2FC82EFDC0@AM4PR1001MB0948.EURPRD10.PROD.OUTLOOK.COM>
[not found] ` <HE1PR1001MB130613C0995C4C21A630373BEF1B0@HE1PR1001MB1306.EURPRD10.PROD.OUTLOOK.COM>
2019-06-10 21:25 ` [PATCH] Fix exception " James-Adam Renquinha Henri
2019-06-12 9:01 ` Alan Hayward
2020-08-29 8:35 ` [PATCH] Fix exception stack " Fredrik Hederstierna
2020-09-02 13:24 ` Alan Hayward [this message]
2020-09-06 9:27 ` Fredrik Hederstierna
2020-09-09 8:12 ` Alan Hayward
2020-09-10 21:00 ` Fredrik Hederstierna
2020-09-14 14:44 ` Alan Hayward
2020-09-14 18:31 ` Joel Brobecker
2020-09-15 14:05 ` Alan Hayward
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=04F0F9D3-6A7D-4F6E-8AE7-93F360CEEA91@arm.com \
--to=alan.hayward@arm.com \
--cc=arenquinha@cimeq.qc.ca \
--cc=fredrik.hederstierna@verisure.com \
--cc=gdb-patches@sourceware.org \
--cc=nd@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).