mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-06 10:17:14 +00:00
SCI: Moved some debug functions from vm.cpp to scriptdebug.cpp
This commit is contained in:
parent
6501a86095
commit
6487d05ddf
@ -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
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user