Started integrating Windows Debugger segment load info with PCjs Debugger symbol tables
This commit is contained in:
parent
b3f1f288d3
commit
1d0b7974fc
19 changed files with 342 additions and 347 deletions
|
|
@ -23,28 +23,31 @@ To verify, type the following into any JavaScript REPL (eg, Node):
|
||||||
> n == -0x80000000
|
> n == -0x80000000
|
||||||
true
|
true
|
||||||
|
|
||||||
So the notion that bitwise operators yield 32-bit results isn't exactly right; the sign (bit 31) of every 32-bit
|
The sign (bit 31) of every 32-bit result is always extended into the entire 52 "significand" bits of the underlying
|
||||||
result is always extended into the entire 52 "significand" bits of the underlying 64-bit float. And it's
|
64-bit float. And it's impossible to simply "mask away" those additional sign bits, thanks to a fundamental
|
||||||
impossible to simply "mask away" those additional sign bits, thanks to the fundamental restriction of JavaScript bitwise
|
restriction of JavaScript bitwise operators: they operate *only* on the low 32 bits.
|
||||||
operators: they operate *only* on the low 32 bits.
|
|
||||||
|
|
||||||
The easiest way to remove the high-order sign bits from a negative 32-bit value is to add the 33-bit value 0x100000000:
|
With one exception: the unsigned right-shift operator. It does more than simply shift zero bits in from
|
||||||
|
the left; it also zeros all the bits above the sign bit. This means that `n >>> 0`, while leaving the low 32 bits
|
||||||
|
unchanged, also clears the upper bits, resulting in a value that is positive, albeit outside the signed 32-bit range.
|
||||||
|
It is equivalent to adding the 33-bit value 0x100000000 to a negative 32-bit number:
|
||||||
|
|
||||||
> n = (n < 0? n + 0x100000000 : n)
|
> n = (n < 0? n + 0x100000000 : n)
|
||||||
2147483648
|
2147483648
|
||||||
> n.toString(16)
|
> n.toString(16)
|
||||||
'80000000'
|
'80000000'
|
||||||
|
|
||||||
This works because JavaScript is perfectly capable of representing 0x80000000, or any other 32-bit value, as a positive
|
These operations work because JavaScript is perfectly capable of representing 0x80000000, or any other 32-bit value,
|
||||||
number, albeit in floating point. And be careful, because as soon as you perform *any* bitwise operation on a value
|
as a positive number, but it must use a floating point value to do so. And be careful, because as soon as you perform
|
||||||
with bit 31 set, even an operation as innocuous-looking as:
|
*any* bitwise operation on a value with bit 31 set, even an operation as innocuous-looking as:
|
||||||
|
|
||||||
> n |= 0
|
> n |= 0
|
||||||
-2147483648
|
-2147483648
|
||||||
> n.toString(16)
|
> n.toString(16)
|
||||||
'-80000000'
|
'-80000000'
|
||||||
|
|
||||||
Viola: instant negative number!
|
the result will be negative again. This is simply how all bitwise operators (except for unsigned right-shift) operate:
|
||||||
|
they truncate the result to a signed 32-bit value.
|
||||||
|
|
||||||
This might tempt you to think that the right way to write negative 32-bit constants in hex is to simply precede
|
This might tempt you to think that the right way to write negative 32-bit constants in hex is to simply precede
|
||||||
them with a minus sign. But that would be wrong. For example, if you wrote the constant 0x80000080 as "-0x80000080",
|
them with a minus sign. But that would be wrong. For example, if you wrote the constant 0x80000080 as "-0x80000080",
|
||||||
|
|
@ -52,8 +55,8 @@ JavaScript would treat that as negation of 2147483776, resulting in a value whos
|
||||||
0x80000080.
|
0x80000080.
|
||||||
|
|
||||||
The safest way to write a 32-bit constant like 0x80000080 is "0x80000080|0", which will produce -2147483520. If you
|
The safest way to write a 32-bit constant like 0x80000080 is "0x80000080|0", which will produce -2147483520. If you
|
||||||
write all your negative 32-bit constants that way, then you won't have to resort to 33-bit addition and potential
|
write all your negative 32-bit constants that way, then you won't have to resort to using either unsigned right-shifts
|
||||||
floating point operations.
|
or 33-bit addition, which in turn avoids the use of floating point values.
|
||||||
|
|
||||||
To continue the fun, try setting bit 0 of 0x80000000, which should give you 0x80000001:
|
To continue the fun, try setting bit 0 of 0x80000000, which should give you 0x80000001:
|
||||||
|
|
||||||
|
|
@ -71,4 +74,4 @@ explain, for a negative number, toString() returns the positive representation o
|
||||||
*not* the "two's complement" of the number.
|
*not* the "two's complement" of the number.
|
||||||
|
|
||||||
*[@jeffpar](http://twitter.com/jeffpar)*
|
*[@jeffpar](http://twitter.com/jeffpar)*
|
||||||
*October 26, 2014*
|
*October 26, 2014 (Updated September 8, 2015)*
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@
|
||||||
<manifest ref="/disks/pc/windows/1.04/manifest.xml" disk="*"/>
|
<manifest ref="/disks/pc/windows/1.04/manifest.xml" disk="*"/>
|
||||||
<manifest ref="/disks/pc/windows/2.03/manifest.xml" disk="*"/>
|
<manifest ref="/disks/pc/windows/2.03/manifest.xml" disk="*"/>
|
||||||
<manifest ref="/disks/pc/windows/3.00/manifest.xml" disk="*"/>
|
<manifest ref="/disks/pc/windows/3.00/manifest.xml" disk="*"/>
|
||||||
<manifest ref="/disks/pc/windows/win95/4.00.499/manifest.xml" disk="*"/>
|
|
||||||
<manifest ref="/disks/pc/windows/win95/4.00.950/manifest.xml" disk="*"/>
|
<manifest ref="/disks/pc/windows/win95/4.00.950/manifest.xml" disk="*"/>
|
||||||
<manifest ref="/disks/pc/minix/1.1/manifest.xml" disk="*"/>
|
<manifest ref="/disks/pc/minix/1.1/manifest.xml" disk="*"/>
|
||||||
<manifest ref="/disks/pc/unix/ibm/pcix/manifest.xml" disk="*"/>
|
<manifest ref="/disks/pc/unix/ibm/pcix/manifest.xml" disk="*"/>
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,49 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<?xml-stylesheet type="text/xsl" href="/versions/pcjs/1.19.4/manifest.xsl"?>
|
|
||||||
<manifest type="software">
|
|
||||||
<title>Windows 95 (Build 499)</title>
|
|
||||||
<version>4.00.499</version>
|
|
||||||
<type>Windows</type>
|
|
||||||
<category>Operating System</category>
|
|
||||||
<author>Microsoft</author>
|
|
||||||
<releaseDate>June 16, 1995</releaseDate>
|
|
||||||
<disk id="disk01" size="1474560" chs="80:2:18" img="../static/4.00.499/WIN95-DISK01.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK01.json" md5="732d1cb011be22d1beda31f4dcd8ea56" md5json="6fa3bc43a08502be56bcf765c2470c35">
|
|
||||||
<name>Win95 Build 499 (Disk 1)</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk02" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK02.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK02.json" md5="3c4ff0741307c736fd956447b82db041" md5json="5688fde3e3f978e4d31127b118383f79">
|
|
||||||
<name>Win95 Build 499 (Disk 2)</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk03" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK03.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK03.json" md5="7c635a4d309ecc182db99dd3e6642bac" md5json="939be24d14aff97578200c8429ca4a05">
|
|
||||||
<name>Win95 Build 499 (Disk 3)</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk04" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK04.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK04.json" md5="59e781f887857883108d3e0a4ea338bc" md5json="4f62253c0731ac0d87d6cdbdc218a921">
|
|
||||||
<name>Win95 Build 499 (Disk 4)</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk05" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK05.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK05.json" md5="4866930efb5198e6e9c9ea6958989547" md5json="e9b2b53575ee7ca1546be36f9c36d143">
|
|
||||||
<name>Win95 Build 499 (Disk 5)</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk06" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK06.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK06.json" md5="99d60c50db21206908d569db0d859f5d" md5json="48aa2717c9cbcc46639cef839eed5378">
|
|
||||||
<name>Win95 Build 499 (Disk 6)</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk07" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK07.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK07.json" md5="c4eb6a910b5310427e3099c079c62261" md5json="75f2d3b963e81c1b37c725f350971562">
|
|
||||||
<name>Win95 Build 499 (Disk 7)</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk08" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK08.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK08.json" md5="d6ba0299f3f02851ac2cc44ed54dbcc3" md5json="2b89cfd0f05934bdc4cca15064f0d7d4">
|
|
||||||
<name>Win95 Build 499 (Disk 8)</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk09" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK09.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK09.json" md5="308387d3c51e837fd7869a7b0b44a3cb" md5json="4a86ce9737eb664450c351fb274f940c">
|
|
||||||
<name>Win95 Build 499 (Disk 9)</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk10" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK10.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK10.json" md5="1cc5e299dfb83dd555227ad9546393fe" md5json="dbee2d4261d25c235f01278fded36a0b">
|
|
||||||
<name>Win95 Build 499 (Disk 10)</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk11" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK11.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK11.json" md5="abe21872967030c77c4b1c5acc330944" md5json="40d23db1b9fd26cb728854aaf3a1d4f8">
|
|
||||||
<name>Win95 Build 499 (Disk 11)</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk12" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK12.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK12.json" md5="55a8eabe146455de6d724912608c4dae" md5json="f609a685c6a4e98447193a969d342a10">
|
|
||||||
<name>Win95 Build 499 (Disk 12)</name>
|
|
||||||
</disk>
|
|
||||||
<disk id="disk13" size="1720320" chs="80:2:21" img="../static/4.00.499/WIN95-DISK13.img" href="/disks/pc/windows/win95/4.00.499/WIN95-DISK13.json" md5="9842dbeabf3b7dc98ee727467c81cef6" md5json="4de833b8106fa20db8b760c2c2633123">
|
|
||||||
<name>Win95 Build 499 (Disk 13)</name>
|
|
||||||
</disk>
|
|
||||||
</manifest>
|
|
||||||
|
|
@ -155,13 +155,14 @@ function Debugger(parmsDbg)
|
||||||
this.dbgAddrAssemble = this.newAddr();
|
this.dbgAddrAssemble = this.newAddr();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* aSymbolTable is an array of 4-element arrays, one per ROM or other chunk of address space.
|
* aSymbolTable is an array of 5-element arrays, one per ROM or other chunk of address space.
|
||||||
* Each 4-element arrays contains:
|
* Each 5-element arrays contains:
|
||||||
*
|
*
|
||||||
* [0]: addr
|
* [0]: sel
|
||||||
* [1]: size
|
* [1]: addr
|
||||||
* [2]: aSymbols
|
* [2]: len
|
||||||
* [3]: aOffsetPairs
|
* [3]: aSymbols
|
||||||
|
* [4]: aOffsetPairs
|
||||||
*
|
*
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
|
|
@ -293,6 +294,7 @@ if (DEBUGGER) {
|
||||||
'u [#]': "unassemble",
|
'u [#]': "unassemble",
|
||||||
'x': "execution options",
|
'x': "execution options",
|
||||||
'if': "eval expression",
|
'if': "eval expression",
|
||||||
|
"ln": "list nearest symbol(s)",
|
||||||
'mouse': "mouse action", // syntax: mouse {action} {delta} (eg, mouse x 10, mouse click 0, etc)
|
'mouse': "mouse action", // syntax: mouse {action} {delta} (eg, mouse x 10, mouse click 0, etc)
|
||||||
'print': "print expression",
|
'print': "print expression",
|
||||||
'reset': "reset machine",
|
'reset': "reset machine",
|
||||||
|
|
@ -1284,6 +1286,71 @@ if (DEBUGGER) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (Interrupts.WINDBG.ENABLED || Interrupts.WINDBGRM.ENABLED) {
|
if (Interrupts.WINDBG.ENABLED || Interrupts.WINDBGRM.ENABLED) {
|
||||||
|
/**
|
||||||
|
* addSegmentInfo(dbgAddr, nSeg, sel, fCode, fPrint)
|
||||||
|
*
|
||||||
|
* @this {Debugger}
|
||||||
|
* @param {DbgAddr} dbgAddr (address of module name)
|
||||||
|
* @param {number} nSeg (logical segment number)
|
||||||
|
* @param {number} sel (current selector)
|
||||||
|
* @param {boolean} fCode (true if code segment, false if data segment)
|
||||||
|
* @param {boolean} [fPrint]
|
||||||
|
*/
|
||||||
|
Debugger.prototype.addSegmentInfo = function(dbgAddr, nSeg, sel, fCode, fPrint)
|
||||||
|
{
|
||||||
|
var sModule = this.getSZ(dbgAddr);
|
||||||
|
var seg = this.getSegment(sel);
|
||||||
|
var len = seg? seg.limit + 1 : 0;
|
||||||
|
var sSection = (fCode? "_CODE" : "_DATA") + str.toHex(nSeg, 2);
|
||||||
|
if (fPrint) {
|
||||||
|
this.println(sModule + "!undefined " + (fCode? "code" : "data") + '(' + str.toHex(nSeg, 4) + ")=#" + str.toHex(sel, 4) + " len " + str.toHex(len));
|
||||||
|
}
|
||||||
|
var aSymbols = {};
|
||||||
|
var off = 0;
|
||||||
|
aSymbols[sModule + sSection] = off;
|
||||||
|
this.addSymbols(sel, off, len, aSymbols);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* addSectionInfo(dbgAddr, fCode, fPrint)
|
||||||
|
*
|
||||||
|
* dbgAddr -> 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)
|
||||||
|
*
|
||||||
|
* @this {Debugger}
|
||||||
|
* @param {DbgAddr} dbgAddr (address of D386_Device_Params)
|
||||||
|
* @param {boolean} fCode (true if code section, false if data section)
|
||||||
|
* @param {boolean} [fPrint]
|
||||||
|
*/
|
||||||
|
Debugger.prototype.addSectionInfo = function(dbgAddr, fCode, fPrint)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
sel = this.getShort(dbgAddr, 2) || sel;
|
||||||
|
var sModule = this.getSZ(dbgAddrModule).toUpperCase();
|
||||||
|
var sDevice = this.getSZ(dbgAddrDevice).toUpperCase();
|
||||||
|
var sSection = (fCode? "_CODE" : "_DATA") + str.toHex(nSeg, 2);
|
||||||
|
if (fPrint) {
|
||||||
|
/*
|
||||||
|
* Mimic WDEB386 output
|
||||||
|
*/
|
||||||
|
this.println(sModule + '!' + sDevice + "!undefined " + (fCode? "code" : "data") + '(' + str.toHex(nSeg, 4) + ")=" + str.toHex(sel, 4) + ':' + str.toHex(off) + " len " + str.toHex(len));
|
||||||
|
}
|
||||||
|
var aSymbols = {};
|
||||||
|
aSymbols[sDevice + sSection] = off;
|
||||||
|
this.addSymbols(sel, off, len, aSymbols);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* intWindowsDebugger()
|
* intWindowsDebugger()
|
||||||
*
|
*
|
||||||
|
|
@ -1345,17 +1412,11 @@ if (DEBUGGER) {
|
||||||
case Interrupts.WINDBG.IS_LOADED:
|
case Interrupts.WINDBG.IS_LOADED:
|
||||||
if (this.fWinDbg) {
|
if (this.fWinDbg) {
|
||||||
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBG.LOADED;
|
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBG.LOADED;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Interrupts.WINDBG.LOAD_SEG:
|
case Interrupts.WINDBG.LOAD_SEG:
|
||||||
if (this.fWinDbg) {
|
this.addSegmentInfo(this.newAddr(DI, ES), BX+1, CX, !(SI & 0x1), this.fWinDbg);
|
||||||
sModule = this.getSZ(this.newAddr(DI, ES));
|
|
||||||
limit = (seg = this.getSegment(CX))? seg.limit : 0;
|
|
||||||
this.println(sModule + "!undefined " + (!(SI & 0x1)? "code" : "data") + '(' + str.toHex(BX+1, 4) + ")=#" + str.toHex(CX, 4) + " len " + str.toHex(limit+1));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Interrupts.WINDBG.LOAD_SEG32:
|
case Interrupts.WINDBG.LOAD_SEG32:
|
||||||
|
|
@ -1363,52 +1424,19 @@ if (DEBUGGER) {
|
||||||
* SI == segment type:
|
* SI == segment type:
|
||||||
* 0x0 code selector
|
* 0x0 code selector
|
||||||
* 0x1 data selector
|
* 0x1 data selector
|
||||||
* DX:EBX -> D386_Device_Params structure (see dumpD386DeviceParms() for details)
|
* DX:EBX -> D386_Device_Params structure (see addSectionInfo() for details)
|
||||||
*/
|
*/
|
||||||
if (this.fWinDbg) {
|
this.addSectionInfo(this.newAddr(cpu.regEBX, DX), !SI, this.fWinDbg);
|
||||||
this.println(this.dumpD386DeviceParms(this.newAddr(cpu.regEBX, DX), !SI));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (this.fWinDbg) {
|
if (this.fWinDbg) {
|
||||||
this.println("INT 0x41: " + str.toHexWord(AX));
|
this.println("INT 0x41: " + str.toHexWord(AX));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return !this.fWinDbg;
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* dumpD386DeviceParms(dbgAddr, fCode)
|
|
||||||
*
|
|
||||||
* dbgAddr -> 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)
|
|
||||||
*
|
|
||||||
* @this {Debugger}
|
|
||||||
* @param {DbgAddr} dbgAddr
|
|
||||||
* @param {boolean} fCode
|
|
||||||
* @return {string}
|
|
||||||
*/
|
|
||||||
Debugger.prototype.dumpD386DeviceParms = function(dbgAddr, fCode)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
return this.getSZ(dbgAddrModule) + '!' + this.getSZ(dbgAddrDevice) + "!undefined " + (fCode? "code" : "data") + '(' + str.toHex(nSeg, 4) + ")=" + str.toHex(selAlias, 4) + ':' + str.toHex(off) + " len " + str.toHex(len);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1482,7 +1510,6 @@ if (DEBUGGER) {
|
||||||
case Interrupts.WINDBGRM.IS_LOADED:
|
case Interrupts.WINDBGRM.IS_LOADED:
|
||||||
if (this.fWinDbgRM) {
|
if (this.fWinDbgRM) {
|
||||||
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBGRM.LOADED;
|
cpu.regEAX = (cpu.regEAX & ~0xffff) | Interrupts.WINDBGRM.LOADED;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -1493,7 +1520,6 @@ if (DEBUGGER) {
|
||||||
cpu.regEDI = a[0];
|
cpu.regEDI = a[0];
|
||||||
cpu.setES(a[1]);
|
cpu.setES(a[1]);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -1525,27 +1551,23 @@ if (DEBUGGER) {
|
||||||
* AL == segment type:
|
* AL == segment type:
|
||||||
* 0x80 device driver code seg
|
* 0x80 device driver code seg
|
||||||
* 0x81 device driver data seg
|
* 0x81 device driver data seg
|
||||||
* ES:DI -> D386_Device_Params structure (see dumpD386DeviceParms() for details)
|
* ES:DI -> D386_Device_Params structure (see addSectionInfo() for details)
|
||||||
*/
|
*/
|
||||||
if (this.fWinDbgRM) {
|
this.addSectionInfo(this.newAddr(DI, ES), !(AL & 0x1), this.fWinDbgRM);
|
||||||
this.println(this.dumpD386DeviceParms(this.newAddr(DI, ES), !(AL & 0x1)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (this.fWinDbgRM) {
|
if (this.fWinDbgRM) {
|
||||||
cpu.regEAX = (cpu.regEAX & ~0xff) | 0x01;
|
cpu.regEAX = (cpu.regEAX & ~0xff) | 0x01;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (this.fWinDbgRM) {
|
if (this.fWinDbgRM) {
|
||||||
this.println("INT 0x68: " + str.toHexByte(AH));
|
this.println("INT 0x68: " + str.toHexByte(AH));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return !this.fWinDbgRM;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2055,6 +2077,120 @@ if (DEBUGGER) {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parseAddr(sAddr, type, fNoChecks, fPrint)
|
||||||
|
*
|
||||||
|
* As discussed above, dbgAddr variables contain one or more of: off, sel, and addr. They represent
|
||||||
|
* a segmented address (sel:off) when sel is defined or a linear address (addr) when sel is undefined
|
||||||
|
* (or null).
|
||||||
|
*
|
||||||
|
* To create a segmented address, specify two values separated by ':'; for a linear address, use
|
||||||
|
* a '%' prefix. We check for ':' after '%', so if for some strange reason you specify both, the
|
||||||
|
* address will be treated as segmented, not linear.
|
||||||
|
*
|
||||||
|
* The '%' syntax is similar to that used by the Windows 80386 kernel debugger (wdeb386) for linear
|
||||||
|
* addresses. If/when we add support for processors with page tables, we will likely adopt the same
|
||||||
|
* convention for linear addresses and provide a different syntax (eg, "%%") physical memory references.
|
||||||
|
*
|
||||||
|
* Address evaluation and validation (eg, range checks) are no longer performed at this stage. That's
|
||||||
|
* done later, by getAddr(), which returns X86.ADDR_INVALID for invalid segments, out-of-range offsets,
|
||||||
|
* etc. The Debugger's low-level get/set memory functions verify all getAddr() results, but even if an
|
||||||
|
* invalid address is passed through to the Bus memory interfaces, the address will simply be masked with
|
||||||
|
* Bus.nBusLimit; in the case of X86.ADDR_INVALID, that will generally refer to the top of the physical
|
||||||
|
* address space.
|
||||||
|
*
|
||||||
|
* @this {Debugger}
|
||||||
|
* @param {string|undefined} sAddr
|
||||||
|
* @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} [fPrint]
|
||||||
|
* @return {DbgAddr|null|undefined}
|
||||||
|
*/
|
||||||
|
Debugger.prototype.parseAddr = function(sAddr, type, fNoChecks, fPrint)
|
||||||
|
{
|
||||||
|
var dbgAddr;
|
||||||
|
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 (sAddr !== undefined) {
|
||||||
|
|
||||||
|
sAddr = this.parseReference(sAddr);
|
||||||
|
|
||||||
|
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);
|
||||||
|
iColon--;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbgAddr = this.findSymbolAddr(sAddr);
|
||||||
|
if (dbgAddr) return dbgAddr;
|
||||||
|
|
||||||
|
if (iColon < 0) {
|
||||||
|
if (sel != null) {
|
||||||
|
off = this.parseExpression(sAddr, fPrint);
|
||||||
|
addr = null;
|
||||||
|
} else {
|
||||||
|
addr = this.parseExpression(sAddr, fPrint);
|
||||||
|
if (addr == null) off = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sel = this.parseExpression(sAddr.substring(0, iColon), fPrint);
|
||||||
|
off = this.parseExpression(sAddr.substring(iColon + 1), fPrint);
|
||||||
|
addr = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (off != null) {
|
||||||
|
dbgAddr = this.newAddr(off, sel, addr, type);
|
||||||
|
if (!fNoChecks && !this.checkLimit(dbgAddr, true)) {
|
||||||
|
this.println("invalid offset: " + this.hexAddr(dbgAddr));
|
||||||
|
dbgAddr = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dbgAddr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* parseAddrOptions(dbdAddr, sOptions)
|
||||||
|
*
|
||||||
|
* @this {Debugger}
|
||||||
|
* @param {DbgAddr} dbgAddr
|
||||||
|
* @param {string} [sOptions]
|
||||||
|
*/
|
||||||
|
Debugger.prototype.parseAddrOptions = function(dbgAddr, sOptions)
|
||||||
|
{
|
||||||
|
if (sOptions) {
|
||||||
|
var a = sOptions.match(/(['"])(.*?)\1/);
|
||||||
|
if (a) {
|
||||||
|
dbgAddr.aCmds = this.parseCommand(dbgAddr.sCmd = a[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* incAddr(dbgAddr, inc)
|
* incAddr(dbgAddr, inc)
|
||||||
*
|
*
|
||||||
|
|
@ -2221,7 +2357,7 @@ if (DEBUGGER) {
|
||||||
var sInfo = "no information";
|
var sInfo = "no information";
|
||||||
if (BACKTRACK) {
|
if (BACKTRACK) {
|
||||||
var sAddr = asArgs[0];
|
var sAddr = asArgs[0];
|
||||||
var dbgAddr = this.parseAddr(sAddr, Debugger.ADDR.CODE, true, true);
|
var dbgAddr = this.parseAddr(sAddr, Debugger.ADDR.CODE, true, false);
|
||||||
if (dbgAddr) {
|
if (dbgAddr) {
|
||||||
var addr = this.getAddr(dbgAddr);
|
var addr = this.getAddr(dbgAddr);
|
||||||
sInfo = '%' + str.toHex(addr) + ": " + (this.bus.getSymbol(addr, true) || sInfo);
|
sInfo = '%' + str.toHex(addr) + ": " + (this.bus.getSymbol(addr, true) || sInfo);
|
||||||
|
|
@ -4075,7 +4211,7 @@ if (DEBUGGER) {
|
||||||
|
|
||||||
for (var iOperand = 1; iOperand <= cOperands; iOperand++) {
|
for (var iOperand = 1; iOperand <= cOperands; iOperand++) {
|
||||||
|
|
||||||
var disp, offset, cch;
|
var disp, off, cch;
|
||||||
var sOperand = "";
|
var sOperand = "";
|
||||||
var type = aOpDesc[iOperand];
|
var type = aOpDesc[iOperand];
|
||||||
if (type === undefined) continue;
|
if (type === undefined) continue;
|
||||||
|
|
@ -4129,12 +4265,12 @@ if (DEBUGGER) {
|
||||||
else if (typeMode == Debugger.TYPE_IMMOFF) {
|
else if (typeMode == Debugger.TYPE_IMMOFF) {
|
||||||
if (!dbgAddr.fAddr32) {
|
if (!dbgAddr.fAddr32) {
|
||||||
cch = 4;
|
cch = 4;
|
||||||
offset = this.getShort(dbgAddr, 2);
|
off = this.getShort(dbgAddr, 2);
|
||||||
} else {
|
} else {
|
||||||
cch = 8;
|
cch = 8;
|
||||||
offset = this.getLong(dbgAddr, 4);
|
off = this.getLong(dbgAddr, 4);
|
||||||
}
|
}
|
||||||
sOperand = '[' + str.toHex(offset, cch) + ']';
|
sOperand = '[' + str.toHex(off, cch) + ']';
|
||||||
}
|
}
|
||||||
else if (typeMode == Debugger.TYPE_IMMREL) {
|
else if (typeMode == Debugger.TYPE_IMMREL) {
|
||||||
if (typeSize == Debugger.TYPE_BYTE) {
|
if (typeSize == Debugger.TYPE_BYTE) {
|
||||||
|
|
@ -4143,9 +4279,9 @@ if (DEBUGGER) {
|
||||||
else {
|
else {
|
||||||
disp = this.getWord(dbgAddr, true);
|
disp = this.getWord(dbgAddr, true);
|
||||||
}
|
}
|
||||||
offset = (dbgAddr.off + disp) & (dbgAddr.fData32? -1 : 0xffff);
|
off = (dbgAddr.off + disp) & (dbgAddr.fData32? -1 : 0xffff);
|
||||||
sOperand = str.toHex(offset, dbgAddr.fData32? 8: 4);
|
sOperand = str.toHex(off, dbgAddr.fData32? 8: 4);
|
||||||
var aSymbol = this.findSymbol(this.newAddr(offset, dbgAddr.sel));
|
var aSymbol = this.findSymbol(this.newAddr(off, dbgAddr.sel));
|
||||||
if (aSymbol[0]) sOperand += " (" + aSymbol[0] + ")";
|
if (aSymbol[0]) sOperand += " (" + aSymbol[0] + ")";
|
||||||
}
|
}
|
||||||
else if (typeMode == Debugger.TYPE_IMPREG) {
|
else if (typeMode == Debugger.TYPE_IMPREG) {
|
||||||
|
|
@ -4618,122 +4754,6 @@ if (DEBUGGER) {
|
||||||
return s;
|
return s;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* parseAddr(sAddr, type, fNoChecks, fQuiet)
|
|
||||||
*
|
|
||||||
* As discussed above, dbgAddr variables contain one or more of: off, sel, and addr. They represent
|
|
||||||
* a segmented address (sel:off) when sel is defined or a linear address (addr) when sel is undefined
|
|
||||||
* (or null).
|
|
||||||
*
|
|
||||||
* To create a segmented address, specify two values separated by ':'; for a linear address, use
|
|
||||||
* a '%' prefix. We check for ':' after '%', so if for some strange reason you specify both, the
|
|
||||||
* address will be treated as segmented, not linear.
|
|
||||||
*
|
|
||||||
* The '%' syntax is similar to that used by the Windows 80386 kernel debugger (wdeb386) for linear
|
|
||||||
* addresses. If/when we add support for processors with page tables, we will likely adopt the same
|
|
||||||
* convention for linear addresses and provide a different syntax (eg, "%%") physical memory references.
|
|
||||||
*
|
|
||||||
* Address evaluation and validation (eg, range checks) are no longer performed at this stage. That's
|
|
||||||
* done later, by getAddr(), which returns X86.ADDR_INVALID for invalid segments, out-of-range offsets,
|
|
||||||
* etc. The Debugger's low-level get/set memory functions verify all getAddr() results, but even if an
|
|
||||||
* invalid address is passed through to the Bus memory interfaces, the address will simply be masked with
|
|
||||||
* Bus.nBusLimit; in the case of X86.ADDR_INVALID, that will generally refer to the top of the physical
|
|
||||||
* address space.
|
|
||||||
*
|
|
||||||
* @this {Debugger}
|
|
||||||
* @param {string|undefined} sAddr
|
|
||||||
* @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}
|
|
||||||
*/
|
|
||||||
Debugger.prototype.parseAddr = function(sAddr, type, fNoChecks, fQuiet)
|
|
||||||
{
|
|
||||||
var dbgAddr, fPrint;
|
|
||||||
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) {
|
|
||||||
|
|
||||||
sAddr = this.parseReference(sAddr);
|
|
||||||
|
|
||||||
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);
|
|
||||||
iColon--;
|
|
||||||
}
|
|
||||||
|
|
||||||
dbgAddr = this.findSymbolAddr(sAddr);
|
|
||||||
if (dbgAddr) return dbgAddr;
|
|
||||||
|
|
||||||
if (iColon < 0) {
|
|
||||||
if (sel != null) {
|
|
||||||
off = this.parseExpression(sAddr, fPrint);
|
|
||||||
addr = null;
|
|
||||||
} else {
|
|
||||||
addr = this.parseExpression(sAddr, fPrint);
|
|
||||||
if (addr == null) off = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sel = this.parseExpression(sAddr.substring(0, iColon), fPrint);
|
|
||||||
off = this.parseExpression(sAddr.substring(iColon + 1), fPrint);
|
|
||||||
addr = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (off != null) {
|
|
||||||
dbgAddr = this.newAddr(off, sel, addr, type);
|
|
||||||
if (!fNoChecks && !this.checkLimit(dbgAddr, true)) {
|
|
||||||
this.println("invalid offset: " + this.hexAddr(dbgAddr));
|
|
||||||
dbgAddr = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dbgAddr;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* parseAddrOptions(dbdAddr, sOptions)
|
|
||||||
*
|
|
||||||
* @this {Debugger}
|
|
||||||
* @param {DbgAddr} dbgAddr
|
|
||||||
* @param {string} [sOptions]
|
|
||||||
*/
|
|
||||||
Debugger.prototype.parseAddrOptions = function(dbgAddr, sOptions)
|
|
||||||
{
|
|
||||||
if (sOptions) {
|
|
||||||
var a = sOptions.match(/(['"])(.*?)\1/);
|
|
||||||
if (a) {
|
|
||||||
dbgAddr.aCmds = this.parseCommand(dbgAddr.sCmd = a[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Debugger.aBinOpPrecedence = {
|
Debugger.aBinOpPrecedence = {
|
||||||
'||': 0, // logical OR
|
'||': 0, // logical OR
|
||||||
'&&': 1, // logical AND
|
'&&': 1, // logical AND
|
||||||
|
|
@ -5068,7 +5088,20 @@ if (DEBUGGER) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* addSymbols(addr, size, aSymbols)
|
* comparePairs(p1, p2)
|
||||||
|
*
|
||||||
|
* @this {Debugger}
|
||||||
|
* @param {number|string|Array|Object} p1
|
||||||
|
* @param {number|string|Array|Object} p2
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
Debugger.prototype.comparePairs = function(p1, p2)
|
||||||
|
{
|
||||||
|
return p1[0] > p2[0]? 1 : p1[0] < p2[0]? -1 : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* addSymbols(sel, addr, len, aSymbols)
|
||||||
*
|
*
|
||||||
* As filedump.js (formerly convrom.php) explains, aSymbols is a JSON-encoded object whose properties consist
|
* As filedump.js (formerly convrom.php) explains, aSymbols is a JSON-encoded object whose properties consist
|
||||||
* of all the symbols (in upper-case), and the values of those properties are objects containing any or all of
|
* of all the symbols (in upper-case), and the values of those properties are objects containing any or all of
|
||||||
|
|
@ -5124,7 +5157,7 @@ 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:
|
||||||
*
|
*
|
||||||
* [addr, size, aSymbols, aOffsetPairs]
|
* [sel, addr, len, aSymbols, aOffsetPairs]
|
||||||
*
|
*
|
||||||
* 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
|
||||||
|
|
@ -5139,29 +5172,27 @@ if (DEBUGGER) {
|
||||||
* properly.
|
* properly.
|
||||||
*
|
*
|
||||||
* @this {Debugger}
|
* @this {Debugger}
|
||||||
* @param {number} addr is the physical address of the region where the given symbols are located
|
* @param {number} sel (the default segment/selector for all symbols in this group)
|
||||||
* @param {number} size is the size of the region, in bytes
|
* @param {number} addr (the physical address of the region where the given symbols are located)
|
||||||
* @param {Object} aSymbols is the collection of symbols (the format of this object is described below)
|
* @param {number} len (the size of the region, in bytes)
|
||||||
|
* @param {Object} aSymbols (collection of symbols in this group; the format of this collection is described below)
|
||||||
*/
|
*/
|
||||||
Debugger.prototype.addSymbols = function(addr, size, aSymbols)
|
Debugger.prototype.addSymbols = function(sel, addr, len, aSymbols)
|
||||||
{
|
{
|
||||||
var dbgAddr = {};
|
var dbgAddr = {};
|
||||||
var aOffsetPairs = [];
|
var aOffsetPairs = [];
|
||||||
var fnComparePairs = function(p1, p2) {
|
|
||||||
return p1[0] > p2[0]? 1 : p1[0] < p2[0]? -1 : 0;
|
|
||||||
};
|
|
||||||
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") {
|
||||||
aSymbols[sSymbol] = symbol = {'o': symbol};
|
aSymbols[sSymbol] = symbol = {'o': symbol};
|
||||||
}
|
}
|
||||||
var off = symbol['o'];
|
var off = symbol['o'];
|
||||||
var sel = symbol['s'];
|
var selSymbol = symbol['s'];
|
||||||
var sAnnotation = symbol['a'];
|
var sAnnotation = symbol['a'];
|
||||||
if (off !== undefined) {
|
if (off !== undefined) {
|
||||||
if (sel !== undefined) {
|
if (selSymbol !== undefined) {
|
||||||
dbgAddr.off = off;
|
dbgAddr.off = off;
|
||||||
dbgAddr.sel = sel;
|
dbgAddr.sel = selSymbol;
|
||||||
dbgAddr.addr = null;
|
dbgAddr.addr = null;
|
||||||
/*
|
/*
|
||||||
* getAddr() computes the corresponding physical address and saves it in dbgAddr.addr.
|
* getAddr() computes the corresponding physical address and saves it in dbgAddr.addr.
|
||||||
|
|
@ -5177,11 +5208,11 @@ if (DEBUGGER) {
|
||||||
}
|
}
|
||||||
symbol['p'] = dbgAddr.addr;
|
symbol['p'] = dbgAddr.addr;
|
||||||
}
|
}
|
||||||
usr.binaryInsert(aOffsetPairs, [off, sSymbol], fnComparePairs);
|
usr.binaryInsert(aOffsetPairs, [off >>> 0, sSymbol], this.comparePairs);
|
||||||
}
|
}
|
||||||
if (sAnnotation) symbol['a'] = sAnnotation.replace(/''/g, "\"");
|
if (sAnnotation) symbol['a'] = sAnnotation.replace(/''/g, "\"");
|
||||||
}
|
}
|
||||||
this.aSymbolTable.push([addr, size, aSymbols, aOffsetPairs]);
|
this.aSymbolTable.push([sel, addr, len, aSymbols, aOffsetPairs]);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -5195,19 +5226,20 @@ if (DEBUGGER) {
|
||||||
Debugger.prototype.dumpSymbols = function()
|
Debugger.prototype.dumpSymbols = function()
|
||||||
{
|
{
|
||||||
for (var i = 0; i < this.aSymbolTable.length; i++) {
|
for (var i = 0; i < this.aSymbolTable.length; i++) {
|
||||||
var addr = this.aSymbolTable[i][0];
|
var sel = this.aSymbolTable[i][0];
|
||||||
//var size = this.aSymbolTable[i][1];
|
var addr = this.aSymbolTable[i][1];
|
||||||
var aSymbols = this.aSymbolTable[i][2];
|
//var len = this.aSymbolTable[i][2];
|
||||||
|
var aSymbols = this.aSymbolTable[i][3];
|
||||||
for (var sSymbol in aSymbols) {
|
for (var sSymbol in aSymbols) {
|
||||||
if (sSymbol.charAt(0) == '.') continue;
|
if (sSymbol.charAt(0) == '.') continue;
|
||||||
var symbol = aSymbols[sSymbol];
|
var symbol = aSymbols[sSymbol];
|
||||||
var off = symbol['o'];
|
var off = symbol['o'];
|
||||||
if (off === undefined) continue;
|
if (off === undefined) continue;
|
||||||
var sel = symbol['s'];
|
var selSym = symbol['s'];
|
||||||
if (sel === undefined) sel = (addr >>> 4);
|
if (selSym === undefined) selSym = sel;
|
||||||
var sSymbolOrig = aSymbols[sSymbol]['l'];
|
var sSymbolOrig = aSymbols[sSymbol]['l'];
|
||||||
if (sSymbolOrig) sSymbol = sSymbolOrig;
|
if (sSymbolOrig) sSymbol = sSymbolOrig;
|
||||||
this.println(this.hexOffset(off, sel) + ' ' + sSymbol);
|
this.println(this.hexOffset(off, selSym) + ' ' + sSymbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -5228,34 +5260,33 @@ if (DEBUGGER) {
|
||||||
Debugger.prototype.findSymbol = function(dbgAddr, fNearest)
|
Debugger.prototype.findSymbol = function(dbgAddr, fNearest)
|
||||||
{
|
{
|
||||||
var aSymbol = [];
|
var aSymbol = [];
|
||||||
var addr = this.getAddr(dbgAddr);
|
var addrSymbol = this.getAddr(dbgAddr) >>> 0;
|
||||||
for (var iTable = 0; iTable < this.aSymbolTable.length; iTable++) {
|
for (var iTable = 0; iTable < this.aSymbolTable.length; iTable++) {
|
||||||
var addrSymbol = this.aSymbolTable[iTable][0];
|
var sel = this.aSymbolTable[iTable][0];
|
||||||
var sizeSymbol = this.aSymbolTable[iTable][1];
|
var addr = this.aSymbolTable[iTable][1] >>> 0;
|
||||||
if (addr >= addrSymbol && addr < addrSymbol + sizeSymbol) {
|
var len = this.aSymbolTable[iTable][2];
|
||||||
var offset = dbgAddr.off;
|
if (sel == dbgAddr.sel || (sel == 0x28 || sel == 0x30) && (dbgAddr.sel == 0x28 || dbgAddr.sel == 0x30)) {
|
||||||
var aOffsetPairs = this.aSymbolTable[iTable][3];
|
if (addrSymbol >= addr && addrSymbol < addr + len) {
|
||||||
var fnComparePairs = function(p1, p2)
|
var off = dbgAddr.off >>> 0;
|
||||||
{
|
var aOffsetPairs = this.aSymbolTable[iTable][4];
|
||||||
return p1[0] > p2[0]? 1 : p1[0] < p2[0]? -1 : 0;
|
var result = usr.binarySearch(aOffsetPairs, [off], this.comparePairs);
|
||||||
};
|
if (result >= 0) {
|
||||||
var result = usr.binarySearch(aOffsetPairs, [offset], fnComparePairs);
|
this.returnSymbol(iTable, result, aSymbol);
|
||||||
if (result >= 0) {
|
}
|
||||||
this.returnSymbol(iTable, result, aSymbol);
|
else if (fNearest) {
|
||||||
|
result = ~result;
|
||||||
|
this.returnSymbol(iTable, result-1, aSymbol);
|
||||||
|
this.returnSymbol(iTable, result, aSymbol);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (fNearest) {
|
|
||||||
result = ~result;
|
|
||||||
this.returnSymbol(iTable, result-1, aSymbol);
|
|
||||||
this.returnSymbol(iTable, result, aSymbol);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!aSymbol.length) {
|
if (!aSymbol.length) {
|
||||||
var sSymbol = this.bus.getSymbol(addr, true);
|
var sSymbol = this.bus.getSymbol(addrSymbol, true);
|
||||||
if (sSymbol) {
|
if (sSymbol) {
|
||||||
aSymbol.push(sSymbol);
|
aSymbol.push(sSymbol);
|
||||||
aSymbol.push(addr);
|
aSymbol.push(addrSymbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return aSymbol;
|
return aSymbol;
|
||||||
|
|
@ -5276,21 +5307,23 @@ if (DEBUGGER) {
|
||||||
if (sSymbol.match(/^[a-z_][a-z0-9_]*$/i)) {
|
if (sSymbol.match(/^[a-z_][a-z0-9_]*$/i)) {
|
||||||
var sUpperCase = sSymbol.toUpperCase();
|
var sUpperCase = sSymbol.toUpperCase();
|
||||||
for (var i = 0; i < this.aSymbolTable.length; i++) {
|
for (var i = 0; i < this.aSymbolTable.length; i++) {
|
||||||
var addr = this.aSymbolTable[i][0];
|
var sel = this.aSymbolTable[i][0];
|
||||||
//var size = this.aSymbolTable[i][1];
|
var addr = this.aSymbolTable[i][1];
|
||||||
var aSymbols = this.aSymbolTable[i][2];
|
//var len = this.aSymbolTable[i][2];
|
||||||
|
var aSymbols = this.aSymbolTable[i][3];
|
||||||
var symbol = aSymbols[sUpperCase];
|
var symbol = aSymbols[sUpperCase];
|
||||||
if (symbol !== undefined) {
|
if (symbol !== undefined) {
|
||||||
var off = symbol['o'];
|
var off = symbol['o'];
|
||||||
if (off !== undefined) {
|
if (off !== undefined) {
|
||||||
/*
|
/*
|
||||||
* We assume that every ROM is ORG'ed at 0x0000, and therefore unless the symbol has an
|
* We assume that every ROM is ORG'ed at 0x0000, and therefore unless the symbol has an
|
||||||
* explicitly-defined segment, we return the segment as "addr >>> 4". Down the road, we may
|
* explicitly-defined segment, we return the segment associated with the entire group; for
|
||||||
* want/need to support a special symbol entry (eg, ".ORG") that defines an alternate origin.
|
* a ROM, that segment is normally "addrROM >>> 4". Down the road, we may want/need to
|
||||||
|
* support a special symbol entry (eg, ".ORG") that defines an alternate origin.
|
||||||
*/
|
*/
|
||||||
var sel = symbol['s'];
|
var selSym = symbol['s'];
|
||||||
if (sel === undefined) sel = addr >>> 4;
|
if (selSym === undefined) selSym = sel;
|
||||||
dbgAddr = this.newAddr(off, sel, symbol['p']);
|
dbgAddr = this.newAddr(off, selSym, symbol['p']);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* The symbol matched, but it wasn't for an address (no 'o' offset), and there's no point
|
* The symbol matched, but it wasn't for an address (no 'o' offset), and there's no point
|
||||||
|
|
@ -5315,14 +5348,14 @@ 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][3];
|
var aOffsetPairs = this.aSymbolTable[iTable][4];
|
||||||
var offset = 0, sSymbol = null;
|
var offset = 0, sSymbol = null;
|
||||||
if (iOffset >= 0 && iOffset < aOffsetPairs.length) {
|
if (iOffset >= 0 && iOffset < aOffsetPairs.length) {
|
||||||
offset = aOffsetPairs[iOffset][0];
|
offset = aOffsetPairs[iOffset][0];
|
||||||
sSymbol = aOffsetPairs[iOffset][1];
|
sSymbol = aOffsetPairs[iOffset][1];
|
||||||
}
|
}
|
||||||
if (sSymbol) {
|
if (sSymbol) {
|
||||||
symbol = this.aSymbolTable[iTable][2][sSymbol];
|
symbol = this.aSymbolTable[iTable][3][sSymbol];
|
||||||
sSymbol = (sSymbol.charAt(0) == '.'? null : (symbol['l'] || sSymbol));
|
sSymbol = (sSymbol.charAt(0) == '.'? null : (symbol['l'] || sSymbol));
|
||||||
}
|
}
|
||||||
aSymbol.push(sSymbol);
|
aSymbol.push(sSymbol);
|
||||||
|
|
@ -5974,38 +6007,49 @@ if (DEBUGGER) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* doList(sSymbol)
|
* doList(sAddr, fPrint)
|
||||||
*
|
*
|
||||||
* @this {Debugger}
|
* @this {Debugger}
|
||||||
* @param {string} sSymbol
|
* @param {string} sAddr
|
||||||
|
* @param {boolean} [fPrint]
|
||||||
|
* @return {string|null}
|
||||||
*/
|
*/
|
||||||
Debugger.prototype.doList = function(sSymbol)
|
Debugger.prototype.doList = function(sAddr, fPrint)
|
||||||
{
|
{
|
||||||
var dbgAddr = this.parseAddr(sSymbol, Debugger.ADDR.CODE);
|
var sSymbol = null;
|
||||||
if (!dbgAddr) return;
|
|
||||||
|
|
||||||
var addr = this.getAddr(dbgAddr);
|
var dbgAddr = this.parseAddr(sAddr, Debugger.ADDR.CODE);
|
||||||
sSymbol = sSymbol? (sSymbol + ": ") : "";
|
if (dbgAddr) {
|
||||||
this.println(sSymbol + this.hexAddr(dbgAddr) + " (%" + str.toHex(addr, this.cchAddr) + ')');
|
|
||||||
|
|
||||||
var aSymbol = this.findSymbol(dbgAddr, true);
|
var addr = this.getAddr(dbgAddr);
|
||||||
if (aSymbol.length) {
|
if (MAXDEBUG && fPrint) {
|
||||||
var nDelta, sDelta;
|
this.println(this.hexAddr(dbgAddr) + " (%" + str.toHex(addr, this.cchAddr) + ')');
|
||||||
if (aSymbol[0]) {
|
|
||||||
sDelta = "";
|
|
||||||
nDelta = dbgAddr.off - aSymbol[1];
|
|
||||||
if (nDelta) sDelta = " + " + str.toHexWord(nDelta);
|
|
||||||
this.println(aSymbol[0] + " (" + this.hexOffset(aSymbol[1], dbgAddr.sel) + ')' + sDelta);
|
|
||||||
}
|
}
|
||||||
if (aSymbol.length > 4 && aSymbol[4]) {
|
|
||||||
sDelta = "";
|
var aSymbol = this.findSymbol(dbgAddr, true);
|
||||||
nDelta = aSymbol[5] - dbgAddr.off;
|
if (aSymbol.length) {
|
||||||
if (nDelta) sDelta = " - " + str.toHexWord(nDelta);
|
var nDelta, sDelta, s;
|
||||||
this.println(aSymbol[4] + " (" + this.hexOffset(aSymbol[5], dbgAddr.sel) + ')' + sDelta);
|
if (aSymbol[0]) {
|
||||||
|
sDelta = "";
|
||||||
|
nDelta = dbgAddr.off - aSymbol[1];
|
||||||
|
if (nDelta) sDelta = " + " + str.toHexWord(nDelta);
|
||||||
|
s = aSymbol[0] + " (" + this.hexOffset(aSymbol[1], dbgAddr.sel) + ')' + sDelta;
|
||||||
|
if (fPrint) this.println(s);
|
||||||
|
sSymbol = s;
|
||||||
|
}
|
||||||
|
if (aSymbol.length > 4 && aSymbol[4]) {
|
||||||
|
sDelta = "";
|
||||||
|
nDelta = aSymbol[5] - dbgAddr.off;
|
||||||
|
if (nDelta) sDelta = " - " + str.toHexWord(nDelta);
|
||||||
|
s = aSymbol[4] + " (" + this.hexOffset(aSymbol[5], dbgAddr.sel) + ')' + sDelta;
|
||||||
|
if (fPrint) this.println(s);
|
||||||
|
if (!sSymbol) sSymbol = s;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (fPrint) this.println("no symbols");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
this.println("no symbols");
|
|
||||||
}
|
}
|
||||||
|
return sSymbol;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -6034,12 +6078,6 @@ if (DEBUGGER) {
|
||||||
if (!asArgs[1] || asArgs[1] == '?') {
|
if (!asArgs[1] || asArgs[1] == '?') {
|
||||||
this.println("list/load commands:");
|
this.println("list/load commands:");
|
||||||
this.println("\tl [address] [drive #] [sector #] [# sectors]");
|
this.println("\tl [address] [drive #] [sector #] [# sectors]");
|
||||||
this.println("\tln [address] lists symbol(s) nearest to address");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asArgs[0] == "ln") {
|
|
||||||
this.doList(asArgs[1]);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6800,11 +6838,15 @@ if (DEBUGGER) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* doStackTrace()
|
* doStackTrace(sCmd, sAddr)
|
||||||
|
*
|
||||||
|
* Use "k" for a normal stack trace and "ks" for a stack trace with symbolic info.
|
||||||
*
|
*
|
||||||
* @this {Debugger}
|
* @this {Debugger}
|
||||||
|
* @param {string} [sCmd]
|
||||||
|
* @param {string} [sAddr] (not used yet)
|
||||||
*/
|
*/
|
||||||
Debugger.prototype.doStackTrace = function()
|
Debugger.prototype.doStackTrace = function(sCmd, sAddr)
|
||||||
{
|
{
|
||||||
var nFrames = 10, cFrames = 0;
|
var nFrames = 10, cFrames = 0;
|
||||||
var selCode = this.cpu.segCS.sel;
|
var selCode = this.cpu.segCS.sel;
|
||||||
|
|
@ -6822,9 +6864,7 @@ if (DEBUGGER) {
|
||||||
if (dbgAddrStack.addr == null || !cTests--) break;
|
if (dbgAddrStack.addr == null || !cTests--) break;
|
||||||
dbgAddrCall.sel = selCode;
|
dbgAddrCall.sel = selCode;
|
||||||
sCall = this.getCall(dbgAddrCall);
|
sCall = this.getCall(dbgAddrCall);
|
||||||
if (sCall) {
|
if (sCall) break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
dbgAddrCall.sel = this.getWord(dbgAddrStack);
|
dbgAddrCall.sel = this.getWord(dbgAddrStack);
|
||||||
sCall = this.getCall(dbgAddrCall, true);
|
sCall = this.getCall(dbgAddrCall, true);
|
||||||
if (sCall) {
|
if (sCall) {
|
||||||
|
|
@ -6838,7 +6878,12 @@ if (DEBUGGER) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!sCall) break;
|
if (!sCall) break;
|
||||||
sCall = str.pad(sCall, 50) + " ;stack=" + this.hexAddr(dbgAddrStack) + " return=" + this.hexAddr(dbgAddrCall);
|
var sSymbol = null;
|
||||||
|
if (sCmd == "ks") {
|
||||||
|
var a = sCall.match(/[0-9A-F]+$/);
|
||||||
|
if (a) sSymbol = this.doList(a[0]);
|
||||||
|
}
|
||||||
|
sCall = str.pad(sCall, 50) + " ;" + (sSymbol || "stack=" + this.hexAddr(dbgAddrStack) + " return=" + this.hexAddr(dbgAddrCall));
|
||||||
this.println(sCall);
|
this.println(sCall);
|
||||||
cFrames++;
|
cFrames++;
|
||||||
}
|
}
|
||||||
|
|
@ -7159,9 +7204,13 @@ if (DEBUGGER) {
|
||||||
this.doInput(asArgs[1]);
|
this.doInput(asArgs[1]);
|
||||||
break;
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
this.doStackTrace();
|
this.doStackTrace(asArgs[0], asArgs[1]);
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
|
if (asArgs[0] == "ln") {
|
||||||
|
this.doList(asArgs[1], true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
this.shiftArgs(asArgs);
|
this.shiftArgs(asArgs);
|
||||||
this.doLoad(asArgs);
|
this.doLoad(asArgs);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ ROM.prototype.powerUp = function(data, fRepower)
|
||||||
{
|
{
|
||||||
if (this.aSymbols) {
|
if (this.aSymbols) {
|
||||||
if (this.dbg) {
|
if (this.dbg) {
|
||||||
this.dbg.addSymbols(this.addrROM, this.sizeROM, this.aSymbols);
|
this.dbg.addSymbols(this.addrROM >>> 4, this.addrROM, this.sizeROM, this.aSymbols);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Our only role in the handling of symbols is to hand them off to the Debugger at our
|
* Our only role in the handling of symbols is to hand them off to the Debugger at our
|
||||||
|
|
|
||||||
|
|
@ -5575,6 +5575,12 @@ Video.prototype.updateScreenGraphicsEGA = function(addrBuffer, addrScreen, addrS
|
||||||
* and in the array that are outside the signed 32-bit range, potentially triggering floating-point.
|
* and in the array that are outside the signed 32-bit range, potentially triggering floating-point.
|
||||||
*
|
*
|
||||||
* if (dwPixel < 0) dwPixel += 0x100000000;
|
* if (dwPixel < 0) dwPixel += 0x100000000;
|
||||||
|
*
|
||||||
|
* An even simpler solution would be to use the unsigned right-shift operator:
|
||||||
|
*
|
||||||
|
* dwPixel >>> 0
|
||||||
|
*
|
||||||
|
* but again, all that does is produce a value outside the signed 32-bit range, which is sub-optimal.
|
||||||
*/
|
*/
|
||||||
this.assert(Video.aEGADWToByte[dwPixel] !== undefined);
|
this.assert(Video.aEGADWToByte[dwPixel] !== undefined);
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue