GDB Remote Serial Protocol support #27

Closed
redoste wants to merge 0 commits from redoste/gint:gdb into dev
First-time contributor

This pull request implements support for the GDB remote serial protocol over USB using the fxlink protocol.

While it's far from complete, it should be good enough for debugging most add-ins. Currently the main issue preventing long debugging sessions is a bug causing 2 messages sent from the calculator to be merged by libfxlink: this was discussed on the projets shoutbox channel last week and a minimal working example of the bug is attached.

A few TODOs were left but they shouldn't impact the user and are mostly design decisions that can be discussed here.

The UBC driver has been tested on Graph 90+E (fx-CG50) and Graph 35+E II (fx-9860G III) and is not guaranteed to work on non-SH7305 calculators.

The feature can be tried using the gdb branch of my gintctl fork and the bridge running on the computer with GDB.

This pull request implements support for the GDB remote serial protocol over USB using the fxlink protocol. While it's far from complete, it should be good enough for debugging most add-ins. Currently the main issue preventing long debugging sessions is a bug causing 2 messages sent from the calculator to be merged by libfxlink: this was discussed on the `projets` shoutbox channel last week and a minimal working example of the bug is attached. A few `TODO`s were left but they shouldn't impact the user and are mostly design decisions that can be discussed here. The UBC driver has been tested on Graph 90+E (fx-CG50) and Graph 35+E II (fx-9860G III) and is not guaranteed to work on non-SH7305 calculators. The feature can be tried using the [`gdb` branch of my gintctl fork](https://gitea.planet-casio.com/redoste/gintctl/src/branch/gdb) and the [bridge](https://gitea.planet-casio.com/redoste/fxlink-gdb-proxy) running on the computer with GDB.
1.8 KiB
redoste added 12 commits 2023-06-04 20:11:33 +02:00
redoste force-pushed gdb from cb9373e873 to 6f53fa7842 2023-06-04 23:22:27 +02:00 Compare
Owner

Fixed the libfxlink bug from the MWE; thanks for reducing it. I'll move to test and merge the debugging support now.

Fixed the libfxlink bug from the MWE; thanks for reducing it. I'll move to test and merge the debugging support now.
Author
First-time contributor

Thanks for the fix! I updated the bridge to properly flush the new IN queue.

Thanks for the fix! I updated the bridge to properly flush the new IN queue.
Owner

Thanks. I plan to integrate the bridge in the fxSDK until proper serial device support gets added to gint (which is a bit far away at the moment). I can imagine a simple fxsdk gdb wrapper that would run the bridge and start gdb with the proper remote settings automatically.

For now I'm trying to get a demo of debugging simple things to work but I don't think it's behaving as intended yet. Essentially gintctl's UI is freezing after starting the connection and an initial round of exchanges. Also the reply to gdb's initial g is all undefined and PC = 0xa0000000, which I don't think it the expected output? Does this ring any bells?

Thanks. I plan to integrate the bridge in the fxSDK until proper serial device support gets added to gint (which is a bit far away at the moment). I can imagine a simple `fxsdk gdb` wrapper that would run the bridge and start gdb with the proper remote settings automatically. For now I'm trying to get a demo of debugging simple things to work but I don't think it's behaving as intended yet. Essentially gintctl's UI is freezing after starting the connection and an initial round of exchanges. Also the reply to gdb's initial `g` is all undefined and PC = 0xa0000000, which I don't think it the expected output? Does this ring any bells?
Author
First-time contributor

It's intended behavior. When gdb starts it expects the target to be stopped but since the server is blocking while accepting the connection it can't "imagine" a fake state. As a workaround I added a GDB_FIRST_BREAK state where all the registers are marked as unavailable, except PC because gdb doesn't like when it's undefined, so I used the reset vector as a placeholder.

It's not the prettiest thing and it might be possible to setup a breakpoint on the return address of gdb_start to achieve a proper break when gdb is connected but I think it's still a good compromise since it let the user setup their future breakpoints safely.

It's intended behavior. When gdb starts it expects the target to be stopped but since the server is blocking while accepting the connection it can't "imagine" a fake state. As a workaround I added a [`GDB_FIRST_BREAK`](https://git.planet-casio.com/redoste/gint/src/commit/6f53fa78428a38a0fc84f1de69796c76549b0454/src/gdb/gdb.c#L43) state where all the registers are [marked as unavailable](https://git.planet-casio.com/redoste/gint/src/commit/6f53fa78428a38a0fc84f1de69796c76549b0454/src/gdb/gdb.c#L234), except `PC` because gdb doesn't like when it's undefined, so I used the reset vector as a placeholder. It's not the prettiest thing and it might be possible to setup a breakpoint on the return address of `gdb_start` to achieve a proper break when gdb is connected but I think it's still a good compromise since it let the user setup their future breakpoints safely.
Owner

Ok, I got it to work now, thanks. It's really cool. I've added a meta-repository for building gdb to the fxSDK so that part can be covered. I think all the code you've written is basically gonna stay as is, I'll mostly wrap this to make the feature easier to use in programs.

Ok, I got it to work now, thanks. It's really cool. I've added a [meta-repository for building gdb](https://git.planet-casio.com/Lephenixnoir/sh-elf-gdb) to the fxSDK so that part can be covered. I think all the code you've written is basically gonna stay as is, I'll mostly wrap this to make the feature easier to use in programs.
Owner

This is now on dev and I'm in the process of testing everything and adjusting the workflow. One change I made was to allow the stub to be started automatically when a crash occurs, which is a convenience I think will be valuable to users (as a quick "what happened?" tool that you can run even if the program didn't go through gdb_start() explicitly).

I'm not getting any Z packets from breakpoints though (b and d commands), even on your commits. Is there any setup required on GDB's side for that?

This is now on dev and I'm in the process of testing everything and adjusting the workflow. One change I made was to allow the stub to be started automatically when a crash occurs, which is a convenience I think will be valuable to users (as a quick "what happened?" tool that you can run even if the program didn't go through `gdb_start()` explicitly). I'm not getting any `Z` packets from breakpoints though (`b` and `d` commands), even on your commits. Is there any setup required on GDB's side for that?
Author
First-time contributor

I just tried it on the latest commit on dev with the latest version of the bridge in the fxsdk repo and it works both with your build of sh-elf-gdb and the gdb-multiarch from the AUR I usually use. Are you using continue before checking if a Z was sent ? gdb will only place the breakpoints once you resume the target.

I just tried it on the latest commit on `dev` with the latest version of the bridge in the fxsdk repo and it works both with your build of `sh-elf-gdb` and the `gdb-multiarch` from the AUR I usually use. Are you using `continue` before checking if a `Z` was sent ? gdb will only place the breakpoints once you resume the target.
Author
First-time contributor

As for the new fxsdk gdb command you might want to add a -ex "set architecture sh4a-nofpu" in the gdb invocation. For now it assumes we have FPU registers and will be confused by their absence when using stepi.

As for the new `fxsdk gdb` command you might want to add a `-ex "set architecture sh4a-nofpu"` in the [gdb invocation](https://git.planet-casio.com/Lephenixnoir/fxsdk/src/commit/e847ad3f6e182d2d295e9f0e3ed92b4a9f3d317f/fxsdk/gdb-bridge.c#L128). For now it assumes we have FPU registers and will be confused by their absence when using `stepi`.
Owner

Aha, I missed the continue bit. I get software breakpoints though... and I assume that's because I'm running with the RAM loader so the code is in RAM. The purpose of using the memory map in the first place is to force hardware breakpoints on code, I assume?

Aha, I missed the continue bit. I get software breakpoints though... and I assume that's because I'm running with the RAM loader so the code is in RAM. The purpose of using the memory map in the first place is to force hardware breakpoints on code, I assume?
Author
First-time contributor

Yes, gdb will place hardware breakpoints in read-only regions and software breakpoints otherwise. You can use hbreak instead of break to force it to use hardware breakpoints.

Yes, gdb will place hardware breakpoints in read-only regions and software breakpoints otherwise. You can use `hbreak` instead of `break` to force it to use hardware breakpoints.
Owner

Ok, cool. I've spotted a few issues that all came down to needing support for C (continue with signal). Otherwise you could, for instance, continue the program from a re-execution type exception like a segfault and just freeze. GDB really doesn't want to do anything until the program sends a stop reply so you'd have to reset. Now I simply abort with a suitable stop reply which is cleaner.

Oh, and this one's fun:

(gdb) x/i $pc
   0x8c202c04:	Cannot access memory at address 0x8c202c04
(gdb) x/i 0x8c202c04
=> 0x8c202c04 <gintctl_gint_gdb+304>:	mov.l	@r1,r10
(gdb) x/i (void (*)())$pc
=> 0x8c202c04 <gintctl_gint_gdb+304>:	mov.l	@r1,r10

GDB thinks $pc: int so x/i $pc reduces to x/i -1944048636, which evidently queries the memory map with signed comparisons and thinks it's out of range. Once again only happens with the RAM loader, for obvious reasons.

The reason PC isn't typed properly is because we're using the sh4-nofpu target (actually sh4al-dsp since it's supported) which doesn't have the register_type gdbarch overload. I'll add a patch to my build and submit it upstream.

Ok, cool. I've spotted a few issues that all came down to needing support for `C` (continue with signal). Otherwise you could, for instance, continue the program from a re-execution type exception like a segfault and just freeze. GDB really doesn't want to do anything until the program sends a stop reply so you'd have to reset. Now I simply abort with a suitable stop reply which is cleaner. Oh, and this one's fun: ``` (gdb) x/i $pc 0x8c202c04: Cannot access memory at address 0x8c202c04 (gdb) x/i 0x8c202c04 => 0x8c202c04 <gintctl_gint_gdb+304>: mov.l @r1,r10 (gdb) x/i (void (*)())$pc => 0x8c202c04 <gintctl_gint_gdb+304>: mov.l @r1,r10 ``` GDB thinks `$pc: int` so `x/i $pc` reduces to `x/i -1944048636`, which evidently queries the memory map with signed comparisons and thinks it's out of range. Once again only happens with the RAM loader, for obvious reasons. The reason PC isn't typed properly is because we're using the `sh4-nofpu` target (actually `sh4al-dsp` since it's supported) which doesn't have the `register_type` gdbarch overload. I'll add a patch to my build and submit it upstream.
Owner

First version published as https://www.planet-casio.com/Fr/forums/topic13572-74-gint-un-noyau-pour-developper-des-add-ins.html#196935 ; I'll close this for now, we can track remaining issues in other threads. The GDB patch is also on its way, modulo response time for maintainers. Thanks for your help!

First version published as https://www.planet-casio.com/Fr/forums/topic13572-74-gint-un-noyau-pour-developper-des-add-ins.html#196935 ; I'll close this for now, we can track remaining issues in other threads. The GDB patch is also on its way, modulo response time for maintainers. Thanks for your help!
Lephenixnoir closed this pull request 2024-04-11 09:05:05 +02:00
Owner

GDB patch was merged today.

GDB patch was [merged today](https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=afdd600c0982f0ce95439f2936c6d6d6d0201f77).

Pull request closed

Sign in to join this conversation.
No reviewers
No Label
No Milestone
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: Lephenixnoir/gint#27
No description provided.