1
0
Fork 0

Add wjp's improved breakpoint handling to the debugger

Rewrite the order of the debug help list so the keys come last

Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@3994
This commit is contained in:
Sjoerd van der Berg 2016-09-07 20:35:10 +00:00
parent 169ca61f9e
commit eefd825fa1

View file

@ -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<CBreakpoint*> 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*> 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<CBreakpoint*>::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<CBreakpoint*>::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<CBreakpoint*>::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<CBreakpoint*>::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<CBreakpoint*>::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<CBreakpoint*>::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<CBreakpoint*>::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<CBreakpoint*>::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;
};
};