-
-
Notifications
You must be signed in to change notification settings - Fork 554
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
GDB stub #1583
GDB stub #1583
Conversation
This is amazing! Only tested out the ARM9 part. It works extremely well. With it, I was able to create a DSi browser exploit. Thank you for this! One thing which I noticed is that reading memory is pretty slow, which makes searching in memory for things impossible. This is my first time interacting with ARM, but isn't the lsb of the pc register supposed to be 1 in thumb mode? The lsb was never set in thumb mode in my experience. Maybe I was supposed to look somewhere else to determine that? Setting the registers with Again thanks for this addon. Couldn't have made the exploit without it. |
no, now thinking about it, it's a bit confusing, but the bit is only mostly in return addresses to signal a mode switch. So it's put there by Thum blx in the link register and on ARMv5 all jumps will pick up this bit to switch to thumb mode. But it will always discard it afterwards. Whether the processor is currently in Thumb mode is stored though in CPSR bit 5. |
Hm, if GDB sends these read packets as 4 bytes at a time (instead of an entire memory chunk), it could be that the event polling queue thingy is only processing one of those messages at a time, which could be slowing down the thing. There's a number of
While what RSDuck says is true, I wouldn't be 100% sure that re-adding the bit isn't needed. For example, due to CPU pipelining,
Hm, that's slightly weird. Can you also say which error exactly is happening here as well, when you uncomment the |
Looks like Though, I should probably support all the mode-banked registers as well, that's currently not implemented. Sadly there's no way to get a good register index↔name linking afaik, so time to hunt through either the OpenOCD or the GDB sources, yaay... |
Also note to self: currently, when trying to connect to the GDB stub with the JIT enabled, GDB will time out, and melonDS sometimes dies with a SIGILL(?). Debugging and JIT are mutually exclusive, as the latter makes it impossible to single-step or to put breakpoints anywhere, and I don't see that changing anytime soon (unless @RSDuck wants to rearchitect the JIT, which I doubt.) So for now it's probably best to disable the GDB stubs completely when the JIT is enabled, and maybe emit a warning when someone tries to connect, instead of it crashing and burning without giving users a clue at all. |
I'm not too sure to understand how to use the gdb stub, like, are there CLI arguments to start it ? because i searched in the source it doesn't seem like it |
No, currently it's always-on (which is also a thing that should change, ideally in the settings menu as well), as long as you pass the |
in this case what port is it using by default ? because i'd like to use it to debug homebrew i'm making but i'm not sure about how to go about it |
I found the port by looking at the source. 3333. |
It's... literally the first thing I wrote in the description here: #1583 (comment)
Ah, alright, I'll put that in as an option when I get around to putting eg. the enable and port numbers in the option UI as well. |
Something I just remembered- in my experience, reading from the GBA slot (whether ROM or save) always returned 0, any idea why that could be? |
don't mind me I spent the night working on some stuff and was half asleep while reading lol |
From GDB or from regular code running in the emulator? The former needs some code duplication for things that don't go through the regular system bus (eg. the ARM9 TCMs), so maybe the GBA ROM is like that too. If the latter, no clue, sorry. |
Does anyone was able to connect this to ghidra debugger ? |
cd15080
to
1f8d407
Compare
Alright, so, updates! Finally! The GDB stub can now also be enabled (and the ports can be configured) in the emu settings window.
|
This is implemented now |
481a2b1
to
2d9fc47
Compare
works now! thank you |
Tested on Windows connecting through VS code and haven't had any issues -- seems to work brilliantly. Thanks for putting this together! |
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 only marked one instance of some stylistic things
… console thru gdb work
Heh, looks like LLDB is also not quite standard-compliant in how it works (it's only supposed to send EDIT: @turtleisaac pushed the 'fix', does it work now? |
Pulled, rebuilt and gave it a shot. Unfortunately, melonDS crashes after I attempt the connection.
Here's the Apple error report if you need it.
On the client side of things, it seems like at the very least the handshake process did get completed because the debugger did seem to be connected. |
What happens if you swap these two lines? |
Ok we're moving along here. Here's what happened: melonDS output:
On the CLion side of things:
|
d3f48ed
to
fae3642
Compare
@turtleisaac Ok, I've implemented a few more commands which should be able to keep lldb happy. Can you try now? |
Still no luck unfortunately. Definitely seems to be a different series of errors tho?
|
Can you try running the LLDB command Also, the "inital handshake: didn't receive inital ack!" at the beginning sounds cursed (and also contradicting what's being said here, hooray). Can you also try the same when commenting away this code, and then with also this code uncommented? |
Will do in a sec, but yeah I think it is detaching purposefully. Look at what I sent earlier:
@PoroCYon ok tried it out and got a shit ton of stuff here. LLDB output (truncated to just the stuff going on at the end):
melonDS ceases execution of the game here unless I use
I think that Now to be clear, at this point, game execution does continue and I haven't tested beyond that point yet. Perhaps everything does work fine in terms of raw manual LLDB in Terminal, and I'll have to try placing some breakpoints and seeing how things go. However, the goal evolves into using this in conjunction with CLion so I can debug in a more friendly environment which should let me go line by line. I know this works with melonDS for Visual Studio and GDB so that's the result I'm trying to work towards on my end. |
The log output means that it seems to work. But, what you're saying is, it works with terminal LLDB but not CLion's LLDB? That's a bit annoying, and not something I can troubleshoot easily (beyond guessing things, like commenting/uncommenting the code I highlighted). |
@Arisotura @RSDuck is this planning to be merged soon ? It would be nice to have access to releases for everyone who do not want to build themself. (Maybe adding a specific debug version for each plateforme in the release channel.) @PoroCYon made an incredible work that already helped a lot of people and I think it would be nice to see it merged |
I already wanted to merge it a while ago, but I've been kept off by the bug reports in this PR. |
@axel7083 did you actually manage to get it to work with a different GDB? (or maybe one of the newer commits automagically fixed things.) |
I've made my own attempts to intercept the communication between CLion and its internal LLDB but that hasn't gone anywhere. However, I did get a different CLion installation on Linux which is actually able to use GDB to connect to melonDS (granted the memory viewer and breakpoints aren't working, just the fact that the debugger seems to connect), so the culprit definitely seems to be down to the implementation of their LLDB in terms of what it expects from the connected gdb-server, but the possibility to make it happy does exist. Anyways, considering the following error message I've still been getting on the Mac side of things:
I think it has something to do with this page, but I'm not smart enough (and mostly just don't have enough information about CLion's internal LLDB and the sequence of events that led to that error) to understand what it is saying in relation to what melonDS either is or isn't doing... Oh also, further testing involving LLDB (the manual Terminal one, not the one inside of CLion) shows things fall apart pretty quickly when I actually try to use it. It's freaking out about the thumb instructions is my theory, because it freaks out about unknown opcodes, halts execution, and after a few times of that and doing
|
I don't think it means much. A "stop reply packet" is the packet sent from the gdbstub that tells the debug client why the debugged program is stopped (breakpoint, crash, user hit the 'pause now' button, etc.). Such a packet is supposed to be sent after a
As the CLion debugger thingy disconnects immediately after sending a single packet (without requesting the stop reply packet in the first place), it seems to be another meaningless error on their end. As for the thumb thing, I'm not sure what's up. It should be reported correctly in the CPSR. Maybe LLDB does want the thumb bit set in the program counter, too (unlike gdb, cf this earlier discussion). Maybe you could try changing the |
Thanks a lot for bringing this. It would be very useful for reverse engineering. I decided to give it a try but unfortunately I am couldn't make it on Windows with Ghidra or IDA. I think it's almost working. For my setup, Ghidra and IDA do work right now with the gdbstub of desmume. Ghidra
gcc-arm-none-eabi-10.3-2021.10Same issue with step into as Ghidra. Rest seems to work via CLI but for some reason Ghidra rejects this GDB. IDA
|
I'm having trouble reproducing some of these, and if I don't, it's exceptionally hard to even figure out what's going on in the other tools. This difficulty in reproduction might be because I'm using a different platform (Linux, also I don't have IDA). But either way,
|
Thanks for taking a look. I think I have found the potential issue with the step / continue. IDA uses the command diff --git a/src/debug/GdbCmds.cpp b/src/debug/GdbCmds.cpp
index 057502f2..d642ef6d 100644
--- a/src/debug/GdbCmds.cpp
+++ b/src/debug/GdbCmds.cpp
@@ -883,13 +883,13 @@ ExecResult GdbStub::Handle_v_MustReplyEmpty(GdbStub* stub, const u8* cmd, ssize_
ExecResult GdbStub::Handle_v_Cont(GdbStub* stub, const u8* cmd, ssize_t len)
{
- if (len < 1)
+ if (len < 2)
{
stub->RespStr("E01");
return ExecResult::Ok;
}
- switch (cmd[0])
+ switch (cmd[1])
{
case 'c':
stub->RespStr("OK"); There is still the issue that sometimes it requires to send several times the step command to advance. I can reproduce that one with GDB directly. It happens at the beginning and randomly from time to time. In the following output it happened at: So the last issue before I can easily use it, it's that step over doesn't work. It seems IDA is sending a regular |
For me, GDB (with PEDA) doesn't show as much information. Take for instance an example executable:
and then on melonDS:
Obviously I can just examine PC:
Maybe this is just an issue with PEDA or GDB. I don't really know. But yeah, there you go |
I'm not sure what you're trying to convey. Why is the disassembly x86? If you want symbols and a usable backtrace in the NDS binary being debugged, you have to load it first:
|
The example executable is x86. I was showing what normally happens on a standard debugging situation. I'm not sure how to get the ELF file correctly. I attempted to But anyway, that's a problem for elsewhere |
I really don't want to let this PR rot, so I'm just going to merge for now. |
Yeah, no, you're supposed to get your ELF file from the compiler you use to compile the source code with. If you aren't debugging something that comes from an ELF file or with source code, there isn't much you can do to get symbols or stack traces.
I guess that's one way of doing it :D |
Ah okay, I was more wondering about it showing the current instruction and stack, but that's off topic. It's good that this got merged though! |
* gdbstub beginnings * gdbstub: finish gdb impl things, next up is integration with melonDS * holy fuck the gdbstub works * gdb breakpoints work, but there's a mysterious crash on continue * fix memory corruption that sometimes happened, and make resetting the console thru gdb work * remove some gdb debug printing * fix things in gdbstub * separate option for enabling gdbstub * add mode-dependent CPU registers * C++ize the GDBstub code * add gdbstub config in emu settings dialog * make sure gdb is disabled when jit is enabled * Remove unnecessary compiler flags, mark ARMJIT assembly code as no-execute-stack This hardens the binary a little bit against common exploitation methods * add option to wait for debugger attach on startup * only insert GNU stack notes on linux * disable gdbstub enable checkbox when jit is enabled * fix non-linux incompatibilities * enable gdbstub by default * fix issues with gdbstub settings disable stuff * format stuff * update gdb test code * Fix segfault when calling StubCallbacks->GetCPU() C++ overrides are hard. Please I'm just a lowly C programmer. * fix packet size not being sent correctly Thanks to @GlowingUmbreon on Github for troubleshooting this * fix select(2) calls (i should read docs more properly) * fix GDB command sequencing/parsing issue (hopefully) * [GDB] implement no-ack mode * fix sending ack on handshake * get lldb to work
i noticed this is supposed to be merged in master but i don't see the option on melonds 0.9.5. Edit : I just realised but yes since 0.9.5 is from 2022. It's very old. |
The GDB stub is a feature to add debug capabilities (using an external debugger like GDB) to melonDS, to reverse-engineer games and system software, or to help with making homebrew NDS/DSi code.
There's an option in the emu settings menu to enable the GDB stub, configure which ports it uses, and to optionally wait until a debugger is attached before starting the system. (Don't enable this last option for both CPU cores at once!)
The GDB stub can be disabled by setting the
ENABLE_GDBSTUB
CMake option toOff
, it is on by default.What works:
What doesn't work:
Oriignal PR comment below: