New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
arm: debug: Add GDB stub for aarch32 #58067
Conversation
I'm not sure many of the reviewers here will have a Zync-7000 to test with (I don't). Could this be made to work with |
Yes, it does seem to work on the emulator, except for single stepping. The emulator seems to ignore the mismatch breakpoint and continues the execution. Do you know whether QEMU also emulates these debug registers? I tried to run the |
I'm not sure about the internals myself, but if we have an easy to reproduce qemu sample I can ping the people who would know around me. See point below to that effect.
Since we'll probably want some sort of basic testing for CI for this, could you add those changes for the qemu target in a separate commit, and we can figure out how to put together a basic test scenario from there? |
Added a new commit with those changes. |
EDIT: My mistake, sorry. This is editing the existing sample in |
@povergoing can you take a look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
arch/arm/core/aarch32/gdbstub.c
Outdated
/* Wrapper function to save and restore execution context */ | ||
void z_gdb_entry(z_arch_esf_t *esf, unsigned int exc_cause) | ||
{ | ||
/* Disable the hardware breapoint in case it was set */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: breakpoint
arch/arm/core/aarch32/gdbstub.c
Outdated
uint32_t reg_val = ctx.registers[PC]; | ||
/* set BVR (Breakpoint value register) to PC, make sure it is word aligned */ | ||
reg_val &= ~(0x3); | ||
__asm__ volatile("mcr p14, 0, %0, c0, c0, 4" ::"r"(reg_val) :); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please use macros to define the registers, e.g. https://github.com/zephyrproject-rtos/zephyr/blob/main/include/zephyr/arch/arm/aarch32/cortex_a_r/lib_helpers.h
arch/arm/core/aarch32/gdbstub.c
Outdated
reg_val |= (0xF & DBGDBCR_BYTE_ADDR_MASK) << DBGDBCR_BYTE_ADDR_SHIFT; | ||
/* Breakpoint enable */ | ||
reg_val |= DBGDBCR_BRK_EN_MASK; | ||
__asm__ volatile("mcr p14, 0, %0, c0, c0, 5" ::"r"(reg_val) :); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
arch/arm/core/aarch32/gdbstub.c
Outdated
{ | ||
int ret = 0; | ||
/* Fill the buffer with 'x' in case the stub does not support the required register */ | ||
memset(buf, "xxxxxxxx", 8); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you mean memset(buf, "x", 8);
?
arch/arm/core/aarch32/gdbstub.c
Outdated
int ret = 0; | ||
/* Fill the buffer with 'x' in case the stub does not support the required register */ | ||
memset(buf, "xxxxxxxx", 8); | ||
ret = 8; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the meaning of ret = 8
, here? Why not int ret = 8
at the beginning? Can you also explain a bit the meaning of the 8? It's the default size of the function read?
arch/arm/core/aarch32/gdbstub.c
Outdated
return ret; | ||
} | ||
|
||
size_t arch_gdb_reg_writeone(struct gdb_ctx *ctx, uint8_t *hex, size_t hexlen, uint32_t regno) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found that all arch_gdb_reg_read/writexxx
s share almost the same logic, would you like to refine them to make them more compact if it's not too difficult?
subsys/debug/Kconfig
Outdated
@@ -415,6 +415,9 @@ endchoice | |||
|
|||
config GDBSTUB_BUF_SZ | |||
int "GDB backend send/receive buffer size (in bytes)" | |||
# GDB for ARM expects up to 18 4-byte plus 8 12-byte | |||
# registers - 336 HEX letters | |||
default 350 if ARM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this one also be set by arch/soc/board specifically instead of default xxx if ARM
arch/arm/core/aarch32/gdbstub.c
Outdated
/* Enable the monitor debug mode */ | ||
__asm__ volatile("mrc p14, 0, %0, c0, c2, 2" : "=r"(reg_val)::); | ||
reg_val |= DBGDSCR_MONITOR_MODE_EN; | ||
__asm__ volatile("mcr p14, 0, %0, c0, c2, 2" ::"r"(reg_val) :); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto, registers defined in lib_heler
#if defined(CONFIG_GDBSTUB) | ||
z_gdb_entry(esf, GDB_EXCEPTION_INVALID_INSTRUCTION); | ||
/* Might not be fatal if GDB stub placed it in the code. */ | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I saw you return false
after z_gdb_entry
, would you like to elaborate on the details if there is a real fault instead of a gdb exception? You are going to send all faults to the gdb clients?
This needs to merge first: #62431 |
Should pass now if you rebase. |
8270983
to
cef38f2
Compare
Thanks for the notification, I rebased on the main branch again. |
It has conflicts now. Would you please rebase it again? @marek-vedral |
cef38f2
to
7b77b1f
Compare
Rebased on the main branch, there should not be conflicts anymore. |
I have tested it again and I always get stuck in the GDB command line after I type |
We discussed the issue with @microbuilder, see the earlier comments. I am not sure whether QEMU also emulates the debug registers, which would allow single stepping. |
Sorry I didn't see it. |
This pull request has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this pull request will automatically be closed in 14 days. Note, that you can always re-open a closed pull request at any time. |
@marek-vedral Sorry, I've been very slow with getting back to this one. I'm OK with the current code, but can you rebase to resolve conflicts since the last push, and we can hopefully get this in? Again, sorry for the delay. |
@marek-vedral please rebase |
If GDBSTUB is enabled and the kernel runs in tickless mode, the timer must not convert the delta cycles to a 32-bit data type (cycle_diff_t in this case). The delta_ticks variable would overflow and the next timeout would be set before the current timestamp, thus generating an interrupt right after leaving the handler. As a result, the system would receive tens of thousands of interrupts per second and would not boot. Cc: Michal Sojka <michal.sojka@cvut.cz> Signed-off-by: Marek Vedral <marek.vedral@gmail.com>
This commit adds a devicetree overlay file and an extra condition in the CMakeLists.txt file to allow remote debugging for the qemu_cortex_a9 board. Signed-off-by: Marek Vedral <marek.vedral@gmail.com>
This commit adds implementation of GDB stub for 32-bit ARM. It has been tested only on the Zynq-7000 SoC and I would like to get any feedback from others. The stub still has these issues: - To implement single stepping, it uses instruction address mismatch breakpoint, as recommended in ARMv7 reference. The breakpoint control register is configured (the state control fields) for the "PL0, Supervisor and System modes only" option. Otherwise the breakpoint would also halt the processor in abort mode, in which the stub loop runs. Zephyr kernel runs in the system mode. This works well until the kernel enables interrupts, as interrupt handlers typically run in Supervisor mode. Single stepping therefore sometimes "catches" a handler instead of the next application instruction. I have not tried User mode, because Cortex-A SoCs do not appear to have the ARCH_HAS_USERSPACE flag. Cc: Michal Sojka <michal.sojka@cvut.cz> Signed-off-by: Marek Vedral <marek.vedral@gmail.com>
cbd7b5a
7b77b1f
to
cbd7b5a
Compare
Rebased on main |
@povergoing Do you mind giving this another look? Thanks. |
@carlocaione Do you have time to give this a review? |
Add implementation of GDB stub for 32-bit ARM. It has been
tested only on the Zynq-7000 SoC and I would like to get any feedback
from others.
The stub still has these issues:
To implement single stepping, it uses instruction address mismatch
breakpoint, as recommended in ARMv7 reference. The breakpoint control
register is configured (the state control fields) for the "PL0, Supervisor
and System modes only" option. Otherwise the breakpoint would also halt the
processor in abort mode, in which the stub loop runs. Zephyr kernel
runs in the system mode. This works well until the kernel enables
interrupts, as interrupt handlers typically run in Supervisor mode.
Single stepping therefore sometimes "catches" a handler instead of the
next application instruction. I have not tried User mode, because
Cortex-A SoCs do not appear to have the ARCH_HAS_USERSPACE flag.
@wentasah
Cc: Michal Sojka michal.sojka@cvut.cz
Signed-off-by: Marek Vedral marek.vedral@gmail.com