diff options
author | Filippos Karapetis | 2011-01-07 18:25:38 +0000 |
---|---|---|
committer | Filippos Karapetis | 2011-01-07 18:25:38 +0000 |
commit | 6b250f8c9be45a4076504263fddab77f58ee9a6a (patch) | |
tree | bb8e60bd9717d5f9d7fa1eaed3849f03545bf977 | |
parent | 2f7c04e54b74f82e7005b09d634c1ceba7ada424 (diff) | |
download | scummvm-rg350-6b250f8c9be45a4076504263fddab77f58ee9a6a.tar.gz scummvm-rg350-6b250f8c9be45a4076504263fddab77f58ee9a6a.tar.bz2 scummvm-rg350-6b250f8c9be45a4076504263fddab77f58ee9a6a.zip |
SCI2/2.1: Improvements to the find_callk debug function, and some kernel function updates
- Improved the find_callk function to properly find the end of script objects, by
monitoring jump calls
- Added three extra special calls to find_callk: find kernel function calls to dummy,
unused and unmapped kernel functions
- Updated several kernel function calls because of the above functionality
- The above functionality has also uncovered a VM bug in some SCI2/2.1 opcode - added
a FIXME for it
svn-id: r55151
-rw-r--r-- | engines/sci/console.cpp | 106 | ||||
-rw-r--r-- | engines/sci/console.h | 7 | ||||
-rw-r--r-- | engines/sci/engine/kernel_tables.h | 11 |
3 files changed, 101 insertions, 23 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index e25b4cdc1a..c515d45a1a 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -2710,27 +2710,13 @@ bool Console::cmdDisassembleAddress(int argc, const char **argv) { return true; } -bool Console::cmdFindKernelFunctionCall(int argc, const char **argv) { - if (argc < 2) { - DebugPrintf("Finds the scripts and methods that call a specific kernel function.\n"); - DebugPrintf("Usage: %s <kernel function>\n", argv[0]); - DebugPrintf("Example: %s Display\n", argv[0]); - return true; - } - - // Find the number of the kernel function call - int kernelFuncNum = _engine->getKernel()->findKernelFuncPos(argv[1]); - - if (kernelFuncNum < 0) { - DebugPrintf("Invalid kernel function requested\n"); - return true; - } - +void Console::printKernelCallsFound(int kernelFuncNum, bool showFoundScripts) { Common::List<ResourceId> *resources = _engine->getResMan()->listResources(kResourceTypeScript); Common::sort(resources->begin(), resources->end()); Common::List<ResourceId>::iterator itr = resources->begin(); - DebugPrintf("%d scripts found, dissassembling...\n", resources->size()); + if (showFoundScripts) + DebugPrintf("%d scripts found, dissassembling...\n", resources->size()); int scriptSegment; Script *script; @@ -2762,6 +2748,7 @@ bool Console::cmdFindKernelFunctionCall(int argc, const char **argv) { int16 opparams[4]; byte extOpcode; byte opcode; + uint16 maxJmpOffset = 0; while (true) { offset += readPMachineInstruction(script->getBuf(offset), extOpcode, opparams); @@ -2778,8 +2765,28 @@ bool Console::cmdFindKernelFunctionCall(int argc, const char **argv) { } } + // Monitor all jump opcodes (bt, bnt and jmp), so that if + // there is a jump after a ret, we don't stop processing + if (opcode == op_bt || opcode == op_bnt || opcode == op_jmp) { + uint16 curJmpOffset = offset + (uint16)opparams[0]; + if (curJmpOffset > maxJmpOffset) + maxJmpOffset = curJmpOffset; + // FIXME: There seems to be a bug in the way we handle the SCI2 debug opcode + // (i.e. 0x7e/0x3f), which is probably why the bugs below occur + if (maxJmpOffset >= script->getBufSize()) { + warning("Called from script %d, object %s, method %s(%d) with %d parameters", + itr->getNumber(), objName, + _engine->getKernel()->getSelectorName(obj->getFuncSelector(i)).c_str(), i, 0); + warning("Script %d has a jump to an invalid offset (%d, script size is %d) - adjusting", + script->getScriptNumber(), maxJmpOffset, script->getBufSize()); + maxJmpOffset = script->getBufSize() - 1; + } + } + // Check for end of function/script - if (opcode == op_ret || offset >= script->getBufSize()) + if (offset >= script->getBufSize()) + break; + if (opcode == op_ret)// && offset >= maxJmpOffset) break; } // while (true) } // for (uint16 i = 0; i < obj->getMethodCount(); i++) @@ -2790,6 +2797,69 @@ bool Console::cmdFindKernelFunctionCall(int argc, const char **argv) { } delete resources; +} + +bool Console::cmdFindKernelFunctionCall(int argc, const char **argv) { + if (argc < 2) { + DebugPrintf("Finds the scripts and methods that call a specific kernel function.\n"); + DebugPrintf("Usage: %s <kernel function>\n", argv[0]); + DebugPrintf("Example: %s Display\n", argv[0]); + DebugPrintf("Special usage:\n"); + DebugPrintf("%s Dummy - find all calls to actual dummy functions " + "(mapped to kDummy, and dummy in the kernel table). " + "There shouldn't be calls to these (apart from a known " + "one in Shivers)\n", argv[0]); + DebugPrintf("%s Unused - find all calls to unused functions (mapped to " + "kDummy - i.e. mapped in SSCI but dummy in ScummVM, thus " + "they'll error out when called). Only debug scripts should " + "be calling these\n", argv[0]); + DebugPrintf("%s Unmapped - find all calls to currently unmapped or " + "unimplemented functions (mapped to kStub/kStubNull)\n", argv[0]); + return true; + } + + Kernel *kernel = _engine->getKernel(); + Common::String funcName(argv[1]); + + if (funcName != "Dummy" && funcName != "Unused" && funcName != "Unmapped") { + // Find the number of the kernel function call + int kernelFuncNum = kernel->findKernelFuncPos(argv[1]); + + if (kernelFuncNum < 0) { + DebugPrintf("Invalid kernel function requested\n"); + return true; + } + + printKernelCallsFound(kernelFuncNum, true); + } else if (funcName == "Dummy") { + // Find all actual dummy kernel functions (mapped to kDummy, and dummy + // in the kernel table) + for (uint i = 0; i < kernel->_kernelFuncs.size(); i++) { + if (kernel->_kernelFuncs[i].function == &kDummy && kernel->getKernelName(i) == "Dummy") { + DebugPrintf("Searching for kernel function %d (%s)...\n", i, kernel->getKernelName(i).c_str()); + printKernelCallsFound(i, false); + } + } + } else if (funcName == "Unused") { + // Find all actual dummy kernel functions (mapped to kDummy - i.e. + // mapped in SSCI but dummy in ScummVM, thus they'll error out when + // called) + for (uint i = 0; i < kernel->_kernelFuncs.size(); i++) { + if (kernel->_kernelFuncs[i].function == &kDummy && kernel->getKernelName(i) != "Dummy") { + DebugPrintf("Searching for kernel function %d (%s)...\n", i, kernel->getKernelName(i).c_str()); + printKernelCallsFound(i, false); + } + } + } else if (funcName == "Unmapped") { + // Find all unmapped kernel functions (mapped to kStub/kStubNull) + for (uint i = 0; i < kernel->_kernelFuncs.size(); i++) { + if (kernel->_kernelFuncs[i].function == &kStub || + kernel->_kernelFuncs[i].function == &kStubNull) { + DebugPrintf("Searching for kernel function %d (%s)...\n", i, kernel->getKernelName(i).c_str()); + printKernelCallsFound(i, false); + } + } + } return true; } diff --git a/engines/sci/console.h b/engines/sci/console.h index 6a6ecc8681..670c89e672 100644 --- a/engines/sci/console.h +++ b/engines/sci/console.h @@ -165,6 +165,13 @@ private: void hexDumpReg(const reg_t *data, int len, int regsPerLine = 4, int startOffset = 0, bool isArray = false); private: + /** + * Prints all the scripts calling the specified kernel function. + * NOTE: The results produced by this aren't 100% correct, as it + * does not dissect script exports + */ + void printKernelCallsFound(int kernelFuncNum, bool showFoundScripts); + SciEngine *_engine; DebugState &_debugState; bool _mouseVisible; diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index 2760d08be8..060fea43b8 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -462,6 +462,7 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_DUMMY(Profiler), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(ShiftScreen), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(ListOps), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + // Used by the sysLogger class (e.g. script 952 in GK1CD), a class used to report bugs by Sierra's testers { MAP_DUMMY(ATan), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(Record), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(PlayBack), SIG_EVERYWHERE, "(.*)", NULL, NULL }, @@ -503,6 +504,8 @@ static SciKernelMapEntry s_kernelMap[] = { // VibrateMouse - used in QFG4 floppy // PalCycle // ObjectIntersect - used in QFG4 floppy + // MakeSaveCatName - used in the Save/Load dialog of GK1CD (SRDialog, script 64990) + // MakeSaveFileName - used in the Save/Load dialog of GK1CD (SRDialog, script 64990) // SCI2 empty functions @@ -524,8 +527,6 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_DUMMY(ShowStylePercent), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(InvertRect), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(InputText), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_DUMMY(MakeSaveCatName), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_DUMMY(MakeSaveFileName), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(TextWidth), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(PointSize), SIG_EVERYWHERE, "(.*)", NULL, NULL }, @@ -564,7 +565,6 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_DUMMY(CelRect), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(BaseLineSpan), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(CelLink), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_DUMMY(UpdateLine), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(AddPolygon), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(DeletePolygon), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(UpdatePolygon), SIG_EVERYWHERE, "(.*)", NULL, NULL }, @@ -573,7 +573,6 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_DUMMY(Priority), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(WinDLL), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(DeletePic), SIG_EVERYWHERE, "(.*)", NULL, NULL }, - { MAP_DUMMY(GetSierraProfileInt), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_DUMMY(GetSierraProfileString), SIG_EVERYWHERE, "(.*)", NULL, NULL }, // SCI2.1 unmapped functions - TODO! @@ -585,11 +584,13 @@ static SciKernelMapEntry s_kernelMap[] = { // ScrollWindow - used by Phantasmagoria 1 and SQ6 // AddLine - used by Torin's Passage to highlight the chapter buttons // DeleteLine - used by Torin's Passage to delete the highlight from the chapter buttons + // UpdateLine = used by LSL6 // GetConfig - used by Phantasmagoria 1 // SetPalStyleRange // NewRoom // MorphOn - used by SQ6 // SetHotRectangles - used by Phantasmagoria 1 + // GetSierraProfileInt - used by Phantasmagoria 1 #endif { NULL, NULL, SIG_EVERYWHERE, NULL, NULL, NULL } @@ -1040,7 +1041,7 @@ static const char *sci21_default_knames[] = { /*0x7e*/ "Table", /*0x7f*/ "WinHelp", // Windows only /*0x80*/ "Dummy", - /*0x81*/ "Dummy", + /*0x81*/ "Dummy", // called when changing rooms in most SCI2.1 games (e.g. KQ7, GK2, MUMG deluxe, Phant1) /*0x82*/ "Dummy", /*0x83*/ "PrintDebug", // debug function, used by Shivers 2 (demo and full) /*0x84*/ "Dummy", |