diff --git a/desmume/src/frontend/posix/cli/main.cpp b/desmume/src/frontend/posix/cli/main.cpp index d5d420d53..690d7c796 100644 --- a/desmume/src/frontend/posix/cli/main.cpp +++ b/desmume/src/frontend/posix/cli/main.cpp @@ -63,6 +63,21 @@ #ifdef GDB_STUB #include "../armcpu.h" #include "../gdbstub.h" +class CliDriver : public BaseDriver +{ +private: + gdbstub_handle_t __stubs[2]; +public: + virtual void EMU_DebugIdleUpdate() { + gdbstub_wait(__stubs); + } + virtual void setStubs(gdbstub_handle_t stubs[2]) { + this->__stubs[0] = stubs[0]; + this->__stubs[1] = stubs[1]; + } +}; +#else +class CliDriver : public BaseDriver {}; #endif volatile bool execute = false; @@ -478,6 +493,19 @@ static void desmume_cycle(struct ctrls_event_config * cfg) SPU_Emulate_user(); } +#ifdef GDB_STUB +static gdbstub_handle_t setup_gdb_stub(u16 port, armcpu_t *cpu, const armcpu_memory_iface *memio, const char* desc) { + gdbstub_handle_t stub = createStub_gdb(port, cpu, memio); + if ( stub == NULL) { + fprintf( stderr, "Failed to create %s gdbstub on port %d\n", desc, port); + exit( 1); + } else { + activateStub_gdb(stub); + } + return stub; +} +#endif + int main(int argc, char ** argv) { class configured_features my_config; struct ctrls_event_config ctrls_cfg; @@ -568,8 +596,8 @@ int main(int argc, char ** argv) { slot2_Init(); slot2_Change((NDS_SLOT2_TYPE)slot2_device_type); - driver = new BaseDriver(); - + driver = new CliDriver(); + #ifdef GDB_STUB gdbstub_mutex_init(); @@ -577,37 +605,22 @@ int main(int argc, char ** argv) { * Activate the GDB stubs * This has to come after NDS_Init() where the CPUs are set up. */ - gdbstub_handle_t arm9_gdb_stub = NULL; - gdbstub_handle_t arm7_gdb_stub = NULL; - + gdbstub_handle_t stubs[2] = {}; if ( my_config.arm9_gdb_port > 0) { - arm9_gdb_stub = createStub_gdb( my_config.arm9_gdb_port, + stubs[0] = setup_gdb_stub(my_config.arm9_gdb_port, &NDS_ARM9, - &arm9_direct_memory_iface); - - if ( arm9_gdb_stub == NULL) { - fprintf( stderr, "Failed to create ARM9 gdbstub on port %d\n", - my_config.arm9_gdb_port); - exit( 1); - } - else { - activateStub_gdb( arm9_gdb_stub); - } + &arm9_direct_memory_iface, "ARM9"); + } if ( my_config.arm7_gdb_port > 0) { - arm7_gdb_stub = createStub_gdb( my_config.arm7_gdb_port, + stubs[1] = setup_gdb_stub(my_config.arm7_gdb_port, &NDS_ARM7, - &arm7_base_memory_iface); - - if ( arm7_gdb_stub == NULL) { - fprintf( stderr, "Failed to create ARM7 gdbstub on port %d\n", - my_config.arm7_gdb_port); - exit( 1); - } - else { - activateStub_gdb( arm7_gdb_stub); - } + &arm7_base_memory_iface, "ARM7"); + } + ((CliDriver*)driver)->setStubs(stubs); + gdbstub_wait_set_enabled(stubs[0], 1); + gdbstub_wait_set_enabled(stubs[1], 1); #endif if ( !my_config.disable_sound) { @@ -795,15 +808,12 @@ int main(int argc, char ** argv) { uninit_joy(); #ifdef GDB_STUB - destroyStub_gdb( arm9_gdb_stub); - arm9_gdb_stub = NULL; - - destroyStub_gdb( arm7_gdb_stub); - arm7_gdb_stub = NULL; + destroyStub_gdb( stubs[0]); + destroyStub_gdb( stubs[1]); gdbstub_mutex_destroy(); #endif - + SDL_Quit(); NDS_DeInit(); diff --git a/desmume/src/gdbstub.h b/desmume/src/gdbstub.h index 84a29785b..02414d7f1 100644 --- a/desmume/src/gdbstub.h +++ b/desmume/src/gdbstub.h @@ -45,6 +45,19 @@ destroyStub_gdb( gdbstub_handle_t stub); void activateStub_gdb( gdbstub_handle_t stub); +/* wait until either of 2 gdb stubs gives control back to the emulator. + pass a stubs[2], one of them may be NULL. + return value: response from stub | (stub number<<31), + i.e. if stub 1 responded, the high bit is set (and so the result negative). + the primary usecase for this is to do a blocking wait until the stub returns + control to the emulator, in order to not waste cpu cycles. + returns 0 on failure or if no response was available. */ +int gdbstub_wait( gdbstub_handle_t *stubs); + +/* enable or disable use of the pipe for gdbstub_wait() */ +void gdbstub_wait_set_enabled(gdbstub_handle_t stub, int on); + + /* * An implementation of the following functions is required * for the GDB stub to function. diff --git a/desmume/src/gdbstub/gdbstub.cpp b/desmume/src/gdbstub/gdbstub.cpp index c05b1bd07..046f017fa 100644 --- a/desmume/src/gdbstub/gdbstub.cpp +++ b/desmume/src/gdbstub/gdbstub.cpp @@ -304,9 +304,35 @@ indicateCPUStop_gdb( struct gdb_stub_state *stub) { SEND( stub->ctl_pipe[1], &command, 1); } +int gdbstub_wait(gdbstub_handle_t *stubs) { + struct gdb_stub_state* g[2]; + g[0] = (struct gdb_stub_state *) stubs[0]; + g[1] = (struct gdb_stub_state *) stubs[1]; + fd_set set; + unsigned i; + FD_ZERO(&set); + for (i = 0; i < 2; ++i) + if(g[i]) FD_SET( g[i]->info_pipe[0], &set); + int res = select( FD_SETSIZE, &set, NULL, NULL, NULL); + if (res <= 0) return 0; + for (i = 0; i < 2; ++i) + if ( g[i] && FD_ISSET( g[i]->info_pipe[0], &set)) { + RECV( g[i]->info_pipe[0], &res, 4); + return res | (i << 31); + } + return 0; +} +void gdbstub_wait_set_enabled(gdbstub_handle_t stub, int on) { + struct gdb_stub_state* g = (struct gdb_stub_state *) stub; + if(g) g->info_pipe_enabled = on; +} - +static void infopipe_send(struct gdb_stub_state* g, int status) { + int resp = status; + if (g->info_pipe_enabled) + SEND(g->info_pipe[1], &resp, 4); +} /* * * @@ -701,6 +727,7 @@ processPacket_gdb( SOCKET_TYPE sock, const uint8_t *packet, /* remove the cpu stall */ stub->cpu_ctrl->unstall( stub->cpu_ctrl->data); NDS_debug_continue(); + infopipe_send(stub, 1); break; case 's': { @@ -725,6 +752,7 @@ processPacket_gdb( SOCKET_TYPE sock, const uint8_t *packet, stub->cpu_ctrl->unstall( stub->cpu_ctrl->data); //NDS_debug_step(); NDS_debug_continue(); + infopipe_send(stub, 2); break; } @@ -1537,7 +1565,7 @@ createStub_gdb( uint16_t port, stub->access_breakpoints = NULL; if ( INIT_SOCKETS() != 0) return NULL; - if ( (res = INIT_PIPE(stub->ctl_pipe)) == 0) { + if ( (res = INIT_PIPE(stub->ctl_pipe)) == 0 && INIT_PIPE(stub->info_pipe) == 0) { stub->active = 1; stub->emu_stub_state = gdb_stub_state::RUNNING_EMU_GDB_STATE; stub->ctl_stub_state = gdb_stub_state::STOPPED_GDB_STATE; diff --git a/desmume/src/gdbstub/gdbstub_internal.h b/desmume/src/gdbstub/gdbstub_internal.h index 0e6d2adf0..4d780a18f 100644 --- a/desmume/src/gdbstub/gdbstub_internal.h +++ b/desmume/src/gdbstub/gdbstub_internal.h @@ -171,8 +171,14 @@ struct gdb_stub_state { /** the free breakpoint descriptor list */ struct breakpoint_gdb *free_breakpoints; - /** the control pipe (or socket) to the gdb stub */ + /** the control pipe (or socket) to the gdb stub. this allows to send commands to the stub. */ SOCKET_TYPE ctl_pipe[2]; + + /** this pipe allows the stub to communicate to the controlling program. */ + SOCKET_TYPE info_pipe[2]; + + /** whether above pipe is enabled */ + int info_pipe_enabled; };