diff options
-rw-r--r-- | engines/sci/engine/kernel.cpp | 96 | ||||
-rw-r--r-- | engines/sci/engine/kernel.h | 3 |
2 files changed, 85 insertions, 14 deletions
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 9bf0371a7a..75eadb9a64 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -669,40 +669,108 @@ int Kernel::findRegType(reg_t reg) { } } +struct SignatureDebugType { + char typeCheck; + const char *text; +}; + +static const SignatureDebugType signatureDebugTypeList[] = { + { KSIG_NULL, "null" }, + { KSIG_ARITHMETIC, "value" }, + { KSIG_OBJECT, "object" }, + { KSIG_REF, "reference" }, + { KSIG_LIST, "list" }, + { KSIG_NODE, "node" }, + { 0, NULL } +}; + +static void kernelSignatureDebugType(const char type) { + bool firstPrint = true; + + const SignatureDebugType *list = signatureDebugTypeList; + while (list->typeCheck) { + if (type & list->typeCheck) { + if (!firstPrint) + printf(", "); + printf("%s", list->text); + firstPrint = false; + } + list++; + } +} + +// Shows kernel call signature and current arguments for debugging purposes +void Kernel::signatureDebug(const char *sig, int argc, const reg_t *argv) { + int argnr = 0; + while (*sig || argc) { + printf("parameter %d: ", argnr++); + if (argc) { + reg_t parameter = *argv; + printf("%04x:%04x (", PRINT_REG(parameter)); + kernelSignatureDebugType(findRegType(parameter)); + printf(")"); + argv++; + argc--; + } else { + printf("not passed"); + } + if (*sig) { + const char signature = *sig; + if ((signature & KSIG_ANY) == KSIG_ANY) { + printf(", may be any"); + } else { + printf(", should be "); + kernelSignatureDebugType(signature); + } + if (signature & KSIG_ELLIPSIS) + printf(" (optional)"); + sig++; + } + printf("\n"); + } +} + bool Kernel::signatureMatch(const char *sig, int argc, const reg_t *argv) { + const char *checkSig = sig; + const reg_t *checkParam = argv; + int checkCount = argc; // Always "match" if no signature is given if (!sig) return true; - while (*sig && argc) { - if ((*sig & KSIG_ANY) != KSIG_ANY) { - int type = findRegType(*argv); + while (*checkSig && checkCount) { + if ((*checkSig & KSIG_ANY) != KSIG_ANY) { + int type = findRegType(*checkParam); if (!type) { - warning("[KERN] Could not determine type of ref %04x:%04x; failing signature check", PRINT_REG(*argv)); + warning("[KERNEL] call signature: couldn't determine type of ref %04x:%04x", PRINT_REG(*argv)); + signatureDebug(sig, argc, argv); return false; } - if (!(type & *sig)) { - warning("kernel_matches_signature: %d args left, is %d, should be %d", argc, type, *sig); + if (!(type & *checkSig)) { + warning("[KERNEL] call signature: %d args left, is %d, should be %d", argc, type, *sig); + signatureDebug(sig, argc, argv); return false; } } - if (!(*sig & KSIG_ELLIPSIS)) - ++sig; - ++argv; - --argc; + if (!(*checkSig & KSIG_ELLIPSIS)) + ++checkSig; + ++checkParam; + --checkCount; } - if (argc) { - warning("kernel_matches_signature: too many arguments"); + if (checkCount) { + warning("[KERNEL] call signature: too many arguments"); + signatureDebug(sig, argc, argv); return false; // Too many arguments } - if (*sig == 0 || (*sig & KSIG_ELLIPSIS)) + if (*checkSig == 0 || (*checkSig & KSIG_ELLIPSIS)) return true; - warning("kernel_matches_signature: too few arguments"); + warning("[KERNEL] call signature: too few arguments"); + signatureDebug(sig, argc, argv); return false; } diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index a347e90d1a..6f7b0d569d 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -169,6 +169,9 @@ public: */ bool signatureMatch(const char *sig, int argc, const reg_t *argv); + // Prints out debug information in case a signature check fails + void signatureDebug(const char *sig, int argc, const reg_t *argv); + /** * Determines the type of the object indicated by reg. * @param reg register to check |