You are not logged in.
UPDATE: I bypassed the whole thing by switching to a Debian Linux box, where I was able to get the GDB stub thing working rather easily.
Hello. I have been trying to install an NDS development system on my Mac, including FPC, devkitPro stuff, libNDS etc. and I've got pretty much everything working nicely, except source level debugging. I managed to compile the newest DeSmuME trunk version in Xcode 5, but apparently it doesn't support the GDB stub things by default. Trying to get it to compile with GDB_STUB defined seems to be hard. I have tried to mix the newest sources with information in this blog post from 2009
http://sigmaris.info/blog/?p=10
...but it looks like the stuff that the blog post talks about has been moved to files named "legacy".
I tried to copy/paste missing GDB_STUB related lines into cocoa_core.mm etc, tackling one compiler or linker error after another, but I don't really know what I'm doing. I'm not very familiar with any of this Cocoa stuff to begin with.
I noticed that there's a sub-folder called "cli", but I couldn't find out how it's supposed to be used really. None of the pre-made Xcode project files seem to use those routines.
There seem to be Automake's Makefile.am files all around. After messing around with the newest trunk version, I also tried the latest release version 0.9.10 and ran "aclocal ; automake ; ./configure" in the root folder, but it eventually failed and complained about missing XML::Parser perl module.
I can think of many things that might lead to a working Mac GDB DeSmuME, like
a) copy/paste snippets of code from cli/main.cpp into some other file, until it compiles... and then GDB debugging support would work? Could or should this work with the current Mac GUI application?
b) create an entirely separate target with cli/main.cpp as the main progam, and none of the things in the cocoa directory. Maybe look at some of the other platform versions as an example? The CLI version seems to use SDL, so I guess there's no real GUI.
c) fix stuff to get all the Automake things working, and then do something in order to build the CLI version without graphical Xcode IDE?
Any ideas? Did I just miss something, and overlooked some obvious way to build a GDB version for Mac? The cli directory has a script "osxbuild", but I didn't understand what it was supposed to do. I could go on and on, trying to solve errors one by one, but I thought that it's best to ask before spending many more hours on this. I don't expect to understand all of the code base.
Last edited by xabccode (2014-12-27 18:46:03)
Offline
gdbstub is a feature that I've wanted to add to the Cocoa port for a while now, and adding the code to get gdbstub to load is easy enough, but I have no idea how to actually test if it works as intended. I'm not familiar with the the workflow involved. This is why I haven't officially added gdbstub to the Cocoa port yet. If you could give me a rundown on how gdbstub is used in the NDS development process, that would be great.
Offline
Here's a more recent explanation for Windows, showing how to use Microsoft Visual Studio and some sort of VS-GDB bridge
http://vgcoding.blogspot.fi/2011/01/how … isual.html
DevkitPro's devkitARM toolset contains a command-line ARM GDB (called "arm-none-eabi-gdb" or "arm-nds-eabi-gdb" or something), which you can use instead.
The blog post http://sigmaris.info/blog/?p=10 explains the Mac side a little bit, calling the executable from inside the DeSmuME.app folder. Here's another explanation of the workflow, using a command-line executable "desmume-cli"
https://code.google.com/p/quirkysoft/wi … ggingNotes
It would of course be ideal to be able to open the application from the command line with all parameters. I tried the old 2009 precompiled version from the blog post above, but it seemed that it only reads the gdb port from the command line parameters and not the ROM file name, or at least I couldn't figure out how it should be done. I guess that's what the main program cli/main.cpp is there for in the current source code.
Last edited by xabccode (2014-12-27 10:03:32)
Offline
Actually, right now I'm trying to figure out how I could get the FPC compiler or perhaps some of the devkitARM tools to produce an ELF file for me. The FPC for ARM-NDS compiler creates a "nef.bin" (which GDB doesn't understand), from which ndstool makes the .nds file, but how to get an ELF format file in order to explain the symbols to GDB.
Offline
you should be using devkitPRO. don't waste your time doing it differently from everyone else.
the best place for support is over there.
the nds example makefiles create .elf files.
Offline
Of course I am using devkitPRO. I was able to compile FPC for ARM-NDS, together with the libnds support libraries and the example programs, and run the produced .nds ROM images in the DeSmuME emulator. This required over a dozen fixes all over the FPC 2.6.4 source tree, and quite many hours of problem-solving.
Perhaps you mean I should be using the C programming language on Windows? Sorry, I want to use Object Pascal on Mac and Linux.
Btw, right now I'm trying to build the development system on a Debian Linux computer. My idea is to try and get the kids interested in programming, and Nintendo DS seems like a good platform to do interesting stuff. I thought, Object Pascal might be a reasonable language for that. Certainly much better than C. And it's fun for me, because I've been programming in Pascal for over 25 years. The ultimate goal is to get this whole thing running with Lazarus, with integrated debugging, so I could show how the program runs line-by-line even on assembly instruction level.
I don't know why what everyone else might be doing with these NDS development things. For me it's mostly about having fun. I'm not trying to make money with this or anything.
Offline
Update. After starting to build DeSmuME for Linux, I found a bunch of "how to" instructions that I probably should have read prior to trying to build the OSX version. Or at least now I understand more about the Legacy stuff. It may have been possible to get further with the Legacy version, but it would have required the old Xcode 3 version... I don't know. At least the Linux build went super smooth compared to OSX, and just following the instructions, building from the newest svn trunk gave me a seemingly working "desmume-cli" binary. It looks like it doesn't support the --arm9gdb parameter. I went back and did "./configure --enable-gdb-stub ; make ; make install" to get a version that does. Great.
I also realized that I should probably try and build the libnds stuff from sources, because now the debug symbols link to files like "c:/Users/davem_000/projects/devkitPro/libnds-master/" etc.
But first I'll just try to get debugging to work for FPC programs.
Offline
Update. I dug into FPC source code, added debug printouts and compared it to how devkitARM's g++ linker phase does it, and guess what... the ".nef", or "not-executable-file" file that it's producing _is_ actually en ELF file. devkitARM's gdb is able to open it and load the symbols. Doh! Now it's supposed to work like this:
I have a "hello world" Pascal program like this
program HelloWorld;
{$mode objfpc}
uses
nds9;
procedure MyProcedure;
begin
printf('Hello World');
end;
procedure Jam;
begin
while true do ;
end;
begin
consoleDemoInit();
MyProcedure;
Jam;
end.
I compile the program and load the resulting ELF file "hello.nef" into GDB like this
ppcrossarm -g hello.pp
arm-none-eabi-gdb hello.nef
Then I give these commands in GDB (if you wonder why MyProcedure is written in ALL CAPS, that's because of FPC's name mangling - maybe there's a way to get rid of that style)
...
(gdb) break MYPROCEDURE
Breakpoint 1 at 0x2013c88
(gdb) target remote :20000
After that, GDB is waiting for a GDB server to show up at port 20000. Then I launch DeSmuME with a command like this:
desmume-cli --arm9gdb=20000 hello.nds
When DeSmuME is up and running, GDB will go on and let me give more commands. Or at least that's the theory. Right now I'm trying to find out if the breakpoint is actually being triggered like I hoped.
EDIT: I am able to set breakpoints, and DeSmuMe recognizes the commands, but it doesn't seem to actually break the execution. I tried this with the graphics/Sprites/allocation_test program, and the random sprite boxes just keep flying in the emulator window. If I press Ctrl-C in GDB, it will pause the emulator and show where it was going. But the breakpoints will not get triggered. In the snippet below, I tried to give a complete function name P$ALLOCATIONTEST_UPDATESPRITES instead of just UPDATESPRITES, but no luck.
(gdb) break UPDATESPRITES
Breakpoint 2 at 0x20153f0
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x02015434 in P$ALLOCATIONTEST_UPDATESPRITES ()
(gdb) break P$ALLOCATIONTEST_UPDATESPRITES
Note: breakpoint 2 also set at pc 0x20153f0.
Breakpoint 3 at 0x20153f0
(gdb) c
Continuing.
Anyway, this has now gone off topic.
EDIT2: for comparison, I tried the same thing with the C versions of the libnds examples, and the GDB functionality seems to behave in the same way as on the Pascal side. I can set breakpoints, but they don't get triggered. Source line stepping with the S command usually gets the whole thing in some sort of deadlock, and the only way I could find to get DeSmuME to break away from this jam situation was to press Ctrl-Z and "killall -9 desmume-cli". Instruction level stepping, with the SI command seems to work without getting stuck, but what good is it if I can't even get breakpoints working... I wonder if anyone's actively using the GDB debugging, and with what kind of workflow it works without getting stuck. Would it help if I had debug versions of all libnds library routines with source line level debug information?
Last edited by xabccode (2014-12-28 17:48:09)
Offline
people use the debugging in windows using insight. thats all i know.
Offline
Ok. I made a post about it in the technical area, hoping that some GDB stub user happens to notice it.
http://forums.desmume.org/viewtopic.php?pid=23827
Offline
I've finally added GDB stub support to the Cocoa port. You will need to use the "OS X App; dev+" build scheme in the "DeSmuME (Latest).xcodeproj" Xcode project file to enable GDB stub. The Cocoa port does not use a command line, so any methods of using GDB stub you've seen so far don't apply here. Instead, to use GDB stub on the Cocoa port, follow these steps:
1. Currently, GDB stub doesn't work well with Dynamic Recompiler, so you will need to switch emulation back to Interpreter. To do this, choose Emulation > Show Emulation Settings. Then in the Emulation Settings panel, under CPU Emulation Engine, choose Interpreter.
2. In DeSmuME, choose Tools > Show GDB Stub Control. (Note that this menu option is available only on the dev+ build!)
3. In the GDB Stub Control panel, enable the CPUs you would like to connect to, then enter the port numbers you would like to connect with. After you've entered your settings, click Start. If GDB stub successfully initializes, then the button should now read Stop.
4. In DeSmuME, load your ROM. After the ROM loads, the CPU should be stalled.
5. In gdb, you can now remote into DeSmuME by connecting to the ports you've set up in Step 3.
I've tested with both gdb and arm-none-eabi-gdb for devkitARM, and both seem to connect fine. But DeSmuME's GDB remote protocol is still incomplete, so there are still a bunch of bugs. You shouldn't expect too much out of GDB remote debugging for now.
UPDATE: Updated instructions to reflect latest changes in r5070 and r5075.
Last edited by rogerman (2015-01-15 01:25:15)
Offline
Thanks for your trouble. I'm getting some progress now.
I was able to compile the Cocoa dev+ version from the svn trunk straight away, and get the GDB stub functionality working, after I realized I had the dynamic recompiler emulation switched on, and so the relevant version of armcpu_exec() was never called, and the post-exec function pointers that the GDB commands were setting had no effect.
I can now keep repeating the "step instruction" GDB command for a very long time, without getting a deadlock situation like what happens with the Linux version. Though to me the whole thing feels suspicious - several threads seem to be reading and manipulating the same variables without any proper synchronization mechanism, and without even declaring the variables as volatile. And setting the stalled flag is in many places coupled with seemingly redundant calls to functions that also set the same flag.
However, I still can't get breakpoints to do anything. It seems that the gdbstub.cpp / check_breaks_gdb() function is never actually called. I guess it _should_ be called because that's the place in the code that's reading the breakpoint lists created by the GDB command handling. And it seems that the only place that would call check_breaks_gdb() for the instruction breakpoint list are the gdb_prefetch32() and gdb_prefetch16() functions in gdbstub.cpp.
Is there some kind of half-done code structure change? Should MMU.h / CheckMemoryDebugEvent() call the GDB stuff, or should one of the _MMU_read32 calls actually go to the GDB prefetch functions, but some function pointer somewhere hasn't been set even though it should have?
In armcpu.cpp / armcpu_prefetch(), there are blocks of #ifdef GDB_STUB code that have been commented out, but no explanation why, and should the _MMU_read32() calls now handle both GDB and non-GDB cases.
In MMU.h, there's this comment:
// Use this macros for reading/writing, so the GDB stub isn't broken
Has that got something to do with something?
By the way, a proper CLI version would also be nice. My final goal is to be able to integrate starting the emulator from within an IDE environment, just by clicking "run". But for now I'll still try and understand what would be the correct way to get the breakpoints to break. The same bug apparently applies to the Linux version as well. Anyway, my Mac mini's i7 processor can actually run the emulation at full speed, unlike the Linux machine's poor old 1.2 GHz Celeron.
Offline
What does createStub_gdb() actually try to accomplish with this line of code
*cpu_memio = &stub->cpu_memio;
You might think that it's redirecting/hooking some interface pointer to its own implementation, so that it can act as a middle-man between the caller and the original implementation, passing through the calls after doing something extra, and that's why it's also saving the original interface pointer. But it's not, because it's actually only changing a local temporary variable in cocoa_core.mm / setIsGdbStubStarted(), right? Writing NULL instead if &stub->cpu_memio works just the same.
MMU.cpp has a block of code titled like this:
////////////////////////////////////////////////////////////
//function pointer handlers for gdb stub stuff
But tracing the program's execution into the _MMU_readX functions I just can't understand how any of that stuff could currently result in checking the breakpoint lists.
Offline
people debug _using breakpoints_ in windows using insight. i've seen it myself. perhaps your GDB_STUB and _DEV or whatever macros arent getting into the needed files
Offline
Ok, I managed to get breakpoints and source line stepping to work with some ugly patchwork. In this example I set a breakpoint, continue, and the breakpoint is triggered, and then I can just Continue, hold down Enter, and eventually the sprite boxes are updated in the DeSmuME window.
(gdb) break P$ALLOCATIONTEST_UPDATESPRITES
Breakpoint 1 at 0x201559c
(gdb) c
Continuing.
Breakpoint 1, 0x0201559c in P$ALLOCATIONTEST_UPDATESPRITES ()
1: x/i $pc
=> 0x201559c <P$ALLOCATIONTEST_UPDATESPRITES+16>: ldr r0, [pc, #304] ; 0x20156d4 <P$ALLOCATIONTEST_UPDATESPRITES+328>
(gdb) c
Continuing.
...
I got it to work with a chewing gum hack, calling the GDB stub functions from MMU.cpp for the prefetchX functions directly, exposing global functions and variables from modules. I don't try to guess what someone had in mind when making the MMU etc. thing, but at least this kludge seems to give me working breakpoints and source line stepping. I didn't try to understand the design principles behind all this code, and what sort of architecture someone had in mind, what was the old way, what is the new way, and so on.
In gdbstub.cpp I removed the "static" declarations from gdb_prefetchX so the linker can connect the things. Then in MMU.cpp, I added calls from armN_prefetchX I added calls to the gdb_prefetchX functions, giving the stub pointers in the data parameter.
////////////////////////////////////////////////////////////
//function pointer handlers for gdb stub stuff
void *arm7_gdb_stub = NULL;
void *arm9_gdb_stub = NULL;
extern uint16_t FASTCALL gdb_prefetch16( void *data, uint32_t adr);
extern uint32_t FASTCALL gdb_prefetch32( void *data, uint32_t adr);
static u16 FASTCALL arm9_prefetch16( void *data, u32 adr) {
if (arm9_gdb_stub)
gdb_prefetch16(arm9_gdb_stub, adr);
return _MMU_read16<ARMCPU_ARM9,MMU_AT_CODE>(adr);
}
static u32 FASTCALL arm9_prefetch32( void *data, u32 adr) {
if (arm9_gdb_stub)
gdb_prefetch32(arm9_gdb_stub, adr);
return _MMU_read32<ARMCPU_ARM9,MMU_AT_CODE>(adr);
}
...
static u16 FASTCALL arm7_prefetch16( void *data, u32 adr) {
if (arm7_gdb_stub)
gdb_prefetch16(arm7_gdb_stub, adr);
return _MMU_read16<ARMCPU_ARM7,MMU_AT_CODE>(adr);
}
static u32 FASTCALL arm7_prefetch32( void *data, u32 adr) {
if (arm7_gdb_stub)
gdb_prefetch32(arm7_gdb_stub, adr);
return _MMU_read32<ARMCPU_ARM7,MMU_AT_CODE>(adr);
}
...
In cocoa_core.h, I introduce the gdbstub.cpp variables so I can write to them
extern void *arm7_gdb_stub;
extern void *arm9_gdb_stub;
In cocoa_core.mm, I write the created stub handles to the void pointers like this.
arm9_gdb_stub = (void *)gdbStubHandleARM9;
...
arm7_gdb_stub = (void *)gdbStubHandleARM7;
...
This is of course a very ugly spaghetti style way to pass things from one module to another. Someone who knows the actual design principles and transition plans can do it properly. I didn't even test the kludge with the ARM7 CPU at all, just with ARM9.
But now I can finally proceed trying to get the Lazarus IDE patched up with the emulator and arm-none-eabi-gdb etc.
Offline
Zeromus: I didn't look at the Windows port, but the Mac port's call to createStub_gdb() is in a file called cocoa_core.mm, and I have a suspicion that Windows folks have something different.
Offline
my point is, none of your weird patches and kludges should be necessary since it's already working essentially. look for gdb_stub related things in the windows main.cpp
although I am somewhat confused about how anything works with gdb_prefetch32() not actually falling through to the real_cpu_memio prefetch call...
..oh. the cpu loop (armcpu_exec) was changed after the gdb stub was written, and it takes responsibility for doing the actual memory reading
Offline
I thought so too. I took a look at the Windows port's main.cpp, and the code around createStub_gdb() looks pretty much the same there. I did triple-check that GDB_STUB was globally defined. Maybe someone who knows more about the code, and can test the breakpoints as well, can find out what if anything might be wrong.
Offline
Yes, the system has clearly been modified in several ways, and the current svn trunk version seems to contain both an old and a new architecture, and the new one isn't completely done - if I understand it correctly.
The "old" way - if I understand it correctly - was to use the GDB stub as a replacement memory interface, so that it calls the original one at each prefetchX call.
static uint32_t FASTCALL gdb_prefetch32( void *data, uint32_t adr) {
struct gdb_stub_state *stub = (struct gdb_stub_state *)data;
int breakpoint;
breakpoint = check_breaks_gdb( stub, stub->instr_breakpoints, adr, 4,
STOP_BREAKPOINT);
//return stub->real_cpu_memio->prefetch32( stub->real_cpu_memio->data, adr);
return 0;
}
It once used to call the original routine real_cpu_memio->prefetch32? At least now it just returns 0, and the call to the saved original prefetch32 is commented out.
I tried to follow the code, and find out where the pointer to gdb_prefetch32() would end up being called, and I couldn't see that happening. The function createStub_gdb() tries to write its own interface as an "out" parameter to **cpu_memio
*cpu_memio = &stub->cpu_memio;
...but look at where that assignment is actually going - practically nowhere that would matter. activateStub_gdb() that's run after creating the stub only seems to manipulate the control interface, not memory interface.
Last edited by xabccode (2015-01-03 19:19:58)
Offline
its called from armcpu_exec from this line:
ARMPROC.mem_if->prefetch32( ARMPROC.mem_if->data, ARMPROC.next_instruction);
since mem_if has been setup by this line:
stub->cpu_memio.prefetch32 = gdb_prefetch32;
in createStub_gdb()
the actual memory reading of the prefetching is done immediately after the mem_if->prefetch32() runs
Offline
your analysis of this line is flawed:
*cpu_memio = &stub->cpu_memio;
You can see precisely where it goes in the windows main.cpp. Its a local which is passed into createStub_gdb() and filled in (you saw that part) and then passed into NDS_Init() immediately afterwards in main.cpp
Offline
Ah, I see the problem now. I switched the order of createStub_gdb() and NDS_Init() so that createStub_gdb() comes after NDS_Init(). I didn't realize that the armcpu_memory_iface function pointer overrides were stored in the gdb_stub_state itself, and then were being passed to armcpu_t via NDS_Init(). So as of r5064, all GDB breakpoint functionality in all ports is currently broken.
I will make sure this gets fixed later today.
Offline
We must be looking at different code, and/or different definitions of the language syntax.
Any way I look at it, ARMPROC.mem_if (which is a pointer) has not been setup by the line you quote. The quoted line only fills in the stub's own sub-struct. A pointer into the sub-struct is passed to the local variable like you say, but ARMPROC.mem_if still points to the original memory interface, e.g. arm9_base_memory_iface. Only the local variable is changed, and the local variable is not passed anywhere, certainly not NDS_Init(), which is called _before_ calling createStub_gdb(), and doesn't even take parameters.
edit: I didn't see Rogerman's post, sorry.
Anyway, great that it's sorted out. I thought, I'm going crazy or how the heck can this work on Windows or anywhere. So nevermind, maybe we actually were looking at different code.
Last edited by xabccode (2015-01-03 22:27:17)
Offline
Okay, try r5066. Breakpoints should work now.
Offline
Thanks now the Mac dev++ version seems to work with breakpoints and all straight from svn trunk. Your most essential fix seems to be this bit in activateStub_gdb():
armcpu_t *theCPU = (armcpu_t *)stub->arm_cpu_object;
theCPU->SetCurrentMemoryInterface(&stub->gdb_memio);
The old code didn't make any changes to the actual CPU objects' function table pointers, so as far as I can see, it cannot have worked in any port, maybe for a long time.
However, now the Linux port seems to be a little bit broken, and it doesn't even compile. gtk/desmume.h still has the old definition of desmume_init(), which you had changed in r5061.
Offline