From 8e683db72b280fbe4319d68466c7f3c61a6c107d Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Fri, 26 May 2017 14:12:41 +0200 Subject: SCI: Add break/log/backtrace actions for triggered breakpoints The action can be set using the new console command bp_action/bpact. --- engines/sci/console.cpp | 83 +++++++++++++++++++++++++++++++++++--- engines/sci/console.h | 1 + engines/sci/debug.h | 7 ++++ engines/sci/engine/scriptdebug.cpp | 25 +++++++++--- 4 files changed, 105 insertions(+), 11 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 2274dac1a7..6c9be970cb 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -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::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 break|log|bt\n", argv[0]); + debugPrintf(" * will process all breakpoints\n"); + return true; + } + + Common::List::iterator bp = _debugState._breakpoints.begin(); + const Common::List::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; diff --git a/engines/sci/console.h b/engines/sci/console.h index 1bb86b9bee..d0faf8a030 100644 --- a/engines/sci/console.h +++ b/engines/sci/console.h @@ -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); diff --git a/engines/sci/debug.h b/engines/sci/debug.h index b8557bb493..03ab594e0d 100644 --- a/engines/sci/debug.h +++ b/engines/sci/debug.h @@ -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 { diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index a4392983a1..c5a617a17a 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -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; } } -- cgit v1.2.3