aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sci/engine/kernel.cpp96
-rw-r--r--engines/sci/engine/kernel.h3
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