Added support for a WDEB386-style "gt" command to force Windows to deal with its own faults

This commit is contained in:
Jeff Parsons 2015-09-16 13:16:33 -07:00
commit c1a3c3d477

View file

@ -1272,6 +1272,7 @@ if (DEBUGGER) {
if (Interrupts.WINDBG.ENABLED || Interrupts.WINDBGRM.ENABLED) { if (Interrupts.WINDBG.ENABLED || Interrupts.WINDBGRM.ENABLED) {
this.fWinDbg = null; this.fWinDbg = null;
this.fIgnoreNextCheckFault = false;
this.cpu.addIntNotify(Interrupts.WINCB.VECTOR, this.intWindowsCallBack.bind(this)); this.cpu.addIntNotify(Interrupts.WINCB.VECTOR, this.intWindowsCallBack.bind(this));
this.cpu.addIntNotify(Interrupts.WINDBG.VECTOR, this.intWindowsDebugger.bind(this)); this.cpu.addIntNotify(Interrupts.WINDBG.VECTOR, this.intWindowsDebugger.bind(this));
} }
@ -1561,25 +1562,30 @@ if (DEBUGGER) {
break; break;
case Interrupts.WINDBG.CHECKFAULT: // 0x007F case Interrupts.WINDBG.CHECKFAULT: // 0x007F
/* if (this.fWinDbg) {
* TODO: We need some UI to control our response to CHECKFAULT notifications. For now, it's hard-coded. /*
*/ * AX == 0 means handle fault normally, 1 means issue TRAPFAULT
if (DEBUG) this.println("CHECKFAULT: fault=" + str.toHexWord(BX) + " type=" + str.toHexWord(CX)); */
if (this.fWinDbg) cpu.regEAX = (cpu.regEAX & ~0xffff)|1; // AX == 0 means handle fault normally, 1 means issue TRAPFAULT cpu.regEAX = (cpu.regEAX & ~0xffff) | (this.fIgnoreNextCheckFault? 0 : 1);
if (DEBUG) this.println("INT 0x41 CHECKFAULT: fault=" + str.toHexWord(BX) + " type=" + str.toHexWord(CX) + " trapped=" + !this.fIgnoreNextCheckFault);
}
break; break;
case Interrupts.WINDBG.TRAPFAULT: // 0x0083 case Interrupts.WINDBG.TRAPFAULT: // 0x0083
/* /*
* Ordinarily (I think), if we respond with AX=0 to all CHECKFAULT notifications, then * If we responded with AX == 1 to a preceding CHECKFAULT notification, then we should receive the
* all TRAPFAULT notifications should be withheld; however, one exception may be if the user * following TRAPFAULT notification; additionally, a TRAPFAULT notification may be issued without
* is presented with a fault dialog containing a "Debug" button, and the user clicks it.... * any CHECKFAULT warning if the user was presented with a fault dialog containing a "Debug" button,
* and the user clicked it.
* *
* Regardless, whenever we receive this notification, we'll allocate a temporary breakpoint * Regardless, whenever we receive this notification, we allocate a temporary breakpoint at the
* at the reported fault address. * reported fault address.
*/ */
dbgAddr = this.newAddr(cpu.regEDX, CX); if (this.fWinDbg) {
this.println("TRAPFAULT: fault=" + str.toHexWord(BX) + " error=" + str.toHexLong(cpu.regESI) + " addr=" + this.hexAddr(dbgAddr)); dbgAddr = this.newAddr(cpu.regEDX, CX);
this.addBreakpoint(this.aBreakExec, dbgAddr, true); this.println("INT 0x41 TRAPFAULT: fault=" + str.toHexWord(BX) + " error=" + str.toHexLong(cpu.regESI) + " addr=" + this.hexAddr(dbgAddr));
this.addBreakpoint(this.aBreakExec, dbgAddr, true);
}
break; break;
case Interrupts.WINDBG.GETSYMBOL: // 0x008D case Interrupts.WINDBG.GETSYMBOL: // 0x008D
@ -1611,6 +1617,11 @@ if (DEBUGGER) {
break; break;
} }
/*
* Let's try to limit the scope of any "gt" command by resetting this flag after any INT 0x41
*/
this.fIgnoreNextCheckFault = false;
return !this.fWinDbg; return !this.fWinDbg;
}; };
} }
@ -4229,7 +4240,7 @@ if (DEBUGGER) {
dbgAddr.fTempBreak = true; dbgAddr.fTempBreak = true;
} }
else { else {
this.printBreakpoint(aBreak, aBreak.length-1); this.printBreakpoint(aBreak, aBreak.length-1, "set");
this.historyInit(); this.historyInit();
} }
} }
@ -6767,7 +6778,7 @@ if (DEBUGGER) {
* *
* @this {Debugger} * @this {Debugger}
* @param {Array.<string>} [asArgs] * @param {Array.<string>} [asArgs]
* @param {boolean} [fInstruction] (default is true) * @param {boolean} [fInstruction] (true to include the current instruction; default is true)
*/ */
Debugger.prototype.doRegisters = function(asArgs, fInstruction) Debugger.prototype.doRegisters = function(asArgs, fInstruction)
{ {
@ -7023,15 +7034,19 @@ if (DEBUGGER) {
}; };
/** /**
* doRun(sAddr, sOptions, fQuiet) * doRun(sCmd, sAddr, sOptions, fQuiet)
* *
* @this {Debugger} * @this {Debugger}
* @param {string} sAddr * @param {string} sCmd
* @param {string} [sOptions] * @param {string|undefined} [sAddr]
* @param {string} [sOptions] (the rest of the breakpoint command-line)
* @param {boolean} [fQuiet] * @param {boolean} [fQuiet]
*/ */
Debugger.prototype.doRun = function(sAddr, sOptions, fQuiet) Debugger.prototype.doRun = function(sCmd, sAddr, sOptions, fQuiet)
{ {
if (sCmd == "gt") {
this.fIgnoreNextCheckFault = true;
}
if (sAddr !== undefined) { if (sAddr !== undefined) {
var dbgAddr = this.parseAddr(sAddr, true); var dbgAddr = this.parseAddr(sAddr, true);
if (!dbgAddr) return; if (!dbgAddr) return;
@ -7496,11 +7511,11 @@ if (DEBUGGER) {
/** /**
* shiftArgs(asArgs) * shiftArgs(asArgs)
* *
* This is used with commands (eg, "b") that have suffixed variations (eg, "bp", "br", "bw"); * Used with any command (eg, "r") that allows but doesn't require whitespace between command and first argument.
* we extract the suffix from the command and insert it into the argument array as a separate element.
* *
* @this {Debugger} * @this {Debugger}
* @param {Array.<string>} [asArgs] * @param {Array.<string>} [asArgs]
* @return {Array.<string>}
*/ */
Debugger.prototype.shiftArgs = function(asArgs) Debugger.prototype.shiftArgs = function(asArgs)
{ {
@ -7516,6 +7531,7 @@ if (DEBUGGER) {
} }
} }
} }
return asArgs;
}; };
/** /**
@ -7565,27 +7581,24 @@ if (DEBUGGER) {
sCmd = "a " + this.hexAddr(this.dbgAddrAssemble) + ' ' + sCmd; sCmd = "a " + this.hexAddr(this.dbgAddrAssemble) + ' ' + sCmd;
} }
var asArgs = sCmd.replace(/ +/g, ' ').split(' '); var asArgs = this.shiftArgs(sCmd.replace(/ +/g, ' ').split(' '));
var ch0 = asArgs[0].charAt(0).toLowerCase();
switch (ch0) { switch (asArgs[0].charAt(0)) {
case 'a': case 'a':
this.doAssemble(asArgs); this.doAssemble(asArgs);
break; break;
case 'b': case 'b':
this.shiftArgs(asArgs);
this.doBreak(asArgs[0], asArgs[1], sCmd); this.doBreak(asArgs[0], asArgs[1], sCmd);
break; break;
case 'c': case 'c':
this.doClear(asArgs[0]); this.doClear(asArgs[0]);
break; break;
case 'd': case 'd':
if (!COMPILED && asArgs[0] == "debug") { if (!COMPILED && sCmd == "debug") {
window.DEBUG = true; window.DEBUG = true;
this.println("DEBUG checks on"); this.println("DEBUG checks on");
break; break;
} }
this.shiftArgs(asArgs);
this.doDump(asArgs); this.doDump(asArgs);
break; break;
case 'e': case 'e':
@ -7596,7 +7609,7 @@ if (DEBUGGER) {
this.doFreqs(asArgs[1]); this.doFreqs(asArgs[1]);
break; break;
case 'g': case 'g':
this.doRun(asArgs[1], sCmd, fQuiet); this.doRun(asArgs[0], asArgs[1], sCmd, fQuiet);
break; break;
case 'h': case 'h':
this.doHalt(fQuiet); this.doHalt(fQuiet);
@ -7611,7 +7624,6 @@ if (DEBUGGER) {
this.doInput(asArgs[1]); this.doInput(asArgs[1]);
break; break;
case 'k': case 'k':
this.shiftArgs(asArgs);
this.doStackTrace(asArgs[0], asArgs[1]); this.doStackTrace(asArgs[0], asArgs[1]);
break; break;
case 'l': case 'l':
@ -7619,7 +7631,6 @@ if (DEBUGGER) {
this.doList(asArgs[1], true); this.doList(asArgs[1], true);
break; break;
} }
this.shiftArgs(asArgs);
this.doLoad(asArgs); this.doLoad(asArgs);
break; break;
case 'm': case 'm':
@ -7640,11 +7651,10 @@ if (DEBUGGER) {
this.doStep(asArgs[0]); this.doStep(asArgs[0]);
break; break;
case 'r': case 'r':
if (asArgs[0] == "reset") { if (sCmd == "reset") {
if (this.cmp) this.cmp.reset(); if (this.cmp) this.cmp.reset();
break; break;
} }
this.shiftArgs(asArgs);
this.doRegisters(asArgs); this.doRegisters(asArgs);
break; break;
case 's': case 's':
@ -7655,7 +7665,6 @@ if (DEBUGGER) {
} }
break; break;
case 't': case 't':
this.shiftArgs(asArgs);
this.doTrace(asArgs[0], asArgs[1]); this.doTrace(asArgs[0], asArgs[1]);
break; break;
case 'u': case 'u':
@ -7665,11 +7674,9 @@ if (DEBUGGER) {
this.println((APPNAME || "PCjs") + " version " + (XMLVERSION || APPVERSION) + " (" + this.cpu.model + (COMPILED? ",RELEASE" : (DEBUG? ",DEBUG" : ",NODEBUG")) + (PREFETCH? ",PREFETCH" : ",NOPREFETCH") + (TYPEDARRAYS? ",TYPEDARRAYS" : (FATARRAYS? ",FATARRAYS" : ",LONGARRAYS")) + (BACKTRACK? ",BACKTRACK" : ",NOBACKTRACK") + ')'); this.println((APPNAME || "PCjs") + " version " + (XMLVERSION || APPVERSION) + " (" + this.cpu.model + (COMPILED? ",RELEASE" : (DEBUG? ",DEBUG" : ",NODEBUG")) + (PREFETCH? ",PREFETCH" : ",NOPREFETCH") + (TYPEDARRAYS? ",TYPEDARRAYS" : (FATARRAYS? ",FATARRAYS" : ",LONGARRAYS")) + (BACKTRACK? ",BACKTRACK" : ",NOBACKTRACK") + ')');
break; break;
case 'x': case 'x':
this.shiftArgs(asArgs);
this.doExecOptions(asArgs); this.doExecOptions(asArgs);
break; break;
case '?': case '?':
this.shiftArgs(asArgs);
if (asArgs[1]) { if (asArgs[1]) {
this.doPrint(sCmd.substr(1)); this.doPrint(sCmd.substr(1));
break; break;
@ -7677,7 +7684,7 @@ if (DEBUGGER) {
this.doHelp(); this.doHelp();
break; break;
case 'n': case 'n':
if (!COMPILED && asArgs[0] == "nodebug") { if (!COMPILED && sCmd == "nodebug") {
window.DEBUG = false; window.DEBUG = false;
this.println("DEBUG checks off"); this.println("DEBUG checks off");
break; break;