Try allocating a temporary breakpoint on a TRAPFAULT debugger notification

This commit is contained in:
Jeff Parsons 2015-09-14 23:05:04 -07:00
commit 5994e91110
2 changed files with 53 additions and 43 deletions

View file

@ -155,9 +155,8 @@ function Debugger(parmsDbg)
this.dbgAddrAssemble = this.newAddr(); this.dbgAddrAssemble = this.newAddr();
/* /*
* aSymbolTable is an array of SymbolTable objects, one per ROM or other chunk of address space. * aSymbolTable is an array of SymbolTable objects, one per ROM or other chunk of address space,
* * where each object contains the following properties:
* Each SymbolTable object contains the following properties:
* *
* sModule * sModule
* nSegment * nSegment
@ -166,7 +165,7 @@ function Debugger(parmsDbg)
* addr (physical address, if any; eg, if symbols are for a ROM) * addr (physical address, if any; eg, if symbols are for a ROM)
* len * len
* aSymbols * aSymbols
* aOffsetPairs * aOffsets
* *
* See addSymbols() for more details, since that's how callers add sets of symbols to the table. * See addSymbols() for more details, since that's how callers add sets of symbols to the table.
*/ */
@ -1388,6 +1387,7 @@ if (DEBUGGER) {
* removeSectionInfo(nSegment, dbgAddr, fPrint) * removeSectionInfo(nSegment, dbgAddr, fPrint)
* *
* @this {Debugger} * @this {Debugger}
* @param {number} nSegment (logical segment number)
* @param {DbgAddr} dbgAddr (address of module) * @param {DbgAddr} dbgAddr (address of module)
* @param {boolean} [fPrint] * @param {boolean} [fPrint]
*/ */
@ -1425,7 +1425,7 @@ if (DEBUGGER) {
* *
* TODO: Consider "consuming" all VW32_Int41Dispatch callbacks, because the Windows 95 kernel goes to * TODO: Consider "consuming" all VW32_Int41Dispatch callbacks, because the Windows 95 kernel goes to
* great effort to pass those requests on to the DEBUG VxD, which end up going nowhere when the VxD isn't * great effort to pass those requests on to the DEBUG VxD, which end up going nowhere when the VxD isn't
* loaded (to load it, you must either run WDEB386.EXE or install it via your SYSTEM.INI). Regrettably, * loaded (to load it, you must either run WDEB386.EXE or install the VxD via SYSTEM.INI). Regrettably,
* Windows 95 assumes that if WDEB386 support is present, then a DEBUG VxD must be present as well. * Windows 95 assumes that if WDEB386 support is present, then a DEBUG VxD must be present as well.
* *
* @this {Debugger} * @this {Debugger}
@ -1487,8 +1487,6 @@ if (DEBUGGER) {
var DI = cpu.regEDI & 0xffff; var DI = cpu.regEDI & 0xffff;
var ES = cpu.segES.sel; var ES = cpu.segES.sel;
var seg, limit, sModule;
if (this.fWinDbg == null) { if (this.fWinDbg == null) {
if (AX == Interrupts.WINDBG.IS_LOADED) { if (AX == Interrupts.WINDBG.IS_LOADED) {
/* /*
@ -1516,22 +1514,22 @@ if (DEBUGGER) {
* responsibility for all requests (don't assume there's valid interrupt handler inside the machine). * responsibility for all requests (don't assume there's valid interrupt handler inside the machine).
*/ */
switch(AX) { switch(AX) {
case Interrupts.WINDBG.IS_LOADED: case Interrupts.WINDBG.IS_LOADED: // 0x004F
if (this.fWinDbg) { if (this.fWinDbg) {
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBG.LOADED; cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBG.LOADED;
this.println("INT 0x41 handling enabled"); this.println("INT 0x41 handling enabled");
} }
break; break;
case Interrupts.WINDBG.LOADSEG: case Interrupts.WINDBG.LOADSEG: // 0x0050
this.addSegmentInfo(this.newAddr(DI, ES), BX+1, CX, !(SI & 0x1), this.fWinDbg); this.addSegmentInfo(this.newAddr(DI, ES), BX+1, CX, !(SI & 0x1), this.fWinDbg);
break; break;
case Interrupts.WINDBG.FREESEG: case Interrupts.WINDBG.FREESEG: // 0x0052
this.removeSegmentInfo(BX); this.removeSegmentInfo(BX);
break; break;
case Interrupts.WINDBG.KRNLVARS: case Interrupts.WINDBG.KRNLVARS: // 0x005A
/* /*
* BX = version number of this data (0x3A0) * BX = version number of this data (0x3A0)
* DX:CX points to: * DX:CX points to:
@ -1551,28 +1549,40 @@ if (DEBUGGER) {
*/ */
break; break;
case Interrupts.WINDBG.RELSEG: case Interrupts.WINDBG.RELSEG: // 0x005C
case Interrupts.WINDBG.LOADDLL: case Interrupts.WINDBG.LOADDLL: // 0x0064
case Interrupts.WINDBG.DELMODULE: case Interrupts.WINDBG.DELMODULE: // 0x0065
/* /*
* TODO: Figure out what to do with these notifications, if anything * TODO: Figure out what to do with these notifications, if anything
*/ */
break; break;
case Interrupts.WINDBG.REGDOTCMD: case Interrupts.WINDBG.LOADHIGH: // 0x005D
case Interrupts.WINDBG.CONDBP: case Interrupts.WINDBG.REGDOTCMD: // 0x0070
case Interrupts.WINDBG.LOADHIGH: case Interrupts.WINDBG.CONDBP: // 0xF001
break; break;
case Interrupts.WINDBG.GETSYMBOL: case Interrupts.WINDBG.CHECKFAULT: // 0x007F
if (this.fWinDbg) cpu.regEAX = (cpu.regEAX & ~0xffff)|1; // AX == 1 means not found
break;
case Interrupts.WINDBG.CHECKFAULT:
if (this.fWinDbg) cpu.regEAX = (cpu.regEAX & ~0xffff)|0; // AX == 0 means handle fault normally if (this.fWinDbg) cpu.regEAX = (cpu.regEAX & ~0xffff)|0; // AX == 0 means handle fault normally
break; break;
case Interrupts.WINDBG.LOADSEG32: case Interrupts.WINDBG.TRAPFAULT: // 0x0083
/*
* Ordinarily (I think), since we're responding with AX=0 to all CHECKFAULT notifications,
* all TRAPFAULT notifications should be withheld; however, one exception may be if the user
* is presented with a fault dialog containing a "Debug" button, and the user clicks it....
*
* So for now, we'll allocate a temporary breakpoint at the reported fault address whenever
* this notification comes through.
*/
this.addBreakpoint(this.aBreakExec, this.newAddr(cpu.regEDX, CX), true);
break;
case Interrupts.WINDBG.GETSYMBOL: // 0x008D
if (this.fWinDbg) cpu.regEAX = (cpu.regEAX & ~0xffff)|1; // AX == 1 means not found
break;
case Interrupts.WINDBG.LOADSEG32: // 0x0150
/* /*
* SI == segment type: * SI == segment type:
* 0x0 code selector * 0x0 code selector
@ -1582,7 +1592,7 @@ if (DEBUGGER) {
this.addSectionInfo(this.newAddr(cpu.regEBX, DX), !SI, this.fWinDbg); this.addSectionInfo(this.newAddr(cpu.regEBX, DX), !SI, this.fWinDbg);
break; break;
case Interrupts.WINDBG.FREESEG32: case Interrupts.WINDBG.FREESEG32: // 0x0152
/* /*
* BX == segment number * BX == segment number
* DX:EDI -> module name * DX:EDI -> module name
@ -1671,13 +1681,13 @@ if (DEBUGGER) {
* responsibility for all requests (don't assume there's valid interrupt handler inside the machine). * responsibility for all requests (don't assume there's valid interrupt handler inside the machine).
*/ */
switch(AH) { switch(AH) {
case Interrupts.WINDBGRM.IS_LOADED: case Interrupts.WINDBGRM.IS_LOADED: // 0x43
if (this.fWinDbgRM) { if (this.fWinDbgRM) {
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBGRM.LOADED; cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBGRM.LOADED;
} }
break; break;
case Interrupts.WINDBGRM.PREP_PMODE: case Interrupts.WINDBGRM.PREP_PMODE: // 0x44
if (this.fWinDbgRM) { if (this.fWinDbgRM) {
var a = cpu.segCS.addCallBreak(this.callWindowsDebuggerPMInit.bind(this)); var a = cpu.segCS.addCallBreak(this.callWindowsDebuggerPMInit.bind(this));
if (a) { if (a) {
@ -1687,18 +1697,18 @@ if (DEBUGGER) {
} }
break; break;
case Interrupts.WINDBGRM.FREESEG: case Interrupts.WINDBGRM.FREESEG: // 0x48
this.removeSegmentInfo(BX); this.removeSegmentInfo(BX);
break; break;
case Interrupts.WINDBGRM.REMOVESEGS: case Interrupts.WINDBGRM.REMOVESEGS: // 0x4F
/* /*
* TODO: This probably just signals the end of module loading; nothing is required, but we should * TODO: This probably just signals the end of module loading; nothing is required, but we should
* clean up whatever we can.... * clean up whatever we can....
*/ */
break; break;
case Interrupts.WINDBGRM.LOADSEG: case Interrupts.WINDBGRM.LOADSEG: // 0x50
if (AL == 0x20) { if (AL == 0x20) {
/* /*
* Real-mode EXE * Real-mode EXE
@ -5394,18 +5404,18 @@ if (DEBUGGER) {
* We add all these entries to our internal symbol table, which is an array of 4-element arrays, each of which * We add all these entries to our internal symbol table, which is an array of 4-element arrays, each of which
* look like: * look like:
* *
* [sel, off, addr, len, aSymbols, aOffsetPairs] * [sel, off, addr, len, aSymbols, aOffsets]
* *
* There are two basic symbol operations: findSymbol(), which takes an address and finds the symbol, if any, * There are two basic symbol operations: findSymbol(), which takes an address and finds the symbol, if any,
* at that address, and findSymbolAddr(), which takes a string and attempts to match it to a non-anonymous * at that address, and findSymbolAddr(), which takes a string and attempts to match it to a non-anonymous
* symbol with a matching offset ('o') property. * symbol with a matching offset ('o') property.
* *
* To implement findSymbol() efficiently, addSymbols() creates an array of [offset, sSymbol] pairs * To implement findSymbol() efficiently, addSymbols() creates an array of [offset, sSymbol] pairs
* (aOffsetPairs), one pair for each symbol that corresponds to an offset within the specified address space. * (aOffsets), one pair for each symbol that corresponds to an offset within the specified address space.
* *
* We guarantee the elements of aOffsetPairs are in offset order, because we build it using binaryInsert(); * We guarantee the elements of aOffsets are in offset order, because we build it using binaryInsert();
* it's quite likely that the MAP file already ordered all its symbols in offset order, but since they're * it's quite likely that the MAP file already ordered all its symbols in offset order, but since they're
* hand-edited files, we can't assume that. This ensures that findSymbol()'s binarySearch() will operate * hand-edited files, we can't assume that, and we need to ensure that findSymbol()'s binarySearch() operates
* properly. * properly.
* *
* @this {Debugger} * @this {Debugger}
@ -5420,7 +5430,7 @@ if (DEBUGGER) {
Debugger.prototype.addSymbols = function(sModule, nSegment, sel, off, addr, len, aSymbols) Debugger.prototype.addSymbols = function(sModule, nSegment, sel, off, addr, len, aSymbols)
{ {
var dbgAddr = {}; var dbgAddr = {};
var aOffsetPairs = []; var aOffsets = [];
for (var sSymbol in aSymbols) { for (var sSymbol in aSymbols) {
var symbol = aSymbols[sSymbol]; var symbol = aSymbols[sSymbol];
if (typeof symbol == "number") { if (typeof symbol == "number") {
@ -5448,7 +5458,7 @@ if (DEBUGGER) {
} }
symbol['p'] = dbgAddr.addr; symbol['p'] = dbgAddr.addr;
} }
usr.binaryInsert(aOffsetPairs, [offSymbol >>> 0, sSymbol], this.comparePairs); usr.binaryInsert(aOffsets, [offSymbol >>> 0, sSymbol], this.comparePairs);
} }
if (sAnnotation) symbol['a'] = sAnnotation.replace(/''/g, "\""); if (sAnnotation) symbol['a'] = sAnnotation.replace(/''/g, "\"");
} }
@ -5460,7 +5470,7 @@ if (DEBUGGER) {
addr: addr, addr: addr,
len: len, len: len,
aSymbols: aSymbols, aSymbols: aSymbols,
aOffsetPairs: aOffsetPairs aOffsets: aOffsets
}; };
this.aSymbolTable.push(symbolTable); this.aSymbolTable.push(symbolTable);
}; };
@ -5541,7 +5551,7 @@ if (DEBUGGER) {
var len = symbolTable.len; var len = symbolTable.len;
if (sel == 0x30) sel = 0x28; // TODO: Remove this hack once we're able to differentiate Windows 95 ring 0 code and data if (sel == 0x30) sel = 0x28; // TODO: Remove this hack once we're able to differentiate Windows 95 ring 0 code and data
if (sel == dbgAddr.sel && offSymbol >= off && offSymbol < off + len || addr != null && addrSymbol >= addr && addrSymbol < addr + len) { if (sel == dbgAddr.sel && offSymbol >= off && offSymbol < off + len || addr != null && addrSymbol >= addr && addrSymbol < addr + len) {
var result = usr.binarySearch(symbolTable.aOffsetPairs, [offSymbol], this.comparePairs); var result = usr.binarySearch(symbolTable.aOffsets, [offSymbol], this.comparePairs);
if (result >= 0) { if (result >= 0) {
this.returnSymbol(iTable, result, aSymbol); this.returnSymbol(iTable, result, aSymbol);
} }
@ -5616,11 +5626,11 @@ if (DEBUGGER) {
Debugger.prototype.returnSymbol = function(iTable, iOffset, aSymbol) Debugger.prototype.returnSymbol = function(iTable, iOffset, aSymbol)
{ {
var symbol = {}; var symbol = {};
var aOffsetPairs = this.aSymbolTable[iTable].aOffsetPairs; var aOffsets = this.aSymbolTable[iTable].aOffsets;
var offset = 0, sSymbol = null; var offset = 0, sSymbol = null;
if (iOffset >= 0 && iOffset < aOffsetPairs.length) { if (iOffset >= 0 && iOffset < aOffsets.length) {
offset = aOffsetPairs[iOffset][0]; offset = aOffsets[iOffset][0];
sSymbol = aOffsetPairs[iOffset][1]; sSymbol = aOffsets[iOffset][1];
} }
if (sSymbol) { if (sSymbol) {
symbol = this.aSymbolTable[iTable].aSymbols[sSymbol]; symbol = this.aSymbolTable[iTable].aSymbols[sSymbol];

View file

@ -265,10 +265,10 @@ Component.subclass(Disk);
* where offset is relative to the segment's offStart value, and symbol is a string describing the * where offset is relative to the segment's offStart value, and symbol is a string describing the
* entry. * entry.
* *
* NOTE: Although aEntries uses a format similar to the Debugger's aOffsetPairs, they are not * NOTE: Although aEntries arrays are similar to the Debugger's aOffsets arrays, they are not
* interchangeable data structures, because ours is ordered by ordinal, whereas aOffsetPairs is * interchangeable data structures, because ours is ordered by ordinal, whereas aOffsets is
* ordered by offset. We provide an interface, getModuleInfo(), to the Debugger that converts * ordered by offset. We provide an interface, getModuleInfo(), to the Debugger that converts
* our data into an intermediate array, aSymbols, which the Debugger then uses to build aOffsetPairs. * our data into an intermediate array, aSymbols, which the Debugger then uses to build aOffsets.
* It would be nice to avoid building that intermediate representation, but it's a side-effect of * It would be nice to avoid building that intermediate representation, but it's a side-effect of
* the Debugger's earlier support for JSON-encoded MAP files. * the Debugger's earlier support for JSON-encoded MAP files.
* *