v1.19.3: More Windows 95-related updates

This commit is contained in:
Jeff Parsons 2015-09-01 16:19:20 -07:00
commit 1a67c7acbd
33 changed files with 8907 additions and 1741 deletions

View file

@ -56,7 +56,7 @@ if (DEBUGGER) {
* off offset, if any
* sel selector, if any (if null, addr should be set to a linear address)
* addr linear address, if any (if null, addr will be recomputed from sel:off)
* fProt true if protected-mode address
* type one of the Debugger.ADDR.* values
* fData32 true if 32-bit operand size in effect
* fAddr32 true if 32-bit address size in effect
* cOverrides non-zero if any overrides were processed with this address
@ -69,7 +69,7 @@ if (DEBUGGER) {
* off:(number|null|undefined),
* sel:(number|null|undefined),
* addr:(number|null|undefined),
* fProt:(boolean|undefined),
* type:(number|undefined),
* fData32:(boolean|undefined),
* fAddr32:(boolean|undefined),
* cOverrides:(number|undefined),
@ -294,10 +294,27 @@ if (DEBUGGER) {
};
/*
* Address types for parseAddr(), to help choose between dbgAddrNextCode and dbgAddrNextData
* Supported address types; the type field in a DbgAddr object may contain ONE of:
*
* NONE, REAL, PROT, V86, LINEAR or PHYSICAL
*
* along with ONE of:
*
* CODE or DATA
*
* REAL and V86 addresses are specifed with a '&' prefix, PROT addresses with a '#' prefix,
* LINEAR addresses with '%', and PHYSICAL addresses with '%%'.
*/
Debugger.ADDR_CODE = 1;
Debugger.ADDR_DATA = 2;
Debugger.ADDR = {
NONE: 0x00,
REAL: 0x01,
PROT: 0x02,
V86: 0x03,
LINEAR: 0x04,
PHYSICAL: 0x05,
CODE: 0x10,
DATA: 0x20
};
/*
* Instruction ordinals
@ -1247,9 +1264,10 @@ if (DEBUGGER) {
this.messageDump(Messages.TSS, function onDumpTSS(s) { dbg.dumpTSS(s); });
this.messageDump(Messages.DOS, function onDumpDOS(s) { dbg.dumpDOS(s); });
this.fWinDbg = this.dbgAddrWinDbg = null;
this.cpu.addIntNotify(Interrupts.WINDBG.VECTOR, this.intWindowsDebugger.bind(this));
if (Interrupts.WINDBG.ENABLED) {
this.fWinDbg = null;
this.cpu.addIntNotify(Interrupts.WINDBG.VECTOR, this.intWindowsDebugger.bind(this));
}
if (Interrupts.WINDBGRM.ENABLED) {
this.fWinDbgRM = null;
this.cpu.addIntNotify(Interrupts.WINDBGRM.VECTOR, this.intWindowsDebuggerRM.bind(this));
@ -1258,72 +1276,79 @@ if (DEBUGGER) {
this.setReady();
};
/**
* intWindowsDebugger()
*
* This intercepts calls to the Windows Debugger protected-mode interface (INT 0x41).
*
* @this {Debugger}
* @param {number} addr
* @return {boolean} true to proceed with the INT 0x41 software interrupt, false to skip
*/
Debugger.prototype.intWindowsDebugger = function(addr)
{
if (this.fWinDbg === false) return true;
if (Interrupts.WINDBG.ENABLED) {
/**
* intWindowsDebugger()
*
* This intercepts calls to the Windows Debugger protected-mode interface (INT 0x41).
*
* @this {Debugger}
* @param {number} addr
* @return {boolean} true to proceed with the INT 0x41 software interrupt, false to skip
*/
Debugger.prototype.intWindowsDebugger = function(addr)
{
var cpu = this.cpu;
var AX = cpu.regEAX & 0xffff;
var BX = cpu.regEBX & 0xffff;
var CX = cpu.regECX & 0xffff;
var DX = cpu.regEDX & 0xffff;
var SI = cpu.regESI & 0xffff;
var DI = cpu.regEDI & 0xffff;
var ES = cpu.segES.sel;
var seg, limit;
var cpu = this.cpu;
var AX = cpu.regEAX & 0xffff;
var BX = cpu.regEBX & 0xffff;
var CX = cpu.regECX & 0xffff;
var DX = cpu.regEDX & 0xffff;
var SI = cpu.regESI & 0xffff;
var DI = cpu.regEDI & 0xffff;
var ES = cpu.segES.sel;
var seg, limit, sModule;
if (!this.fWinDbg) {
if (AX == Interrupts.WINDBG.IS_LOADED) {
/*
* We're only going to respond to this function if no one else did, in which case,
* we'll set fWinDbg to true and handle additional notifications.
*/
cpu.addIntReturn(addr, function(dbg) {
return function onInt41Return(nLevel) {
if ((cpu.regEAX & 0xffff) != Interrupts.WINDBG.LOADED) {
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBG.LOADED;
dbg.println("INT 0x41 processing enabled");
dbg.dbgAddrWinDbg = dbg.newAddr();
dbg.fWinDbg = true;
} else {
dbg.println("INT 0x41 processing disabled");
dbg.fWinDbg = false;
}
};
}(this));
if (this.fWinDbg == null) {
if (AX == Interrupts.WINDBG.IS_LOADED) {
/*
* We're only going to respond to this function if no one else did, in which case,
* we'll set fWinDbg to true and handle additional notifications.
*/
cpu.addIntReturn(addr, function(dbg) {
return function onInt41Return(nLevel) {
if ((cpu.regEAX & 0xffff) != Interrupts.WINDBG.LOADED) {
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBG.LOADED;
dbg.println("INT 0x41 handling enabled");
dbg.fWinDbg = true;
} else {
dbg.println("INT 0x41 monitoring enabled");
dbg.fWinDbg = false;
}
};
}(this));
}
return true;
}
switch(AX) {
case Interrupts.WINDBG.IS_LOADED:
if (this.fWinDbg) {
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBG.LOADED;
}
break;
case Interrupts.WINDBG.LOAD_SEG:
/*
* The following output should completely mimic WDEB386....
*/
sModule = this.getSZ(this.newAddr(DI, ES));
limit = (seg = this.getSegment(CX))? seg.limit : 0;
if (!this.fWinDbg) {
this.println(sModule + "!undefined " + ((SI & 0x1)? "data" : "code") + '(' + str.toHex(BX+1, 4) + ")=#" + str.toHex(CX, 4) + " len " + str.toHex(limit+1));
}
break;
default:
if (this.fWinDbg) {
this.println("INT 0x41: " + str.toHexWord(AX));
}
break;
}
return true;
}
switch(AX) {
case Interrupts.WINDBG.IS_LOADED:
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBG.LOADED;
break;
case Interrupts.WINDBG.LOAD_SEG:
/*
* The following output should completely mimic WDEB386....
*/
limit = (seg = this.getSegment(CX))? seg.limit : 0;
this.println(this.getSZ(this.setAddr(this.dbgAddrWinDbg, DI, ES)) + "!undefined " + ((SI & 0x1)? "data" : "code") + '(' + str.toHex(BX+1, 4) + ")=#" + str.toHex(CX, 4) + " len " + str.toHex(limit+1));
break;
default:
// this.println("INT 0x41: " + str.toHexWord(AX));
break;
}
return true;
};
};
}
if (Interrupts.WINDBGRM.ENABLED) {
/**
@ -1337,12 +1362,14 @@ if (DEBUGGER) {
*/
Debugger.prototype.intWindowsDebuggerRM = function(addr)
{
if (this.fWinDbgRM === false) return true;
var dbgAddr;
var cpu = this.cpu;
var AH = this.cpu.regEAX & 0xff;
var AL = cpu.regEAX & 0xff;
var AH = (cpu.regEAX >> 8) & 0xff;
var DI = cpu.regEDI & 0xffff;
var ES = cpu.segES.sel;
if (!this.fWinDbgRM) {
if (this.fWinDbgRM == null) {
if (AH == Interrupts.WINDBGRM.IS_LOADED) {
/*
* We're only going to respond to this function if no one else did, in which case,
@ -1352,10 +1379,10 @@ if (DEBUGGER) {
return function onInt68Return(nLevel) {
if ((cpu.regEAX & 0xffff) != Interrupts.WINDBGRM.LOADED) {
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBGRM.LOADED;
dbg.println("INT 0x68 processing enabled");
dbg.println("INT 0x68 handling enabled");
dbg.fWinDbgRM = true;
} else {
dbg.println("INT 0x68 processing disabled");
dbg.println("INT 0x68 monitoring enabled");
dbg.fWinDbgRM = false;
}
};
@ -1366,11 +1393,67 @@ if (DEBUGGER) {
switch(AH) {
case Interrupts.WINDBGRM.IS_LOADED:
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBGRM.LOADED;
if (this.fWinDbgRM) {
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBGRM.LOADED;
}
break;
case Interrupts.WINDBGRM.LOAD_SEG:
if (AL == 0x20) {
/*
* Real-mode EXE
* CX == paragraph
* ES:DI -> module name
*/
}
else if (AL < 0x80) {
/*
* AL == segment type:
* 0x00 code selector
* 0x01 data selector
* 0x10 code segment
* 0x11 data segment
* 0x40 code segment & sel
* 0x41 data segment & sel
* BX == segment #
* CX == actual segment/selector
* DX == actual selector (if 0x40 or 0x41)
* ES:DI -> module name
*/
}
else {
/*
* AL == segment type:
* 0x80 device driver code seg
* 0x81 device driver data seg
* ES:DI -> D386_Device_Params structure:
* DD_logical_seg dw ? ; logical segment # from map
* DD_actual_sel dw ? ; actual selector value
* DD_base dd ? ; linear address offset for start of segment
* DD_length dd ? ; actual length of segment
* DD_name df ? ; 16:32 ptr to null terminated device name
* DD_sym_name df ? ; 16:32 ptr to null terminated symbolic module name (i.e. Win386)
* DD_alias_sel dw ? ; alias selector value (0 = none)
*/
dbgAddr = this.newAddr(DI, ES);
var nSeg = this.getShort(dbgAddr, 2);
var sel = this.getShort(dbgAddr, 2);
var off = this.getLong(dbgAddr, 4);
var len = this.getLong(dbgAddr, 4);
var dbgAddrDevice = this.newAddr(this.getLong(dbgAddr, 4), this.getShort(dbgAddr, 2));
var dbgAddrModule = this.newAddr(this.getLong(dbgAddr, 4), this.getShort(dbgAddr, 2));
var selAlias = this.getShort(dbgAddr, 2) || sel;
if (!this.fWinDbgRM) {
this.log(this.getSZ(dbgAddrModule) + '!' + this.getSZ(dbgAddrDevice) + "!undefined " + ((AL & 0x1)? "data" : "code") + '(' + str.toHex(nSeg, 4) + ")=" + str.toHex(selAlias, 4) + ':' + str.toHex(off) + " len " + str.toHex(len));
}
}
cpu.regEAX = (cpu.regEAX & ~0xff) | 0x01;
break;
default:
// this.println("INT 0x68: " + str.toHexByte(AH));
if (this.fWinDbgRM) {
this.log("INT 0x68: " + str.toHexByte(AH));
}
break;
}
@ -1488,18 +1571,29 @@ if (DEBUGGER) {
};
/**
* getProtMode()
* getCurrentMode()
*
* @this {Debugger}
* @return {boolean}
* @return {boolean} (true if protected mode, false if not)
*/
Debugger.prototype.getProtMode = function()
Debugger.prototype.getCurrentMode = function()
{
return this.cpu && !!(this.cpu.regCR0 & X86.CR0.MSW.PE) && !(this.cpu.regPS & X86.PS.VM);
};
/**
* getSegment(sel, fProt)
* getCurrentType()
*
* @this {Debugger}
* @return {number}
*/
Debugger.prototype.getCurrentType = function()
{
return this.getCurrentMode()? Debugger.ADDR.PROT : Debugger.ADDR.REAL;
};
/**
* getSegment(sel, type)
*
* If the selector matches that of any of the CPU segment registers, then return the CPU's segment
* register, instead of using our own segDebugger segment register. This makes it possible for us to
@ -1509,15 +1603,16 @@ if (DEBUGGER) {
*
* @this {Debugger}
* @param {number|null|undefined} sel
* @param {boolean} [fProt]
* @param {number} [type] (defaults to getCurrentType())
* @return {X86Seg|null} seg
*/
Debugger.prototype.getSegment = function(sel, fProt)
Debugger.prototype.getSegment = function(sel, type)
{
var fProtMode = this.getProtMode();
if (fProt === undefined) fProt = fProtMode;
var typeDefault = this.getCurrentType();
if (fProt == fProtMode) {
if (!type) type = typeDefault;
if (type == typeDefault) {
if (sel === this.cpu.getCS()) return this.cpu.segCS;
if (sel === this.cpu.getDS()) return this.cpu.segDS;
if (sel === this.cpu.getES()) return this.cpu.segES;
@ -1530,10 +1625,10 @@ if (DEBUGGER) {
* Even if nSuppressBreaks is set, we'll allow the call in real-mode,
* because a loadReal() request using segDebugger should generally be safe.
*/
if (this.nSuppressBreaks && fProt || !this.segDebugger) return null;
if (this.nSuppressBreaks && type == Debugger.ADDR.PROT || !this.segDebugger) return null;
}
var seg = this.segDebugger;
if (!fProt) {
if (type != Debugger.ADDR.PROT) {
seg.loadReal(sel);
seg.limit = 0xffff; // although an ACTUAL real-mode segment load would not modify the limit,
seg.offMax = 0x10000; // proper segDebugger operation requires that we update the limit ourselves
@ -1564,7 +1659,7 @@ if (DEBUGGER) {
if (addr == null) {
addr = X86.ADDR_INVALID;
if (dbgAddr) {
var seg = this.getSegment(dbgAddr.sel, dbgAddr.fProt);
var seg = this.getSegment(dbgAddr.sel, dbgAddr.type);
if (seg) {
if (!fWrite) {
addr = seg.checkReadDebugger(dbgAddr.off || 0, nb || 1);
@ -1690,7 +1785,7 @@ if (DEBUGGER) {
};
/**
* newAddr(off, sel, addr, fProt, fData32, fAddr32)
* newAddr(off, sel, addr, type, fData32, fAddr32)
*
* Returns a NEW DbgAddr object, initialized with specified values and/or defaults.
*
@ -1698,18 +1793,43 @@ if (DEBUGGER) {
* @param {number|null|undefined} [off] (default is zero)
* @param {number|null|undefined} [sel] (default is undefined)
* @param {number|null|undefined} [addr] (default is undefined)
* @param {boolean} [fProt] (default is the current CPU mode)
* @param {number} [type] (default is based on current CPU mode)
* @param {boolean} [fData32] (default is the current CPU operand size)
* @param {boolean} [fAddr32] (default is the current CPU address size)
* @return {DbgAddr}
*/
Debugger.prototype.newAddr = function(off, sel, addr, fProt, fData32, fAddr32)
Debugger.prototype.newAddr = function(off, sel, addr, type, fData32, fAddr32)
{
return this.setAddr({}, off, sel, addr, fProt, fData32, fAddr32);
return this.setAddr({}, off, sel, addr, type, fData32, fAddr32);
};
/**
* setAddr(dbgAddr, off, sel, addr, fProt, fData32, fAddr32)
* getAddrPrefix(dbgAddr)
*
* @this {Debugger}
* @param {DbgAddr} dbgAddr
* @return {string}
*/
Debugger.prototype.getAddrPrefix = function(dbgAddr)
{
var ch = '';
switch (dbgAddr.type) {
case Debugger.ADDR.REAL:
case Debugger.ADDR.V86:
ch = '&';
break;
case Debugger.ADDR.PROT:
ch = '#';
break;
case Debugger.ADDR.LINEAR:
ch = '%';
break;
}
return ch;
};
/**
* setAddr(dbgAddr, off, sel, addr, type, fData32, fAddr32)
*
* Updates an EXISTING DbgAddr object, initialized with specified values and/or defaults.
*
@ -1718,17 +1838,17 @@ if (DEBUGGER) {
* @param {number|null|undefined} [off] (default is zero)
* @param {number|null|undefined} [sel] (default is undefined)
* @param {number|null|undefined} [addr] (default is undefined)
* @param {boolean} [fProt] (default is the current CPU mode)
* @param {number} [type] (default is based on current CPU mode)
* @param {boolean} [fData32] (default is the current CPU operand size)
* @param {boolean} [fAddr32] (default is the current CPU address size)
* @return {DbgAddr}
*/
Debugger.prototype.setAddr = function(dbgAddr, off, sel, addr, fProt, fData32, fAddr32)
Debugger.prototype.setAddr = function(dbgAddr, off, sel, addr, type, fData32, fAddr32)
{
dbgAddr.off = off || 0;
dbgAddr.sel = sel;
dbgAddr.addr = addr;
dbgAddr.fProt = (fProt != null)? fProt : this.getProtMode();
dbgAddr.type = type || this.getCurrentType();
dbgAddr.fData32 = (fData32 != null)? fData32 : (this.cpu && this.cpu.segCS.sizeData == 4);
dbgAddr.fAddr32 = (fAddr32 != null)? fAddr32 : (this.cpu && this.cpu.segCS.sizeAddr == 4);
dbgAddr.fTempBreak = false;
@ -1764,22 +1884,27 @@ if (DEBUGGER) {
};
/**
* checkLimit(dbgAddr)
* checkLimit(dbgAddr, fUpdate)
*
* Used by incAddr() and parseAddr() to ensure that the (updated) dbgAddr offset is within segment bounds.
*
* @this {Debugger}
* @param {DbgAddr} dbgAddr
* @param {boolean} [fUpdate] (true to update segment info)
* @return {boolean}
*/
Debugger.prototype.checkLimit = function(dbgAddr)
Debugger.prototype.checkLimit = function(dbgAddr, fUpdate)
{
if (dbgAddr.sel != null) {
var seg = this.getSegment(dbgAddr.sel, dbgAddr.fProt);
var seg = this.getSegment(dbgAddr.sel, dbgAddr.type);
if (seg) {
var off = dbgAddr.off & seg.maskAddr;
if ((off >>> 0) >= seg.offMax) return false;
dbgAddr.off = off;
if (fUpdate) {
dbgAddr.off = off;
dbgAddr.fData32 = (seg.sizeData == 4);
dbgAddr.fAddr32 = (seg.sizeAddr == 4);
}
}
}
return true;
@ -1833,7 +1958,8 @@ if (DEBUGGER) {
*/
Debugger.prototype.hexAddr = function(dbgAddr)
{
return dbgAddr.sel == null? ('%' + str.toHex(dbgAddr.addr)) : this.hexOffset(dbgAddr.off, dbgAddr.sel, dbgAddr.fAddr32);
var ch = this.getAddrPrefix(dbgAddr);
return dbgAddr.sel == null? ('%' + str.toHex(dbgAddr.addr)) : (ch + this.hexOffset(dbgAddr.off, dbgAddr.sel, dbgAddr.fAddr32));
};
/**
@ -1947,7 +2073,7 @@ if (DEBUGGER) {
{
var sInfo = "no information";
if (BACKTRACK) {
var dbgAddr = this.parseAddr(sAddr, Debugger.ADDR_CODE, true, true);
var dbgAddr = this.parseAddr(sAddr, Debugger.ADDR.CODE, true, true);
if (dbgAddr) {
var addr = this.getAddr(dbgAddr);
sInfo = '%' + str.toHex(addr) + ": " + (this.bus.getSymbol(addr, true) || sInfo);
@ -2024,7 +2150,7 @@ if (DEBUGGER) {
return;
}
var seg = this.getSegment(sel, true);
var seg = this.getSegment(sel, Debugger.ADDR.PROT);
this.println("dumpDesc(" + str.toHexWord(seg? seg.sel : sel) + "): %" + str.toHex(seg? seg.addrDesc : null, this.cchAddr));
if (!seg) return;
@ -2135,8 +2261,6 @@ if (DEBUGGER) {
*
* If you re-enable this protection, be sure to re-enable the decrement below, too.
*/
var fData32 = null, fAddr32 = null;
while (nLines > 0 && iHistory != this.iOpcodeHistory) {
var dbgAddr = aHistory[iHistory++];
@ -2146,7 +2270,8 @@ if (DEBUGGER) {
* We must create a new dbgAddr from the address in aHistory, because dbgAddr was
* a reference, not a copy, and we don't want getInstruction() modifying the original.
*/
dbgAddr = this.newAddr(dbgAddr.off, dbgAddr.sel, dbgAddr.addr, dbgAddr.fProt, fData32 == null? dbgAddr.fData32 : fData32, fAddr32 == null? dbgAddr.fAddr32 : fAddr32);
dbgAddr = this.newAddr(dbgAddr.off, dbgAddr.sel, dbgAddr.addr, dbgAddr.type, dbgAddr.fData32, dbgAddr.fAddr32);
var sInstruction = this.getInstruction(dbgAddr, "history", nPrev--);
if (!aFilters.length || sInstruction.indexOf(aFilters[0]) >= 0) {
this.println(sInstruction);
@ -2156,11 +2281,8 @@ if (DEBUGGER) {
* If there were OPERAND or ADDRESS overrides on the previous instruction, getInstruction()
* will have automatically disassembled additional bytes, so skip additional history entries.
*/
if (!dbgAddr.cOverrides) {
fData32 = fAddr32 = null;
} else {
if (dbgAddr.cOverrides) {
iHistory += dbgAddr.cOverrides; nLines -= dbgAddr.cOverrides; nPrev -= dbgAddr.cOverrides;
fData32 = dbgAddr.fData32; fAddr32 = dbgAddr.fAddr32;
}
if (iHistory >= aHistory.length) iHistory = 0;
@ -2256,7 +2378,7 @@ if (DEBUGGER) {
this.println("invalid task selector: " + s);
return;
}
seg = this.getSegment(sel, true);
seg = this.getSegment(sel, Debugger.ADDR.PROT);
}
this.println("dumpTSS(" + str.toHexWord(seg? seg.sel : sel) + "): %" + str.toHex(seg? seg.base : null, this.cchAddr));
@ -3712,30 +3834,33 @@ if (DEBUGGER) {
*/
Debugger.prototype.getInstruction = function(dbgAddr, sComment, nSequence)
{
var dbgAddrIns = this.newAddr(dbgAddr.off, dbgAddr.sel, dbgAddr.addr, dbgAddr.fProt);
var dbgAddrIns = this.newAddr(dbgAddr.off, dbgAddr.sel, dbgAddr.addr, dbgAddr.type);
var bOpcode = this.getByte(dbgAddr, 1);
/*
* Incorporate OS and AS prefixes into the current instruction.
* Incorporate OPERAND and ADDRESS size prefixes into the current instruction.
*
* And the verdict is in: redundant OS and AS prefixes must be ignored;
* see opOS() and opAS() for details. We limit the amount of redundancy
* to something reasonable (ie, 4).
* And the verdict is in: redundant OPERAND and ADDRESS prefixes must be ignored;
* see opOS() and opAS() for details. We limit the amount of redundancy to something
* reasonable (ie, 4).
*/
var cMax = 4;
var cMaxOverrides = 4, cOverrides = 0;
var fDataPrefix = false, fAddrPrefix = false;
while ((bOpcode == X86.OPCODE.OS || bOpcode == X86.OPCODE.AS) && cMax--) {
while ((bOpcode == X86.OPCODE.OS || bOpcode == X86.OPCODE.AS) && cMaxOverrides--) {
if (bOpcode == X86.OPCODE.OS) {
if (!fDataPrefix) {
dbgAddr.fData32 = !dbgAddr.fData32;
fDataPrefix = true;
}
cOverrides++;
} else {
if (!fAddrPrefix) {
dbgAddr.fAddr32 = !dbgAddr.fAddr32;
fAddrPrefix = true;
}
cOverrides++;
}
bOpcode = this.getByte(dbgAddr, 1);
}
@ -3889,7 +4014,7 @@ if (DEBUGGER) {
}
}
this.initAddrSize(dbgAddr, fNonPrefix, (fDataPrefix? 1 : 0) + (fAddrPrefix? 1 : 0));
this.initAddrSize(dbgAddr, fNonPrefix, cOverrides);
return sLine;
};
@ -3931,7 +4056,7 @@ if (DEBUGGER) {
sOperand = str.toHex(this.getShort(dbgAddr, 2), 4);
break;
case Debugger.TYPE_FARP:
dbgAddr = this.newAddr(this.getWord(dbgAddr, true), this.getShort(dbgAddr, 2), null, dbgAddr.fProt, dbgAddr.fData32, dbgAddr.fAddr32);
dbgAddr = this.newAddr(this.getWord(dbgAddr, true), this.getShort(dbgAddr, 2), null, dbgAddr.type, dbgAddr.fData32, dbgAddr.fAddr32);
sOperand = this.hexAddr(dbgAddr);
var aSymbol = this.findSymbol(dbgAddr);
if (aSymbol[0]) sOperand += " (" + aSymbol[0] + ")";
@ -4263,7 +4388,8 @@ if (DEBUGGER) {
Debugger.prototype.getRegDump = function(fProt)
{
var s;
if (fProt === undefined) fProt = this.getProtMode();
if (fProt === undefined) fProt = this.getCurrentMode();
s = this.getRegOutput(Debugger.REG_AX) +
this.getRegOutput(Debugger.REG_BX) +
this.getRegOutput(Debugger.REG_CX) +
@ -4275,6 +4401,7 @@ if (DEBUGGER) {
this.getSegOutput(this.cpu.segSS, fProt) + ' ' +
this.getSegOutput(this.cpu.segDS, fProt) + ' ' +
this.getSegOutput(this.cpu.segES, fProt) + ' ';
if (fProt) {
var sTR = "TR=" + str.toHex(this.cpu.segTSS.sel, 4);
var sA20 = "A20=" + (this.bus.getA20()? "ON " : "OFF ");
@ -4302,9 +4429,11 @@ if (DEBUGGER) {
this.getSegOutput(this.cpu.segGS, fProt) + ' ';
}
}
s += this.getRegOutput(Debugger.REG_PS) +
this.getFlagOutput('V') + this.getFlagOutput('D') + this.getFlagOutput('I') + this.getFlagOutput('T') +
this.getFlagOutput('S') + this.getFlagOutput('Z') + this.getFlagOutput('A') + this.getFlagOutput('P') + this.getFlagOutput('C');
return s;
};
@ -4332,7 +4461,7 @@ if (DEBUGGER) {
*
* @this {Debugger}
* @param {string|undefined} sAddr
* @param {number|undefined} [type] is the address segment type, in case sAddr doesn't specify a segment
* @param {number|undefined} [type] is either CODE or DATA, in case sAddr doesn't specify a segment
* @param {boolean} [fNoChecks] (eg, true when setting breakpoints that may not be valid now, but will be later)
* @param {boolean} [fQuiet]
* @return {DbgAddr|null|undefined}
@ -4340,24 +4469,45 @@ if (DEBUGGER) {
Debugger.prototype.parseAddr = function(sAddr, type, fNoChecks, fQuiet)
{
var dbgAddr, fPrint;
var dbgAddrNext = (type === Debugger.ADDR_CODE? this.dbgAddrNextCode : this.dbgAddrNextData);
var dbgAddrNext = (type === Debugger.ADDR.CODE? this.dbgAddrNextCode : this.dbgAddrNextData);
var off = dbgAddrNext.off, sel = dbgAddrNext.sel, addr = dbgAddrNext.addr;
type = fNoChecks? Debugger.ADDR.NONE : dbgAddrNext.type;
if (fQuiet) fPrint = false;
if (sAddr !== undefined) {
if (sAddr.charAt(0) == '%') {
var ch = sAddr.charAt(0);
var iColon = sAddr.indexOf(':');
switch(ch) {
case '&':
type = Debugger.ADDR.REAL;
break;
case '#':
type = Debugger.ADDR.PROT;
break;
case '%':
type = Debugger.ADDR.LINEAR;
off = addr = 0;
sel = null; // we still have code that relies on this crutch, instead of the type field
break;
default:
if (iColon >= 0) type = Debugger.ADDR.NONE;
ch = '';
break;
}
if (ch) {
sAddr = sAddr.substr(1);
off = 0;
sel = null;
addr = 0;
iColon--;
}
dbgAddr = this.findSymbolAddr(sAddr);
if (dbgAddr) return dbgAddr;
var iColon = sAddr.indexOf(':');
if (iColon < 0) {
if (sel != null) {
off = this.parseExpression(sAddr, fPrint);
@ -4375,8 +4525,8 @@ if (DEBUGGER) {
}
if (off != null) {
dbgAddr = this.newAddr(off, sel, addr);
if (!fNoChecks && !this.checkLimit(dbgAddr)) {
dbgAddr = this.newAddr(off, sel, addr, type);
if (!fNoChecks && !this.checkLimit(dbgAddr, true)) {
this.println("invalid offset: " + this.hexAddr(dbgAddr));
dbgAddr = null;
}
@ -5045,7 +5195,7 @@ if (DEBUGGER) {
*/
Debugger.prototype.doAssemble = function(asArgs)
{
var dbgAddr = this.parseAddr(asArgs[1], Debugger.ADDR_CODE);
var dbgAddr = this.parseAddr(asArgs[1], Debugger.ADDR.CODE);
if (!dbgAddr) return;
this.dbgAddrAssemble = dbgAddr;
@ -5124,17 +5274,10 @@ if (DEBUGGER) {
}
var dbgAddr = {};
if (sAddr != '*') {
dbgAddr = this.parseAddr(sAddr, Debugger.ADDR_CODE, true);
dbgAddr = this.parseAddr(sAddr, Debugger.ADDR.CODE, true);
if (!dbgAddr) return;
}
/*
* We want our breakpoints to be "mode-less"; ie, independent of the processor mode at the
* time they're set. Therefore, it's critical that we erase the fProt setting that parseAddr(),
* via newAddr(), initialized dbgAddr with.
*/
dbgAddr.fProt = undefined;
sAddr = (dbgAddr.off == null? sAddr : str.toHexWord(dbgAddr.off));
if (sParm == 'c') {
@ -5310,7 +5453,7 @@ if (DEBUGGER) {
return;
}
var dbgAddr = this.parseAddr(sAddr, Debugger.ADDR_DATA);
var dbgAddr = this.parseAddr(sAddr, Debugger.ADDR.DATA);
if (!dbgAddr || dbgAddr.sel == null && dbgAddr.addr == null) return;
var cb = 0; // 0 is not a default; it triggers the appropriate default below
@ -5375,7 +5518,7 @@ if (DEBUGGER) {
return;
}
var dbgAddr = this.parseAddr(sAddr, Debugger.ADDR_DATA);
var dbgAddr = this.parseAddr(sAddr, Debugger.ADDR.DATA);
if (!dbgAddr) return;
for (var i = 2; i < asArgs.length; i++) {
@ -5629,7 +5772,7 @@ if (DEBUGGER) {
*/
Debugger.prototype.doList = function(sSymbol)
{
var dbgAddr = this.parseAddr(sSymbol, Debugger.ADDR_CODE);
var dbgAddr = this.parseAddr(sSymbol, Debugger.ADDR.CODE);
if (!dbgAddr) return;
var addr = this.getAddr(dbgAddr);
@ -5690,7 +5833,7 @@ if (DEBUGGER) {
var fJSON = (asArgs[1] == "json");
var iDrive, iSector = 0, nSectors = 0;
var dbgAddr = (fJSON? {} : this.parseAddr(asArgs[1], Debugger.ADDR_DATA));
var dbgAddr = (fJSON? {} : this.parseAddr(asArgs[1], Debugger.ADDR.DATA));
if (!dbgAddr) return;
iDrive = this.parseValue(asArgs[2], "drive #");
@ -6273,13 +6416,13 @@ if (DEBUGGER) {
Debugger.prototype.doRun = function(sAddr, sOptions, fQuiet)
{
if (sAddr !== undefined) {
var dbgAddr = this.parseAddr(this.parseReference(sAddr), Debugger.ADDR_CODE);
var dbgAddr = this.parseAddr(this.parseReference(sAddr), Debugger.ADDR.CODE);
if (!dbgAddr) return;
this.parseAddrOptions(dbgAddr, sOptions);
this.setTempBreakpoint(dbgAddr);
}
if (!fQuiet && !this.runCPU(true)) {
this.println('cpu busy, "g" command ignored');
this.println('cpu busy or unavailable, command ignored');
}
};
@ -6432,7 +6575,7 @@ if (DEBUGGER) {
var sCall = null;
var off = dbgAddr.off;
var offOrig = off;
for (var n = 1; n <= 6; n++) {
for (var n = 1; n <= 6 && !!off; n++) {
if (n > 2) {
dbgAddr.off = off;
dbgAddr.addr = null;
@ -6442,7 +6585,7 @@ if (DEBUGGER) {
break;
}
}
if (!--off) break;
off--;
}
dbgAddr.off = offOrig;
return sCall;
@ -6537,7 +6680,7 @@ if (DEBUGGER) {
/*
* Use cOverrides to record whether we previously processed any OPERAND or ADDRESS overrides.
*/
dbgAddr.cOverrides = cOverrides;
dbgAddr.cOverrides = cOverrides || 0;
/*
* For proper disassembly of instructions preceded by an OPERAND (0x66) size prefix, we set
* dbgAddr.fData32 to true whenever the operand size is 32-bit; similarly, for an ADDRESS (0x67)
@ -6545,8 +6688,10 @@ if (DEBUGGER) {
* both fields must be set to match the size of the current code segment.
*/
if (fNonPrefix) {
dbgAddr.fData32 = (this.cpu.segCS.sizeData == 4);
dbgAddr.fAddr32 = (this.cpu.segCS.sizeAddr == 4);
if (dbgAddr.fData32Orig != null) dbgAddr.fData32 = dbgAddr.fData32Orig;
if (dbgAddr.fAddr32Orig != null) dbgAddr.fAddr32 = dbgAddr.fAddr32Orig;
dbgAddr.fData32Orig = dbgAddr.fData32;
dbgAddr.fAddr32Orig = dbgAddr.fAddr32;
}
/*
* We also use dbgAddr.fComplete to record whether the caller (ie, getInstruction()) is reporting that
@ -6577,16 +6722,15 @@ if (DEBUGGER) {
*/
Debugger.prototype.doUnassemble = function(sAddr, sAddrEnd, n)
{
var dbgAddr = this.parseAddr(sAddr, Debugger.ADDR_CODE);
var dbgAddr = this.parseAddr(sAddr, Debugger.ADDR.CODE);
if (!dbgAddr) return;
if (n === undefined) n = 1;
var dbgAddrEnd = this.newAddr(this.maskReg, dbgAddr.sel, this.bus.nBusLimit);
var cb = 0x100;
var dbgAddrEnd, cb = 0x100;
if (sAddrEnd !== undefined) {
dbgAddrEnd = this.parseAddr(sAddrEnd, Debugger.ADDR_CODE);
dbgAddrEnd = this.parseAddr(sAddrEnd, Debugger.ADDR.CODE);
if (!dbgAddrEnd || dbgAddrEnd.off < dbgAddr.off) return;
cb = dbgAddrEnd.off - dbgAddr.off;
@ -6601,6 +6745,9 @@ if (DEBUGGER) {
}
n = -1;
}
else {
dbgAddrEnd = this.newAddr(this.maskReg, dbgAddr.sel, this.bus.nBusLimit, dbgAddr.type, dbgAddr.fData32, dbgAddr.fAddr32);
}
var cLines = 0;
this.initAddrSize(dbgAddr, true);
@ -6629,7 +6776,7 @@ if (DEBUGGER) {
var sInstruction = this.getInstruction(dbgAddr, sComment, nSequence);
/*
* If getInstruction() reported that it did not yet process a complete instruction (via dbgAddr.fComplete),
* If getInstruction() reported that it did not process a complete instruction (via dbgAddr.fComplete),
* then bump the instruction count by one, so that we display one more line (and hopefully the complete
* instruction).
*/
@ -6677,7 +6824,12 @@ if (DEBUGGER) {
* for (var i = 0; i < a.length; i++) a[i] = str.trim(a[i]);
*
* We may now split on semi-colons ONLY if they are outside a quoted sequence.
*
* Also, to allow quoted strings *inside* breakpoint commands, we first replace all
* DOUBLE double-quotes with single quotes.
*/
sCmd = sCmd.replace(/""/g, "'");
var iPrev = 0;
var chQuote = null;
chSep = chSep || ';';