diff --git a/src/debug/debug.cpp b/src/debug/debug.cpp index 2a54c3b5..20c39429 100644 --- a/src/debug/debug.cpp +++ b/src/debug/debug.cpp @@ -305,13 +305,16 @@ public: static CBreakpoint* AddBreakpoint (Bit16u seg, Bit32u off, bool once); static CBreakpoint* AddIntBreakpoint (Bit8u intNum, Bit16u ah, Bit16u al, bool once); static CBreakpoint* AddMemBreakpoint (Bit16u seg, Bit32u off); - static void ActivateBreakpoints (PhysPt adr, bool activate); + static void DeactivateBreakpoints(); + static void ActivateBreakpoints (); + static void ActivateBreakpointsExceptAt(PhysPt adr); static bool CheckBreakpoint (PhysPt adr); static bool CheckBreakpoint (Bitu seg, Bitu off); static bool CheckIntBreakpoint (PhysPt adr, Bit8u intNr, Bit16u ahValue, Bit16u alValue); - static bool IsBreakpoint (PhysPt where); - static bool IsBreakpointDrawn (PhysPt where); - static bool DeleteBreakpoint (PhysPt where); + static CBreakpoint* FindPhysBreakpoint (Bit16u seg, Bit32u off, bool once); + static CBreakpoint* FindOtherActiveBreakpoint(PhysPt adr, CBreakpoint* skip); + static bool IsBreakpoint (Bit16u seg, Bit32u off); + static bool DeleteBreakpoint (Bit16u seg, Bit32u off); static bool DeleteByIndex (Bit16u index); static void DeleteAll (void); static void ShowList (void); @@ -333,12 +336,10 @@ private: bool once; static std::list BPoints; -public: - static CBreakpoint* ignoreOnce; }; CBreakpoint::CBreakpoint(void): -location(0), +location(0),oldData(0xCC), active(false),once(false), segment(0),offset(0),intNr(0),ahValue(0),alValue(0), type(BKPNT_UNKNOWN) { }; @@ -346,18 +347,36 @@ type(BKPNT_UNKNOWN) { }; void CBreakpoint::Activate(bool _active) { #if !C_HEAVY_DEBUG - if (GetType()==BKPNT_PHYSICAL) { + if (GetType() == BKPNT_PHYSICAL) { if (_active) { // Set 0xCC and save old value Bit8u data = mem_readb(location); - if (data!=0xCC) { + if (data != 0xCC) { oldData = data; mem_writeb(location,0xCC); + } else if (!active) { + // Another activate breakpoint is already here. + // Find it, and copy its oldData value + CBreakpoint *bp = FindOtherActiveBreakpoint(location, this); + + if (!bp || bp->oldData == 0xCC) { + // This might also happen if there is a real 0xCC instruction here + DEBUG_ShowMsg("DEBUG: Internal error while activating breakpoint.\n"); + oldData = 0xCC; + } else + oldData = bp->oldData; }; } else { - // Remove 0xCC and set old value - if (mem_readb (location)==0xCC) { - mem_writeb(location,oldData); + if (mem_readb(location) == 0xCC) { + if (oldData == 0xCC) + DEBUG_ShowMsg("DEBUG: Internal error while deactivating breakpoint.\n"); + + // Check if we are the last active breakpoint at this location + bool otherActive = (FindOtherActiveBreakpoint(location, this) != 0); + + // If so, remove 0xCC and set old value + if (!otherActive) + mem_writeb(location, oldData); }; } } @@ -367,8 +386,6 @@ void CBreakpoint::Activate(bool _active) // Statics std::list CBreakpoint::BPoints; -CBreakpoint* CBreakpoint::ignoreOnce = 0; -PhysPt ignoreAddressOnce = 0; CBreakpoint* CBreakpoint::AddBreakpoint(Bit16u seg, Bit32u off, bool once) { @@ -398,43 +415,44 @@ CBreakpoint* CBreakpoint::AddMemBreakpoint(Bit16u seg, Bit32u off) return bp; }; -void CBreakpoint::ActivateBreakpoints(PhysPt adr, bool activate) +void CBreakpoint::ActivateBreakpoints() { // activate all breakpoints std::list::iterator i; - CBreakpoint* bp; - for(i=BPoints.begin(); i != BPoints.end(); i++) { - bp = (*i); - // Do not activate, when bp is an actual address - if (activate && (bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==adr)) { - // Do not activate :) + for (i = BPoints.begin(); i != BPoints.end(); i++) + (*i)->Activate(true); +} + +void CBreakpoint::DeactivateBreakpoints() +{ + // deactivate all breakpoints + std::list::iterator i; + for (i = BPoints.begin(); i != BPoints.end(); i++) + (*i)->Activate(false); +} + +void CBreakpoint::ActivateBreakpointsExceptAt(PhysPt adr) +{ + // activate all breakpoints, except those at adr + std::list::iterator i; + for (i = BPoints.begin(); i != BPoints.end(); i++) { + CBreakpoint* bp = (*i); + // Do not activate breakpoints at adr + if (bp->GetType() == BKPNT_PHYSICAL && bp->GetLocation() == adr) continue; - } - bp->Activate(activate); + bp->Activate(true); }; }; bool CBreakpoint::CheckBreakpoint(Bitu seg, Bitu off) // Checks if breakpoint is valid and should stop execution { - if ((ignoreAddressOnce!=0) && (GetAddress(seg,off)==ignoreAddressOnce)) { - ignoreAddressOnce = 0; - return false; - } else - ignoreAddressOnce = 0; - // Search matching breakpoint std::list::iterator i; CBreakpoint* bp; for(i=BPoints.begin(); i != BPoints.end(); i++) { bp = (*i); if ((bp->GetType()==BKPNT_PHYSICAL) && bp->IsActive() && (bp->GetSegment()==seg) && (bp->GetOffset()==off)) { - // Ignore Once ? - if (ignoreOnce==bp) { - ignoreOnce=0; - bp->Activate(true); - return false; - }; // Found, if (bp->GetOnce()) { // delete it, if it should only be used once @@ -442,8 +460,14 @@ bool CBreakpoint::CheckBreakpoint(Bitu seg, Bitu off) bp->Activate(false); delete bp; } else { - ignoreOnce = bp; - }; + // Also look for once-only breakpoints at this address + bp = FindPhysBreakpoint(seg, off, true); + if (bp) { + BPoints.remove(bp); + bp->Activate(false); + delete bp; + } + } return true; } #if C_HEAVY_DEBUG @@ -481,12 +505,6 @@ bool CBreakpoint::CheckBreakpoint(Bitu seg, Bitu off) bool CBreakpoint::CheckIntBreakpoint(PhysPt adr, Bit8u intNr, Bit16u ahValue, Bit16u alValue) // Checks if interrupt breakpoint is valid and should stop execution { - if ((ignoreAddressOnce!=0) && (adr==ignoreAddressOnce)) { - ignoreAddressOnce = 0; - return false; - } else - ignoreAddressOnce = 0; - // Search matching breakpoint std::list::iterator i; CBreakpoint* bp; @@ -495,19 +513,12 @@ bool CBreakpoint::CheckIntBreakpoint(PhysPt adr, Bit8u intNr, Bit16u ahValue, Bi if ((bp->GetType()==BKPNT_INTERRUPT) && bp->IsActive() && (bp->GetIntNr()==intNr)) { if (((bp->GetValue()==BPINT_ALL) || (bp->GetValue()==ahValue)) && ((bp->GetOther()==BPINT_ALL) || (bp->GetOther()==alValue))) { // Ignore it once ? - if (ignoreOnce==bp) { - ignoreOnce=0; - bp->Activate(true); - return false; - }; // Found if (bp->GetOnce()) { // delete it, if it should only be used once (BPoints.erase)(i); bp->Activate(false); delete bp; - } else { - ignoreOnce = bp; } return true; } @@ -548,56 +559,60 @@ bool CBreakpoint::DeleteByIndex(Bit16u index) return false; }; -bool CBreakpoint::DeleteBreakpoint(PhysPt where) +CBreakpoint* CBreakpoint::FindPhysBreakpoint(Bit16u seg, Bit32u off, bool once) { - // Search matching breakpoint +#if !C_HEAVY_DEBUG + PhysPt adr = GetAddress(seg, off); +#endif + // Search for matching breakpoint std::list::iterator i; CBreakpoint* bp; for(i=BPoints.begin(); i != BPoints.end(); i++) { bp = (*i); - if ((bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==where)) { - (BPoints.erase)(i); - bp->Activate(false); - delete bp; - return true; - } - }; - return false; -}; +#if C_HEAVY_DEBUG + // Heavy debugging breakpoints are triggered by matching seg:off + bool atLocation = bp->GetSegment() == seg && bp->GetOffset() == off; +#else + // Normal debugging breakpoints are triggered at an address + bool atLocation = bp->GetLocation() == adr; +#endif -bool CBreakpoint::IsBreakpoint(PhysPt adr) -// is there a breakpoint at address ? -{ - // Search matching breakpoint - std::list::iterator i; - CBreakpoint* bp; - for(i=BPoints.begin(); i != BPoints.end(); i++) { - bp = (*i); - if ((bp->GetType()==BKPNT_PHYSICAL) && (bp->GetSegment()==adr)) { - return true; - }; - if ((bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==adr)) { - return true; - }; - }; - return false; -}; + if (bp->GetType() == BKPNT_PHYSICAL && atLocation && bp->GetOnce() == once) + return bp; + } -bool CBreakpoint::IsBreakpointDrawn(PhysPt adr) -// valid breakpoint, that should be drawn ? + return 0; +} + +CBreakpoint* CBreakpoint::FindOtherActiveBreakpoint(PhysPt adr, CBreakpoint* skip) { - // Search matching breakpoint std::list::iterator i; - CBreakpoint* bp; - for(i=BPoints.begin(); i != BPoints.end(); i++) { - bp = (*i); - if ((bp->GetType()==BKPNT_PHYSICAL) && (bp->GetLocation()==adr)) { - // Only draw, if breakpoint is not only once, - return !bp->GetOnce(); - }; - }; + for (i = BPoints.begin(); i != BPoints.end(); i++) { + CBreakpoint* bp = (*i); + if (bp != skip && bp->GetType() == BKPNT_PHYSICAL && bp->GetLocation() == adr && bp->IsActive()) + return bp; + } + return 0; +} + +// is there a permanent breakpoint at address ? +bool CBreakpoint::IsBreakpoint(Bit16u seg, Bit32u off) +{ + return FindPhysBreakpoint(seg, off, false) != 0; +} + +bool CBreakpoint::DeleteBreakpoint(Bit16u seg, Bit32u off) +{ + CBreakpoint* bp = FindPhysBreakpoint(seg, off, false); + if (bp) { + BPoints.remove(bp); + delete bp; + return true; + } + return false; -}; +} + void CBreakpoint::ShowList(void) { @@ -629,7 +644,7 @@ bool DEBUG_Breakpoint(void) if (!CBreakpoint::CheckBreakpoint(SegValue(cs),reg_eip)) return false; // Found. Breakpoint is valid PhysPt where=GetAddress(SegValue(cs),reg_eip); - CBreakpoint::ActivateBreakpoints(where,false); // Deactivate all breakpoints + CBreakpoint::DeactivateBreakpoints(); // Deactivate all breakpoints return true; }; @@ -639,7 +654,7 @@ bool DEBUG_IntBreakpoint(Bit8u intNum) PhysPt where=GetAddress(SegValue(cs),reg_eip); if (!CBreakpoint::CheckIntBreakpoint(where,intNum,reg_ah,reg_al)) return false; // Found. Breakpoint is valid - CBreakpoint::ActivateBreakpoints(where,false); // Deactivate all breakpoints + CBreakpoint::DeactivateBreakpoints(); // Deactivate all breakpoints return true; }; @@ -651,11 +666,12 @@ static bool StepOver() size=DasmI386(dline, start, reg_eip, cpu.code.big); if (strstr(dline,"call") || strstr(dline,"int") || strstr(dline,"loop") || strstr(dline,"rep")) { - CBreakpoint::AddBreakpoint (SegValue(cs),reg_eip+size, true); - CBreakpoint::ActivateBreakpoints(start, true); + // Don't add a temporary breakpoint if there's already one here + if (!CBreakpoint::FindPhysBreakpoint(SegValue(cs), reg_eip+size, true)) + CBreakpoint::AddBreakpoint(SegValue(cs),reg_eip+size, true); + CBreakpoint::ActivateBreakpointsExceptAt(start); debugging=false; DrawCode(); - DOSBOX_SetNormalLoop(); return true; } return false; @@ -798,7 +814,7 @@ static void DrawCode(void) { codeViewData.cursorSeg = codeViewData.useCS; codeViewData.cursorOfs = disEIP; saveSel = true; - } else if (CBreakpoint::IsBreakpointDrawn(start)) { + } else if (CBreakpoint::IsBreakpoint(codeViewData.useCS, disEIP)) { wattrset(dbg.win_code,COLOR_PAIR(PAIR_GREY_RED)); } else { wattrset(dbg.win_code,0); @@ -1197,8 +1213,7 @@ bool ParseCommand(char* str) { cpuLogCounter = GetHexValue(found,found); debugging = false; - CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,true); - ignoreAddressOnce = SegPhys(cs)+reg_eip; + CBreakpoint::ActivateBreakpointsExceptAt(SegPhys(cs)+reg_eip); DOSBOX_SetNormalLoop(); return true; }; @@ -1217,7 +1232,7 @@ bool ParseCommand(char* str) { Bit8u intNr = (Bit8u)GetHexValue(found,found); DEBUG_ShowMsg("DEBUG: Starting INT %02X\n",intNr); CBreakpoint::AddBreakpoint(SegValue(cs),reg_eip, true); - CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip-1,true); + CBreakpoint::ActivateBreakpointsExceptAt(SegPhys(cs)+reg_eip-1); debugging = false; DrawCode(); DOSBOX_SetNormalLoop(); @@ -1295,17 +1310,7 @@ bool ParseCommand(char* str) { #endif if (command == "HELP" || command == "?") { DEBUG_ShowMsg("Debugger commands (enter all values in hex or as register):\n"); - DEBUG_ShowMsg("--------------------------------------------------------------------------\n"); - DEBUG_ShowMsg("F3/F6 - Previous command in history.\n"); - DEBUG_ShowMsg("F4/F7 - Next command in history.\n"); - DEBUG_ShowMsg("F5 - Run.\n"); - DEBUG_ShowMsg("F9 - Set/Remove breakpoint.\n"); - DEBUG_ShowMsg("F10/F11 - Step over / trace into instruction.\n"); - DEBUG_ShowMsg("ALT + D/E/S/X/B - Set data view to DS:SI/ES:DI/SS:SP/DS:DX/ES:BX.\n"); - DEBUG_ShowMsg("Escape - Clear input line."); - DEBUG_ShowMsg("Up/Down - Move code view cursor.\n"); - DEBUG_ShowMsg("Page Up/Down - Scroll data view.\n"); - DEBUG_ShowMsg("Home/End - Scroll log messages.\n"); + DEBUG_ShowMsg("Commands------------------------------------------------\n"); DEBUG_ShowMsg("BP [segment]:[offset] - Set breakpoint.\n"); DEBUG_ShowMsg("BPINT [intNr] * - Set interrupt breakpoint.\n"); DEBUG_ShowMsg("BPINT [intNr] [ah] * - Set interrupt breakpoint with ah.\n"); @@ -1351,6 +1356,17 @@ bool ParseCommand(char* str) { DEBUG_ShowMsg("TIMERIRQ - Run the system timer.\n"); DEBUG_ShowMsg("HELP - Help\n"); + DEBUG_ShowMsg("Keys------------------------------------------------\n"); + DEBUG_ShowMsg("F3/F6 - Previous command in history.\n"); + DEBUG_ShowMsg("F4/F7 - Next command in history.\n"); + DEBUG_ShowMsg("F5 - Run.\n"); + DEBUG_ShowMsg("F9 - Set/Remove breakpoint.\n"); + DEBUG_ShowMsg("F10/F11 - Step over / trace into instruction.\n"); + DEBUG_ShowMsg("ALT + D/E/S/X/B - Set data view to DS:SI/ES:DI/SS:SP/DS:DX/ES:BX.\n"); + DEBUG_ShowMsg("Escape - Clear input line."); + DEBUG_ShowMsg("Up/Down - Move code view cursor.\n"); + DEBUG_ShowMsg("Page Up/Down - Scroll data view.\n"); + DEBUG_ShowMsg("Home/End - Scroll log messages.\n"); return true; }; @@ -1535,18 +1551,25 @@ char* AnalyzeInstruction(char* inst, bool saveSelector) { Bit32u DEBUG_CheckKeys(void) { Bits ret=0; bool numberrun = false; + bool skipDraw = false; int key=getch(); if (key >='1' && key <='5' && strlen(codeViewData.inputStr) == 0) { const Bit32s v[] ={5,500,1000,5000,10000}; CPU_Cycles= v[key - '1']; + skipFirstInstruction = true; + ret = (*cpudecoder)(); SetCodeWinStart(); - CBreakpoint::ignoreOnce = 0; /* Setup variables so we end up at the proper ret processing */ numberrun = true; + + // Don't redraw the screen if it's going to get redrawn immediately + // afterwards, to avoid resetting oldregs. + if (ret == debugCallback) + skipDraw = true; key = -1; } @@ -1677,31 +1700,49 @@ Bit32u DEBUG_CheckKeys(void) { break; case KEY_F(5): // Run Program debugging=false; - CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,true); - ignoreAddressOnce = SegPhys(cs)+reg_eip; - DOSBOX_SetNormalLoop(); + CBreakpoint::ActivateBreakpointsExceptAt(SegPhys(cs)+reg_eip); + + skipFirstInstruction = true; // for heavy debugger + CPU_Cycles = 1; + ret=(*cpudecoder)(); + + // ensure all breakpoints are activated + CBreakpoint::ActivateBreakpoints(); + + skipDraw = true; // don't update screen after this instruction + + DOSBOX_SetNormalLoop(); break; case KEY_F(9): // Set/Remove Breakpoint - { PhysPt ptr = GetAddress(codeViewData.cursorSeg,codeViewData.cursorOfs); - if (CBreakpoint::IsBreakpoint(ptr)) { - CBreakpoint::DeleteBreakpoint(ptr); + if (CBreakpoint::IsBreakpoint(codeViewData.cursorSeg, codeViewData.cursorOfs)) { + if (CBreakpoint::DeleteBreakpoint(codeViewData.cursorSeg, codeViewData.cursorOfs)) DEBUG_ShowMsg("DEBUG: Breakpoint deletion success.\n"); - } - else { - CBreakpoint::AddBreakpoint(codeViewData.cursorSeg, codeViewData.cursorOfs, false); - DEBUG_ShowMsg("DEBUG: Set breakpoint at %04X:%04X\n",codeViewData.cursorSeg,codeViewData.cursorOfs); - } + else + DEBUG_ShowMsg("DEBUG: Failed to delete breakpoint.\n"); + } + else { + CBreakpoint::AddBreakpoint(codeViewData.cursorSeg, codeViewData.cursorOfs, false); + DEBUG_ShowMsg("DEBUG: Set breakpoint at %04X:%04X\n",codeViewData.cursorSeg,codeViewData.cursorOfs); } break; case KEY_F(10): // Step over inst - if (StepOver()) return 0; - else { + if (StepOver()) { + skipFirstInstruction = true; // for heavy debugger + CPU_Cycles = 1; + ret=(*cpudecoder)(); + + DOSBOX_SetNormalLoop(); + + // ensure all breakpoints are activated + CBreakpoint::ActivateBreakpoints(); + + return 0; + } else { exitLoop = false; skipFirstInstruction = true; // for heavy debugger CPU_Cycles = 1; ret=(*cpudecoder)(); SetCodeWinStart(); - CBreakpoint::ignoreOnce = 0; } break; case KEY_F(11): // trace into @@ -1710,7 +1751,6 @@ Bit32u DEBUG_CheckKeys(void) { CPU_Cycles = 1; ret = (*cpudecoder)(); SetCodeWinStart(); - CBreakpoint::ignoreOnce = 0; break; case 0x0A: //Parse typed Command codeViewData.inputStr[MAXCMDLEN] = '\0'; @@ -1773,7 +1813,8 @@ Bit32u DEBUG_CheckKeys(void) { } } ret=0; - DEBUG_DrawScreen(); + if (!skipDraw) + DEBUG_DrawScreen(); } return ret; }; @@ -1788,7 +1829,7 @@ Bitu DEBUG_Loop(void) { SDL_Delay(1); if ((oldCS!=SegValue(cs)) || (oldEIP!=reg_eip)) { CBreakpoint::AddBreakpoint(oldCS,oldEIP,true); - CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,true); + CBreakpoint::ActivateBreakpointsExceptAt(SegPhys(cs)+reg_eip); debugging=false; DOSBOX_SetNormalLoop(); return 0; @@ -2112,7 +2153,7 @@ void DEBUG_CheckExecuteBreakpoint(Bit16u seg, Bit32u off) { if (pDebugcom && pDebugcom->IsActive()) { CBreakpoint::AddBreakpoint(seg,off,true); - CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,true); + CBreakpoint::ActivateBreakpointsExceptAt(SegPhys(cs)+reg_eip); pDebugcom = 0; }; };