diff --git a/ChangeLog b/ChangeLog index b0f3ac23..114c0b53 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +October 9, 2009 Wei Mingzhi + + * gui/hdebug.c: Removed PCSX-df debugger, which is incompleted and buggy. + * gui/hdebug.h: Likewise. + * gui/Makefile.am: Likewise. + * libpcsxcore/debug.c: Added telnet-based debugger from PCSX CVS. GUI-based + debugger should be worked on for better usability. + * libpcsxcore/debug.h: Likewise. + * libpcsxcore/socket.c: Likewise. + * libpcsxcore/socket.h: Likewise. + * libpcsxcore/psxinterpreter.c: Likewise. + * libpcsxcore/psxmem.c: Likewise. + * libpcsxcore/r3000a.c: Likewise. + * libpcsxcore/r3000a.h: Likewise. + * libpcsxcore/psxcommon.h: Likewise. + * libpcsxcore/psxcounters.c: Likewise. + * libpcsxcore/Makefile.am: Likewise. + * gui/Config.c: Likewise. + * gui/LnxMain.c: Likewise. + * gui/Gtk2Gui.c: Likewise. + October 4, 2009 Wei Mingzhi * plugins/dfxvideo/gpucfg-0.1df/main.c: Fixed: when trying to choose diff --git a/gui/Config.c b/gui/Config.c index 18c897d7..102f1b09 100644 --- a/gui/Config.c +++ b/gui/Config.c @@ -116,7 +116,7 @@ int LoadConfig(PcsxConfig *Conf) { GetValuel(data, "PsxType", &Config.PsxType); GetValuel(data, "Cdda", &Config.Cdda); GetValuel(data, "Cpu", &Config.Cpu); - GetValuel(data, "Dbg", &Config.Dbg); + GetValuel(data, "Dbg", &Config.Debug); GetValuel(data, "PsxOut", &Config.PsxOut); GetValuel(data, "SpuIrq", &Config.SpuIrq); GetValuel(data, "RCntFix", &Config.RCntFix); @@ -154,7 +154,7 @@ void SaveConfig() { SetValuel("PsxType", Config.PsxType); SetValuel("Cdda", Config.Cdda); SetValuel("Cpu", Config.Cpu); - SetValuel("Dbg", Config.Dbg); + SetValuel("Dbg", Config.Debug); SetValuel("PsxOut", Config.PsxOut); SetValuel("SpuIrq", Config.SpuIrq); SetValuel("RCntFix", Config.RCntFix); diff --git a/gui/Gtk2Gui.c b/gui/Gtk2Gui.c index 11e6f7ab..1397abbd 100644 --- a/gui/Gtk2Gui.c +++ b/gui/Gtk2Gui.c @@ -32,8 +32,6 @@ #include "Linux.h" -#include "hdebug.h" - #include "../libpcsxcore/plugins.h" #include "../libpcsxcore/sio.h" #include "../libpcsxcore/cheat.h" @@ -539,7 +537,6 @@ void OnFile_RunExe() { if (Load(file) == 0) { g_free(file); - if (Config.Dbg) hdb_start(); psxCpu->Execute(); } else { g_free(file); @@ -587,7 +584,6 @@ void OnFile_RunCd() { SysRunGui(); } - if (Config.Dbg) hdb_start(); psxCpu->Execute(); } @@ -618,7 +614,6 @@ void OnFile_RunBios() { CdromId[0] = '\0'; CdromLabel[0] = '\0'; - if (Config.Dbg) hdb_start(); psxCpu->Execute(); } @@ -714,7 +709,6 @@ void OnFile_RunImage() { SysRunGui(); } - if (Config.Dbg) hdb_start(); psxCpu->Execute(); } @@ -731,7 +725,6 @@ void OnEmu_Run() { return; } - if (Config.Dbg) hdb_start(); CheatSearchBackupMemory(); psxCpu->Execute(); } @@ -755,7 +748,6 @@ void OnEmu_Reset() { LoadCdrom(); } - if (Config.Dbg) hdb_start(); psxCpu->Execute(); } @@ -784,7 +776,6 @@ void OnEmu_SwitchImage() { cdOpenCase = time(NULL) + 2; - if (Config.Dbg) hdb_start(); CheatSearchBackupMemory(); psxCpu->Execute(); } @@ -888,7 +879,6 @@ void state_load (gchar *state_filename) { #endif sprintf(Text, _("Loaded state %s."), state_filename); GPU_displayText(Text); - if (Config.Dbg) hdb_start(); psxCpu->Execute(); } else { sprintf(Text, _("Error loading state %s!"), state_filename); @@ -1769,7 +1759,12 @@ void OnCpu_Clicked (GtkDialog *dialog, gint arg1, gpointer user_data) { Config.PsxAuto = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_PsxAuto"))); - Config.Dbg = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_Dbg"))); + t = Config.Debug; + Config.Debug = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_Dbg"))); + if (t != Config.Debug) { + if (Config.Debug) StartDebugger(); + else StopDebugger(); + } t = Config.Cpu; Config.Cpu = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "GtkCheckButton_Cpu"))); @@ -1777,13 +1772,11 @@ void OnCpu_Clicked (GtkDialog *dialog, gint arg1, gpointer user_data) { psxCpu->Shutdown(); #ifdef PSXREC if (Config.Cpu) { - if (Config.Dbg) psxCpu = &psxIntDbg; - else psxCpu = &psxInt; + psxCpu = &psxInt; } else psxCpu = &psxRec; #else - if (Config.Dbg) psxCpu = &psxIntDbg; - else psxCpu = &psxInt; + psxCpu = &psxInt; #endif if (psxCpu->Init() == -1) { SysClose(); @@ -1848,7 +1841,7 @@ void OnConf_Cpu() { gtk_widget_set_sensitive (GTK_WIDGET (glade_xml_get_widget(xml, "GtkCheckButton_Cpu")), FALSE); #endif - gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (glade_xml_get_widget(xml, "GtkCheckButton_Dbg")), Config.Cpu && Config.Dbg); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (glade_xml_get_widget(xml, "GtkCheckButton_Dbg")), Config.Cpu && Config.Debug); gtk_widget_set_sensitive (GTK_WIDGET (glade_xml_get_widget(xml, "GtkCheckButton_Dbg")), Config.Cpu); gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (glade_xml_get_widget(xml, "GtkCheckButton_PsxOut")), Config.PsxOut); diff --git a/gui/LnxMain.c b/gui/LnxMain.c index 9223e636..f1fe1846 100644 --- a/gui/LnxMain.c +++ b/gui/LnxMain.c @@ -464,6 +464,10 @@ int SysInit() { LoadMcds(Config.Mcd1, Config.Mcd2); /* TODO Do we need to have this here, or in the calling main() function?? */ + if (Config.Debug) { + StartDebugger(); + } + return 0; } @@ -475,6 +479,8 @@ void SysClose() { psxShutdown(); ReleasePlugins(); + StopDebugger(); + if (emuLog != NULL) fclose(emuLog); } diff --git a/gui/Makefile.am b/gui/Makefile.am index ee62fa66..a89ed2e2 100644 --- a/gui/Makefile.am +++ b/gui/Makefile.am @@ -13,8 +13,7 @@ pcsx_SOURCES = \ Plugin.c \ Config.c \ Gtk2Gui.c \ - Cheat.c \ - hdebug.c + Cheat.c pcsx_LDADD = \ $(GTK2_LIBS) $(GLADE2_LIBS) -lpthread -lz -lm ../libpcsxcore/libpcsxcore.a diff --git a/gui/Makefile.in b/gui/Makefile.in index 6a61653e..37066e28 100644 --- a/gui/Makefile.in +++ b/gui/Makefile.in @@ -47,7 +47,7 @@ am__installdirs = "$(DESTDIR)$(bindir)" binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) am_pcsx_OBJECTS = LnxMain.$(OBJEXT) Plugin.$(OBJEXT) Config.$(OBJEXT) \ - Gtk2Gui.$(OBJEXT) Cheat.$(OBJEXT) hdebug.$(OBJEXT) + Gtk2Gui.$(OBJEXT) Cheat.$(OBJEXT) pcsx_OBJECTS = $(am_pcsx_OBJECTS) am__DEPENDENCIES_1 = pcsx_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @@ -228,8 +228,7 @@ pcsx_SOURCES = \ Plugin.c \ Config.c \ Gtk2Gui.c \ - Cheat.c \ - hdebug.c + Cheat.c pcsx_LDADD = \ $(GTK2_LIBS) $(GLADE2_LIBS) -lpthread -lz -lm ../libpcsxcore/libpcsxcore.a @@ -310,7 +309,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Gtk2Gui.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LnxMain.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Plugin.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hdebug.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/gui/hdebug.c b/gui/hdebug.c deleted file mode 100644 index 996ba2dd..00000000 --- a/gui/hdebug.c +++ /dev/null @@ -1,386 +0,0 @@ -/*************************************************************************** - * Debugger-Interface for PCSX-DF * - * * - * Copyright (C) 2008 Stefan Sikora * - * hoshy['at']schrauberstube['dot']de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Steet, Fifth Floor, Boston, MA 02111-1307 USA. * - ***************************************************************************/ - -// TODO: -// - setting register values -// - step over instruction -// - Dumping/Loading of memory -// - Better gui-integration - -#include -#include -#include -#include "r3000a.h" -#include "hdebug.h" - -// Global variables -char buffer[1024*2]; -GtkTextBuffer *hdb_listing = 0; -GtkTextBuffer *hdb_memdump = 0; -GtkTextBuffer *hdb_logging = 0; -GtkTextBuffer *hdb_registers = 0; -GtkWidget *hdb_command = 0; -GtkWidget *hdb_pausebutton = 0; - -u32 hdb_memptr = 0x80000000; - -int ready = 0; - -// little helper for syncing with emulator -void waitforpause() { - int actualPC; - - actualPC = psxRegs.pc; - while(actualPC != psxRegs.pc) actualPC = psxRegs.pc; - - gtk_button_set_label(GTK_BUTTON(hdb_pausebutton), "RESUME"); -} - - -// core-debugger-functions -void hdb_update_registers() { - snprintf(buffer, 1024, - "v0 0x%08x s0 0x%08x t0 0x%08x\n" \ - "v1 0x%08x s1 0x%08x t1 0x%08x\n" \ - " s2 0x%08x t2 0x%08x\n" \ - "a0 0x%08x s3 0x%08x t3 0x%08x\n" \ - "a1 0x%08x s4 0x%08x t4 0x%08x\n" \ - "a2 0x%08x s5 0x%08x t5 0x%08x\n" \ - "a3 0x%08x s6 0x%08x t6 0x%08x\n" \ - " s7 0x%08x t7 0x%08x\n" \ - "k0 0x%08x s8 0x%08x t8 0x%08x\n" \ - "k1 0x%08x t9 0x%08x\n\n" \ - "gp 0x%08x at 0x%08x ra 0x%08x\n" \ - "sp 0x%08x pc 0x%08x\n", - psxRegs.GPR.r[2], psxRegs.GPR.r[16], psxRegs.GPR.r[8], - psxRegs.GPR.r[3], psxRegs.GPR.r[17], psxRegs.GPR.r[9], - psxRegs.GPR.r[18], psxRegs.GPR.r[10], - psxRegs.GPR.r[4], psxRegs.GPR.r[19], psxRegs.GPR.r[11], - psxRegs.GPR.r[5], psxRegs.GPR.r[20], psxRegs.GPR.r[12], - psxRegs.GPR.r[6], psxRegs.GPR.r[21], psxRegs.GPR.r[13], - psxRegs.GPR.r[7], psxRegs.GPR.r[22], psxRegs.GPR.r[14], - psxRegs.GPR.r[23], psxRegs.GPR.r[15], - psxRegs.GPR.r[26], psxRegs.GPR.r[30], psxRegs.GPR.r[24], - psxRegs.GPR.r[27], psxRegs.GPR.r[25], - psxRegs.GPR.r[28], psxRegs.GPR.r[1], psxRegs.GPR.r[31], - psxRegs.GPR.r[29], psxRegs.pc); - - gtk_text_buffer_set_text(hdb_registers, buffer, strlen(buffer)); -} - - -void hdb_update_listing(u32 opc) { - int t; - u32 *cptr; - u32 ocod; - char tbuf[100]; - char *bptr; - - buffer[0] = '\0'; - bptr = (char *)&buffer; - opc -= 15*4; - - for(t=0; t<=30; t++) { - cptr = (u32 *)PSXM(opc); - if (t == 15) strcat(bptr, ">"); else strcat(bptr, " "); - ocod = cptr == NULL ? 0 : SWAP32(*cptr); - sprintf(tbuf, "%s\n", disR3000AF(ocod, opc)); - strcat(bptr, tbuf); - opc+=4; - } - strcat(bptr,"\0"); - gtk_text_buffer_set_text(hdb_listing, buffer, strlen(buffer)); -} - - -void hdb_update_memdump() { - int r, c; - char tbuf[100]; - char *bptr; - - buffer[0] = '\0'; - bptr = (char*)&buffer; - - for(r=0; r<8; r++) { - sprintf(tbuf, "0x%08x", hdb_memptr+r*16); - strcat(bptr, tbuf); - for(c=0; c<16; c++) { - if(c==8) sprintf(tbuf, "-%02x", PSXMu8(hdb_memptr+r*16+c)); - else sprintf(tbuf, " %02x", PSXMu8(hdb_memptr+r*16+c)); - strcat(bptr, tbuf); - } - strcat(bptr, "\n"); - } - strcat(bptr, "\0"); - gtk_text_buffer_set_text(hdb_memdump, buffer, strlen(buffer)); -} - - -// Callback-functions -void on_hdb_mainwindow_destroy(GtkWidget *widget, gpointer data) { - hdb_pause = 0; // Run CPU - gtk_widget_destroy((GtkWidget*)widget); - gtk_main_quit(); - while (gtk_events_pending()) gtk_main_iteration(); - pthread_exit(NULL); - ready = 0; -} - - -void on_hdb_pausebutton_clicked(GtkWidget *widget, gpointer data) { - if(hdb_pause == 0) { - hdb_pause = 1; - waitforpause(); - - hdb_update_registers(); - hdb_update_listing(psxRegs.pc); - hdb_update_memdump(); - } - else { - hdb_pause = 0; - gtk_button_set_label(GTK_BUTTON(widget), "PAUSE"); - } -} - -void hdb_auto_pause () { - if(hdb_pause == 0) { - hdb_pause = 1; - //waitforpause(); - - hdb_update_registers(); - hdb_update_listing(psxRegs.pc); - hdb_update_memdump(); - } - else { - hdb_pause = 0; - //gtk_button_set_label(GTK_BUTTON(widget), "PAUSE"); - } -} - -void on_hdb_tracebutton_clicked(GtkWidget *widget, gpointer data) { - // Let emulator do one step and refresh debugger when in pause-mode! - if(hdb_pause == 1) { - hdb_pause = 2; - - waitforpause(); - hdb_update_registers(); - hdb_update_listing(psxRegs.pc); - } -} - - -void on_hdb_dumpbutton_clicked(GtkWidget *widget, gpointer data) { - // Save psx-memory for external analysis/modification - // TODO -} - - -void on_hdb_loadbutton_clicked(GtkWidget *widget, gpointer data) { - // Load psx-memory - // TODO -} - - -void on_hdb_cmdbutton_clicked(GtkWidget *widget, gpointer data) { - const gchar *cmdentry; - char *actcmd; - char *cmdsub; - u32 tval; - u8 tval8; - int t; - - if ((cmdentry = gtk_entry_get_text(GTK_ENTRY(hdb_command))) != NULL) { - actcmd = strdup(cmdentry); - /* split and interpret debugger's commandline - t - trace one instruction - c - continue execution - d addr - disassemble at addr - m addr - show memory at addr (hex) - s addr op1 op2 op3 ... - set memory - b addr - break on addr - bc - clear breakpoint - r reg val - set register to a specific value (TODO) - */ - - // get the command - if ((cmdsub = strtok(actcmd, " ")) != NULL) { - if(!strcmp(cmdsub, "t")) { - hdb_pause = 2; - usleep(100); // wait 1/10th of a second - hdb_update_registers(); - hdb_update_listing(psxRegs.pc); - } - - if(!strcmp(cmdsub, "c")) hdb_pause = 0; - - if(!strcmp(cmdsub, "bc")) { - hdb_break = 0; - } - - if(!strcmp(cmdsub, "b")) { - cmdsub = strtok(NULL, " "); - sscanf(cmdsub, "%x", (u32*)&tval); - hdb_break = tval; - hdb_pause = 3; - - waitforpause(); - hdb_update_memdump(); - hdb_update_registers(); - hdb_update_listing(psxRegs.pc); - } - - if(!strcmp(cmdsub, "d")) { - cmdsub = strtok(NULL, " "); - sscanf(cmdsub, "%x", (u32*)&tval); - hdb_update_listing(tval); - } - - if(!strcmp(cmdsub, "m")) { - cmdsub = strtok(NULL, " "); - sscanf(cmdsub, "%x", (u32*)&tval); - hdb_memptr = tval; - hdb_update_memdump(); - } - - if(!strcmp(cmdsub, "s")) { - cmdsub = strtok(NULL, " "); - sscanf(cmdsub, "%x", (u32 *)&tval); - t = 0; - while((cmdsub = strtok(NULL, " "))) { - u8 v; - sscanf(cmdsub, "%x", (u8 *)&tval8); - PSXMu8(tval+t) = tval8; - t++; - } - hdb_update_memdump(); - hdb_update_listing(psxRegs.pc); - } - - free(actcmd); - } - else { - hdb_update_memdump(); - hdb_update_registers(); - hdb_update_listing(psxRegs.pc); - } - } -} - - -// init debugger and gui -void hdb_init() { - if (ready) return; - GtkWidget *hdb_mainwindow; - GtkWidget *hdb_tracebutton; - GtkWidget *hdb_dumpbutton; - GtkWidget *hdb_loadbutton; - GtkWidget *hdb_cmdbutton; - GtkWidget *hdb_listbox, *hdb_membox, *hdb_logbox, *hdb_regbox; - GtkWidget *hbox, *vbox, *hbox2, *hbox3; - PangoFontDescription *font_desc; - - hdb_pause = 0; // Run CPU - - gtk_init(NULL, NULL); - font_desc = pango_font_description_from_string ("Fixed 8"); - - // create and show the widgets - hdb_mainwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title((GtkWindow*)hdb_mainwindow, "PCSX-DF Debugger"); - gtk_window_set_position((GtkWindow*)hdb_mainwindow, GTK_WIN_POS_CENTER); - - hbox = gtk_hbox_new(FALSE, 2); - vbox = gtk_vbox_new(FALSE, 2); - hbox2 = gtk_hbox_new(FALSE, 2); - hbox3 = gtk_hbox_new(FALSE, 2); - - hdb_registers = gtk_text_buffer_new(NULL); - hdb_regbox = gtk_text_view_new_with_buffer(hdb_registers); - gtk_widget_modify_font(hdb_regbox, font_desc); - - hdb_listing = gtk_text_buffer_new(NULL); - hdb_listbox = gtk_text_view_new_with_buffer(hdb_listing); - gtk_widget_modify_font(hdb_listbox, font_desc); - - hdb_memdump = gtk_text_buffer_new(NULL); - hdb_membox = gtk_text_view_new_with_buffer(hdb_memdump); - gtk_widget_modify_font(hdb_membox, font_desc); - - hdb_logging = gtk_text_buffer_new(NULL); - hdb_logbox = gtk_text_view_new_with_buffer(hdb_logging); - gtk_widget_modify_font(hdb_logbox, font_desc); - - hdb_command = gtk_entry_new(); - hdb_cmdbutton = gtk_button_new_with_label(">"); - - hdb_pausebutton = gtk_button_new_with_label("PAUSE"); - hdb_tracebutton = gtk_button_new_with_label("TRACE"); - hdb_dumpbutton = gtk_button_new_with_label("DUMP"); - hdb_loadbutton = gtk_button_new_with_label("LOAD"); - - gtk_container_add(GTK_CONTAINER(hdb_mainwindow), hbox); - gtk_container_add(GTK_CONTAINER(hbox), vbox); - gtk_container_add(GTK_CONTAINER(hbox), hdb_listbox); - - gtk_container_add(GTK_CONTAINER(vbox), hdb_regbox); - gtk_container_add(GTK_CONTAINER(vbox), hdb_membox); - gtk_container_add(GTK_CONTAINER(vbox), hdb_logbox); - - gtk_container_add(GTK_CONTAINER(hbox3), hdb_command); - gtk_container_add(GTK_CONTAINER(hbox3), hdb_cmdbutton); - - gtk_container_add(GTK_CONTAINER(vbox), hbox3); - gtk_container_add(GTK_CONTAINER(vbox), hbox2); - gtk_container_add(GTK_CONTAINER(hbox2), hdb_pausebutton); - gtk_container_add(GTK_CONTAINER(hbox2), hdb_tracebutton); - gtk_container_add(GTK_CONTAINER(hbox2), hdb_dumpbutton); - gtk_container_add(GTK_CONTAINER(hbox2), hdb_loadbutton); - - pango_font_description_free (font_desc); - - gtk_widget_show_all(hdb_mainwindow); - - // connect signals to callback functions - g_signal_connect(G_OBJECT(hdb_mainwindow), "destroy", G_CALLBACK(on_hdb_mainwindow_destroy), NULL); - g_signal_connect(G_OBJECT(hdb_pausebutton), "clicked", G_CALLBACK(on_hdb_pausebutton_clicked), NULL); - g_signal_connect(G_OBJECT(hdb_tracebutton), "clicked", G_CALLBACK(on_hdb_tracebutton_clicked), NULL); - g_signal_connect(G_OBJECT(hdb_dumpbutton), "clicked", G_CALLBACK(on_hdb_dumpbutton_clicked), NULL); - g_signal_connect(G_OBJECT(hdb_loadbutton), "clicked", G_CALLBACK(on_hdb_loadbutton_clicked), NULL); - g_signal_connect(G_OBJECT(hdb_cmdbutton), "clicked", G_CALLBACK(on_hdb_cmdbutton_clicked), NULL); - - hdb_update_registers(); - hdb_update_listing(psxRegs.pc); - hdb_update_memdump(); - - ready = 1; - gtk_main(); - pthread_exit(NULL); -} - - -// Start debugger in own thread -void hdb_start() { - pthread_t tid; - - pthread_create(&tid, NULL, (void *)hdb_init, NULL); -// hdb_init(); -} diff --git a/gui/hdebug.h b/gui/hdebug.h deleted file mode 100644 index 4e53f69a..00000000 --- a/gui/hdebug.h +++ /dev/null @@ -1,33 +0,0 @@ -/*************************************************************************** - * Debugger-Interface for PCSX-DF * - * * - * Copyright (C) 2008 Stefan Sikora * - * hoshy['at']schrauberstube['dot']de * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Steet, Fifth Floor, Boston, MA 02111-1307 USA. * - ***************************************************************************/ - -#ifndef __HDBUG_H__ -#define __HDBUG_H__ - -// 0 = run cpu, 1 = pause cpu, 2 = trace cpu -int hdb_pause; -unsigned long hdb_break; - -void hdb_start(); -void hdb_auto_pause (); - -#endif /* __HDBUG_H__ */ diff --git a/libpcsxcore/Makefile.am b/libpcsxcore/Makefile.am index cda48978..5704ec5e 100644 --- a/libpcsxcore/Makefile.am +++ b/libpcsxcore/Makefile.am @@ -23,6 +23,7 @@ libpcsxcore_a_SOURCES = \ $(top_builddir)/libpcsxcore/psxhle.c \ $(top_builddir)/libpcsxcore/cdrom.h \ $(top_builddir)/libpcsxcore/coff.h \ + $(top_builddir)/libpcsxcore/debug.c \ $(top_builddir)/libpcsxcore/debug.h \ $(top_builddir)/libpcsxcore/decode_xa.h \ $(top_builddir)/libpcsxcore/gte.h \ @@ -44,7 +45,9 @@ libpcsxcore_a_SOURCES = \ $(top_builddir)/libpcsxcore/cdriso.c \ $(top_builddir)/libpcsxcore/cdriso.h \ $(top_builddir)/libpcsxcore/cheat.c \ - $(top_builddir)/libpcsxcore/cheat.h + $(top_builddir)/libpcsxcore/cheat.h \ + $(top_builddir)/libpcsxcore/socket.c \ + $(top_builddir)/libpcsxcore/socket.h if ARCH_X86_64 libpcsxcore_a_SOURCES += \ diff --git a/libpcsxcore/Makefile.in b/libpcsxcore/Makefile.in index 8483f7b8..87d9fc77 100644 --- a/libpcsxcore/Makefile.in +++ b/libpcsxcore/Makefile.in @@ -88,6 +88,7 @@ am__libpcsxcore_a_SOURCES_DIST = \ $(top_builddir)/libpcsxcore/psxhle.c \ $(top_builddir)/libpcsxcore/cdrom.h \ $(top_builddir)/libpcsxcore/coff.h \ + $(top_builddir)/libpcsxcore/debug.c \ $(top_builddir)/libpcsxcore/debug.h \ $(top_builddir)/libpcsxcore/decode_xa.h \ $(top_builddir)/libpcsxcore/gte.h \ @@ -110,6 +111,8 @@ am__libpcsxcore_a_SOURCES_DIST = \ $(top_builddir)/libpcsxcore/cdriso.h \ $(top_builddir)/libpcsxcore/cheat.c \ $(top_builddir)/libpcsxcore/cheat.h \ + $(top_builddir)/libpcsxcore/socket.c \ + $(top_builddir)/libpcsxcore/socket.h \ $(top_builddir)/libpcsxcore/ix86_64/iR3000A-64.c \ $(top_builddir)/libpcsxcore/ix86_64/ix86-64.c \ $(top_builddir)/libpcsxcore/ix86_64/ix86_cpudetect.c \ @@ -137,9 +140,9 @@ am_libpcsxcore_a_OBJECTS = psxbios.$(OBJEXT) cdrom.$(OBJEXT) \ spu.$(OBJEXT) sio.$(OBJEXT) psxhw.$(OBJEXT) mdec.$(OBJEXT) \ psxmem.$(OBJEXT) misc.$(OBJEXT) plugins.$(OBJEXT) \ decode_xa.$(OBJEXT) r3000a.$(OBJEXT) psxinterpreter.$(OBJEXT) \ - gte.$(OBJEXT) psxhle.$(OBJEXT) cdriso.$(OBJEXT) \ - cheat.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ - $(am__objects_3) + gte.$(OBJEXT) psxhle.$(OBJEXT) debug.$(OBJEXT) \ + cdriso.$(OBJEXT) cheat.$(OBJEXT) socket.$(OBJEXT) \ + $(am__objects_1) $(am__objects_2) $(am__objects_3) libpcsxcore_a_OBJECTS = $(am_libpcsxcore_a_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include depcomp = $(SHELL) $(top_srcdir)/depcomp @@ -330,6 +333,7 @@ libpcsxcore_a_SOURCES = $(top_builddir)/libpcsxcore/psxbios.c \ $(top_builddir)/libpcsxcore/psxhle.c \ $(top_builddir)/libpcsxcore/cdrom.h \ $(top_builddir)/libpcsxcore/coff.h \ + $(top_builddir)/libpcsxcore/debug.c \ $(top_builddir)/libpcsxcore/debug.h \ $(top_builddir)/libpcsxcore/decode_xa.h \ $(top_builddir)/libpcsxcore/gte.h \ @@ -351,7 +355,9 @@ libpcsxcore_a_SOURCES = $(top_builddir)/libpcsxcore/psxbios.c \ $(top_builddir)/libpcsxcore/cdriso.c \ $(top_builddir)/libpcsxcore/cdriso.h \ $(top_builddir)/libpcsxcore/cheat.c \ - $(top_builddir)/libpcsxcore/cheat.h $(am__append_1) \ + $(top_builddir)/libpcsxcore/cheat.h \ + $(top_builddir)/libpcsxcore/socket.c \ + $(top_builddir)/libpcsxcore/socket.h $(am__append_1) \ $(am__append_2) $(am__append_3) @ARCH_PPC_TRUE@libpcsxcore_a_CCASFLAGS = -x assembler-with-cpp -mregnames all: all-am @@ -404,6 +410,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdriso.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdrom.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cheat.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode_xa.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/disr3000a.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gte.Po@am__quote@ @@ -431,6 +438,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/r3000a.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reguse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sio.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spu.Po@am__quote@ .c.o: @@ -692,6 +700,20 @@ psxhle.obj: $(top_builddir)/libpcsxcore/psxhle.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o psxhle.obj `if test -f '$(top_builddir)/libpcsxcore/psxhle.c'; then $(CYGPATH_W) '$(top_builddir)/libpcsxcore/psxhle.c'; else $(CYGPATH_W) '$(srcdir)/$(top_builddir)/libpcsxcore/psxhle.c'; fi` +debug.o: $(top_builddir)/libpcsxcore/debug.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT debug.o -MD -MP -MF $(DEPDIR)/debug.Tpo -c -o debug.o `test -f '$(top_builddir)/libpcsxcore/debug.c' || echo '$(srcdir)/'`$(top_builddir)/libpcsxcore/debug.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/debug.Tpo $(DEPDIR)/debug.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(top_builddir)/libpcsxcore/debug.c' object='debug.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o debug.o `test -f '$(top_builddir)/libpcsxcore/debug.c' || echo '$(srcdir)/'`$(top_builddir)/libpcsxcore/debug.c + +debug.obj: $(top_builddir)/libpcsxcore/debug.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT debug.obj -MD -MP -MF $(DEPDIR)/debug.Tpo -c -o debug.obj `if test -f '$(top_builddir)/libpcsxcore/debug.c'; then $(CYGPATH_W) '$(top_builddir)/libpcsxcore/debug.c'; else $(CYGPATH_W) '$(srcdir)/$(top_builddir)/libpcsxcore/debug.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/debug.Tpo $(DEPDIR)/debug.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(top_builddir)/libpcsxcore/debug.c' object='debug.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o debug.obj `if test -f '$(top_builddir)/libpcsxcore/debug.c'; then $(CYGPATH_W) '$(top_builddir)/libpcsxcore/debug.c'; else $(CYGPATH_W) '$(srcdir)/$(top_builddir)/libpcsxcore/debug.c'; fi` + cdriso.o: $(top_builddir)/libpcsxcore/cdriso.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdriso.o -MD -MP -MF $(DEPDIR)/cdriso.Tpo -c -o cdriso.o `test -f '$(top_builddir)/libpcsxcore/cdriso.c' || echo '$(srcdir)/'`$(top_builddir)/libpcsxcore/cdriso.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/cdriso.Tpo $(DEPDIR)/cdriso.Po @@ -720,6 +742,20 @@ cheat.obj: $(top_builddir)/libpcsxcore/cheat.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cheat.obj `if test -f '$(top_builddir)/libpcsxcore/cheat.c'; then $(CYGPATH_W) '$(top_builddir)/libpcsxcore/cheat.c'; else $(CYGPATH_W) '$(srcdir)/$(top_builddir)/libpcsxcore/cheat.c'; fi` +socket.o: $(top_builddir)/libpcsxcore/socket.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket.o -MD -MP -MF $(DEPDIR)/socket.Tpo -c -o socket.o `test -f '$(top_builddir)/libpcsxcore/socket.c' || echo '$(srcdir)/'`$(top_builddir)/libpcsxcore/socket.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/socket.Tpo $(DEPDIR)/socket.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(top_builddir)/libpcsxcore/socket.c' object='socket.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o socket.o `test -f '$(top_builddir)/libpcsxcore/socket.c' || echo '$(srcdir)/'`$(top_builddir)/libpcsxcore/socket.c + +socket.obj: $(top_builddir)/libpcsxcore/socket.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket.obj -MD -MP -MF $(DEPDIR)/socket.Tpo -c -o socket.obj `if test -f '$(top_builddir)/libpcsxcore/socket.c'; then $(CYGPATH_W) '$(top_builddir)/libpcsxcore/socket.c'; else $(CYGPATH_W) '$(srcdir)/$(top_builddir)/libpcsxcore/socket.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/socket.Tpo $(DEPDIR)/socket.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$(top_builddir)/libpcsxcore/socket.c' object='socket.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o socket.obj `if test -f '$(top_builddir)/libpcsxcore/socket.c'; then $(CYGPATH_W) '$(top_builddir)/libpcsxcore/socket.c'; else $(CYGPATH_W) '$(srcdir)/$(top_builddir)/libpcsxcore/socket.c'; fi` + iR3000A-64.o: $(top_builddir)/libpcsxcore/ix86_64/iR3000A-64.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT iR3000A-64.o -MD -MP -MF $(DEPDIR)/iR3000A-64.Tpo -c -o iR3000A-64.o `test -f '$(top_builddir)/libpcsxcore/ix86_64/iR3000A-64.c' || echo '$(srcdir)/'`$(top_builddir)/libpcsxcore/ix86_64/iR3000A-64.c @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/iR3000A-64.Tpo $(DEPDIR)/iR3000A-64.Po diff --git a/libpcsxcore/debug.c b/libpcsxcore/debug.c new file mode 100644 index 00000000..b5c02b1e --- /dev/null +++ b/libpcsxcore/debug.c @@ -0,0 +1,1144 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2003 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "psxcommon.h" +#include "r3000a.h" +#include "debug.h" +#include "socket.h" + +/* +PCSX Debug console protocol description, version 1.0 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Commands number are formatted using %03X (yes) +Registers number are formatted using %02X. +Breakpoints numbers are formatted using %X +All other values are formatted using %08X, unless specified. + + +Client inputs: +~~~~~~~~~~~~~ +Basic commands (1xx): +-------------------- +100 + Sends a dumb message. Will be replied with a 200 reply, followed by the message. +101 + Gets PCSX version. +102 + Gets protocol version. +103 + Gets status +110 + Gets PC. +111 [reg] + Gets GP register, or all, if no argument. +112 + Gets LO/HI registers. +113 [reg] + Gets COP0 register, or all, if no argument. +114 [reg] + Gets COP2 control register, or all, if no argument. +115 [reg] + Gets COP2 data register, or all, if no argument. +119 [pc] + Disassemble current PC, or given PC. +121 = + Sets a GP register. Will return a 221 message. +122 = + Sets LO or HI register. Will return a 222 message. +123 = + Sets a COP0 register. Will return a 223 message. +124 = + Sets a COP2 control register. Will return a 224 message. +125 = + Sets a COP2 data register. Will return a 225 message. +130 @ + Dumps a range of memory, of size bytes starting at addr. +140 @ + Sets a range of memory, of size bytes starting at addr. + Will have to send immediately exactly size bytes afterward. +150 [number] + Starts/reset mapping execution flow, or stop it if number = 0 +151 [number] + Starts/reset mapping read8 flow, or stop it if number = 0 +152 [number] + Starts/reset mapping read16 flow, or stop it if number = 0 +153 [number] + Starts/reset mapping read32 flow, or stop it if number = 0 +154 [number] + Starts/reset mapping write8 flow, or stop it if number = 0 +155 [number] + Starts/reset mapping write16 flow, or stop it if number = 0 +156 [number] + Starts/reset mapping write32 flow, or stop it if number = 0 +160 [number] + Breaks on map exec flow, or stop it if number = 0 +161 [number] + Breaks on map read8 flow, or stop it if number = 0 +162 [number] + Breaks on map read16 flow, or stop it if number = 0 +163 [number] + Breaks on map read32 flow, or stop it if number = 0 +164 [number] + Breaks on map write8 flow, or stop it if number = 0 +165 [number] + Breaks on map write16 flow, or stop it if number = 0 +166 [number] + Breaks on map write32 flow, or stop it if number = 0 +170 + Dumps the execution flow map in an IDC file + +Execution flow control commands (3xx): +------------------------------------- +300 [number] + Get a list of the actual breakpoints. Will get '400' answers. +301 [number] + Deletes a breakpoint, or all, if no arguments. +310
+ Sets an exec breakpoint. +320
+ Sets a read breakpoint, 1 byte / 8 bits. +321
+ Sets a read breakpoint, 2 bytes / 16 bits, has to be on an even address. +322
+ Sets a read breakpoint, 4 bytes / 32 bits, address has to be 4-bytes aligned. +330
+ Sets a write breakpoint, 1 byte / 8 bits. +331
+ Sets a write breakpoint, 2 bytes / 16 bits, has to be on an even address. +332
+ Sets a write breakpoint, 4 bytes / 32 bits, address has to be 4-bytes aligned. +390 + Pauses execution. Equivalents to a breakpoint. +391 + Restarts execution. +395 [number] + Traces execution, 1 instruction by default. Formatted using %i +398 + Soft (quick) resets. +399 + Resets. + + +Server outputs: +~~~~~~~~~~~~~~ +Spontaneous messages (0xx): +-------------------------- +000 + Greeting banner. +010 / 011 / 012 / 013 / 014 / 015 / 016 + Execution hit mapping flow automatic breakpoint. +030 @ + Execution hit breakpoint, PCSX is paused. Displays PC's value. + +Basic commands acknowledge (2xx): +-------------------------------- +200 + Sends a dumb message. +201 + Returns PCSX version. +202 + Returns protocol version. +203 + status = 0: running; = 1: paused; = 2: trace +210 PC= + Displays current PC value. +211 = + Displays one GP register value. +212 LO= HI= + Displays LO/HI registers. +213 = + Displays one COP0 register value. +214 = + Displays one COP2 control register value. +215 = + Displays one COP2 data register value. +219 + Displays one line of disassembled code. +221 = + Displays one GP register value, ack for modification. +222 LO= HI= + Displays LO/HI registers, ack for modification. +223 = + Displays one COP0 register value, ack for modification. +224 = + Displays one COP2 control register value, ack for modification. +225 = + Displays one COP2 data register value, ack for modification. +230 @ + Dumping memory. Will then raw outputs size bytes. +240 @ + Memory set acknowledge. +250 / 251 / 252 / 253 / 254 / 255 / 256 + Acknolwedge of 15x commands. +260 / 261 / 262 / 263 / 264 / 265 / 266 + Acknolwedge of 16x commands. +270 + Acknolwedge of 170 command. + +Execution flow control commands acknowledge (4xx): +------------------------------------------------- +400 @
- + Displays a breakpoint, where 'type' can be of E, R1, R2, R4, W1, W2 or W4. +401 + Breakpoint deleting acknowledge. +410, 420, 421, 422, 430, 431, 432 + Breakpoint adding acknowledge. Returns the number of the added breakpoint. +490 + Pausing. +491 + Resuming. +495 + Tracing. +498 + Soft resetting. +499 + Resetting. + +Error messages (5xx): +-------------------- +500 + Command not understood. +511 + Invalid GPR register. +512 + Invalid LO/HI register. +513, 514 + Invalid range or address. +530 + Non existant breakpoint. +531, 532, 533 + Invalid breakpoint address. +*/ + +static int debugger_active = 0, paused = 0, trace = 0, reset = 0, resetting = 0; +static int mapping_e = 0, mapping_r8 = 0, mapping_r16 = 0, mapping_r32 = 0, mapping_w8 = 0, mapping_w16 = 0, mapping_w32 = 0; +static int breakmp_e = 0, breakmp_r8 = 0, breakmp_r16 = 0, breakmp_r32 = 0, breakmp_w8 = 0, breakmp_w16 = 0, breakmp_w32 = 0; + +static void ProcessCommands(); + +static u8 *MemoryMap = NULL; + +enum { + MAP_EXEC = 1, + MAP_R8 = 2, + MAP_R16 = 4, + MAP_R32 = 8, + MAP_W8 = 16, + MAP_W16 = 32, + MAP_W32 = 64, + MAP_EXEC_JAL = 128, +}; + +char *breakpoint_type_names[] = { + "E", "R1", "R2", "R4", "W1", "W2", "W4" +}; + +typedef struct breakpoint_s { + struct breakpoint_s *next, *prev; + int number, type; + u32 address; +} breakpoint_t; + +static breakpoint_t *first = NULL; + +int add_breakpoint(int type, u32 address) { + breakpoint_t *bp = (breakpoint_t *)malloc(sizeof(breakpoint_t)); + + bp->type = type; + bp->address = address; + + if (first) { + bp->number = first->prev->number + 1; + bp->next = first; + bp->prev = first->prev; + first->prev = bp; + bp->prev->next = bp; + } else { + first = bp; + bp->number = 1; + bp->next = bp; + bp->prev = bp; + } + + return bp->number; +} + +void delete_breakpoint(breakpoint_t * bp) { + if (bp == first) { + if (bp->next == bp) { + first = NULL; + } else { + first = bp->next; + } + } + + bp->next->prev = bp->prev; + bp->prev->next = bp->next; + + free(bp); +} + +breakpoint_t *next_breakpoint(breakpoint_t *bp) { + return bp->next != first ? bp->next : 0; +} + +breakpoint_t *find_breakpoint(int number) { + breakpoint_t *p; + + for (p = first; p; p = next_breakpoint(p)) { + if (p->number == number) + return p; + } + + return 0; +} + +void StartDebugger() { + if (debugger_active) + return; + + MemoryMap = (u8 *)malloc(0x200000); + if (MemoryMap == NULL) { + SysMessage(_("Error allocating memory")); + return; + } + + if (StartServer() == -1) { + SysPrintf(_("Unable to start debug server.\n")); + return; + } + + SysPrintf(_("Debugger started.\n")); + debugger_active = 1; +} + +void StopDebugger() { + if (!debugger_active) { + StopServer(); + SysPrintf(_("Debugger stopped.\n")); + } + if (MemoryMap != NULL) { + free(MemoryMap); + MemoryMap = NULL; + } + + while (first != NULL) delete_breakpoint(first); + + debugger_active = 0; +} + +void PauseDebugger() { + trace = 0; + paused = 1; +} + +void ResumeDebugger() { + trace = 0; + paused = 0; +} + +void DebugVSync() { + if (!debugger_active || resetting) + return; + + if (reset) { + resetting = 1; + CheckCdrom(); + SysReset(); + if (reset == 2) + LoadCdrom(); + reset = resetting = 0; + return; + } + + GetClient(); + ProcessCommands(); +} + +void MarkMap(u32 address, int mask) { + if ((address & 0xff000000) != 0x80000000) return; + MemoryMap[address & 0x001fffff] |= mask; +} + +int IsMapMarked(u32 address, int mask) { + return (MemoryMap[address & 0x001fffff] & mask) != 0; +} + +void ProcessDebug() { + if (!debugger_active || reset || resetting) + return; + if (trace) { + if (!(--trace)) { + paused = 1; + } + } + if (!paused) { + DebugCheckBP(psxRegs.pc, E); + } + if (mapping_e) { + MarkMap(psxRegs.pc, MAP_EXEC); + if ((psxRegs.code >> 26) == 3) { + MarkMap(_JumpTarget_, MAP_EXEC_JAL); + } + if (((psxRegs.code >> 26) == 0) && ((psxRegs.code && 0x3F) == 9)) { + MarkMap(_Rd_, MAP_EXEC_JAL); + } + } + while (paused) { + GetClient(); + ProcessCommands(); + GPU_updateLace(); + SysUpdate(); + } +} + +static void ProcessCommands() { + int code, i, dumping; + FILE *sfile; + char cmd[257], *arguments, *p, reply[10240], sname[L_tmpnam], *save, *dump; + u32 reg, value, size, address; + breakpoint_t *bp; + + if (!HasClient()) + return; + if (ReadSocket(cmd, 256) > 0) { + arguments = 0; + if (strlen(cmd) <= 2) { + code = 0; + } else if (strlen(cmd) == 3) { + code = strtol(cmd, 0, 16); + } else if (!(isxdigit(cmd[0]) && isxdigit(cmd[1]) && isxdigit(cmd[2]) && (cmd[3] == 0x20))) { + code = 0; + } else if (sscanf(cmd, "%3X ", &code) != 1) { + code = 0; + } else { + arguments = cmd + 4; + } + code = strtol(cmd, &arguments, 16); + while (arguments && *arguments && *arguments == 0x20) + arguments++; + + if (!*arguments) + arguments = 0; + + dumping = 0; + save = 0; + + switch (code) { + case 0x100: + sprintf(reply, "200 %s\r\n", arguments); + break; + case 0x101: + sprintf(reply, "201 %s\r\n", PACKAGE_VERSION); + break; + case 0x102: + sprintf(reply, "202 1.0\r\n"); + break; + case 0x103: + sprintf(reply, "203 %i\r\n", paused ? 1 : trace ? 2 : 0); + break; + case 0x110: + sprintf(reply, "210 PC=%08X\r\n", psxRegs.pc); + break; + case 0x111: + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "511 Malformed 111 command '%s'\r\n", cmd); + break; + } + } + if (!arguments) { + reply[0] = 0; + for (i = 0; i < 32; i++) { + sprintf(reply, "%s211 %02X=%08X\r\n", reply, i, psxRegs.GPR.r[i]); + } + } else { + if ((code >= 0) && (code < 32)) { + sprintf(reply, "211 %02X=%08X\r\n", code, psxRegs.GPR.r[code]); + } else { + sprintf(reply, "511 Invalid GPR register: %X\r\n", code); + } + } + break; + case 0x112: + sprintf(reply, "212 LO=%08X HI=%08X\r\n", psxRegs.GPR.r[33], psxRegs.GPR.r[34]); + break; + case 0x113: + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "511 Malformed 113 command '%s'\r\n", cmd); + break; + } + } + if (!arguments) { + reply[0] = 0; + for (i = 0; i < 32; i++) { + sprintf(reply, "%s213 %02X=%08X\r\n", reply, i, psxRegs.CP0.r[i]); + } + } else { + if ((code >= 0) && (code < 32)) { + sprintf(reply, "213 %02X=%08X\r\n", code, psxRegs.CP0.r[code]); + } else { + sprintf(reply, "511 Invalid COP0 register: %X\r\n", code); + } + } + break; + case 0x114: + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "511 Malformed 114 command '%s'\r\n", cmd); + break; + } + } + if (!arguments) { + reply[0] = 0; + for (i = 0; i < 32; i++) { + sprintf(reply, "%s214 %02X=%08X\r\n", reply, i, psxRegs.CP2C.r[i]); + } + } else { + if ((code >= 0) && (code < 32)) { + sprintf(reply, "214 %02X=%08X\r\n", code, psxRegs.CP2C.r[code]); + } else { + sprintf(reply, "511 Invalid COP2C register: %X\r\n", code); + } + } + break; + case 0x115: + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "511 Malformed 111 command '%s'\r\n", cmd); + break; + } + } + if (!arguments) { + reply[0] = 0; + for (i = 0; i < 32; i++) { + sprintf(reply, "%s215 %02X=%08X\r\n", reply, i, psxRegs.CP2D.r[i]); + } + } else { + if ((code >= 0) && (code < 32)) { + sprintf(reply, "215 %02X=%08X\r\n", code, psxRegs.CP2D.r[code]); + } else { + sprintf(reply, "511 Invalid COP2D register: %X\r\n", code); + } + } + break; + case 0x119: + if (arguments) { + if (sscanf(arguments, "%08X", &code) != 1) { + sprintf(reply, "511 Malformed 119 command '%s'\r\n", cmd); + break; + } + } + if (!arguments) + code = psxRegs.pc; + + sprintf(reply, "219 %s\r\n", disR3000AF(psxMemRead32(code), code)); + break; + case 0x121: + if (!arguments || sscanf(arguments, "%02X=%08X", ®, &value) != 2) { + sprintf(reply, "500 Malformed 121 command '%s'\r\n", arguments); + break; + } + + if (reg < 32) { + psxRegs.GPR.r[reg] = value; + sprintf(reply, "221 %02X=%08X\r\n", reg, value); + } else { + sprintf(reply, "512 Invalid GPR register: %02X\r\n", reg); + } + break; + case 0x122: + if (!arguments || strncmp(arguments, "HI=", 3) == 0) { + reg = 34; + } else if (arguments && strncmp(arguments, "LO=", 3) == 0) { + reg = 33; + } else { + arguments[2] = 0; + sprintf(reply, "512 Invalid LO/HI register: '%s'\r\n", arguments); + break; + } + + if (sscanf(arguments + 3, "%08X", &value) != 1) { + sprintf(reply, "500 Malformed 122 command '%s'\r\n", arguments); + } else { + psxRegs.GPR.r[reg] = value; + sprintf(reply, "222 LO=%08X HI=%08X\r\n", psxRegs.GPR.r[33], psxRegs.GPR.r[34]); + } + break; + case 0x123: + if (!arguments || sscanf(arguments, "%02X=%08X", ®, &value) != 2) { + sprintf(reply, "500 Malformed 123 command '%s'\r\n", arguments); + break; + } + + if (reg < 32) { + psxRegs.CP0.r[reg] = value; + sprintf(reply, "223 %02X=%08X\r\n", reg, value); + } else { + sprintf(reply, "512 Invalid COP0 register: %02X\r\n", reg); + } + break; + case 0x124: + if (!arguments || sscanf(arguments, "%02X=%08X", ®, &value) != 2) { + sprintf(reply, "500 Malformed 124 command '%s'\r\n", arguments); + break; + } + + if (reg < 32) { + psxRegs.CP2C.r[reg] = value; + sprintf(reply, "224 %02X=%08X\r\n", reg, value); + } else { + sprintf(reply, "512 Invalid COP2C register: %02X\r\n", reg); + } + break; + case 0x125: + if (!arguments || sscanf(arguments, "%02X=%08X", ®, &value) != 2) { + sprintf(reply, "500 Malformed 121 command '%s'\r\n", arguments); + break; + } + + if (reg < 32) { + psxRegs.CP2D.r[reg] = value; + sprintf(reply, "225 %02X=%08X\r\n", reg, value); + } else { + sprintf(reply, "512 Invalid COP2D register: %02X\r\n", reg); + } + break; + case 0x130: + if (!arguments || sscanf(arguments, "%08X@%08X", &size, &address) != 2) { + sprintf(reply, "500 Malformed 130 command '%s'\r\n", arguments); + break; + } + + if ((address >= 0x80000000) && ((address + size) <= 0x80200000)) { + sprintf(reply, "230 %08X@%08X\r\n", size, address); + dump = (char *) PSXM(address); + dumping = 1; + } else { + sprintf(reply, "513 Invalid address or range: '%s'\r\n", arguments); + } + break; + case 0x140: + if (!arguments || sscanf(arguments, "%08X@%08X", &size, &address) != 2) { + sprintf(reply, "500 Malformed 140 command '%s'\r\n", arguments); + break; + } + + if ((address >= 0x80000000) && ((address + size) <= 0x80200000)) { + sprintf(reply, "240 %08X@%08X\r\n", size, address); + RawReadSocket((char *)PSXM(address), size); + } else { + sprintf(reply, "514 Invalid address or range: '%s'\r\n", arguments); + } + break; + case 0x150: + code = 1; + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "500 Malformed 150 command '%s'\r\n", cmd); + break; + } + } + if (code) { + mapping_e = 1; + for (i = 0; i < 0x00200000; i++) { + MemoryMap[i] &= ~MAP_EXEC; + MemoryMap[i] &= ~MAP_EXEC_JAL; + } + } else { + mapping_e = 0; + } + sprintf(reply, "250 Mapping of exec flow %s\r\n", code ? "started" : "stopped"); + break; + case 0x151: + code = 1; + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "500 Malformed 151 command '%s'\r\n", cmd); + break; + } + } + if (code) { + mapping_r8 = 1; + for (i = 0; i < 0x00200000; i++) { + MemoryMap[i] &= ~MAP_R8; + } + } else { + mapping_r8 = 0; + } + sprintf(reply, "251 Mapping of read8 flow %s\r\n", code ? "started" : "stopped"); + break; + case 0x152: + code = 1; + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "500 Malformed 152 command '%s'\r\n", cmd); + break; + } + } + if (code) { + mapping_r16 = 1; + for (i = 0; i < 0x00200000; i++) { + MemoryMap[i] &= ~MAP_R16; + } + } else { + mapping_r16 = 0; + } + sprintf(reply, "252 Mapping of read16 flow %s\r\n", code ? "started" : "stopped"); + break; + case 0x153: + code = 1; + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "500 Malformed 153 command '%s'\r\n", cmd); + break; + } + } + if (code) { + mapping_r32 = 1; + for (i = 0; i < 0x00200000; i++) { + MemoryMap[i] &= ~MAP_R32; + } + } else { + mapping_r32 = 0; + } + sprintf(reply, "253 Mapping of read32 flow %s\r\n", code ? "started" : "stopped"); + break; + case 0x154: + code = 1; + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "500 Malformed 154 command '%s'\r\n", cmd); + break; + } + } + if (code) { + mapping_w8 = 1; + for (i = 0; i < 0x00200000; i++) { + MemoryMap[i] &= ~MAP_W8; + } + } else { + mapping_w8 = 0; + } + sprintf(reply, "254 Mapping of write8 flow %s\r\n", code ? "started" : "stopped"); + break; + case 0x155: + code = 1; + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "500 Malformed 155 command '%s'\r\n", cmd); + break; + } + } + if (code) { + mapping_w16 = 1; + for (i = 0; i < 0x00200000; i++) { + MemoryMap[i] &= ~MAP_W16; + } + } else { + mapping_w16 = 0; + } + sprintf(reply, "255 Mapping of write16 flow %s\r\n", code ? "started" : "stopped"); + break; + case 0x156: + code = 1; + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "500 Malformed 156 command '%s'\r\n", cmd); + break; + } + } + if (code) { + mapping_w32 = 1; + for (i = 0; i < 0x00200000; i++) { + MemoryMap[i] &= ~MAP_W32; + } + } else { + mapping_w32 = 0; + } + sprintf(reply, "256 Mapping of write32 flow %s\r\n", code ? "started" : "stopped"); + break; + case 0x160: + code = 1; + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "500 Malformed 160 command '%s'\r\n", cmd); + break; + } + } + if (code) { + breakmp_e = 1; + } else { + breakmp_e = 0; + } + sprintf(reply, "260 Break on map of exec flow %s\r\n", code ? "started" : "stopped"); + break; + case 0x161: + code = 1; + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "500 Malformed 161 command '%s'\r\n", cmd); + break; + } + } + if (code) { + breakmp_r8 = 1; + } else { + breakmp_r8 = 0; + } + sprintf(reply, "261 Break on map of read8 flow %s\r\n", code ? "started" : "stopped"); + break; + case 0x162: + code = 1; + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "500 Malformed 162 command '%s'\r\n", cmd); + break; + } + } + if (code) { + breakmp_r16 = 1; + } else { + breakmp_r16 = 0; + } + sprintf(reply, "262 Break on map of read16 flow %s\r\n", code ? "started" : "stopped"); + break; + case 0x163: + code = 1; + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "500 Malformed 163 command '%s'\r\n", cmd); + break; + } + } + if (code) { + breakmp_r32 = 1; + } else { + breakmp_r32 = 0; + } + sprintf(reply, "263 Break on map of read32 flow %s\r\n", code ? "started" : "stopped"); + break; + case 0x164: + code = 1; + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "500 Malformed 164 command '%s'\r\n", cmd); + break; + } + } + if (code) { + breakmp_w8 = 1; + } else { + breakmp_w8 = 0; + } + sprintf(reply, "264 Break on map of write8 flow %s\r\n", code ? "started" : "stopped"); + break; + case 0x165: + code = 1; + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "500 Malformed 165 command '%s'\r\n", cmd); + break; + } + } + if (code) { + breakmp_w16 = 1; + } else { + breakmp_w16 = 0; + } + sprintf(reply, "265 Break on map of write16 flow %s\r\n", code ? "started" : "stopped"); + break; + case 0x166: + code = 1; + if (arguments) { + if (sscanf(arguments, "%02X", &code) != 1) { + sprintf(reply, "500 Malformed 166 command '%s'\r\n", cmd); + break; + } + } + if (code) { + breakmp_w32 = 1; + } else { + breakmp_w32 = 0; + } + sprintf(reply, "266 Break on map of write32 flow %s\r\n", code ? "started" : "stopped"); + break; + case 0x170: + sfile = fopen("flow.idc", "wb"); + fprintf(sfile, "#include \r\n\r\n"); + fprintf(sfile, "static main(void) {\r\n"); + for (i = 0; i < 0x00200000; i++) { + if (IsMapMarked(i, MAP_EXEC_JAL)) { + fprintf(sfile, "\tMakeFunction(0X8%07X,BADADDR);\r\n", i); + } + } + fprintf(sfile, "}\r\n"); + fclose(sfile); + sfile = fopen("markcode.idc", "wb"); + fprintf(sfile, "#include \r\n\r\n"); + fprintf(sfile, "static main(void) {\r\n"); + for (i = 0; i < 0x00200000; i++) { + if (IsMapMarked(i, MAP_EXEC)) { + fprintf(sfile, "\tMakeCode(0X8%07X);\r\n", i); + } + } + fprintf(sfile, "}\r\n"); + fclose(sfile); + sprintf(reply, "270 flow.idc and markcode.idc dumped\r\n"); + break; + case 0x300: + p = arguments; + if (arguments) { + code = strtol(arguments, &p, 16); + } + if (p == arguments) { + if (first) { + reply[0] = 0; + for (bp = first; bp; bp = next_breakpoint(bp)) { + sprintf(reply, "%s400 %X@%08X-%s\r\n", reply, bp->number, bp->address, breakpoint_type_names[bp->type]); + } + } else { + sprintf(reply, "530 No breakpoint\r\n"); + } + } else { + if ((bp = find_breakpoint(code))) { + sprintf(reply, "400 %X@%08X-%s\r\n", bp->number, bp->address, breakpoint_type_names[bp->type]); + } else { + sprintf(reply, "530 Invalid breakpoint number: %X\r\n", code); + } + } + break; + case 0x301: + p = arguments; + if (arguments) { + code = strtol(arguments, &p, 16); + } + if (p == arguments) { + while (first != NULL) delete_breakpoint(first); + sprintf(reply, "401 All breakpoints deleted.\r\n"); + } else { + if ((bp = find_breakpoint(code))) { + delete_breakpoint(bp); + sprintf(reply, "401 Breakpoint %X deleted.\r\n", code); + } else { + sprintf(reply, "530 Invalid breakpoint number: %X\r\n", code); + } + } + break; + case 0x310: + if (!arguments || sscanf(arguments, "%08X", &address) != 1) { + sprintf(reply, "500 Malformed 310 command '%s'\r\n", arguments); + break; + } +// if ((address & 3) || (address < 0x80000000) || (address >= 0x80200000)) { +// sprintf(reply, "531 Invalid address %08X\r\n", address); +// break; +// } + code = add_breakpoint(E, address); + sprintf(reply, "410 %X\r\n", code); + break; + case 0x320: + if (!arguments || sscanf(arguments, "%08X", &address) != 1) { + sprintf(reply, "500 Malformed 320 command '%s'\r\n", arguments); + break; + } + if ((address < 0x80000000) || (address >= 0x80200000)) { + sprintf(reply, "532 Invalid address %08X\r\n", address); + break; + } + code = add_breakpoint(R1, address); + sprintf(reply, "420 %X\r\n", code); + break; + case 0x321: + if (!arguments || sscanf(arguments, "%08X", &address) != 1) { + sprintf(reply, "500 Malformed 321 command '%s'\r\n", arguments); + break; + } + if ((address & 1) || (address < 0x80000000) || (address >= 0x80200000)) { + sprintf(reply, "532 Invalid address %08X\r\n", address); + break; + } + code = add_breakpoint(R2, address); + sprintf(reply, "421 %X\r\n", code); + break; + case 0x322: + if (!arguments || sscanf(arguments, "%08X", &address) != 1) { + sprintf(reply, "500 Malformed 322 command '%s'\r\n", arguments); + break; + } + if ((address & 3) || (address < 0x80000000) || (address >= 0x80200000)) { + sprintf(reply, "532 Invalid address %08X\r\n", address); + break; + } + code = add_breakpoint(R4, address); + sprintf(reply, "422 %X\r\n", code); + break; + case 0x330: + if (!arguments || sscanf(arguments, "%08X", &address) != 1) { + sprintf(reply, "500 Malformed 330 command '%s'\r\n", arguments); + break; + } + if ((address < 0x80000000) || (address >= 0x80200000)) { + sprintf(reply, "533 Invalid address %08X\r\n", address); + break; + } + code = add_breakpoint(W1, address); + sprintf(reply, "430 %X\r\n", code); + break; + case 0x331: + if (!arguments || sscanf(arguments, "%08X", &address) != 1) { + sprintf(reply, "500 Malformed 331 command '%s'\r\n", arguments); + break; + } + if ((address & 1) || (address < 0x80000000) || (address >= 0x80200000)) { + sprintf(reply, "533 Invalid address %08X\r\n", address); + break; + } + code = add_breakpoint(W2, address); + sprintf(reply, "431 %X\r\n", code); + break; + case 0x332: + if (!arguments || sscanf(arguments, "%08X", &address) != 1) { + sprintf(reply, "500 Malformed 332 command '%s'\r\n", arguments); + break; + } + if ((address & 3) || (address < 0x80000000) || (address >= 0x80200000)) { + sprintf(reply, "533 Invalid address %08X\r\n", address); + break; + } + code = add_breakpoint(W4, address); + sprintf(reply, "432 %X\r\n", code); + break; + case 0x390: + paused = 1; + sprintf(reply, "490 Paused\r\n"); + break; + case 0x391: + paused = 0; + sprintf(reply, "491 Resumed\r\n"); + break; + case 0x395: + p = arguments; + if (arguments) { + trace = strtol(arguments, &p, 10); + } + if (p == arguments) { + trace = 1; + } + paused = 0; + sprintf(reply, "495 Tracing\r\n"); + break; + case 0x398: + paused = 0; + trace = 0; + reset = 2; + sprintf(reply, "498 Soft resetting\r\n"); + break; + case 0x399: + paused = 0; + trace = 0; + reset = 1; + sprintf(reply, "499 Resetting\r\n"); + break; + default: + sprintf(reply, "500 Unknown command '%s'\r\n", cmd); + break; + } + WriteSocket(reply, strlen(reply)); + + if (dumping) { + WriteSocket(dump, size); + } + + if (save) { + free(save); + } + } +} + +void DebugCheckBP(u32 address, enum breakpoint_types type) { + breakpoint_t *bp; + char reply[512]; + + if (!debugger_active || reset) + return; + for (bp = first; bp; bp = next_breakpoint(bp)) { + if ((bp->type == type) && (bp->address == address)) { + sprintf(reply, "030 %X@%08X\r\n", bp->number, psxRegs.pc); + WriteSocket(reply, strlen(reply)); + paused = 1; + return; + } + } + if (breakmp_e && type == E) { + if (!IsMapMarked(address, MAP_EXEC)) { + sprintf(reply, "010 %08X@%08X\r\n", address, psxRegs.pc); + WriteSocket(reply, strlen(reply)); + paused = 1; + } + } + if (breakmp_r8 && type == R1) { + if (!IsMapMarked(address, MAP_R8)) { + sprintf(reply, "011 %08X@%08X\r\n", address, psxRegs.pc); + WriteSocket(reply, strlen(reply)); + paused = 1; + } + } + if (breakmp_r16 && type == R2) { + if (!IsMapMarked(address, MAP_R16)) { + sprintf(reply, "012 %08X@%08X\r\n", address, psxRegs.pc); + WriteSocket(reply, strlen(reply)); + paused = 1; + } + } + if (breakmp_r32 && type == R4) { + if (!IsMapMarked(address, MAP_R32)) { + sprintf(reply, "013 %08X@%08X\r\n", address, psxRegs.pc); + WriteSocket(reply, strlen(reply)); + paused = 1; + } + } + if (breakmp_w8 && type == W1) { + if (!IsMapMarked(address, MAP_W8)) { + sprintf(reply, "014 %08X@%08X\r\n", address, psxRegs.pc); + WriteSocket(reply, strlen(reply)); + paused = 1; + } + } + if (breakmp_w16 && type == W2) { + if (!IsMapMarked(address, MAP_W16)) { + sprintf(reply, "015 %08X@%08X\r\n", address, psxRegs.pc); + WriteSocket(reply, strlen(reply)); + paused = 1; + } + } + if (breakmp_w32 && type == W4) { + if (!IsMapMarked(address, MAP_W32)) { + sprintf(reply, "016 %08X@%08X\r\n", address, psxRegs.pc); + WriteSocket(reply, strlen(reply)); + paused = 1; + } + } + if (mapping_r8 && type == R1) MarkMap(address, MAP_R8); + if (mapping_r16 && type == R2) MarkMap(address, MAP_R16); + if (mapping_r32 && type == R4) MarkMap(address, MAP_R32); + if (mapping_w8 && type == W1) MarkMap(address, MAP_W8); + if (mapping_w16 && type == W2) MarkMap(address, MAP_W16); + if (mapping_w32 && type == W4) MarkMap(address, MAP_W32); + } diff --git a/libpcsxcore/debug.h b/libpcsxcore/debug.h index d61f2ba0..84aa8492 100644 --- a/libpcsxcore/debug.h +++ b/libpcsxcore/debug.h @@ -18,20 +18,35 @@ * 51 Franklin Steet, Fifth Floor, Boston, MA 02111-1307 USA. * ***************************************************************************/ -/* -* Specficies which logs should be activated. -* Ryan TODO: These should ALL be definable with configure flags. -*/ - #ifndef __DEBUG_H__ #define __DEBUG_H__ +enum breakpoint_types { + E, R1, R2, R4, W1, W2, W4 +}; + +void StartDebugger(); +void StopDebugger(); + +void DebugVSync(); +void ProcessDebug(); + +void DebugCheckBP(u32 address, enum breakpoint_types type); + +void PauseDebugger(); +void ResumeDebugger(); + extern char *disRNameCP0[]; char* disR3000AF(u32 code, u32 pc); FILE *emuLog; +/* + * Specficies which logs should be activated. + * Ryan TODO: These should ALL be definable with configure flags. + */ + //#define GTE_DUMP #ifdef GTE_DUMP diff --git a/libpcsxcore/psxcommon.h b/libpcsxcore/psxcommon.h index c3f21ffe..1ccf73fc 100644 --- a/libpcsxcore/psxcommon.h +++ b/libpcsxcore/psxcommon.h @@ -107,7 +107,7 @@ typedef struct { long Cdda; long HLE; long Cpu; - long Dbg; + long Debug; long PsxOut; long SpuIrq; long RCntFix; diff --git a/libpcsxcore/psxcounters.c b/libpcsxcore/psxcounters.c index 0daf3cb8..ef61f9e0 100644 --- a/libpcsxcore/psxcounters.c +++ b/libpcsxcore/psxcounters.c @@ -159,6 +159,7 @@ void psxRcntUpdate() { } psxRcntSet(); + DebugVSync(); } void psxRcntWcount(u32 index, u32 value) { diff --git a/libpcsxcore/psxinterpreter.c b/libpcsxcore/psxinterpreter.c index 2eabc16e..ff5d41b1 100644 --- a/libpcsxcore/psxinterpreter.c +++ b/libpcsxcore/psxinterpreter.c @@ -26,8 +26,6 @@ #include "r3000a.h" #include "gte.h" #include "psxhle.h" -/*FIXME*/ -#include "../gui/hdebug.h" static int branch = 0; static int branch2 = 0; @@ -42,7 +40,6 @@ static u32 branchPC; #endif inline void execI(); -inline void execIDbg(); // Subsets void (*psxBSC[64])(); @@ -773,21 +770,11 @@ static void intExecute() { execI(); } -static void intExecuteDbg() { - for (;;) - execIDbg(); -} - static void intExecuteBlock() { branch2 = 0; while (!branch2) execI(); } -static void intExecuteBlockDbg() { - branch2 = 0; - while (!branch2) execIDbg(); -} - static void intClear(u32 Addr, u32 Size) { } @@ -801,43 +788,14 @@ inline void execI() { debugI(); + if (Config.Debug) ProcessDebug(); + psxRegs.pc += 4; psxRegs.cycle++; psxBSC[psxRegs.code >> 26](); } -/* debugger version */ -inline void execIDbg() { - u32 *code = (u32 *)PSXM(psxRegs.pc); - psxRegs.code = ((code == NULL) ? 0 : SWAP32(*code)); - - // dump opcode when LOG_CPU is enabled - debugI(); - - // normal execution - if (!hdb_pause) { - psxRegs.pc += 4; - psxRegs.cycle++; - psxBSC[psxRegs.code >> 26](); - } - - // trace one instruction - if(hdb_pause == 2) { - psxRegs.pc += 4; - psxRegs.cycle++; - psxBSC[psxRegs.code >> 26](); - hdb_pause = 1; - } - - // wait for breakpoint - if(hdb_pause == 3) { - psxRegs.pc+= 4; psxRegs.cycle++; - psxBSC[psxRegs.code >> 26](); - if(psxRegs.pc == hdb_break) hdb_pause = 1; - } -} - R3000Acpu psxInt = { intInit, intReset, @@ -846,12 +804,3 @@ R3000Acpu psxInt = { intClear, intShutdown }; - -R3000Acpu psxIntDbg = { - intInit, - intReset, - intExecuteDbg, - intExecuteBlockDbg, - intClear, - intShutdown -}; diff --git a/libpcsxcore/psxmem.c b/libpcsxcore/psxmem.c index 8dfc00e6..86ccc121 100644 --- a/libpcsxcore/psxmem.c +++ b/libpcsxcore/psxmem.c @@ -141,6 +141,8 @@ u8 psxMemRead8(u32 mem) { } else { p = (char *)(psxMemRLUT[t]); if (p != NULL) { + if (Config.Debug) + DebugCheckBP((mem & 0xffffff) | 0x80000000, R1); return *(u8 *)(p + (mem & 0xffff)); } else { #ifdef PSXMEM_LOG @@ -164,6 +166,8 @@ u16 psxMemRead16(u32 mem) { } else { p = (char *)(psxMemRLUT[t]); if (p != NULL) { + if (Config.Debug) + DebugCheckBP((mem & 0xffffff) | 0x80000000, R2); return SWAPu16(*(u16 *)(p + (mem & 0xffff))); } else { #ifdef PSXMEM_LOG @@ -187,6 +191,8 @@ u32 psxMemRead32(u32 mem) { } else { p = (char *)(psxMemRLUT[t]); if (p != NULL) { + if (Config.Debug) + DebugCheckBP((mem & 0xffffff) | 0x80000000, R4); return SWAPu32(*(u32 *)(p + (mem & 0xffff))); } else { #ifdef PSXMEM_LOG @@ -210,7 +216,9 @@ void psxMemWrite8(u32 mem, u8 value) { } else { p = (char *)(psxMemWLUT[t]); if (p != NULL) { - *(u8 *)(p + (mem & 0xffff)) = value; + if (Config.Debug) + DebugCheckBP((mem & 0xffffff) | 0x80000000, W1); + *(u8 *)(p + (mem & 0xffff)) = value; #ifdef PSXREC psxCpu->Clear((mem & (~3)), 1); #endif @@ -235,6 +243,8 @@ void psxMemWrite16(u32 mem, u16 value) { } else { p = (char *)(psxMemWLUT[t]); if (p != NULL) { + if (Config.Debug) + DebugCheckBP((mem & 0xffffff) | 0x80000000, W2); *(u16 *)(p + (mem & 0xffff)) = SWAPu16(value); #ifdef PSXREC psxCpu->Clear((mem & (~1)), 1); @@ -261,6 +271,8 @@ void psxMemWrite32(u32 mem, u32 value) { } else { p = (char *)(psxMemWLUT[t]); if (p != NULL) { + if (Config.Debug) + DebugCheckBP((mem & 0xffffff) | 0x80000000, W4); *(u32 *)(p + (mem & 0xffff)) = SWAPu32(value); #ifdef PSXREC psxCpu->Clear(mem, 1); diff --git a/libpcsxcore/r3000a.c b/libpcsxcore/r3000a.c index 6f45a1bb..72d52f37 100644 --- a/libpcsxcore/r3000a.c +++ b/libpcsxcore/r3000a.c @@ -35,12 +35,10 @@ int psxInit() { #ifdef PSXREC if (Config.Cpu) { - if (Config.Dbg) psxCpu = &psxIntDbg; - else psxCpu = &psxInt; + psxCpu = &psxInt; } else psxCpu = &psxRec; #else - if (Config.Dbg) psxCpu = &psxIntDbg; - else psxCpu = &psxInt; + psxCpu = &psxInt; #endif Log = 0; diff --git a/libpcsxcore/r3000a.h b/libpcsxcore/r3000a.h index 56c965fc..aed6ce84 100644 --- a/libpcsxcore/r3000a.h +++ b/libpcsxcore/r3000a.h @@ -37,7 +37,6 @@ typedef struct { R3000Acpu *psxCpu; extern R3000Acpu psxInt; -extern R3000Acpu psxIntDbg; #if (defined(__x86_64__) || defined(__i386__) || defined(__sh__) || defined(__ppc__)) && !defined(NOPSXREC) extern R3000Acpu psxRec; #define PSXREC diff --git a/libpcsxcore/socket.c b/libpcsxcore/socket.c new file mode 100644 index 00000000..5d0cd9f5 --- /dev/null +++ b/libpcsxcore/socket.c @@ -0,0 +1,254 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2003 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#ifdef _WIN32 +#include +#else +#include +#include +#include +#include +#include +#endif +#include + +#include "psxcommon.h" +#include "socket.h" + +static int server_socket = 0; +static int client_socket = 0; + +static char tbuf[513]; +static int ptr = 0; + +#define PORT_NUMBER 12345 + +int StartServer() { + struct hostent * localhostent; + struct in_addr localhostaddr; + struct sockaddr_in localsocketaddr; + +#ifdef _WIN32 + WSADATA wsaData; + + if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) + return -1; +#endif + + server_socket = socket(AF_INET, SOCK_STREAM, 0); + +#ifdef _WIN32 + if (server_socket == INVALID_SOCKET) + return -1; +#else + if (server_socket == -1) + return -1; +#endif + + SetsNonblock(); + + memset((void *)&localhostaddr, 0, sizeof(localhostaddr)); + memset(&localsocketaddr, 0, sizeof(struct sockaddr_in)); + +#ifdef _WIN32 + localhostaddr.S_un.S_addr = htonl(INADDR_ANY); +#else + localhostaddr.s_addr = htonl(INADDR_ANY); +#endif + localsocketaddr.sin_family = AF_INET; + localsocketaddr.sin_addr = localhostaddr; + localsocketaddr.sin_port = htons(PORT_NUMBER); + + if (bind(server_socket, (struct sockaddr *) &localsocketaddr, sizeof(localsocketaddr)) < 0) + return -1; + + if (listen(server_socket, 1) != 0) + return -1; + + return 0; +} + +void StopServer() { +#ifdef _WIN32 + shutdown(server_socket, SD_BOTH); + closesocket(server_socket); + WSACleanup(); +#else + shutdown(server_socket, SHUT_RDWR); + close(server_socket); +#endif +} + +void GetClient() { + int new_socket; + char hello[256]; + + new_socket = accept(server_socket, 0, 0); + +#ifdef _WIN32 + if (new_socket == INVALID_SOCKET) + return; +#else + if (new_socket == -1) + return; +#endif + if (client_socket) + CloseClient(); + client_socket = new_socket; + +#ifndef _WIN32 + { + int flags; + flags = fcntl(client_socket, F_GETFL, 0); + fcntl(client_socket, F_SETFL, flags | O_NONBLOCK); + } +#endif + + sprintf(hello, "000 PCSX Version %s - Debug console\r\n", PACKAGE_VERSION); + WriteSocket(hello, strlen(hello)); + ptr = 0; +} + +void CloseClient() { + if (client_socket) { +#ifdef _WIN32 + shutdown(client_socket, SD_BOTH); + closesocket(client_socket); +#else + shutdown(client_socket, SHUT_RDWR); + close(client_socket); +#endif + client_socket = 0; + } +} + +int HasClient() { + return client_socket ? 1 : 0; +} + +int ReadSocket(char * buffer, int len) { + int r; + char * endl; + + if (!client_socket) + return -1; + + r = recv(client_socket, tbuf + ptr, 512 - ptr, 0); + + if (r == 0) { + client_socket = 0; + if (!ptr) + return 0; + } +#ifdef _WIN32 + if (r == SOCKET_ERROR) +#else + if (r == -1) +#endif + { + if (ptr == 0) + return -1; + r = 0; + } + ptr += r; + tbuf[ptr] = 0; + + endl = strstr(tbuf, "\r\n"); + + if (endl) { + r = endl - tbuf; + strncpy(buffer, tbuf, r); + + r += 2; + memmove(tbuf, tbuf + r, 512 - r); + ptr -= r; + memset(tbuf + r, 0, 512 - r); + r -= 2; + + } else { + r = 0; + } + + buffer[r] = 0; + + return r; +} + +int RawReadSocket(char * buffer, int len) { + int r; + int mlen = len < ptr ? len : ptr; + + if (!client_socket) + return -1; + + if (ptr) { + memcpy(buffer, tbuf, mlen); + ptr -= mlen; + memmove(tbuf, tbuf + mlen, 512 - mlen); + } + + if (len - mlen) + r = recv(client_socket, buffer + mlen, len - mlen, 0); + + if (r == 0) { + client_socket = 0; + if (!ptr) + return 0; + } +#ifdef _WIN32 + if (r == SOCKET_ERROR) +#else + if (r == -1) +#endif + { + if (ptr == 0) + return -1; + r = 0; + } + + r += mlen; + + return r; +} + +void WriteSocket(char * buffer, int len) { + if (!client_socket) + return; + + send(client_socket, buffer, len, 0); +} + +void SetsBlock() { +#ifdef _WIN32 + u_long b = 0; + ioctlsocket(server_socket, FIONBIO, &b); +#else + int flags = fcntl(server_socket, F_GETFL, 0); + fcntl(server_socket, F_SETFL, flags & ~O_NONBLOCK); +#endif +} + +void SetsNonblock() { +#ifdef _WIN32 + u_long b = 1; + ioctlsocket(server_socket, FIONBIO, &b); +#else + int flags = fcntl(server_socket, F_GETFL, 0); + fcntl(server_socket, F_SETFL, flags | O_NONBLOCK); +#endif +} diff --git a/libpcsxcore/socket.h b/libpcsxcore/socket.h new file mode 100644 index 00000000..bb0a978d --- /dev/null +++ b/libpcsxcore/socket.h @@ -0,0 +1,36 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2003 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef __SOCKET_H__ +#define __SOCKET_H__ + +int StartServer(); +void StopServer(); + +void GetClient(); +void CloseClient(); + +int HasClient(); + +int ReadSocket(char * buffer, int len); +int RawReadSocket(char * buffer, int len); +void WriteSocket(char * buffer, int len); + +void SetsBlock(); +void SetsNonblock(); + +#endif