mirror of
https://github.com/libretro/scummvm.git
synced 2025-04-01 14:21:41 +00:00
SCI: Add break/log/backtrace actions for triggered breakpoints
The action can be set using the new console command bp_action/bpact.
This commit is contained in:
parent
cb69d10e96
commit
8e683db72b
@ -205,6 +205,8 @@ Console::Console(SciEngine *engine) : GUI::Debugger(),
|
||||
registerCmd("bp_del", WRAP_METHOD(Console, cmdBreakpointDelete));
|
||||
registerCmd("bpdel", WRAP_METHOD(Console, cmdBreakpointDelete)); // alias
|
||||
registerCmd("bc", WRAP_METHOD(Console, cmdBreakpointDelete)); // alias
|
||||
registerCmd("bp_action", WRAP_METHOD(Console, cmdBreakpointAction));
|
||||
registerCmd("bpact", WRAP_METHOD(Console, cmdBreakpointAction)); // alias
|
||||
registerCmd("bp_address", WRAP_METHOD(Console, cmdBreakpointAddress));
|
||||
registerCmd("bpa", WRAP_METHOD(Console, cmdBreakpointAddress)); // alias
|
||||
registerCmd("bp_method", WRAP_METHOD(Console, cmdBreakpointMethod));
|
||||
@ -443,6 +445,7 @@ bool Console::cmdHelp(int argc, const char **argv) {
|
||||
debugPrintf("Breakpoints:\n");
|
||||
debugPrintf(" bp_list / bplist / bl - Lists the current breakpoints\n");
|
||||
debugPrintf(" bp_del / bpdel / bc - Deletes a breakpoint with the specified index\n");
|
||||
debugPrintf(" bp_action / bpact - Set action to be performed when breakpoint is triggered\n");
|
||||
debugPrintf(" bp_address / bpa - Sets a breakpoint on a script address\n");
|
||||
debugPrintf(" bp_method / bpx - Sets a breakpoint on the execution of a specified method/selector\n");
|
||||
debugPrintf(" bp_read / bpr - Sets a breakpoint on reading of a specified selector\n");
|
||||
@ -3729,22 +3732,34 @@ bool Console::cmdBreakpointList(int argc, const char **argv) {
|
||||
Common::List<Breakpoint>::const_iterator end = _debugState._breakpoints.end();
|
||||
for (; bp != end; ++bp) {
|
||||
debugPrintf(" #%i: ", i);
|
||||
const char *bpaction;
|
||||
|
||||
switch (bp->_action) {
|
||||
case BREAK_LOG:
|
||||
bpaction = " (action: log only)";
|
||||
break;
|
||||
case BREAK_BACKTRACE:
|
||||
bpaction = " (action: show backtrace)";
|
||||
break;
|
||||
default:
|
||||
bpaction = "";
|
||||
}
|
||||
switch (bp->_type) {
|
||||
case BREAK_SELECTOREXEC:
|
||||
debugPrintf("Execute %s\n", bp->_name.c_str());
|
||||
debugPrintf("Execute %s%s\n", bp->_name.c_str(), bpaction);
|
||||
break;
|
||||
case BREAK_SELECTORREAD:
|
||||
debugPrintf("Read %s\n", bp->_name.c_str());
|
||||
debugPrintf("Read %s%s\n", bp->_name.c_str(), bpaction);
|
||||
break;
|
||||
case BREAK_SELECTORWRITE:
|
||||
debugPrintf("Write %s\n", bp->_name.c_str());
|
||||
debugPrintf("Write %s%s\n", bp->_name.c_str(), bpaction);
|
||||
break;
|
||||
case BREAK_EXPORT:
|
||||
bpdata = bp->_address;
|
||||
debugPrintf("Execute script %d, export %d\n", bpdata >> 16, bpdata & 0xFFFF);
|
||||
debugPrintf("Execute script %d, export %d%s\n", bpdata >> 16, bpdata & 0xFFFF, bpaction);
|
||||
break;
|
||||
case BREAK_ADDRESS:
|
||||
debugPrintf("Execute address %04x:%04x\n", PRINT_REG(bp->_regAddress));
|
||||
debugPrintf("Execute address %04x:%04x%s\n", PRINT_REG(bp->_regAddress), bpaction);
|
||||
}
|
||||
|
||||
i++;
|
||||
@ -3798,6 +3813,59 @@ bool Console::cmdBreakpointDelete(int argc, const char **argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::cmdBreakpointAction(int argc, const char **argv) {
|
||||
bool usage = false;
|
||||
|
||||
if (argc != 3) {
|
||||
usage = true;
|
||||
}
|
||||
|
||||
Common::String arg;
|
||||
if (argc >= 3)
|
||||
arg = argv[2];
|
||||
|
||||
BreakpointAction bpaction;
|
||||
if (arg == "break")
|
||||
bpaction = BREAK_BREAK;
|
||||
else if (arg == "log")
|
||||
bpaction = BREAK_LOG;
|
||||
else if (arg == "bt")
|
||||
bpaction = BREAK_BACKTRACE;
|
||||
else
|
||||
usage = true;
|
||||
|
||||
if (usage) {
|
||||
debugPrintf("Change the action for the breakpoint with the specified index.\n");
|
||||
debugPrintf("Usage: %s <breakpoint index> break|log|bt\n", argv[0]);
|
||||
debugPrintf("<index> * will process all breakpoints\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::List<Breakpoint>::iterator bp = _debugState._breakpoints.begin();
|
||||
const Common::List<Breakpoint>::iterator end = _debugState._breakpoints.end();
|
||||
if (strcmp(argv[1], "*") == 0) {
|
||||
for (; bp != end; ++bp)
|
||||
bp->_action = bpaction;
|
||||
return true;
|
||||
}
|
||||
|
||||
const int idx = atoi(argv[1]);
|
||||
|
||||
// Find the breakpoint at index idx.
|
||||
for (int i = 0; bp != end && i < idx; ++bp, ++i) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
if (bp == end) {
|
||||
debugPrintf("Invalid breakpoint index %i\n", idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
bp->_action = bpaction;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Console::cmdBreakpointMethod(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Sets a breakpoint on execution of a specified method/selector.\n");
|
||||
@ -3814,6 +3882,7 @@ bool Console::cmdBreakpointMethod(int argc, const char **argv) {
|
||||
Breakpoint bp;
|
||||
bp._type = BREAK_SELECTOREXEC;
|
||||
bp._name = argv[1];
|
||||
bp._action = BREAK_BREAK;
|
||||
|
||||
_debugState._breakpoints.push_back(bp);
|
||||
_debugState._activeBreakpointTypes |= BREAK_SELECTOREXEC;
|
||||
@ -3831,6 +3900,7 @@ bool Console::cmdBreakpointRead(int argc, const char **argv) {
|
||||
Breakpoint bp;
|
||||
bp._type = BREAK_SELECTORREAD;
|
||||
bp._name = argv[1];
|
||||
bp._action = BREAK_BREAK;
|
||||
|
||||
_debugState._breakpoints.push_back(bp);
|
||||
_debugState._activeBreakpointTypes |= BREAK_SELECTORREAD;
|
||||
@ -3848,6 +3918,7 @@ bool Console::cmdBreakpointWrite(int argc, const char **argv) {
|
||||
Breakpoint bp;
|
||||
bp._type = BREAK_SELECTORWRITE;
|
||||
bp._name = argv[1];
|
||||
bp._action = BREAK_BREAK;
|
||||
|
||||
_debugState._breakpoints.push_back(bp);
|
||||
_debugState._activeBreakpointTypes |= BREAK_SELECTORWRITE;
|
||||
@ -3894,6 +3965,7 @@ bool Console::cmdBreakpointFunction(int argc, const char **argv) {
|
||||
bp._type = BREAK_EXPORT;
|
||||
// script number, export number
|
||||
bp._address = (atoi(argv[1]) << 16 | atoi(argv[2]));
|
||||
bp._action = BREAK_BREAK;
|
||||
|
||||
_debugState._breakpoints.push_back(bp);
|
||||
_debugState._activeBreakpointTypes |= BREAK_EXPORT;
|
||||
@ -3919,6 +3991,7 @@ bool Console::cmdBreakpointAddress(int argc, const char **argv) {
|
||||
Breakpoint bp;
|
||||
bp._type = BREAK_ADDRESS;
|
||||
bp._regAddress = make_reg32(addr.getSegment(), addr.getOffset());
|
||||
bp._action = BREAK_BREAK;
|
||||
|
||||
_debugState._breakpoints.push_back(bp);
|
||||
_debugState._activeBreakpointTypes |= BREAK_ADDRESS;
|
||||
|
@ -149,6 +149,7 @@ private:
|
||||
// Breakpoints
|
||||
bool cmdBreakpointList(int argc, const char **argv);
|
||||
bool cmdBreakpointDelete(int argc, const char **argv);
|
||||
bool cmdBreakpointAction(int argc, const char **argv);
|
||||
bool cmdBreakpointMethod(int argc, const char **argv);
|
||||
bool cmdBreakpointRead(int argc, const char **argv);
|
||||
bool cmdBreakpointWrite(int argc, const char **argv);
|
||||
|
@ -46,11 +46,18 @@ enum BreakpointType {
|
||||
BREAK_ADDRESS = 1 << 4 // break when pc is at this address
|
||||
};
|
||||
|
||||
enum BreakpointAction {
|
||||
BREAK_BREAK, // break into debugger when breakpoint is triggered
|
||||
BREAK_LOG, // log the breakpoint, and don't break into debugger
|
||||
BREAK_BACKTRACE // show a backtrace, and don't break into debugger
|
||||
};
|
||||
|
||||
struct Breakpoint {
|
||||
BreakpointType _type;
|
||||
uint32 _address; ///< Breakpoints on exports
|
||||
reg32_t _regAddress; ///< Breakpoints on addresses
|
||||
Common::String _name; ///< Breakpoints on selector names
|
||||
BreakpointAction _action;
|
||||
};
|
||||
|
||||
enum DebugSeeking {
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "sci/engine/state.h"
|
||||
#include "sci/engine/kernel.h"
|
||||
#include "sci/engine/script.h"
|
||||
#include "sci/engine/scriptdebug.h"
|
||||
|
||||
namespace Sci {
|
||||
|
||||
@ -690,8 +691,12 @@ bool SciEngine::checkSelectorBreakpoint(BreakpointType breakpointType, reg_t sen
|
||||
if (bpIter->_name == methodName ||
|
||||
(bpIter->_name.hasSuffix("::") && methodName.hasPrefix(bpIter->_name))) {
|
||||
_console->debugPrintf("Break on %s (in [%04x:%04x])\n", methodName.c_str(), PRINT_REG(send_obj));
|
||||
_debugState.debugging = true;
|
||||
_debugState.breakpointWasHit = true;
|
||||
if (bpIter->_action == BREAK_BREAK) {
|
||||
_debugState.debugging = true;
|
||||
_debugState.breakpointWasHit = true;
|
||||
} else if (bpIter->_action == BREAK_BACKTRACE) {
|
||||
logBacktrace();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -706,8 +711,12 @@ bool SciEngine::checkExportBreakpoint(uint16 script, uint16 pubfunct) {
|
||||
for (bp = _debugState._breakpoints.begin(); bp != _debugState._breakpoints.end(); ++bp) {
|
||||
if (bp->_type == BREAK_EXPORT && bp->_address == bpaddress) {
|
||||
_console->debugPrintf("Break on script %d, export %d\n", script, pubfunct);
|
||||
_debugState.debugging = true;
|
||||
_debugState.breakpointWasHit = true;
|
||||
if (bp->_action == BREAK_BREAK) {
|
||||
_debugState.debugging = true;
|
||||
_debugState.breakpointWasHit = true;
|
||||
} else if (bp->_action == BREAK_BACKTRACE) {
|
||||
logBacktrace();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -722,8 +731,12 @@ bool SciEngine::checkAddressBreakpoint(const reg32_t &address) {
|
||||
for (bp = _debugState._breakpoints.begin(); bp != _debugState._breakpoints.end(); ++bp) {
|
||||
if (bp->_type == BREAK_ADDRESS && bp->_regAddress == address) {
|
||||
_console->debugPrintf("Break at %04x:%04x\n", PRINT_REG(address));
|
||||
_debugState.debugging = true;
|
||||
_debugState.breakpointWasHit = true;
|
||||
if (bp->_action == BREAK_BREAK) {
|
||||
_debugState.debugging = true;
|
||||
_debugState.breakpointWasHit = true;
|
||||
} else if (bp->_action == BREAK_BACKTRACE) {
|
||||
logBacktrace();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user