Added support for user-defined Debugger variables (see 'let' and 'print' commands)

This commit is contained in:
Jeff Parsons 2015-08-12 14:25:45 -07:00
commit 8fef77f067
4 changed files with 334 additions and 99 deletions

View file

@ -166,6 +166,21 @@ function Debugger(parmsDbg)
*/ */
this.aSymbolTable = []; this.aSymbolTable = [];
/*
* 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,
* 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()
* and setVariable() for details.
*
* Note that parseValue(), through its reliance on str.parseInt(), assumes a default base of 16
* 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
* 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.
*/
this.aVariables = {};
/* /*
* clearBreakpoints() initializes the breakpoints lists: aBreakExec is a list of addresses * clearBreakpoints() initializes the breakpoints lists: aBreakExec is a list of addresses
* to halt on whenever attempting to execute an instruction at the corresponding address, * to halt on whenever attempting to execute an instruction at the corresponding address,
@ -269,7 +284,10 @@ if (DEBUGGER) {
't [#]': "step instruction(s)", 't [#]': "step instruction(s)",
'u [#]': "unassemble", 'u [#]': "unassemble",
'x': "execution options", 'x': "execution options",
'reset': "reset computer", 'if': "eval expression",
'let': "assign expression",
'print': "print expression",
'reset': "reset machine",
'ver': "display version" 'ver': "display version"
}; };
@ -2244,144 +2262,204 @@ if (DEBUGGER) {
}; };
/** /**
* getRegValue(iReg) * getRegString(iReg)
* *
* @this {Debugger} * @this {Debugger}
* @param {number} iReg * @param {number} iReg
* @return {string} * @return {string}
*/ */
Debugger.prototype.getRegString = function(iReg) {
var cch = 0;
var n = this.getRegValue(iReg);
if (n !== undefined) {
switch(iReg) {
case Debugger.REG_AL:
case Debugger.REG_CL:
case Debugger.REG_DL:
case Debugger.REG_BL:
case Debugger.REG_AH:
case Debugger.REG_CH:
case Debugger.REG_DH:
case Debugger.REG_BH:
cch = 2;
break;
case Debugger.REG_AX:
case Debugger.REG_CX:
case Debugger.REG_DX:
case Debugger.REG_BX:
case Debugger.REG_SP:
case Debugger.REG_BP:
case Debugger.REG_SI:
case Debugger.REG_DI:
case Debugger.REG_IP:
case Debugger.REG_SEG + Debugger.REG_ES:
case Debugger.REG_SEG + Debugger.REG_CS:
case Debugger.REG_SEG + Debugger.REG_SS:
case Debugger.REG_SEG + Debugger.REG_DS:
case Debugger.REG_SEG + Debugger.REG_FS:
case Debugger.REG_SEG + Debugger.REG_GS:
cch = 4;
break;
case Debugger.REG_EAX:
case Debugger.REG_ECX:
case Debugger.REG_EDX:
case Debugger.REG_EBX:
case Debugger.REG_ESP:
case Debugger.REG_EBP:
case Debugger.REG_ESI:
case Debugger.REG_EDI:
case Debugger.REG_CR0:
case Debugger.REG_CR1:
case Debugger.REG_CR2:
case Debugger.REG_CR3:
case Debugger.REG_EIP:
cch = 8;
break;
case Debugger.REG_PS:
cch = this.cchReg;
break;
}
}
return cch? str.toHex(n, cch) : "??";
};
/**
* getRegValue(iReg)
*
* @this {Debugger}
* @param {number} iReg
* @return {number|undefined}
*/
Debugger.prototype.getRegValue = function(iReg) { Debugger.prototype.getRegValue = function(iReg) {
var s = "??"; var n;
if (iReg >= 0) { if (iReg >= 0) {
var n, cch;
var cpu = this.cpu; var cpu = this.cpu;
switch(iReg) { switch(iReg) {
case Debugger.REG_AL: case Debugger.REG_AL:
n = cpu.regEAX; cch = 2; n = cpu.regEAX;
break; break;
case Debugger.REG_CL: case Debugger.REG_CL:
n = cpu.regECX; cch = 2; n = cpu.regECX;
break; break;
case Debugger.REG_DL: case Debugger.REG_DL:
n = cpu.regEDX; cch = 2; n = cpu.regEDX;
break; break;
case Debugger.REG_BL: case Debugger.REG_BL:
n = cpu.regEBX; cch = 2; n = cpu.regEBX;
break; break;
case Debugger.REG_AH: case Debugger.REG_AH:
n = cpu.regEAX >> 8; cch = 2; n = cpu.regEAX >> 8;
break; break;
case Debugger.REG_CH: case Debugger.REG_CH:
n = cpu.regECX >> 8; cch = 2; n = cpu.regECX >> 8;
break; break;
case Debugger.REG_DH: case Debugger.REG_DH:
n = cpu.regEDX >> 8; cch = 2; n = cpu.regEDX >> 8;
break; break;
case Debugger.REG_BH: case Debugger.REG_BH:
n = cpu.regEBX >> 8; cch = 2; n = cpu.regEBX >> 8;
break; break;
case Debugger.REG_AX: case Debugger.REG_AX:
n = cpu.regEAX; cch = 4; n = cpu.regEAX;
break; break;
case Debugger.REG_CX: case Debugger.REG_CX:
n = cpu.regECX; cch = 4; n = cpu.regECX;
break; break;
case Debugger.REG_DX: case Debugger.REG_DX:
n = cpu.regEDX; cch = 4; n = cpu.regEDX;
break; break;
case Debugger.REG_BX: case Debugger.REG_BX:
n = cpu.regEBX; cch = 4; n = cpu.regEBX;
break; break;
case Debugger.REG_SP: case Debugger.REG_SP:
n = cpu.getSP(); cch = 4; n = cpu.getSP();
break; break;
case Debugger.REG_BP: case Debugger.REG_BP:
n = cpu.regEBP; cch = 4; n = cpu.regEBP;
break; break;
case Debugger.REG_SI: case Debugger.REG_SI:
n = cpu.regESI; cch = 4; n = cpu.regESI;
break; break;
case Debugger.REG_DI: case Debugger.REG_DI:
n = cpu.regEDI; cch = 4; n = cpu.regEDI;
break; break;
case Debugger.REG_IP: case Debugger.REG_IP:
n = cpu.getIP(); cch = 4; n = cpu.getIP();
break; break;
case Debugger.REG_PS: case Debugger.REG_PS:
n = cpu.getPS(); cch = this.cchReg; n = cpu.getPS();
break; break;
case Debugger.REG_SEG + Debugger.REG_ES: case Debugger.REG_SEG + Debugger.REG_ES:
n = cpu.getES(); cch = 4; n = cpu.getES();
break; break;
case Debugger.REG_SEG + Debugger.REG_CS: case Debugger.REG_SEG + Debugger.REG_CS:
n = cpu.getCS(); cch = 4; n = cpu.getCS();
break; break;
case Debugger.REG_SEG + Debugger.REG_SS: case Debugger.REG_SEG + Debugger.REG_SS:
n = cpu.getSS(); cch = 4; n = cpu.getSS();
break; break;
case Debugger.REG_SEG + Debugger.REG_DS: case Debugger.REG_SEG + Debugger.REG_DS:
n = cpu.getDS(); cch = 4; n = cpu.getDS();
break; break;
} default:
if (!cch) {
if (this.cpu.model == X86.MODEL_80286) { if (this.cpu.model == X86.MODEL_80286) {
if (iReg == Debugger.REG_CR0) { if (iReg == Debugger.REG_CR0) {
n = cpu.regCR0; cch = 4; n = cpu.regCR0;
} }
} }
else if (I386 && this.cpu.model >= X86.MODEL_80386) { else if (I386 && this.cpu.model >= X86.MODEL_80386) {
switch(iReg) { switch(iReg) {
case Debugger.REG_EAX: case Debugger.REG_EAX:
n = cpu.regEAX; cch = 8; n = cpu.regEAX;
break; break;
case Debugger.REG_ECX: case Debugger.REG_ECX:
n = cpu.regECX; cch = 8; n = cpu.regECX;
break; break;
case Debugger.REG_EDX: case Debugger.REG_EDX:
n = cpu.regEDX; cch = 8; n = cpu.regEDX;
break; break;
case Debugger.REG_EBX: case Debugger.REG_EBX:
n = cpu.regEBX; cch = 8; n = cpu.regEBX;
break; break;
case Debugger.REG_ESP: case Debugger.REG_ESP:
n = cpu.getSP(); cch = 8; n = cpu.getSP();
break; break;
case Debugger.REG_EBP: case Debugger.REG_EBP:
n = cpu.regEBP; cch = 8; n = cpu.regEBP;
break; break;
case Debugger.REG_ESI: case Debugger.REG_ESI:
n = cpu.regESI; cch = 8; n = cpu.regESI;
break; break;
case Debugger.REG_EDI: case Debugger.REG_EDI:
n = cpu.regEDI; cch = 8; n = cpu.regEDI;
break; break;
case Debugger.REG_CR0: case Debugger.REG_CR0:
n = cpu.regCR0; cch = 8; n = cpu.regCR0;
break; break;
case Debugger.REG_CR1: case Debugger.REG_CR1:
n = cpu.regCR1; cch = 8; n = cpu.regCR1;
break; break;
case Debugger.REG_CR2: case Debugger.REG_CR2:
n = cpu.regCR2; cch = 8; n = cpu.regCR2;
break; break;
case Debugger.REG_CR3: case Debugger.REG_CR3:
n = cpu.regCR3; cch = 8; n = cpu.regCR3;
break; break;
case Debugger.REG_SEG + Debugger.REG_FS: case Debugger.REG_SEG + Debugger.REG_FS:
n = cpu.getFS(); cch = 4; n = cpu.getFS();
break; break;
case Debugger.REG_SEG + Debugger.REG_GS: case Debugger.REG_SEG + Debugger.REG_GS:
n = cpu.getGS(); cch = 4; n = cpu.getGS();
break; break;
case Debugger.REG_EIP: case Debugger.REG_EIP:
n = cpu.getIP(); cch = 8; n = cpu.getIP();
break; break;
} }
} }
break;
} }
if (cch) s = str.toHex(n, cch);
} }
return s; return n;
}; };
/** /**
@ -2400,7 +2478,7 @@ if (DEBUGGER) {
while ((i = s.indexOf('%', i)) >= 0) { while ((i = s.indexOf('%', i)) >= 0) {
var iReg = this.getRegIndex(s, i + 1); var iReg = this.getRegIndex(s, i + 1);
if (iReg >= 0) { if (iReg >= 0) {
s = s.substr(0, i) + this.getRegValue(iReg) + s.substr(i + 1 + Debugger.REGS[iReg].length); s = s.substr(0, i) + this.getRegString(iReg) + s.substr(i + 1 + Debugger.REGS[iReg].length);
} }
i++; i++;
} }
@ -2485,28 +2563,34 @@ if (DEBUGGER) {
}; };
/** /**
* messageInt(nInt, addr) * messageInt(nInt, addr, fForce)
* *
* @this {Debugger} * @this {Debugger}
* @param {number} nInt * @param {number} nInt
* @param {number} addr (LIP after the "INT n" instruction has been fetched but not dispatched) * @param {number} addr (LIP after the "INT n" instruction has been fetched but not dispatched)
* @param {boolean} [fForce] (true if the message should be forced)
* @return {boolean} true if message generated (which in turn triggers addIntReturn() inside checkIntNotify()), false if not * @return {boolean} true if message generated (which in turn triggers addIntReturn() inside checkIntNotify()), false if not
*/ */
Debugger.prototype.messageInt = function(nInt, addr) Debugger.prototype.messageInt = function(nInt, addr, fForce)
{ {
var AH = this.cpu.regEAX >> 8; var fMessage, AH, DL;
var fMessage = this.messageEnabled(Messages.CPU) && nInt != 0x28 && nInt != 0x2A; if (fForce) {
var nCategory = Debugger.INT_MESSAGES[nInt]; fMessage = true;
if (nCategory) { } else {
if (this.messageEnabled(nCategory)) { fMessage = this.messageEnabled(Messages.CPU) && nInt != Interrupts.DOS_IDLE.VECTOR /* 0x28 */ && nInt != Interrupts.DOS_NETBIOS.VECTOR /* 0x2A */;
fMessage = true; var nCategory = Debugger.INT_MESSAGES[nInt];
} else { if (nCategory) {
fMessage = (nCategory == Messages.FDC && this.messageEnabled(nCategory = Messages.HDC)); if (this.messageEnabled(nCategory)) {
fMessage = true;
} else {
fMessage = (nCategory == Messages.FDC && this.messageEnabled(nCategory = Messages.HDC));
}
} }
} }
if (fMessage) { if (fMessage) {
var DL = this.cpu.regEDX & 0xff; AH = this.cpu.regEAX >> 8;
if (nInt == Interrupts.DOS.VECTOR && AH == 0x0b || DL = this.cpu.regEDX & 0xff;
if (nInt == Interrupts.DOS.VECTOR /* 0x21 */ && AH == 0x0b ||
nCategory == Messages.FDC && DL >= 0x80 || nCategory == Messages.HDC && DL < 0x80) { nCategory == Messages.FDC && DL >= 0x80 || nCategory == Messages.HDC && DL < 0x80) {
fMessage = false; fMessage = false;
} }
@ -3838,13 +3922,13 @@ if (DEBUGGER) {
}; };
/** /**
* getFlagStr(sFlag) * getFlagOutput(sFlag)
* *
* @this {Debugger} * @this {Debugger}
* @param {string} sFlag * @param {string} sFlag
* @return {string} value of flag * @return {string} value of flag
*/ */
Debugger.prototype.getFlagStr = function(sFlag) Debugger.prototype.getFlagOutput = function(sFlag)
{ {
var b; var b;
switch (sFlag) { switch (sFlag) {
@ -3895,35 +3979,35 @@ if (DEBUGGER) {
}; };
/** /**
* getRegString(iReg) * getRegOutput(iReg)
* *
* @this {Debugger} * @this {Debugger}
* @param {number} iReg * @param {number} iReg
* @return {string} * @return {string}
*/ */
Debugger.prototype.getRegString = function(iReg) Debugger.prototype.getRegOutput = function(iReg)
{ {
if (iReg >= Debugger.REG_AX && iReg <= Debugger.REG_DI && this.cchReg > 4) iReg += Debugger.REG_EAX - Debugger.REG_AX; if (iReg >= Debugger.REG_AX && iReg <= Debugger.REG_DI && this.cchReg > 4) iReg += Debugger.REG_EAX - Debugger.REG_AX;
var sReg = Debugger.REGS[iReg]; var sReg = Debugger.REGS[iReg];
if (iReg == Debugger.REG_CR0 && this.cpu.model == X86.MODEL_80286) sReg = "MS"; if (iReg == Debugger.REG_CR0 && this.cpu.model == X86.MODEL_80286) sReg = "MS";
return sReg + '=' + this.getRegValue(iReg) + ' '; return sReg + '=' + this.getRegString(iReg) + ' ';
}; };
/** /**
* getSegString(seg, fProt) * getSegOutput(seg, fProt)
* *
* @this {Debugger} * @this {Debugger}
* @param {X86Seg} seg * @param {X86Seg} seg
* @param {boolean} [fProt] * @param {boolean} [fProt]
* @return {string} * @return {string}
*/ */
Debugger.prototype.getSegString = function(seg, fProt) Debugger.prototype.getSegOutput = function(seg, fProt)
{ {
return seg.sName + '=' + str.toHex(seg.sel, 4) + (fProt? '[' + str.toHex(seg.base, this.cchAddr) + ',' + this.getLimitString(seg.limit) + ']' : ""); return seg.sName + '=' + str.toHex(seg.sel, 4) + (fProt? '[' + str.toHex(seg.base, this.cchAddr) + ',' + this.getLimitString(seg.limit) + ']' : "");
}; };
/** /**
* getDTRString(sName, sel, addr, addrLimit) * getDTROutput(sName, sel, addr, addrLimit)
* *
* @this {Debugger} * @this {Debugger}
* @param {string} sName * @param {string} sName
@ -3932,7 +4016,7 @@ if (DEBUGGER) {
* @param {number} addrLimit * @param {number} addrLimit
* @return {string} * @return {string}
*/ */
Debugger.prototype.getDTRString = function(sName, sel, addr, addrLimit) Debugger.prototype.getDTROutput = function(sName, sel, addr, addrLimit)
{ {
return sName + '=' + (sel != null? str.toHex(sel, 4) : "") + '[' + str.toHex(addr, this.cchAddr) + ',' + str.toHex(addrLimit - addr, 4) + ']'; return sName + '=' + (sel != null? str.toHex(sel, 4) : "") + '[' + str.toHex(addr, this.cchAddr) + ',' + str.toHex(addrLimit - addr, 4) + ']';
}; };
@ -3985,17 +4069,17 @@ if (DEBUGGER) {
{ {
var s; var s;
if (fProt === undefined) fProt = this.getProtMode(); if (fProt === undefined) fProt = this.getProtMode();
s = this.getRegString(Debugger.REG_AX) + s = this.getRegOutput(Debugger.REG_AX) +
this.getRegString(Debugger.REG_BX) + this.getRegOutput(Debugger.REG_BX) +
this.getRegString(Debugger.REG_CX) + this.getRegOutput(Debugger.REG_CX) +
this.getRegString(Debugger.REG_DX) + (this.cchReg > 4? '\n' : '') + this.getRegOutput(Debugger.REG_DX) + (this.cchReg > 4? '\n' : '') +
this.getRegString(Debugger.REG_SP) + this.getRegOutput(Debugger.REG_SP) +
this.getRegString(Debugger.REG_BP) + this.getRegOutput(Debugger.REG_BP) +
this.getRegString(Debugger.REG_SI) + this.getRegOutput(Debugger.REG_SI) +
this.getRegString(Debugger.REG_DI) + '\n' + this.getRegOutput(Debugger.REG_DI) + '\n' +
this.getSegString(this.cpu.segSS, fProt) + ' ' + this.getSegOutput(this.cpu.segSS, fProt) + ' ' +
this.getSegString(this.cpu.segDS, fProt) + ' ' + this.getSegOutput(this.cpu.segDS, fProt) + ' ' +
this.getSegString(this.cpu.segES, fProt) + ' '; this.getSegOutput(this.cpu.segES, fProt) + ' ';
if (fProt) { if (fProt) {
var sTR = "TR=" + str.toHex(this.cpu.segTSS.sel, 4); var sTR = "TR=" + str.toHex(this.cpu.segTSS.sel, 4);
var sA20 = "A20=" + (this.bus.getA20()? "ON " : "OFF "); var sA20 = "A20=" + (this.bus.getA20()? "ON " : "OFF ");
@ -4003,29 +4087,29 @@ if (DEBUGGER) {
sTR = '\n' + sTR; sTR = '\n' + sTR;
s += sA20; sA20 = ''; s += sA20; sA20 = '';
} }
s += '\n' + this.getSegString(this.cpu.segCS, fProt) + ' '; s += '\n' + this.getSegOutput(this.cpu.segCS, fProt) + ' ';
if (I386 && this.cpu.model >= X86.MODEL_80386) { if (I386 && this.cpu.model >= X86.MODEL_80386) {
sA20 += '\n'; sA20 += '\n';
s += this.getSegString(this.cpu.segFS, fProt) + ' ' + s += this.getSegOutput(this.cpu.segFS, fProt) + ' ' +
this.getSegString(this.cpu.segGS, fProt) + '\n'; this.getSegOutput(this.cpu.segGS, fProt) + '\n';
} }
s += this.getDTRString("LD", this.cpu.segLDT.sel, this.cpu.segLDT.base, this.cpu.segLDT.base + this.cpu.segLDT.limit) + ' ' + s += this.getDTROutput("LD", this.cpu.segLDT.sel, this.cpu.segLDT.base, this.cpu.segLDT.base + this.cpu.segLDT.limit) + ' ' +
this.getDTRString("GD", null, this.cpu.addrGDT, this.cpu.addrGDTLimit) + ' ' + this.getDTROutput("GD", null, this.cpu.addrGDT, this.cpu.addrGDTLimit) + ' ' +
this.getDTRString("ID", null, this.cpu.addrIDT, this.cpu.addrIDTLimit) + ' '; this.getDTROutput("ID", null, this.cpu.addrIDT, this.cpu.addrIDTLimit) + ' ';
s += sTR + ' ' + sA20; s += sTR + ' ' + sA20;
s += this.getRegString(Debugger.REG_CR0); s += this.getRegOutput(Debugger.REG_CR0);
if (I386 && this.cpu.model >= X86.MODEL_80386) { if (I386 && this.cpu.model >= X86.MODEL_80386) {
s += this.getRegString(Debugger.REG_CR2) + this.getRegString(Debugger.REG_CR3); s += this.getRegOutput(Debugger.REG_CR2) + this.getRegOutput(Debugger.REG_CR3);
} }
} else { } else {
if (I386 && this.cpu.model >= X86.MODEL_80386) { if (I386 && this.cpu.model >= X86.MODEL_80386) {
s += this.getSegString(this.cpu.segFS, fProt) + ' ' + s += this.getSegOutput(this.cpu.segFS, fProt) + ' ' +
this.getSegString(this.cpu.segGS, fProt) + ' '; this.getSegOutput(this.cpu.segGS, fProt) + ' ';
} }
} }
s += this.getRegString(Debugger.REG_PS) + s += this.getRegOutput(Debugger.REG_PS) +
this.getFlagStr('V') + this.getFlagStr('D') + this.getFlagStr('I') + this.getFlagStr('T') + this.getFlagOutput('V') + this.getFlagOutput('D') + this.getFlagOutput('I') + this.getFlagOutput('T') +
this.getFlagStr('S') + this.getFlagStr('Z') + this.getFlagStr('A') + this.getFlagStr('P') + this.getFlagStr('C'); this.getFlagOutput('S') + this.getFlagOutput('Z') + this.getFlagOutput('A') + this.getFlagOutput('P') + this.getFlagOutput('C');
return s; return s;
}; };
@ -4282,7 +4366,7 @@ if (DEBUGGER) {
} }
if (!fError) { if (!fError) {
value = aVals.pop(); value = aVals.pop();
if (fPrint) this.println(sExpOrig + '=' + str.toHex(value) + "h (" + value + ". " + str.toBinBytes(value) + ')'); if (fPrint) this.printValue(null, value);
} else { } else {
if (fPrint) this.println("error parsing '" + sExpOrig + "' at character " + (sExpOrig.length - sExp.length)); if (fPrint) this.println("error parsing '" + sExpOrig + "' at character " + (sExpOrig.length - sExp.length));
} }
@ -4302,8 +4386,14 @@ if (DEBUGGER) {
var value; var value;
if (sValue !== undefined) { if (sValue !== undefined) {
var iReg = this.getRegIndex(sValue); var iReg = this.getRegIndex(sValue);
if (iReg >= 0) sValue = this.getRegValue(iReg); if (iReg >= 0) {
value = str.parseInt(sValue); value = this.getRegValue(iReg);
} else {
value = this.getVariable(sValue);
if (value === undefined) {
value = str.parseInt(sValue);
}
}
if (value === undefined) this.println("invalid " + (sName? sName : "value") + ": " + sValue); if (value === undefined) this.println("invalid " + (sName? sName : "value") + ": " + sValue);
} else { } else {
this.println("missing " + (sName || "value")); this.println("missing " + (sName || "value"));
@ -4311,6 +4401,82 @@ if (DEBUGGER) {
return value; return value;
}; };
/**
* printValue(sVar, value)
*
* @this {Debugger}
* @param {string|null} sVar
* @param {number|undefined} value
* @return {boolean} true if value defined, false if not
*/
Debugger.prototype.printValue = function(sVar, value)
{
var sValue;
var fDefined = false;
if (value !== undefined) {
fDefined = true;
sValue = str.toHexLong(value) + " (" + value + ')'; /* + str.toBinBytes(value) */
}
sVar = (sVar != null? (sVar + ": ") : "");
this.println(sVar + sValue);
return fDefined;
};
/**
* printVariable(sVar)
*
* @this {Debugger}
* @param {string} [sVar]
* @return {boolean} true if all value(s) defined, false if not
*/
Debugger.prototype.printVariable = function(sVar)
{
if (sVar) {
return this.printValue(sVar, this.aVariables[sVar]);
}
var cVariables = 0;
for (sVar in this.aVariables) {
this.printValue(sVar, this.aVariables[sVar]);
cVariables++;
}
return cVariables > 0;
};
/**
* delVariable(sVar)
*
* @this {Debugger}
* @param {string} sVar
*/
Debugger.prototype.delVariable = function(sVar)
{
delete this.aVariables[sVar];
};
/**
* getVariable(sVar)
*
* @this {Debugger}
* @param {string} sVar
* @return {number|undefined}
*/
Debugger.prototype.getVariable = function(sVar)
{
return this.aVariables[sVar];
};
/**
* setVariable(sVar, value)
*
* @this {Debugger}
* @param {string} sVar
* @param {number} value
*/
Debugger.prototype.setVariable = function(sVar, value)
{
this.aVariables[sVar] = value;
};
/** /**
* addSymbols(addr, size, aSymbols) * addSymbols(addr, size, aSymbols)
* *
@ -4801,7 +4967,7 @@ if (DEBUGGER) {
if (BACKTRACK) { if (BACKTRACK) {
this.println("\tdi [a] dump backtrack info at address a"); this.println("\tdi [a] dump backtrack info at address a");
} }
this.println("\tds [#] dump selector # descriptor info"); 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);
return; return;
} }
@ -4812,7 +4978,7 @@ if (DEBUGGER) {
var cLines = 0; var cLines = 0;
if (sLen) { if (sLen) {
if (sLen.charAt(0) == 'l') sLen = sLen.substr(1); if (sLen.charAt(0) == 'l') sLen = sLen.substr(1);
cLines = +sLen; cLines = str.parseInt(sLen, 10);
} }
if (sCmd == 'd') { if (sCmd == 'd') {
sCmd = this.sCmdDumpPrev || "db"; sCmd = this.sCmdDumpPrev || "db";
@ -4827,6 +4993,16 @@ if (DEBUGGER) {
this.dumpHistory(sAddr, cLines); this.dumpHistory(sAddr, cLines);
return; return;
} }
if (sCmd == "dos") {
/*
* The "dos" command is an undocumented command that's useful any time we're inside an internal
* DOS dispatch function where the registers are substantially the same as the corresponding INT 0x21;
* "m int on; m dos on" produces the same output, but only when an actual INT 0x21 instruction is used.
* Issuing this command at any other time should also be OK, but the results will be meaningless.
*/
this.messageInt(Interrupts.DOS.VECTOR, this.cpu.regLIP, true);
return;
}
if (sCmd == "ds") { // transform a "ds" command into a "d desc" command if (sCmd == "ds") { // transform a "ds" command into a "d desc" command
sCmd = 'd'; sCmd = 'd';
sLen = sAddr; sLen = sAddr;
@ -5090,6 +5266,46 @@ if (DEBUGGER) {
} }
}; };
/**
* doLet(sCmd)
*
* The command must be of the form "{variable} = [{expression}]", where expression may contain constants,
* operators, registers, symbols, other variables, or nothing at all; in the latter case, the variable, if
* any, is deleted.
*
* Other supported shorthand: "let" with no parameters prints the values of all variables, and "let {variable}"
* prints the value of the specified variable.
*
* @this {Debugger}
* @param {string} sCmd
* @return {boolean} true if valid "let" assignment, false if not
*/
Debugger.prototype.doLet = function(sCmd)
{
var a = sCmd.match(/^\s*([A-Z_]?[A-Z0-9_]*)\s*(=?)\s*(.*)$/i);
if (a) {
if (!a[1]) {
if (!this.printVariable()) this.println("no variables");
return true; // it's not considered an error to print an empty list of variables
}
if (!a[2]) {
return this.printVariable(a[1]);
}
if (!a[3]) {
this.delVariable(a[1]);
return true; // it's not considered an error to delete a variable that didn't exist
}
var v = this.parseExpression(a[3]);
if (v !== undefined) {
this.setVariable(a[1], v);
return true;
}
return false;
}
this.println("invalid assignment:" + sCmd);
return false;
};
/** /**
* doList(sSymbol) * doList(sSymbol)
* *
@ -5686,6 +5902,9 @@ if (DEBUGGER) {
/** /**
* doPrint(sCmd) * doPrint(sCmd)
* *
* If the string to print is a quoted string, then we run it through replaceRegs(), so that
* you can take advantage of all the special replacement options used for software interrupt logging.
*
* @this {Debugger} * @this {Debugger}
* @param {string} sCmd * @param {string} sCmd
*/ */
@ -6164,6 +6383,12 @@ if (DEBUGGER) {
this.doStackTrace(); this.doStackTrace();
break; break;
case 'l': case 'l':
if (asArgs[0] == "let") {
if (!this.doLet(sCmd.substr(3))) {
result = false;
}
break;
}
this.shiftArgs(asArgs); this.shiftArgs(asArgs);
this.doLoad(asArgs); this.doLoad(asArgs);
break; break;
@ -6174,6 +6399,10 @@ if (DEBUGGER) {
this.doOutput(asArgs[1], asArgs[2]); this.doOutput(asArgs[1], asArgs[2]);
break; break;
case 'p': case 'p':
if (asArgs[0] == "print") {
this.doPrint(sCmd.substr(5));
break;
}
this.doProcStep(asArgs[0]); this.doProcStep(asArgs[0]);
break; break;
case 'r': case 'r':

View file

@ -90,7 +90,7 @@ var TYPEDARRAYS = (typeof ArrayBuffer !== 'undefined');
* we'll have to rethink that choice OR provide a Debugger command that dynamically enables/disables as much of * we'll have to rethink that choice OR provide a Debugger command that dynamically enables/disables as much of
* the backtracking support as possible. * the backtracking support as possible.
*/ */
var BACKTRACK = false; // !COMPILED; var BACKTRACK = !COMPILED;
/** /**
* @define {boolean} * @define {boolean}

View file

@ -70,6 +70,12 @@ var Interrupts = {
DOS: { DOS: {
VECTOR: 0x21 VECTOR: 0x21
}, },
DOS_IDLE: {
VECTOR: 0x28
},
DOS_NETBIOS: {
VECTOR: 0x2A
},
MOUSE: { MOUSE: {
VECTOR: 0x33 VECTOR: 0x33
} }

View file

@ -3846,7 +3846,7 @@ X86.fnFaultMessage = function(nFault, nError, fHalt)
fHalt = false; fHalt = false;
} }
} else { } else {
if (nFault == X86.EXCEPTION.SS_FAULT || nFault == X86.EXCEPTION.GP_FAULT && this.model == X86.MODEL_80386 /* || nFault == X86.EXCEPTION.NP_FAULT && bOpcode == 0x8E */) { if (nFault == X86.EXCEPTION.SS_FAULT || nFault == X86.EXCEPTION.PG_FAULT || nFault == X86.EXCEPTION.GP_FAULT && this.model == X86.MODEL_80386 /* || nFault == X86.EXCEPTION.NP_FAULT && bOpcode == 0x8E */) {
fHalt = true; fHalt = true;
} }
} }