Re: [hatari-devel] Re: Hatari debugging help with WinUAE CPU core |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/hatari-devel Archives
]
Hi,
On maanantai 20 tammikuu 2014, Eero Tamminen wrote:
> > Of course - I wouldn't want to have that effect in any debugger. But I
> > would like to be able to configure Hatari to behave like a programmer's
> > debugger as well as an emulation-mode debugger, and respond helpfully
> > to unusual events without much manual intervention while using it. It
> > may just be a case of making a small script and and launching Hatari
> > with that script - but it may not be, which is why I have outlined the
> > scenarios above to add some colour.
>
> With above, "--exceptions <list>" option would specify what things
> will invoke debugger, and "-D" option [1] would toggle that set on
> and off. Normally you would probably specify the set in command
> line and enable catching then in debugger like this:
> > setopt -D
Attached patch implements that and adds several new exception points
for old UAE CPU core. It's help looks following:
-------------------------------------------
$ src/hatari --exceptions help
List of available option flags :
none
bus
address
illegal
zerodiv
chk
trapv
privilege
nohandler
dsp
all
Multiple flags can be separated by ','
They can be prefixed by '+' or '-' to be mixed.
Giving just flags 'none' disables all of them.
-------------------------------------------
Thomas, does the patch look OK to you?
For now all DSP exceptions are behind single "dsp" flag for --exception
option, but I can separate them if it's thought useful.
It would be nice if somebody would look into adding similar stuff
as is in the diff for old UAE newcpu.c, for the WinUAE CPU code...
> (As TOS causes some exceptions at boot for HW detection.)
Not all TOS versions, just some of them (EmuTOS most),
as can be seen with:
$ hatari --exceptions all -D
(-D option needs to be given after changing what exceptions
trigger the debugger.)
- Eero
diff -r 32fe6f0bf5c3 src/includes/configuration.h
--- a/src/includes/configuration.h Mon Jan 20 01:56:24 2014 +0200
+++ b/src/includes/configuration.h Fri Jan 24 00:01:06 2014 +0200
@@ -13,6 +13,7 @@
{
char sLogFileName[FILENAME_MAX];
char sTraceFileName[FILENAME_MAX];
+ int nExceptionDebugMask;
int nTextLogLevel;
int nAlertDlgLogLevel;
bool bConfirmQuit;
diff -r 32fe6f0bf5c3 src/configuration.c
--- a/src/configuration.c Mon Jan 20 01:56:24 2014 +0200
+++ b/src/configuration.c Fri Jan 24 00:01:06 2014 +0200
@@ -41,6 +41,7 @@
{
{ "sLogFileName", String_Tag, ConfigureParams.Log.sLogFileName },
{ "sTraceFileName", String_Tag, ConfigureParams.Log.sTraceFileName },
+ { "nExceptionDebugMask", Int_Tag, &ConfigureParams.Log.nExceptionDebugMask },
{ "nTextLogLevel", Int_Tag, &ConfigureParams.Log.nTextLogLevel },
{ "nAlertDlgLogLevel", Int_Tag, &ConfigureParams.Log.nAlertDlgLogLevel },
{ "bConfirmQuit", Bool_Tag, &ConfigureParams.Log.bConfirmQuit },
@@ -400,6 +401,7 @@
/* Set defaults for logging and tracing */
strcpy(ConfigureParams.Log.sLogFileName, "stderr");
strcpy(ConfigureParams.Log.sTraceFileName, "stderr");
+ ConfigureParams.Log.nExceptionDebugMask = DEFAULT_EXCEPTIONS;
ConfigureParams.Log.nTextLogLevel = LOG_TODO;
ConfigureParams.Log.nAlertDlgLogLevel = LOG_ERROR;
ConfigureParams.Log.bConfirmQuit = true;
diff -r 32fe6f0bf5c3 src/options.c
--- a/src/options.c Mon Jan 20 01:56:24 2014 +0200
+++ b/src/options.c Fri Jan 24 00:01:06 2014 +0200
@@ -142,6 +142,7 @@
OPT_WINCON, /* debug options */
#endif
OPT_DEBUG,
+ OPT_EXCEPTIONS,
OPT_BIOSINTERCEPT,
OPT_CONOUT,
OPT_DISASM,
@@ -377,6 +378,8 @@
#endif
{ OPT_DEBUG, "-D", "--debug",
NULL, "Toggle whether CPU exceptions invoke debugger" },
+ { OPT_EXCEPTIONS, NULL, "--exceptions",
+ NULL, "Which exceptions invoke debugger, see --exceptions help" },
{ OPT_BIOSINTERCEPT, NULL, "--bios-intercept",
NULL, "Toggle X/Bios interception & Hatari XBios 255 support" },
{ OPT_CONOUT, NULL, "--conout",
@@ -1644,15 +1647,29 @@
break;
#endif
case OPT_DEBUG:
- if (bExceptionDebugging)
+ if (ExceptionDebugMask)
{
fprintf(stderr, "Exception debugging disabled.\n");
- bExceptionDebugging = false;
+ ExceptionDebugMask = 0;
}
else
{
- fprintf(stderr, "Exception debugging enabled.\n");
- bExceptionDebugging = true;
+ ExceptionDebugMask = ConfigureParams.Log.nExceptionDebugMask;
+ fprintf(stderr, "Exception debugging enabled (0x%x).\n", ExceptionDebugMask);
+ }
+ break;
+
+ case OPT_EXCEPTIONS:
+ i += 1;
+ /* sets ConfigureParams.Log.nExceptionDebugMask */
+ errstr = Log_SetExceptionDebugMask(argv[i]);
+ if (errstr)
+ {
+ if (!errstr[0]) {
+ /* silent parsing termination */
+ return false;
+ }
+ return Opt_ShowError(OPT_EXCEPTIONS, argv[i], errstr);
}
break;
diff -r 32fe6f0bf5c3 src/debug/debugui.h
--- a/src/debug/debugui.h Mon Jan 20 01:56:24 2014 +0200
+++ b/src/debug/debugui.h Fri Jan 24 00:01:06 2014 +0200
@@ -28,9 +28,6 @@
REASON_USER // e.g. keyboard shortcut
} debug_reason_t;
-/* Whether CPU exceptions invoke DebugUI */
-extern int bExceptionDebugging;
-
extern void DebugUI_Init(void);
extern void DebugUI(debug_reason_t reason);
extern bool DebugUI_ParseLine(const char *input);
diff -r 32fe6f0bf5c3 src/debug/log.h
--- a/src/debug/log.h Mon Jan 20 01:56:24 2014 +0200
+++ b/src/debug/log.h Fri Jan 24 00:01:06 2014 +0200
@@ -11,6 +11,36 @@
#include <SDL_types.h>
+/* Exception debugging
+ * -------------------
+ */
+
+/* CPU exception flags
+ * is catching needed also for: traps 0, 3-12, 15? (MonST catches them)
+ */
+#define EXCEPT_BUS (1<<0)
+#define EXCEPT_ADDRESS (1<<1)
+#define EXCEPT_ILLEGAL (1<<2)
+#define EXCEPT_ZERODIV (1<<3)
+#define EXCEPT_CHK (1<<4)
+#define EXCEPT_TRAPV (1<<5)
+#define EXCEPT_PRIVILEGE (1<<6)
+#define EXCEPT_NOHANDLER (1<<7)
+
+/* DSP exception flags */
+#define EXCEPT_DSP (1<<8)
+
+/* general flags */
+#define EXCEPT_NONE (0)
+#define EXCEPT_ALL (~0)
+
+/* defaults are same as with earlier -D option */
+#define DEFAULT_EXCEPTIONS (EXCEPT_BUS|EXCEPT_ADDRESS|EXCEPT_DSP)
+
+extern int ExceptionDebugMask;
+extern const char* Log_SetExceptionDebugMask(const char *OptionsStr);
+
+
/* Logging
* -------
* Is always enabled as it's information that can be useful
diff -r 32fe6f0bf5c3 src/debug/log.c
--- a/src/debug/log.c Mon Jan 20 01:56:24 2014 +0200
+++ b/src/debug/log.c Fri Jan 24 00:01:06 2014 +0200
@@ -29,12 +29,32 @@
#include "file.h"
#include "vdi.h"
+int ExceptionDebugMask;
+
+typedef struct {
+ Uint64 flag;
+ const char *name;
+} flagname_t;
+
+static flagname_t ExceptionFlags[] = {
+ { EXCEPT_NONE, "none" },
+
+ { EXCEPT_BUS, "bus" },
+ { EXCEPT_ADDRESS, "address" },
+ { EXCEPT_ILLEGAL, "illegal" },
+ { EXCEPT_ZERODIV, "zerodiv" },
+ { EXCEPT_CHK, "chk" },
+ { EXCEPT_TRAPV, "trapv" },
+ { EXCEPT_PRIVILEGE, "privilege" },
+ { EXCEPT_NOHANDLER, "nohandler" },
+
+ { EXCEPT_DSP, "dsp" },
+
+ { EXCEPT_ALL, "all" }
+};
+
#if ENABLE_TRACING
-static struct {
- Uint64 Level;
- const char *Name;
-}
-TraceOptions[] = {
+static flagname_t TraceFlags[] = {
{ TRACE_NONE , "none" },
{ TRACE_VIDEO_SYNC , "video_sync" } ,
@@ -253,55 +273,49 @@
}
-#if ENABLE_TRACING
-
/*-----------------------------------------------------------------------*/
/**
* Parse a list of comma separated strings.
* If the string is prefixed with an optional '+',
- * corresponding trace flag is turned on.
+ * corresponding mask flag is turned on.
* If the string is prefixed with a '-',
- * corresponding trace flag is turned off.
- * Result is stored in LogTraceFlags.
+ * corresponding mask flag is turned off.
* Return error string (""=silent 'error') or NULL for success.
*/
-const char* Log_SetTraceOptions (const char *OptionsStr)
+static const char*
+Log_ParseOptionFlags (const char *FlagsStr, flagname_t *Flags, int MaxFlags, Uint64 *Mask)
{
- char *OptionsCopy;
+ char *FlagsCopy;
char *cur, *sep;
int i;
int Mode; /* 0=add, 1=del */
- int MaxOptions;
-
- MaxOptions = ARRAYSIZE(TraceOptions);
- /* special case for "help" : display the list of possible trace levels */
- if (strcmp (OptionsStr, "help") == 0)
+ /* special case for "help" : display the list of possible settings */
+ if (strcmp (FlagsStr, "help") == 0)
{
- fprintf(stderr, "\nList of available trace levels :\n");
+ fprintf(stderr, "\nList of available option flags :\n");
- for (i = 0; i < MaxOptions; i++)
- fprintf(stderr, " %s\n", TraceOptions[i].Name);
+ for (i = 0; i < MaxFlags; i++)
+ fprintf(stderr, " %s\n", Flags[i].name);
- fprintf(stderr, "Multiple trace levels can be separated by ','\n");
- fprintf(stderr, "Levels can be prefixed by '+' or '-' to be mixed.\n");
- fprintf(stderr, "Giving just trace level 'none' disables all traces.\n\n");
+ fprintf(stderr, "Multiple flags can be separated by ','\n");
+ fprintf(stderr, "They can be prefixed by '+' or '-' to be mixed.\n");
+ fprintf(stderr, "Giving just flags 'none' disables all of them.\n\n");
return "";
}
- LogTraceFlags = TRACE_NONE;
- if (strcmp (OptionsStr, "none") == 0)
+ if (strcmp (FlagsStr, "none") == 0)
{
return NULL;
}
- OptionsCopy = strdup(OptionsStr);
- if (!OptionsCopy)
+ FlagsCopy = strdup(FlagsStr);
+ if (!FlagsCopy)
{
- return "strdup error in ParseTraceOptions";
+ return "strdup error in Log_OptionFlags";
}
- cur = OptionsCopy;
+ cur = FlagsCopy;
while (cur)
{
sep = strchr(cur, ',');
@@ -314,29 +328,67 @@
else if (*cur == '-')
{ Mode = 1; cur++; }
- for (i = 0; i < MaxOptions; i++)
+ for (i = 0; i < MaxFlags; i++)
{
- if (strcmp(cur, TraceOptions[i].Name) == 0)
+ if (strcmp(cur, Flags[i].name) == 0)
break;
}
- if (i < MaxOptions) /* option found */
+ if (i < MaxFlags) /* option found */
{
if (Mode == 0)
- LogTraceFlags |= TraceOptions[i].Level;
+ *Mask |= Flags[i].flag;
else
- LogTraceFlags &= (~TraceOptions[i].Level);
+ *Mask &= (~Flags[i].flag);
}
else
{
- fprintf(stderr, "Unknown trace type '%s'\n", cur);
- free(OptionsCopy);
- return "Unknown trace type.";
+ fprintf(stderr, "Unknown flag type '%s'\n", cur);
+ free(FlagsCopy);
+ return "Unknown flag type.";
}
cur = sep;
}
+ //fprintf(stderr, "flags parse <%x>\n", Mask);
+
+ free (FlagsCopy);
+ return NULL;
+}
+
+/**
+ * Parse exception flags and store results in ExceptionDebugMask.
+ * Return error string or NULL for success.
+ *
+ * See Log_ParseOptionFlags() for details.
+ */
+const char* Log_SetExceptionDebugMask (const char *FlagsStr)
+{
+ const char *errstr;
+
+ Uint64 mask = EXCEPT_NONE;
+ errstr = Log_ParseOptionFlags(FlagsStr, ExceptionFlags, ARRAYSIZE(ExceptionFlags), &mask);
+ ConfigureParams.Log.nExceptionDebugMask = mask;
+ return errstr;
+}
+
+
+#if ENABLE_TRACING
+
+/**
+ * Parse trace flags and store results in LogTraceFlags.
+ * Return error string or NULL for success.
+ *
+ * See Log_ParseOptionFlags() for details.
+ */
+const char* Log_SetTraceOptions (const char *FlagsStr)
+{
+ const char *errstr;
+
+ LogTraceFlags = TRACE_NONE;
+ errstr = Log_ParseOptionFlags(FlagsStr, TraceFlags, ARRAYSIZE(TraceFlags), &LogTraceFlags);
+
/* Enable Hatari flags needed for tracing selected items.
*
* Doesn't enable bBiosInterception for X/Bios because
@@ -345,13 +397,9 @@
if (LogTraceFlags & (TRACE_OS_AES|TRACE_OS_VDI))
bVdiAesIntercept = true;
- //fprintf(stderr, "trace parse <%x>\n", LogTraceFlags);
-
- free (OptionsCopy);
- return NULL;
+ return errstr;
}
-
/**
* Readline match callback for trace type name completion.
* STATE = 0 -> different text from previous one.
@@ -368,8 +416,8 @@
i = 0;
}
/* next match */
- while (i < ARRAYSIZE(TraceOptions)) {
- name = TraceOptions[i++].Name;
+ while (i < ARRAYSIZE(TraceFlags)) {
+ name = TraceFlags[i++].name;
if (strncasecmp(name, text, len) == 0)
return (strdup(name));
}
@@ -379,7 +427,7 @@
#else /* !ENABLE_TRACING */
/** dummy */
-const char* Log_SetTraceOptions (const char *OptionsStr)
+const char* Log_SetTraceOptions (const char *FlagsStr)
{
return "Hatari has been compiled without ENABLE_TRACING!";
}
diff -r 32fe6f0bf5c3 src/falcon/dsp_cpu.c
--- a/src/falcon/dsp_cpu.c Mon Jan 20 01:56:24 2014 +0200
+++ b/src/falcon/dsp_cpu.c Fri Jan 24 00:01:06 2014 +0200
@@ -1425,7 +1425,7 @@
dsp_core.registers[DSP_REG_SP] = value & (3<<DSP_SP_SE);
if (!isDsp_in_disasm_mode)
fprintf(stderr,"Dsp: Stack Overflow or Underflow\n");
- if (bExceptionDebugging)
+ if (ExceptionDebugMask & EXCEPT_DSP)
DebugUI(REASON_DSP_EXCEPTION);
}
else
@@ -1468,7 +1468,7 @@
dsp_add_interrupt(DSP_INTER_STACK_ERROR);
if (!isDsp_in_disasm_mode)
fprintf(stderr,"Dsp: Stack Overflow\n");
- if (bExceptionDebugging)
+ if (ExceptionDebugMask & EXCEPT_DSP)
DebugUI(REASON_DSP_EXCEPTION);
}
@@ -1505,7 +1505,7 @@
dsp_add_interrupt(DSP_INTER_STACK_ERROR);
if (!isDsp_in_disasm_mode)
fprintf(stderr,"Dsp: Stack underflow\n");
- if (bExceptionDebugging)
+ if (ExceptionDebugMask & EXCEPT_DSP)
DebugUI(REASON_DSP_EXCEPTION);
}
@@ -1823,7 +1823,7 @@
cur_inst_len = 1;
dsp_core.instr_cycle = 0;
}
- if (bExceptionDebugging) {
+ if (ExceptionDebugMask & EXCEPT_DSP) {
DebugUI(REASON_DSP_EXCEPTION);
}
}
@@ -2368,7 +2368,7 @@
{
/* Raise interrupt p:0x003e */
dsp_add_interrupt(DSP_INTER_ILLEGAL);
- if (bExceptionDebugging) {
+ if (ExceptionDebugMask & EXCEPT_DSP) {
DebugUI(REASON_DSP_EXCEPTION);
}
}
diff -r 32fe6f0bf5c3 src/uae-cpu/newcpu.c
--- a/src/uae-cpu/newcpu.c Mon Jan 20 01:56:24 2014 +0200
+++ b/src/uae-cpu/newcpu.c Fri Jan 24 00:01:06 2014 +0200
@@ -987,7 +987,7 @@
put_long (m68k_areg(regs, 7)+2, last_fault_for_exception_3);
put_word (m68k_areg(regs, 7)+6, last_op_for_exception_3);
put_long (m68k_areg(regs, 7)+10, last_addr_for_exception_3);
- if (bExceptionDebugging) {
+ if (ExceptionDebugMask & EXCEPT_ADDRESS) {
fprintf(stderr,"Address Error at address $%x, PC=$%x\n",last_fault_for_exception_3,currpc);
DebugUI(REASON_CPU_EXCEPTION);
}
@@ -1014,7 +1014,7 @@
fprintf(stderr, "Detected double bus error at address $%x, PC=$%lx => CPU halted!\n",
BusErrorAddress, (long)currpc);
unset_special(SPCFLAG_BUSERROR);
- if (bExceptionDebugging)
+ if (ExceptionDebugMask & EXCEPT_BUS)
DebugUI(REASON_CPU_EXCEPTION);
else
DlgAlert_Notice("Detected double bus error => CPU halted!\nEmulation needs to be reset.\n");
@@ -1022,7 +1022,7 @@
m68k_setstopped(true);
return;
}
- if (bExceptionDebugging && BusErrorAddress!=0xff8a00) {
+ if ((ExceptionDebugMask & EXCEPT_BUS) && BusErrorAddress!=0xff8a00) {
fprintf(stderr,"Bus Error at address $%x, PC=$%lx\n", BusErrorAddress, (long)currpc);
DebugUI(REASON_CPU_EXCEPTION);
}
@@ -1030,8 +1030,8 @@
}
/* Set PC and flags */
- if (bExceptionDebugging && get_long (regs.vbr + 4*nr) == 0) {
- write_log("Uninitialized exception handler #%i!\n", nr);
+ if ((ExceptionDebugMask & EXCEPT_NOHANDLER) && (regs.vbr + 4*nr) == 0) {
+ fprintf(stderr,"Uninitialized exception handler #%i!\n", nr);
DebugUI(REASON_CPU_EXCEPTION);
}
newpc = get_long (regs.vbr + 4*nr);
@@ -1039,8 +1039,11 @@
{
if ( nr==2 || nr==3 ) /* address error during bus/address error -> stop emulation */
{
- fprintf(stderr,"Address Error during exception 2/3, aborting new PC=$%x\n",newpc);
- DebugUI(REASON_CPU_EXCEPTION);
+ fprintf(stderr,"Address Error during exception 2/3, aborting new PC=$%x\n",newpc);
+ if (ExceptionDebugMask & (EXCEPT_BUS|EXCEPT_ADDRESS))
+ DebugUI(REASON_CPU_EXCEPTION);
+ else
+ DlgAlert_Notice("Address Error during exception 2/3 => CPU halted!\nEmulation needs to be reset.\n");
}
else
{
@@ -1075,16 +1078,46 @@
}
else switch(nr)
{
- case 2: M68000_AddCycles(50); break; /* Bus error */
- case 3: M68000_AddCycles(50); break; /* Address error */
- case 4: M68000_AddCycles(34); break; /* Illegal instruction */
- case 5: M68000_AddCycles(38); break; /* Div by zero */
- case 6: M68000_AddCycles(40); break; /* CHK */
- case 7: M68000_AddCycles(34); break; /* TRAPV */
- case 8: M68000_AddCycles(34); break; /* Privilege violation */
- case 9: M68000_AddCycles(34); break; /* Trace */
- case 10: M68000_AddCycles(34); break; /* Line-A - probably wrong */
- case 11: M68000_AddCycles(34); break; /* Line-F - probably wrong */
+ case 2: /* Bus error */
+ M68000_AddCycles(50); break;
+ case 3: /* Address error */
+ M68000_AddCycles(50); break;
+ case 4: /* Illegal instruction */
+ if (ExceptionDebugMask & EXCEPT_ILLEGAL) {
+ fprintf(stderr, "Illegal instruction at $%lx\n", (long)currpc);
+ DebugUI(REASON_CPU_EXCEPTION);
+ }
+ M68000_AddCycles(34); break;
+ case 5: /* Div by zero */
+ if (ExceptionDebugMask & EXCEPT_ZERODIV) {
+ fprintf(stderr, "Division by zero at $%lx\n", (long)currpc);
+ DebugUI(REASON_CPU_EXCEPTION);
+ }
+ M68000_AddCycles(38); break;
+ case 6: /* CHK */
+ if (ExceptionDebugMask & EXCEPT_CHK) {
+ fprintf(stderr, "CHK instruction at $%lx\n", (long)currpc);
+ DebugUI(REASON_CPU_EXCEPTION);
+ }
+ M68000_AddCycles(40); break;
+ case 7: /* TRAPV */
+ if (ExceptionDebugMask & EXCEPT_TRAPV) {
+ fprintf(stderr, "TRAPV instruction at $%lx\n", (long)currpc);
+ DebugUI(REASON_CPU_EXCEPTION);
+ }
+ M68000_AddCycles(34); break;
+ case 8: /* Privilege violation */
+ if (ExceptionDebugMask & EXCEPT_PRIVILEGE) {
+ fprintf(stderr, "Privilege violation at $%lx\n", (long)currpc);
+ DebugUI(REASON_CPU_EXCEPTION);
+ }
+ M68000_AddCycles(34); break;
+ case 9: /* Trace */
+ M68000_AddCycles(34); break;
+ case 10: /* Line-A - probably wrong */
+ M68000_AddCycles(34); break;
+ case 11: /* Line-F - probably wrong */
+ M68000_AddCycles(34); break;
default:
/* FIXME: Add right cycles value for MFP interrupts and copro exceptions ... */
if(nr < 64)
@@ -1093,7 +1126,6 @@
M68000_AddCycles(44+12); /* Must be a MFP or DSP interrupt */
break;
}
-
}