More (very minor) Debugger tweaks

This commit is contained in:
Jeff Parsons 2015-08-12 15:14:50 -07:00
commit 490289c75d

View file

@ -63,6 +63,7 @@ if (DEBUGGER) {
* fComplete true if a complete instruction was processed with this address * fComplete true if a complete instruction was processed with this address
* fTempBreak true if this is a temporary breakpoint address * fTempBreak true if this is a temporary breakpoint address
* sCmd set for breakpoint addresses if there's an associated command string * sCmd set for breakpoint addresses if there's an associated command string
* aCmds preprocessed commands (from sCmd)
* *
* @typedef {{ * @typedef {{
* off:(number|null|undefined), * off:(number|null|undefined),
@ -167,7 +168,7 @@ function Debugger(parmsDbg)
this.aSymbolTable = []; this.aSymbolTable = [];
/* /*
* aVariables is an Object with properties that grows as setVariable() assigns more variables; * aVariables is an object with properties that grows as setVariable() assigns more variables;
* each property corresponds to one variable, where the property name is the variable name (ie, * each property corresponds to one variable, where the property name is the variable name (ie,
* a string beginning with a letter or underscore, followed by zero or more additional letters, * a string beginning with a letter or underscore, followed by zero or more additional letters,
* digits, or underscores) and the property value is the variable's numeric value. See doLet() * digits, or underscores) and the property value is the variable's numeric value. See doLet()
@ -177,7 +178,7 @@ function Debugger(parmsDbg)
* if no base is explicitly indicated (eg, a trailing decimal period), and if you define variable * if no base is explicitly indicated (eg, a trailing decimal period), and if you define variable
* names containing exclusively hex alpha characters (a-f), those variables will take precedence * names containing exclusively hex alpha characters (a-f), those variables will take precedence
* over the corresponding hex values. In other words, if you define variables "a" and "b", you * over the corresponding hex values. In other words, if you define variables "a" and "b", you
* will no longer be able to simply type "a" or "b" to specify the numeric values 10 or 11. * will no longer be able to simply type "a" or "b" to specify the decimal values 10 or 11.
*/ */
this.aVariables = {}; this.aVariables = {};
@ -267,7 +268,7 @@ if (DEBUGGER) {
Debugger.COMMANDS = { Debugger.COMMANDS = {
'?': "help/print", '?': "help/print",
'a [#]': "assemble", 'a [#]': "assemble",
'b [#]': "breakpoint", 'b [#]': "breakpoint", // multiple variations (use b? to list them)
'c': "clear output", 'c': "clear output",
'd [#]': "dump memory", 'd [#]': "dump memory",
'e [#]': "edit memory", 'e [#]': "edit memory",
@ -279,9 +280,9 @@ if (DEBUGGER) {
'l': "load sector(s)", 'l': "load sector(s)",
'm': "messages", 'm': "messages",
'o [#]': "output port #", 'o [#]': "output port #",
'p': "step over", 'p': "step over", // other variations: pr (step and dump registers)
'r': "dump/set registers", 'r': "dump/set registers",
't [#]': "step instruction(s)", 't [#]': "trace", // other variations: tr (trace and dump registers)
'u [#]': "unassemble", 'u [#]': "unassemble",
'x': "execution options", 'x': "execution options",
'if': "eval expression", 'if': "eval expression",
@ -2072,7 +2073,7 @@ if (DEBUGGER) {
var iHistory = this.iOpcodeHistory; var iHistory = this.iOpcodeHistory;
var aHistory = this.aOpcodeHistory; var aHistory = this.aOpcodeHistory;
if (aHistory.length) { if (aHistory.length) {
var n = (sCount === undefined? this.nextHistory : +sCount); var n = (sCount === undefined? this.nextHistory : +sCount); // warning: decimal instead of hex conversion
if (isNaN(n)) if (isNaN(n))
n = cLines; n = cLines;
else else
@ -2814,7 +2815,7 @@ if (DEBUGGER) {
/* /*
* Because we called cpu.stepCPU() and not cpu.runCPU(), we must nudge the cpu's update code, * Because we called cpu.stepCPU() and not cpu.runCPU(), we must nudge the cpu's update code,
* and then update our own state. Normally, the only time fUpdateCPU will be false is when doStep() * and then update our own state. Normally, the only time fUpdateCPU will be false is when doTrace()
* is calling us in a loop, in which case it will perform its own updateCPU() when it's done. * is calling us in a loop, in which case it will perform its own updateCPU() when it's done.
*/ */
if (fUpdateCPU !== false) this.cpu.updateCPU(); if (fUpdateCPU !== false) this.cpu.updateCPU();
@ -2846,11 +2847,11 @@ if (DEBUGGER) {
this.dbgAddrNextCode = this.newAddr(this.cpu.getIP(), this.cpu.getCS()); this.dbgAddrNextCode = this.newAddr(this.cpu.getIP(), this.cpu.getCS());
/* /*
* this.fProcStep used to be a simple boolean, but now it's 0 (or undefined) * this.nStep used to be a simple boolean, but now it's 0 (or undefined)
* if inactive, 1 if stepping over an instruction without a register dump, or 2 * if inactive, 1 if stepping over an instruction without a register dump, or 2
* if stepping over an instruction with a register dump. * if stepping over an instruction with a register dump.
*/ */
if (!fRegs || this.fProcStep == 1) if (!fRegs || this.nStep == 1)
this.doUnassemble(); this.doUnassemble();
else { else {
this.doRegisters(null); this.doRegisters(null);
@ -3005,7 +3006,7 @@ if (DEBUGGER) {
*/ */
Debugger.prototype.start = function(ms, nCycles) Debugger.prototype.start = function(ms, nCycles)
{ {
if (!this.fProcStep) this.println("running"); if (!this.nStep) this.println("running");
this.aFlags.fRunning = true; this.aFlags.fRunning = true;
this.msStart = ms; this.msStart = ms;
this.nCyclesStart = nCycles; this.nCyclesStart = nCycles;
@ -3025,7 +3026,7 @@ if (DEBUGGER) {
if (this.aFlags.fRunning) { if (this.aFlags.fRunning) {
this.aFlags.fRunning = false; this.aFlags.fRunning = false;
this.nCycles = nCycles - this.nCyclesStart; this.nCycles = nCycles - this.nCyclesStart;
if (!this.fProcStep) { if (!this.nStep) {
var sStopped = "stopped"; var sStopped = "stopped";
if (this.nCycles) { if (this.nCycles) {
var msTotal = ms - this.msStart; var msTotal = ms - this.msStart;
@ -3378,7 +3379,7 @@ if (DEBUGGER) {
{ {
if (addr !== undefined) { if (addr !== undefined) {
this.checkBreakpoint(addr, 1, this.aBreakExec, true); this.checkBreakpoint(addr, 1, this.aBreakExec, true);
this.fProcStep = 0; this.nStep = 0;
} else { } else {
for (var i = 1; i < this.aBreakExec.length; i++) { for (var i = 1; i < this.aBreakExec.length; i++) {
var dbgAddrBreak = this.aBreakExec[i]; var dbgAddrBreak = this.aBreakExec[i];
@ -4378,10 +4379,11 @@ if (DEBUGGER) {
* *
* @this {Debugger} * @this {Debugger}
* @param {string|undefined} sValue * @param {string|undefined} sValue
* @param {string} [sName] is the name of the value, if any * @param {string|null} [sName] is the name of the value, if any
* @param {boolean} [fQuiet]
* @return {number|undefined} numeric value, or undefined if sValue is either undefined or invalid * @return {number|undefined} numeric value, or undefined if sValue is either undefined or invalid
*/ */
Debugger.prototype.parseValue = function(sValue, sName) Debugger.prototype.parseValue = function(sValue, sName, fQuiet)
{ {
var value; var value;
if (sValue !== undefined) { if (sValue !== undefined) {
@ -4390,13 +4392,11 @@ if (DEBUGGER) {
value = this.getRegValue(iReg); value = this.getRegValue(iReg);
} else { } else {
value = this.getVariable(sValue); value = this.getVariable(sValue);
if (value === undefined) { if (value === undefined) value = str.parseInt(sValue);
value = str.parseInt(sValue);
}
} }
if (value === undefined) this.println("invalid " + (sName? sName : "value") + ": " + sValue); if (value === undefined && !fQuiet) this.println("invalid " + (sName? sName : "value") + ": " + sValue);
} else { } else {
this.println("missing " + (sName || "value")); if (!fQuiet) this.println("missing " + (sName || "value"));
} }
return value; return value;
}; };
@ -4965,7 +4965,7 @@ if (DEBUGGER) {
this.println("\tdd [a] [#] dump # dwords at address a"); this.println("\tdd [a] [#] dump # dwords at address a");
this.println("\tdh [#] [#] dump # instructions from history"); this.println("\tdh [#] [#] dump # instructions from history");
if (BACKTRACK) { if (BACKTRACK) {
this.println("\tdi [a] dump backtrack info at address a"); this.println("\tdi [a] dump backtrack info for address a");
} }
this.println("\tds [#] dump descriptor info for selector #"); this.println("\tds [#] dump descriptor info for selector #");
if (sDumpers.length) this.println("dump extensions:\n\t" + sDumpers); if (sDumpers.length) this.println("dump extensions:\n\t" + sDumpers);
@ -5204,7 +5204,7 @@ if (DEBUGGER) {
var fPrint = false; var fPrint = false;
if (sCategory == "DUMP") { if (sCategory == "DUMP") {
var sDump = ""; var sDump = "";
var cLines = (sEnable === undefined? -1 : +sEnable); var cLines = (sEnable === undefined? -1 : +sEnable); // warning: decimal instead of hex conversion
var i = this.iTraceBuffer; var i = this.iTraceBuffer;
do { do {
var s = this.aTraceBuffer[i++]; var s = this.aTraceBuffer[i++];
@ -5562,7 +5562,7 @@ if (DEBUGGER) {
switch (asArgs[1]) { switch (asArgs[1]) {
case "cs": case "cs":
var nCycles; var nCycles;
if (asArgs[3] !== undefined) nCycles = +asArgs[3]; if (asArgs[3] !== undefined) nCycles = +asArgs[3]; // warning: decimal instead of hex conversion
switch (asArgs[2]) { switch (asArgs[2]) {
case "int": case "int":
this.cpu.aCounts.nCyclesChecksumInterval = nCycles; this.cpu.aCounts.nCyclesChecksumInterval = nCycles;
@ -5929,21 +5929,21 @@ if (DEBUGGER) {
}; };
/** /**
* doProcStep(sCmd) * doStep(sCmd)
* *
* @this {Debugger} * @this {Debugger}
* @param {string} [sCmd] "p" or "pr" * @param {string} [sCmd] "p" or "pr"
*/ */
Debugger.prototype.doProcStep = function(sCmd) Debugger.prototype.doStep = function(sCmd)
{ {
var fCallStep = true; var fCallStep = true;
var fRegs = (sCmd == "pr"? 1 : 0); var fRegs = (sCmd == "pr"? 1 : 0);
/* /*
* Set up the value for this.fProcStep (ie, 1 or 2) depending on whether the user wants * Set up the value for this.nStep (ie, 1 or 2) depending on whether the user wants
* a subsequent register dump ("pr") or not ("p"). * a subsequent register dump ("pr") or not ("p").
*/ */
var fProcStep = 1 + fRegs; var nStep = 1 + fRegs;
if (!this.fProcStep) { if (!this.nStep) {
var fPrefix; var fPrefix;
var fRepeat = false; var fRepeat = false;
var dbgAddr = this.newAddr(this.cpu.getIP(), this.cpu.getCS()); var dbgAddr = this.newAddr(this.cpu.getIP(), this.cpu.getCS());
@ -5965,25 +5965,25 @@ if (DEBUGGER) {
break; break;
case X86.OPCODE.INT3: case X86.OPCODE.INT3:
case X86.OPCODE.INTO: case X86.OPCODE.INTO:
this.fProcStep = fProcStep; this.nStep = nStep;
this.incAddr(dbgAddr, 1); this.incAddr(dbgAddr, 1);
break; break;
case X86.OPCODE.INTN: case X86.OPCODE.INTN:
case X86.OPCODE.LOOPNZ: case X86.OPCODE.LOOPNZ:
case X86.OPCODE.LOOPZ: case X86.OPCODE.LOOPZ:
case X86.OPCODE.LOOP: case X86.OPCODE.LOOP:
this.fProcStep = fProcStep; this.nStep = nStep;
this.incAddr(dbgAddr, 2); this.incAddr(dbgAddr, 2);
break; break;
case X86.OPCODE.CALL: case X86.OPCODE.CALL:
if (fCallStep) { if (fCallStep) {
this.fProcStep = fProcStep; this.nStep = nStep;
this.incAddr(dbgAddr, 3); this.incAddr(dbgAddr, 3);
} }
break; break;
case X86.OPCODE.CALLF: case X86.OPCODE.CALLF:
if (fCallStep) { if (fCallStep) {
this.fProcStep = fProcStep; this.nStep = nStep;
this.incAddr(dbgAddr, 5); this.incAddr(dbgAddr, 5);
} }
break; break;
@ -5991,7 +5991,7 @@ if (DEBUGGER) {
if (fCallStep) { if (fCallStep) {
var w = this.getWord(dbgAddr) & X86.OPCODE.CALLMASK; var w = this.getWord(dbgAddr) & X86.OPCODE.CALLMASK;
if (w == X86.OPCODE.CALLW || w == X86.OPCODE.CALLFDW) { if (w == X86.OPCODE.CALLW || w == X86.OPCODE.CALLFDW) {
this.fProcStep = fProcStep; this.nStep = nStep;
this.getInstruction(dbgAddr); // advance dbgAddr past this variable-length CALL this.getInstruction(dbgAddr); // advance dbgAddr past this variable-length CALL
} }
} }
@ -6016,7 +6016,7 @@ if (DEBUGGER) {
case X86.OPCODE.SCASB: case X86.OPCODE.SCASB:
case X86.OPCODE.SCASW: case X86.OPCODE.SCASW:
if (fRepeat) { if (fRepeat) {
this.fProcStep = fProcStep; this.nStep = nStep;
this.incAddr(dbgAddr, 1); this.incAddr(dbgAddr, 1);
} }
break; break;
@ -6025,19 +6025,19 @@ if (DEBUGGER) {
} }
} while (fPrefix); } while (fPrefix);
if (this.fProcStep) { if (this.nStep) {
this.setTempBreakpoint(dbgAddr); this.setTempBreakpoint(dbgAddr);
if (!this.runCPU()) { if (!this.runCPU()) {
this.cpu.setFocus(); this.cpu.setFocus();
this.fProcStep = 0; this.nStep = 0;
} }
/* /*
* A successful run will ultimately call stop(), which will in turn call clearTempBreakpoint(), * A successful run will ultimately call stop(), which will in turn call clearTempBreakpoint(),
* which will clear fProcStep, so there's your assurance that fProcStep will be reset. Now we may * which will clear nStep, so there's your assurance that nStep will be reset. Now we may
* have stopped for reasons unrelated to the temporary breakpoint, but that's OK. * have stopped for reasons unrelated to the temporary breakpoint, but that's OK.
*/ */
} else { } else {
this.doStep(fRegs? "tr" : "t"); this.doTrace(fRegs? "tr" : "t");
} }
} else { } else {
this.println("step in progress"); this.println("step in progress");
@ -6120,17 +6120,17 @@ if (DEBUGGER) {
}; };
/** /**
* doStep(sCmd, sCount) * doTrace(sCmd, sCount)
* *
* @this {Debugger} * @this {Debugger}
* @param {string} [sCmd] "t" or "tr" * @param {string} [sCmd] "t" or "tr"
* @param {string} [sCount] # of instructions to step * @param {string} [sCount] # of instructions to step
*/ */
Debugger.prototype.doStep = function(sCmd, sCount) Debugger.prototype.doTrace = function(sCmd, sCount)
{ {
var dbg = this; var dbg = this;
var fRegs = (sCmd == "tr"); var fRegs = (sCmd == "tr");
var count = (sCount != null? +sCount : 1); var count = this.parseValue(sCount, null, true) || 1;
var nCycles = (count == 1? 0 : 1); var nCycles = (count == 1? 0 : 1);
web.onCountRepeat( web.onCountRepeat(
count, count,
@ -6234,7 +6234,7 @@ if (DEBUGGER) {
var bOpcode = this.getByte(dbgAddr); var bOpcode = this.getByte(dbgAddr);
var addr = dbgAddr.addr; var addr = dbgAddr.addr;
var nSequence = (this.isBusy(false) || this.fProcStep)? this.nCycles : null; var nSequence = (this.isBusy(false) || this.nStep)? this.nCycles : null;
var sComment = (nSequence != null? "cycles" : null); var sComment = (nSequence != null? "cycles" : null);
var aSymbol = this.findSymbolAtAddr(dbgAddr); var aSymbol = this.findSymbolAtAddr(dbgAddr);
@ -6412,7 +6412,7 @@ if (DEBUGGER) {
this.doPrint(sCmd.substr(5)); this.doPrint(sCmd.substr(5));
break; break;
} }
this.doProcStep(asArgs[0]); this.doStep(asArgs[0]);
break; break;
case 'r': case 'r':
if (asArgs[0] == "reset") { if (asArgs[0] == "reset") {
@ -6424,13 +6424,13 @@ if (DEBUGGER) {
break; break;
case 't': case 't':
this.shiftArgs(asArgs); this.shiftArgs(asArgs);
this.doStep(asArgs[0], asArgs[1]); this.doTrace(asArgs[0], asArgs[1]);
break; break;
case 'u': case 'u':
this.doUnassemble(asArgs[1], asArgs[2], 8); this.doUnassemble(asArgs[1], asArgs[2], 8);
break; break;
case 'v': case 'v':
this.println((APPNAME || "PCjs") + " version " + 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.shiftArgs(asArgs);