From ad95e9374005a255e08d0b742537ecff12412e38 Mon Sep 17 00:00:00 2001 From: Jeff Parsons Date: Mon, 1 Jun 2015 13:02:23 -0700 Subject: [PATCH] Stack trace command actually works now --- modules/pcjs/lib/debugger.js | 73 ++++++++++++++++++++++++++++++------ modules/pcjs/lib/video.js | 6 +-- 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/modules/pcjs/lib/debugger.js b/modules/pcjs/lib/debugger.js index e89e37bda..373388520 100644 --- a/modules/pcjs/lib/debugger.js +++ b/modules/pcjs/lib/debugger.js @@ -1652,6 +1652,9 @@ if (DEBUGGER) { if (dbgAddr.sel != null) { var seg = this.getSegment(dbgAddr.sel); if (!seg || dbgAddr.off > seg.limit) { + /* + * TODO: This automatic wrap-to-zero is OK for normal segments, but for expand-down segments, not so much. + */ dbgAddr.off = 0; dbgAddr.addr = null; } @@ -5183,6 +5186,35 @@ if (DEBUGGER) { } }; + /** + * getCall(dbgAddr, fFar) + * + * @this {Debugger} + * @param {{DbgAddr}} dbgAddr + * @param {boolean} [fFar] + * @return {string|null} CALL instruction at or near dbgAddr, or null if none + */ + Debugger.prototype.getCall = function(dbgAddr, fFar) + { + var sCall = null; + var off = dbgAddr.off; + var offOrig = off; + for (var n = 1; n <= 6; n++) { + if (n > 2) { + dbgAddr.off = off; + dbgAddr.addr = null; + var s = this.getInstruction(dbgAddr); + if (s.indexOf("CALL") > 0 || fFar && s.indexOf("INT") > 0) { + sCall = s; + break; + } + } + if (!--off) break; + } + dbgAddr.off = offOrig; + return sCall; + }; + /** * doStackTrace() * @@ -5190,26 +5222,43 @@ if (DEBUGGER) { */ Debugger.prototype.doStackTrace = function() { - var cFrames = 0; + var nFrames = 10, cFrames = 0; + var selCode = this.cpu.segCS.sel; var dbgAddrCall = this.newAddr(); var dbgAddrStack = this.newAddr(this.cpu.getSP(), this.cpu.getSS()); - while (cFrames++ < 10) { - var fFound = false; + this.println("stack trace for " + this.hexAddr(dbgAddrStack) + ':'); + while (cFrames < nFrames) { + var sCall = null, cTests = 256; while ((dbgAddrStack.off >>> 0) < (this.cpu.regLSPLimit >>> 0)) { - dbgAddrCall.off = this.getWord(dbgAddrCall); - dbgAddrCall.sel = this.cpu.segCS.sel; + dbgAddrCall.off = this.getWord(dbgAddrStack, true); /* - * Check the near-call case first + * Because we're using the auto-increment feature of getWord(), and because that will automatically + * wrap the offset around the end of the segment, we must also check the addr property to detect the wrap. */ - dbgAddrCall.off -= 3; - if (this.getByte(dbgAddrCall) == X86.OPCODE.CALL) { - fFound = true; + if (dbgAddrStack.addr == null || !cTests--) break; + dbgAddrCall.sel = selCode; + sCall = this.getCall(dbgAddrCall); + if (sCall) { + break; + } + dbgAddrCall.sel = this.getWord(dbgAddrStack); + sCall = this.getCall(dbgAddrCall, true); + if (sCall) { + selCode = this.getWord(dbgAddrStack, true); + /* + * It's not strictly necessary that we skip over the flags word that's pushed as part of any INT + * instruction, but it reduces the risk of misinterpreting it as a return address on the next iteration. + */ + if (sCall.indexOf("INT") > 0) this.getWord(dbgAddrStack, true); + break; } - dbgAddrStack.off += this.cpu.segCS.dataSize; } - if (!fFound) return; - this.println(this.getInstruction(dbgAddrCall)); + if (!sCall) break; + sCall = str.pad(sCall, 56) + ";SS:SP=" + this.hexAddr(dbgAddrStack); + this.println(sCall); + cFrames++; } + if (!cFrames) this.println("no return addresses found"); }; /** diff --git a/modules/pcjs/lib/video.js b/modules/pcjs/lib/video.js index 5e19545ba..b430d8a18 100644 --- a/modules/pcjs/lib/video.js +++ b/modules/pcjs/lib/video.js @@ -2080,13 +2080,13 @@ Card.prototype.dumpCard = function() this.dumpRegs("CRTC", this.regCRTIndx, this.regCRTData, this.asCRTCRegs); if (this.nCard == Video.CARD.MDA || this.nCard == Video.CARD.CGA) { - this.dumpRegs(" MODEREG", this.regMode); + this.dumpRegs(" MODEREG", this.regMode); } - this.dumpRegs(" STATUS1", this.regStatus); + this.dumpRegs(" STATUS1", this.regStatus); if (this.nCard == Video.CARD.CGA) { - this.dumpRegs(" COLOR", this.regColor); + this.dumpRegs(" COLOR", this.regColor); } if (this.nCard >= Video.CARD.EGA) {