diff options
-rw-r--r-- | engines/sci/engine/scriptdebug.cpp | 186 | ||||
-rw-r--r-- | engines/sci/engine/vm.cpp | 188 |
2 files changed, 189 insertions, 185 deletions
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index 76490217c3..857b074678 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -281,8 +281,7 @@ reg_t disassemble(EngineState *s, reg_t pos, bool printBWTag, bool printBytecode return retval; } -bool isJumpOpcode(EngineState *s, reg_t pos, reg_t& jumpTarget) -{ +bool isJumpOpcode(EngineState *s, reg_t pos, reg_t& jumpTarget) { SegmentObj *mobj = s->_segMan->getSegment(pos.segment, SEG_TYPE_SCRIPT); if (!mobj) return false; @@ -571,4 +570,187 @@ void Kernel::dissectScript(int scriptNumber, Vocabulary *vocab) { debugN("Script ends without terminator\n"); } +bool SciEngine::checkSelectorBreakpoint(BreakpointType breakpointType, reg_t send_obj, int selector) { + Common::String methodName = _gamestate->_segMan->getObjectName(send_obj); + methodName += ("::" + getKernel()->getSelectorName(selector)); + + Common::List<Breakpoint>::const_iterator bpIter; + for (bpIter = _debugState._breakpoints.begin(); bpIter != _debugState._breakpoints.end(); ++bpIter) { + if ((*bpIter).type == breakpointType && (*bpIter).name == methodName) { + _console->DebugPrintf("Break on %s (in [%04x:%04x])\n", methodName.c_str(), PRINT_REG(send_obj)); + _debugState.debugging = true; + _debugState.breakpointWasHit = true; + return true; + } + } + return false; +} + +bool SciEngine::checkExportBreakpoint(uint16 script, uint16 pubfunct) { + if (_debugState._activeBreakpointTypes & BREAK_EXPORT) { + uint32 bpaddress = (script << 16 | pubfunct); + + Common::List<Breakpoint>::const_iterator bp; + 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; + return true; + } + } + } + + return false; +} + +void debugSelectorCall(reg_t send_obj, Selector selector, int argc, StackPtr argp, ObjVarRef &varp, reg_t funcp, SegManager *segMan, SelectorType selectorType) { + int activeBreakpointTypes = g_sci->_debugState._activeBreakpointTypes; + const char *objectName = segMan->getObjectName(send_obj); + const char *selectorName = g_sci->getKernel()->getSelectorName(selector).c_str(); + Console *con = g_sci->getSciDebugger(); + +#ifdef VM_DEBUG_SEND + debugN("Send to %04x:%04x (%s), selector %04x (%s):", PRINT_REG(send_obj), + s->_segMan->getObjectName(send_obj), selector, + g_sci->getKernel()->getSelectorName(selector).c_str()); +#endif // VM_DEBUG_SEND + + switch (selectorType) { + case kSelectorNone: + break; + case kSelectorVariable: +#ifdef VM_DEBUG_SEND + if (argc) + debugN("Varselector: Write %04x:%04x\n", PRINT_REG(argp[1])); + else + debugN("Varselector: Read\n"); +#endif // VM_DEBUG_SEND + + // argc == 0: read selector + // argc == 1: write selector + // argc can be bigger than 1 in some cases, because of a script bug. + // Usually, these aren't fatal. + if ((activeBreakpointTypes & BREAK_SELECTORREAD) || + (activeBreakpointTypes & BREAK_SELECTORWRITE) || + argc > 1) { + + reg_t selectorValue = *varp.getPointer(segMan); + if (!argc && (activeBreakpointTypes & BREAK_SELECTORREAD)) { + if (g_sci->checkSelectorBreakpoint(BREAK_SELECTORREAD, send_obj, selector)) + con->DebugPrintf("Read from selector (%s:%s): %04x:%04x\n", + objectName, selectorName, + PRINT_REG(selectorValue)); + } else if (argc && (activeBreakpointTypes & BREAK_SELECTORWRITE)) { + if (g_sci->checkSelectorBreakpoint(BREAK_SELECTORWRITE, send_obj, selector)) + con->DebugPrintf("Write to selector (%s:%s): change %04x:%04x to %04x:%04x\n", + objectName, selectorName, + PRINT_REG(selectorValue), PRINT_REG(argp[1])); + } + + if (argc > 1) + debug(kDebugLevelScripts, "Write to selector (%s:%s): change %04x:%04x to %04x:%04x, argc == %d\n", + objectName, selectorName, + PRINT_REG(selectorValue), PRINT_REG(argp[1]), argc); + } + break; + case kSelectorMethod: +#ifndef VM_DEBUG_SEND + if (activeBreakpointTypes & BREAK_SELECTOREXEC) { + if (g_sci->checkSelectorBreakpoint(BREAK_SELECTOREXEC, send_obj, selector)) { +#else + if (true) { + if (true) { +#endif + con->DebugPrintf("%s::%s(", objectName, selectorName); + for (int i = 0; i < argc; i++) { + con->DebugPrintf("%04x:%04x", PRINT_REG(argp[i+1])); + if (i + 1 < argc) + con->DebugPrintf(", "); + } + con->DebugPrintf(") at %04x:%04x\n", PRINT_REG(funcp)); + } + } + break; + } // switch +} + +void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunction *kernelSubCall, EngineState *s, int argc, reg_t *argv, reg_t result) { + Kernel *kernel = g_sci->getKernel(); + if (!kernelSubCall) { + debugN("k%s: ", kernelCall->name); + } else { + int callNameLen = strlen(kernelCall->name); + if (strncmp(kernelCall->name, kernelSubCall->name, callNameLen) == 0) { + const char *subCallName = kernelSubCall->name + callNameLen; + debugN("k%s(%s): ", kernelCall->name, subCallName); + } else { + debugN("k%s(%s): ", kernelCall->name, kernelSubCall->name); + } + } + for (int parmNr = 0; parmNr < argc; parmNr++) { + if (parmNr) + debugN(", "); + uint16 regType = kernel->findRegType(argv[parmNr]); + if (regType & SIG_TYPE_NULL) + debugN("0"); + else if (regType & SIG_TYPE_UNINITIALIZED) + debugN("UNINIT"); + else if (regType & SIG_IS_INVALID) + debugN("INVALID"); + else if (regType & SIG_TYPE_INTEGER) + debugN("%d", argv[parmNr].offset); + else { + debugN("%04x:%04x", PRINT_REG(argv[parmNr])); + switch (regType) { + case SIG_TYPE_OBJECT: + debugN(" (%s)", s->_segMan->getObjectName(argv[parmNr])); + break; + case SIG_TYPE_REFERENCE: + { + SegmentObj *mobj = s->_segMan->getSegmentObj(argv[parmNr].segment); + switch (mobj->getType()) { + case SEG_TYPE_HUNK: + { + HunkTable *ht = (HunkTable*)mobj; + int index = argv[parmNr].offset; + if (ht->isValidEntry(index)) { + // NOTE: This ", deleted" isn't as useful as it could + // be because it prints the status _after_ the kernel + // call. + debugN(" ('%s' hunk%s)", ht->_table[index].type, ht->_table[index].mem ? "" : ", deleted"); + } else + debugN(" (INVALID hunk ref)"); + break; + } + default: + // TODO: Any other segment types which could + // use special handling? + + if (kernelCall->function == kSaid) { + SegmentRef saidSpec = s->_segMan->dereference(argv[parmNr]); + if (saidSpec.isRaw) { + debugN(" ('"); + g_sci->getVocabulary()->debugDecipherSaidBlock(saidSpec.raw); + debugN("')"); + } else { + debugN(" (non-raw said-spec)"); + } + } else { + debugN(" ('%s')", s->_segMan->getString(argv[parmNr]).c_str()); + } + break; + } + } + default: + break; + } + } + } + if (result.isPointer()) + debugN(" = %04x:%04x\n", PRINT_REG(result)); + else + debugN(" = %d\n", result.offset); +} + } // End of namespace Sci diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 89e8ed787f..f1e1980064 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -257,112 +257,6 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP return &(s->_executionStack.back()); } -bool SciEngine::checkSelectorBreakpoint(BreakpointType breakpointType, reg_t send_obj, int selector) { - Common::String methodName = _gamestate->_segMan->getObjectName(send_obj); - methodName += ("::" + getKernel()->getSelectorName(selector)); - - Common::List<Breakpoint>::const_iterator bpIter; - for (bpIter = _debugState._breakpoints.begin(); bpIter != _debugState._breakpoints.end(); ++bpIter) { - if ((*bpIter).type == breakpointType && (*bpIter).name == methodName) { - _console->DebugPrintf("Break on %s (in [%04x:%04x])\n", methodName.c_str(), PRINT_REG(send_obj)); - _debugState.debugging = true; - _debugState.breakpointWasHit = true; - return true; - } - } - return false; -} - -bool SciEngine::checkExportBreakpoint(uint16 script, uint16 pubfunct) { - if (_debugState._activeBreakpointTypes & BREAK_EXPORT) { - uint32 bpaddress = (script << 16 | pubfunct); - - Common::List<Breakpoint>::const_iterator bp; - 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; - return true; - } - } - } - - return false; -} - -void debugSelectorCall(reg_t send_obj, Selector selector, int argc, StackPtr argp, ObjVarRef &varp, reg_t funcp, SegManager *segMan, SelectorType selectorType) { - int activeBreakpointTypes = g_sci->_debugState._activeBreakpointTypes; - const char *objectName = segMan->getObjectName(send_obj); - const char *selectorName = g_sci->getKernel()->getSelectorName(selector).c_str(); - Console *con = g_sci->getSciDebugger(); - -#ifdef VM_DEBUG_SEND - debugN("Send to %04x:%04x (%s), selector %04x (%s):", PRINT_REG(send_obj), - s->_segMan->getObjectName(send_obj), selector, - g_sci->getKernel()->getSelectorName(selector).c_str()); -#endif // VM_DEBUG_SEND - - switch (selectorType) { - case kSelectorNone: - break; - case kSelectorVariable: -#ifdef VM_DEBUG_SEND - if (argc) - debugN("Varselector: Write %04x:%04x\n", PRINT_REG(argp[1])); - else - debugN("Varselector: Read\n"); -#endif // VM_DEBUG_SEND - - // argc == 0: read selector - // argc == 1: write selector - // argc can be bigger than 1 in some cases, because of a script bug. - // Usually, these aren't fatal. - if ((activeBreakpointTypes & BREAK_SELECTORREAD) || - (activeBreakpointTypes & BREAK_SELECTORWRITE) || - argc > 1) { - - reg_t selectorValue = *varp.getPointer(segMan); - if (!argc && (activeBreakpointTypes & BREAK_SELECTORREAD)) { - if (g_sci->checkSelectorBreakpoint(BREAK_SELECTORREAD, send_obj, selector)) - con->DebugPrintf("Read from selector (%s:%s): %04x:%04x\n", - objectName, selectorName, - PRINT_REG(selectorValue)); - } else if (argc && (activeBreakpointTypes & BREAK_SELECTORWRITE)) { - if (g_sci->checkSelectorBreakpoint(BREAK_SELECTORWRITE, send_obj, selector)) - con->DebugPrintf("Write to selector (%s:%s): change %04x:%04x to %04x:%04x\n", - objectName, selectorName, - PRINT_REG(selectorValue), PRINT_REG(argp[1])); - } - - if (argc > 1) - debug(kDebugLevelScripts, "Write to selector (%s:%s): change %04x:%04x to %04x:%04x, argc == %d\n", - objectName, selectorName, - PRINT_REG(selectorValue), PRINT_REG(argp[1]), argc); - } - break; - case kSelectorMethod: -#ifndef VM_DEBUG_SEND - if (activeBreakpointTypes & BREAK_SELECTOREXEC) { - if (g_sci->checkSelectorBreakpoint(BREAK_SELECTOREXEC, send_obj, selector)) { -#else - if (true) { - if (true) { -#endif - con->DebugPrintf("%s::%s(", objectName, selectorName); - for (int i = 0; i < argc; i++) { - con->DebugPrintf("%04x:%04x", PRINT_REG(argp[i+1])); - if (i + 1 < argc) - con->DebugPrintf(", "); - } - con->DebugPrintf(") at %04x:%04x\n", PRINT_REG(funcp)); - } - } - break; - } // switch -} - - static void _exec_varselectors(EngineState *s) { // Executes all varselector read/write ops on the TOS while (!s->_executionStack.empty() && s->_executionStack.back().type == EXEC_STACK_TYPE_VARSELECTOR) { @@ -382,6 +276,9 @@ static void _exec_varselectors(EngineState *s) { } } +// from scriptdebug.cpp +extern void debugSelectorCall(reg_t send_obj, Selector selector, int argc, StackPtr argp, ObjVarRef &varp, reg_t funcp, SegManager *segMan, SelectorType selectorType); + ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPtr sp, int framesize, StackPtr argp) { // send_obj and work_obj are equal for anything but 'super' // Returns a pointer to the TOS exec_stack element @@ -453,83 +350,8 @@ static void addKernelCallToExecStack(EngineState *s, int kernelCallNr, int argc, s->_executionStack.push_back(xstack); } -static void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunction *kernelSubCall, EngineState *s, int argc, reg_t *argv, reg_t result) { - Kernel *kernel = g_sci->getKernel(); - if (!kernelSubCall) { - debugN("k%s: ", kernelCall->name); - } else { - int callNameLen = strlen(kernelCall->name); - if (strncmp(kernelCall->name, kernelSubCall->name, callNameLen) == 0) { - const char *subCallName = kernelSubCall->name + callNameLen; - debugN("k%s(%s): ", kernelCall->name, subCallName); - } else { - debugN("k%s(%s): ", kernelCall->name, kernelSubCall->name); - } - } - for (int parmNr = 0; parmNr < argc; parmNr++) { - if (parmNr) - debugN(", "); - uint16 regType = kernel->findRegType(argv[parmNr]); - if (regType & SIG_TYPE_NULL) - debugN("0"); - else if (regType & SIG_TYPE_UNINITIALIZED) - debugN("UNINIT"); - else if (regType & SIG_IS_INVALID) - debugN("INVALID"); - else if (regType & SIG_TYPE_INTEGER) - debugN("%d", argv[parmNr].offset); - else { - debugN("%04x:%04x", PRINT_REG(argv[parmNr])); - switch (regType) { - case SIG_TYPE_OBJECT: - debugN(" (%s)", s->_segMan->getObjectName(argv[parmNr])); - break; - case SIG_TYPE_REFERENCE: - { - SegmentObj *mobj = s->_segMan->getSegmentObj(argv[parmNr].segment); - switch (mobj->getType()) { - case SEG_TYPE_HUNK: - { - HunkTable *ht = (HunkTable*)mobj; - int index = argv[parmNr].offset; - if (ht->isValidEntry(index)) { - // NOTE: This ", deleted" isn't as useful as it could - // be because it prints the status _after_ the kernel - // call. - debugN(" ('%s' hunk%s)", ht->_table[index].type, ht->_table[index].mem ? "" : ", deleted"); - } else - debugN(" (INVALID hunk ref)"); - break; - } - default: - // TODO: Any other segment types which could - // use special handling? - - if (kernelCall->function == kSaid) { - SegmentRef saidSpec = s->_segMan->dereference(argv[parmNr]); - if (saidSpec.isRaw) { - debugN(" ('"); - g_sci->getVocabulary()->debugDecipherSaidBlock(saidSpec.raw); - debugN("')"); - } else { - debugN(" (non-raw said-spec)"); - } - } else { - debugN(" ('%s')", s->_segMan->getString(argv[parmNr]).c_str()); - } - break; - } - } - default: - break; - } - } - } - if (result.isPointer()) - debugN(" = %04x:%04x\n", PRINT_REG(result)); - else - debugN(" = %d\n", result.offset); -} +// from scriptdebug.cpp +extern void logKernelCall(const KernelFunction *kernelCall, const KernelSubFunction *kernelSubCall, EngineState *s, int argc, reg_t *argv, reg_t result); static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) { Kernel *kernel = g_sci->getKernel(); |