Skip to content
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

Implement basic gdb server functionality. #52

Merged
merged 2 commits into from
Jan 5, 2025

Conversation

asanza
Copy link

@asanza asanza commented Jan 4, 2025

This commit introduces basic gdbserver support to the zmu ARM simulator, enabling remote debugging with a gdb client.

The following features are implemented:

  • Breakpoints: Users can set, clear, and manage breakpoints during program execution.
  • Continue: Execution can be resumed from the current breakpoint or paused state.
  • Step Instruction: Users can step through program instructions for detailed debugging.

This functionality significantly enhances the debugging capabilities of zmu, making it more versatile for developers.

To start the gdbserver just call zmu with the --gdb flag:

$ zmu.exe run --gdb binary.elf

A gdb server will be open on localhost port 9001
image

@asanza asanza marked this pull request as draft January 4, 2025 11:56
@asanza asanza force-pushed the implement_gdb_server branch from 7715cb6 to 49ddf23 Compare January 4, 2025 11:58
This commit introduces basic gdbserver support to the zmu ARM simulator,
enabling remote debugging with a gdb client.

The following features are implemented:

* Breakpoints: Users can set, clear, and manage breakpoints during program execution.
* Continue: Execution can be resumed from the current breakpoint or paused state.
* Step Instruction: Users can step through program instructions for detailed debugging.

This functionality significantly enhances the debugging capabilities of zmu,
making it more versatile for developers.

To start the gdbserver just call zmu with the --gdb flag:

$ zmu.exe run --gdb binary.elf

A gdb server will be open on localhost port 9001

Signed-off-by: Diego Asanza <[email protected]>
@asanza asanza marked this pull request as ready for review January 4, 2025 11:59
Copy link
Owner

@jjkt jjkt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Impressive! I found some smaller improvement ideas and marked them below.

Could you also please update README.md with description of the gdb functionality.

@jjkt
Copy link
Owner

jjkt commented Jan 5, 2025

Which gdb version did you use on your testing?
I installed gdb-multiarch on ubuntu: GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git and got some errors:

Start the emulator with gdb flag
./target/release/zmu-armv7em run --gdb tests/pi/pi-cm7-sp-d16.elf Starting GDB server

Run gdb:

$ gdb
GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) file tests/pi/pi-cm7-sp-d16.elf
Reading symbols from tests/pi/pi-cm7-sp-d16.elf...
(gdb) target remote localhost:9001
Remote debugging using localhost:9001
warning: while parsing target description (at line 1): Target description specified unknown architecture "armv4t"
warning: Could not load XML target description; ignoring
0x00000000 in __isr_vector ()
(gdb) b main
Breakpoint 1 at 0x5c: main. (2 locations)
(gdb) c
Continuing.
Remote connection closed
Command aborted.
(gdb) Quit

And got error from the zmu side:
> read_registers> read_addrs> read_addrs> read_addrsgdbstub encountered a fatal error: Received a packet with too much data for the given target

@jjkt
Copy link
Owner

jjkt commented Jan 5, 2025

tested with arm-gnu-toolchain 14.2.Rel1 arm-none-eabi-gdb, seems to work for me!

@asanza
Copy link
Author

asanza commented Jan 5, 2025

Impressive! I found some smaller improvement ideas and marked them below.

Could you also please update README.md with description of the gdb functionality.

Thanks for your feedback! This is more like a proof of concept and also a way for me to learn Rust 😅.

Ideally, I would like to have ZMU running in a separate thread and communicating with the GDB server through shared memory (or something similar). I actually tried implementing it that way, but I ran into problems with the Processor struct. Specifically, the itm_file and semihos_func references were causing issues because they depend on things that can’t be easily shared between threads.

In my mind, the setup would involve the GDB server in one thread and the ZMU simulator in another. The GDB server could control ZMU using the step command and directly inspect the processor’s memory to check its status. However, I have to admit my Rust knowledge is still quite basic, so I’m not sure what the best approach would be for this.

Right now, the GDB implementation isn’t very efficient, as it uses a polled TCP connection and waits 1ms in each step to check for incoming data.

What do you think? Should we merge this as it is for now, or do you have any tips for how to approach the multithreading idea? I’d be happy to give it another try based on your suggestions.

@asanza
Copy link
Author

asanza commented Jan 5, 2025

Which gdb version did you use on your testing? I installed gdb-multiarch on ubuntu: GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git and got some errors:

Start the emulator with gdb flag ./target/release/zmu-armv7em run --gdb tests/pi/pi-cm7-sp-d16.elf Starting GDB server

Run gdb:

$ gdb
GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) file tests/pi/pi-cm7-sp-d16.elf
Reading symbols from tests/pi/pi-cm7-sp-d16.elf...
(gdb) target remote localhost:9001
Remote debugging using localhost:9001
warning: while parsing target description (at line 1): Target description specified unknown architecture "armv4t"
warning: Could not load XML target description; ignoring
0x00000000 in __isr_vector ()
(gdb) b main
Breakpoint 1 at 0x5c: main. (2 locations)
(gdb) c
Continuing.
Remote connection closed
Command aborted.
(gdb) Quit

And got error from the zmu side: > read_registers> read_addrs> read_addrs> read_addrsgdbstub encountered a fatal error: Received a packet with too much data for the given target

I think the right command is gdb-multiarch

$ gdb-multiarch
GNU gdb (Debian 13.1-3) 13.1
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word".
(gdb) file tests/pi/pi-cm7-
pi-cm7-d16.elf     pi-cm7-sp-d16.elf
(gdb) file tests/pi/pi-cm7-sp-d16.elf
Reading symbols from tests/pi/pi-cm7-sp-d16.elf...
(gdb) target remote localhost:9001
Remote debugging using localhost:9001
Reset_Handler ()
    at /usr/share/doc/gcc-arm-none-eabi/examples/startup/startup_ARMCM7.S:149
149             ldr     r1, =__etext
(gdb) b main
Breakpoint 1 at 0x5c: file main.c, line 14.
(gdb) c
Continuing.

Breakpoint 1, main () at main.c:14
14          for (i = 0; i < 2801; i++)
(gdb)

@asanza asanza force-pushed the implement_gdb_server branch from 5039b76 to 4d8883a Compare January 5, 2025 09:19
Mostly comment fixes.

Signed-off-by: Diego Asanza <[email protected]>
@jjkt
Copy link
Owner

jjkt commented Jan 5, 2025

Impressive! I found some smaller improvement ideas and marked them below.
Could you also please update README.md with description of the gdb functionality.

Thanks for your feedback! This is more like a proof of concept and also a way for me to learn Rust 😅.

This whole project has been a hobby for learning rust, so no worries 👍

Ideally, I would like to have ZMU running in a separate thread and communicating with the GDB server through shared memory (or something similar). I actually tried implementing it that way, but I ran into problems with the Processor struct. Specifically, the itm_file and semihos_func references were causing issues because they depend on things that can’t be easily shared between threads.

In my mind, the setup would involve the GDB server in one thread and the ZMU simulator in another. The GDB server could control ZMU using the step command and directly inspect the processor’s memory to check its status. However, I have to admit my Rust knowledge is still quite basic, so I’m not sure what the best approach would be for this.

Right now, the GDB implementation isn’t very efficient, as it uses a polled TCP connection and waits 1ms in each step to check for incoming data.

What do you think? Should we merge this as it is for now, or do you have any tips for how to approach the multithreading idea? I’d be happy to give it another try based on your suggestions.

I think even this non-optimal version brings value to zmu development, I can see how it will be easier to implement new simulation features when there is well known UI for testing and inspecting things. So I would proceed to merge this non-optimal version. Maybe the doc/todo.md could be updated with a gdb heading that discusses the possibilities for the multi-threaded version.

The shared memory approach would require wrapping stuff into Arc / Mutex, and with rust borrow checker sometimes that becomes quite tricky to manage overall. Another approach would be making a clear message-passing type API (eg using crossbeam). That could be used for semihosting, itm trace AND also controlling the simulator and reading processor information. Likely some experimentation is needed to find a good solution for this.

@asanza asanza requested a review from jjkt January 5, 2025 10:58
@jjkt jjkt merged commit ff8b008 into jjkt:master Jan 5, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants