aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sci/console.cpp667
-rw-r--r--engines/sci/console.h8
-rw-r--r--engines/sci/engine/scriptdebug.cpp218
-rw-r--r--engines/sci/engine/vm.cpp4
4 files changed, 468 insertions, 429 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index eab8dbf57b..0c57240057 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -53,189 +53,6 @@ bool _kdebug_track_mouse_clicks = false;
int _weak_validations = 1; // Some validation errors are reduced to warnings if non-0
-int parse_reg_t(EngineState *s, const char *str, reg_t *dest) { // Returns 0 on success
- int rel_offsetting = 0;
- const char *offsetting = NULL;
- // Non-NULL: Parse end of string for relative offsets
- char *endptr;
-
- if (*str == '$') { // Register
- rel_offsetting = 1;
-
- if (!scumm_strnicmp(str + 1, "PC", 2)) {
- *dest = s->_executionStack.back().addr.pc;
- offsetting = str + 3;
- } else if (!scumm_strnicmp(str + 1, "P", 1)) {
- *dest = s->_executionStack.back().addr.pc;
- offsetting = str + 2;
- } else if (!scumm_strnicmp(str + 1, "PREV", 4)) {
- *dest = s->r_prev;
- offsetting = str + 5;
- } else if (!scumm_strnicmp(str + 1, "ACC", 3)) {
- *dest = s->r_acc;
- offsetting = str + 4;
- } else if (!scumm_strnicmp(str + 1, "A", 1)) {
- *dest = s->r_acc;
- offsetting = str + 2;
- } else if (!scumm_strnicmp(str + 1, "OBJ", 3)) {
- *dest = s->_executionStack.back().objp;
- offsetting = str + 4;
- } else if (!scumm_strnicmp(str + 1, "O", 1)) {
- *dest = s->_executionStack.back().objp;
- offsetting = str + 2;
- } else
- return 1; // No matching register
-
- if (!*offsetting)
- offsetting = NULL;
- else if (*offsetting != '+' && *offsetting != '-')
- return 1;
- } else if (*str == '&') {
- int script_nr;
- // Look up by script ID
- char *colon = (char *)strchr(str, ':');
-
- if (!colon)
- return 1;
- *colon = 0;
- offsetting = colon + 1;
-
- script_nr = strtol(str + 1, &endptr, 10);
-
- if (*endptr)
- return 1;
-
- dest->segment = s->seg_manager->segGet(script_nr);
-
- if (!dest->segment) {
- return 1;
- }
- } else if (*str == '?') {
- int index = -1;
- int times_found = 0;
- char *tmp;
- const char *str_objname;
- char *str_suffix;
- char suffchar = 0;
- uint i;
- // Parse obj by name
-
- tmp = (char *)strchr(str, '+');
- str_suffix = (char *)strchr(str, '-');
- if (tmp < str_suffix)
- str_suffix = tmp;
- if (str_suffix) {
- suffchar = (*str_suffix);
- *str_suffix = 0;
- }
-
- tmp = (char *)strchr(str, '.');
-
- if (tmp) {
- *tmp = 0;
- index = strtol(tmp + 1, &endptr, 16);
- if (*endptr)
- return -1;
- }
-
- str_objname = str + 1;
-
- // Now all values are available; iterate over all objects.
- for (i = 0; i < s->seg_manager->_heap.size(); i++) {
- MemObject *mobj = s->seg_manager->_heap[i];
- int idx = 0;
- int max_index = 0;
-
- if (mobj) {
- if (mobj->getType() == MEM_OBJ_SCRIPT)
- max_index = (*(Script *)mobj)._objects.size();
- else if (mobj->getType() == MEM_OBJ_CLONES)
- max_index = (*(CloneTable *)mobj)._table.size();
- }
-
- while (idx < max_index) {
- int valid = 1;
- Object *obj = NULL;
- reg_t objpos;
- objpos.offset = 0;
- objpos.segment = i;
-
- if (mobj->getType() == MEM_OBJ_SCRIPT) {
- obj = &(*(Script *)mobj)._objects[idx];
- objpos.offset = obj->pos.offset;
- } else if (mobj->getType() == MEM_OBJ_CLONES) {
- obj = &((*(CloneTable *)mobj)._table[idx]);
- objpos.offset = idx;
- valid = ((CloneTable *)mobj)->isValidEntry(idx);
- }
-
- if (valid) {
- const char *objname = obj_get_name(s, objpos);
- if (!strcmp(objname, str_objname)) {
- // Found a match!
- if ((index < 0) && (times_found > 0)) {
- if (times_found == 1) {
- // First time we realized the ambiguity
- printf("Ambiguous:\n");
- printf(" %3x: [%04x:%04x] %s\n", 0, PRINT_REG(*dest), str_objname);
- }
- printf(" %3x: [%04x:%04x] %s\n", times_found, PRINT_REG(objpos), str_objname);
- }
- if (index < 0 || times_found == index)
- *dest = objpos;
- ++times_found;
- }
- }
- ++idx;
- }
-
- }
-
- if (!times_found)
- return 1;
-
- if (times_found > 1 && index < 0) {
- printf("Ambiguous: Aborting.\n");
- return 1; // Ambiguous
- }
-
- if (times_found <= index)
- return 1; // Not found
-
- offsetting = str_suffix;
- if (offsetting)
- *str_suffix = suffchar;
- rel_offsetting = 1;
- } else {
- char *colon = (char *)strchr(str, ':');
-
- if (!colon) {
- offsetting = str;
- dest->segment = 0;
- } else {
- *colon = 0;
- offsetting = colon + 1;
-
- dest->segment = strtol(str, &endptr, 16);
- if (*endptr)
- return 1;
- }
- }
- if (offsetting) {
- int val = strtol(offsetting, &endptr, 16);
-
- if (rel_offsetting)
- dest->offset += val;
- else
- dest->offset = val;
-
- if (*endptr)
- return 1;
- }
-
- return 0;
-}
-
Console::Console(SciEngine *vm) : GUI::Debugger() {
_vm = vm;
@@ -311,10 +128,16 @@ Console::Console(SciEngine *vm) : GUI::Debugger() {
DCmd_Register("dissect_script", WRAP_METHOD(Console, cmdDissectScript));
DCmd_Register("script_steps", WRAP_METHOD(Console, cmdScriptSteps));
DCmd_Register("set_acc", WRAP_METHOD(Console, cmdSetAccumulator));
+ DCmd_Register("bp_list", WRAP_METHOD(Console, cmdBreakpointList));
+ DCmd_Register("bp_del", WRAP_METHOD(Console, cmdBreakpointDelete));
// VM
DCmd_Register("vm_varlist", WRAP_METHOD(Console, cmdVMVarlist));
DCmd_Register("stack", WRAP_METHOD(Console, cmdStack));
DCmd_Register("value_type", WRAP_METHOD(Console, cmdValueType));
+ DCmd_Register("view_object", WRAP_METHOD(Console, cmdViewListNode));
+ DCmd_Register("view_object", WRAP_METHOD(Console, cmdViewObject));
+ DCmd_Register("active_object", WRAP_METHOD(Console, cmdViewActiveObject));
+ DCmd_Register("acc_object", WRAP_METHOD(Console, cmdViewAccumulatorObject));
DCmd_Register("sleep_factor", WRAP_METHOD(Console, cmdSleepFactor));
DCmd_Register("exit", WRAP_METHOD(Console, cmdExit));
@@ -1356,40 +1179,6 @@ bool Console::segmentInfo(int nr) {
return true;
}
-void Console::printList(List *l) {
- reg_t pos = l->first;
- reg_t my_prev = NULL_REG;
-
- DebugPrintf("\t<\n");
-
- while (!pos.isNull()) {
- Node *node;
- NodeTable *nt = (NodeTable *)GET_SEGMENT(*g_EngineState->seg_manager, pos.segment, MEM_OBJ_NODES);
-
- if (!nt || !nt->isValidEntry(pos.offset)) {
- DebugPrintf(" WARNING: %04x:%04x: Doesn't contain list node!\n",
- PRINT_REG(pos));
- return;
- }
-
- node = &(nt->_table[pos.offset]);
-
- DebugPrintf("\t%04x:%04x : %04x:%04x -> %04x:%04x\n", PRINT_REG(pos), PRINT_REG(node->key), PRINT_REG(node->value));
-
- if (my_prev != node->pred)
- DebugPrintf(" WARNING: current node gives %04x:%04x as predecessor!\n",
- PRINT_REG(node->pred));
-
- my_prev = pos;
- pos = node->succ;
- }
-
- if (my_prev != l->last)
- DebugPrintf(" WARNING: Last node was expected to be %04x:%04x, was %04x:%04x!\n",
- PRINT_REG(l->last), PRINT_REG(my_prev));
- DebugPrintf("\t>\n");
-}
-
bool Console::cmdSegmentInfo(int argc, const char **argv) {
if (argc != 2) {
DebugPrintf("Provides information on the specified segment(s)\n");
@@ -1700,6 +1489,66 @@ bool Console::cmdValueType(int argc, const char **argv) {
return true;
}
+bool Console::cmdViewListNode(int argc, const char **argv) {
+ if (argc != 2) {
+ DebugPrintf("Examines the list node at the given address.\n");
+ DebugPrintf("Usage: %s <address>\n", argv[0]);
+ DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
+ return true;
+ }
+
+ reg_t addr;
+
+ if (parse_reg_t(g_EngineState, argv[1], &addr)) {
+ DebugPrintf("Invalid address passed.\n");
+ DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
+ return true;
+ }
+
+ printNode(addr);
+ return true;
+}
+
+bool Console::cmdViewObject(int argc, const char **argv) {
+ if (argc != 2) {
+ DebugPrintf("Examines the object at the given address.\n");
+ DebugPrintf("Usage: %s <address>\n", argv[0]);
+ DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
+ return true;
+ }
+
+ reg_t addr;
+
+ if (parse_reg_t(g_EngineState, argv[1], &addr)) {
+ DebugPrintf("Invalid address passed.\n");
+ DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
+ return true;
+ }
+
+ DebugPrintf("Information on the object at the given address:\n");
+ printObject(g_EngineState, addr);
+
+ return true;
+}
+
+bool Console::cmdViewActiveObject(int argc, const char **argv) {
+ DebugPrintf("Information on the currently active object or class:\n");
+
+#if 0
+ // TODO: p_objp
+ printObject(g_EngineState, *p_objp);
+#endif
+
+ return true;
+}
+
+bool Console::cmdViewAccumulatorObject(int argc, const char **argv) {
+ DebugPrintf("Information on the currently active object or class at the address indexed by the accumulator:\n");
+ printObject(g_EngineState, g_EngineState->r_acc);
+
+ return true;
+}
+
bool Console::cmdSleepFactor(int argc, const char **argv) {
if (argc != 2) {
DebugPrintf("Factor to multiply with wait times in kWait().\n");
@@ -1741,6 +1590,82 @@ bool Console::cmdSetAccumulator(int argc, const char **argv) {
return true;
}
+bool Console::cmdBreakpointList(int argc, const char **argv) {
+ Breakpoint *bp = g_EngineState->bp_list;
+ int i = 0;
+ int bpdata;
+
+ DebugPrintf("Breakpoint list:\n");
+
+ while (bp) {
+ DebugPrintf(" #%i: ", i);
+ switch (bp->type) {
+ case BREAK_SELECTOR:
+ DebugPrintf("Execute %s\n", bp->data.name);
+ break;
+ case BREAK_EXPORT:
+ bpdata = bp->data.address;
+ DebugPrintf("Execute script %d, export %d\n", bpdata >> 16, bpdata & 0xFFFF);
+ break;
+ }
+
+ bp = bp->next;
+ i++;
+ }
+
+ return true;
+}
+
+bool Console::cmdBreakpointDelete(int argc, const char **argv) {
+ if (argc != 2) {
+ DebugPrintf("Deletes a breakpoint with the specified index.\n");
+ DebugPrintf("Usage: %s <breakpoint index>\n", argv[0]);
+ return true;
+ }
+
+ Breakpoint *bp, *bp_next, *bp_prev;
+ int i = 0, found = 0;
+ int type;
+ int idx = atoi(argv[1]);
+
+ // Find breakpoint with given index
+ bp_prev = NULL;
+ bp = g_EngineState->bp_list;
+ while (bp && i < idx) {
+ bp_prev = bp;
+ bp = bp->next;
+ i++;
+ }
+ if (!bp) {
+ DebugPrintf("Invalid breakpoint index %i\n", idx);
+ return true;
+ }
+
+ // Delete it
+ bp_next = bp->next;
+ type = bp->type;
+ if (type == BREAK_SELECTOR) free(bp->data.name);
+ free(bp);
+ if (bp_prev)
+ bp_prev->next = bp_next;
+ else
+ g_EngineState->bp_list = bp_next;
+
+ // Check if there are more breakpoints of the same type. If not, clear
+ // the respective bit in s->have_bp.
+ for (bp = g_EngineState->bp_list; bp; bp = bp->next) {
+ if (bp->type == type) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ g_EngineState->have_bp &= ~type;
+
+ return true;
+}
+
bool Console::cmdIsSample(int argc, const char **argv) {
if (argc != 2) {
DebugPrintf("Tests whether a given sound resource is a PCM sample, \n");
@@ -2036,4 +1961,312 @@ bool Console::cmdAddresses(int argc, const char **argv) {
return true;
}
+int parse_reg_t(EngineState *s, const char *str, reg_t *dest) { // Returns 0 on success
+ int rel_offsetting = 0;
+ const char *offsetting = NULL;
+ // Non-NULL: Parse end of string for relative offsets
+ char *endptr;
+
+ if (*str == '$') { // Register
+ rel_offsetting = 1;
+
+ if (!scumm_strnicmp(str + 1, "PC", 2)) {
+ *dest = s->_executionStack.back().addr.pc;
+ offsetting = str + 3;
+ } else if (!scumm_strnicmp(str + 1, "P", 1)) {
+ *dest = s->_executionStack.back().addr.pc;
+ offsetting = str + 2;
+ } else if (!scumm_strnicmp(str + 1, "PREV", 4)) {
+ *dest = s->r_prev;
+ offsetting = str + 5;
+ } else if (!scumm_strnicmp(str + 1, "ACC", 3)) {
+ *dest = s->r_acc;
+ offsetting = str + 4;
+ } else if (!scumm_strnicmp(str + 1, "A", 1)) {
+ *dest = s->r_acc;
+ offsetting = str + 2;
+ } else if (!scumm_strnicmp(str + 1, "OBJ", 3)) {
+ *dest = s->_executionStack.back().objp;
+ offsetting = str + 4;
+ } else if (!scumm_strnicmp(str + 1, "O", 1)) {
+ *dest = s->_executionStack.back().objp;
+ offsetting = str + 2;
+ } else
+ return 1; // No matching register
+
+ if (!*offsetting)
+ offsetting = NULL;
+ else if (*offsetting != '+' && *offsetting != '-')
+ return 1;
+ } else if (*str == '&') {
+ int script_nr;
+ // Look up by script ID
+ char *colon = (char *)strchr(str, ':');
+
+ if (!colon)
+ return 1;
+ *colon = 0;
+ offsetting = colon + 1;
+
+ script_nr = strtol(str + 1, &endptr, 10);
+
+ if (*endptr)
+ return 1;
+
+ dest->segment = s->seg_manager->segGet(script_nr);
+
+ if (!dest->segment) {
+ return 1;
+ }
+ } else if (*str == '?') {
+ int index = -1;
+ int times_found = 0;
+ char *tmp;
+ const char *str_objname;
+ char *str_suffix;
+ char suffchar = 0;
+ uint i;
+ // Parse obj by name
+
+ tmp = (char *)strchr(str, '+');
+ str_suffix = (char *)strchr(str, '-');
+ if (tmp < str_suffix)
+ str_suffix = tmp;
+ if (str_suffix) {
+ suffchar = (*str_suffix);
+ *str_suffix = 0;
+ }
+
+ tmp = (char *)strchr(str, '.');
+
+ if (tmp) {
+ *tmp = 0;
+ index = strtol(tmp + 1, &endptr, 16);
+ if (*endptr)
+ return -1;
+ }
+
+ str_objname = str + 1;
+
+ // Now all values are available; iterate over all objects.
+ for (i = 0; i < s->seg_manager->_heap.size(); i++) {
+ MemObject *mobj = s->seg_manager->_heap[i];
+ int idx = 0;
+ int max_index = 0;
+
+ if (mobj) {
+ if (mobj->getType() == MEM_OBJ_SCRIPT)
+ max_index = (*(Script *)mobj)._objects.size();
+ else if (mobj->getType() == MEM_OBJ_CLONES)
+ max_index = (*(CloneTable *)mobj)._table.size();
+ }
+
+ while (idx < max_index) {
+ int valid = 1;
+ Object *obj = NULL;
+ reg_t objpos;
+ objpos.offset = 0;
+ objpos.segment = i;
+
+ if (mobj->getType() == MEM_OBJ_SCRIPT) {
+ obj = &(*(Script *)mobj)._objects[idx];
+ objpos.offset = obj->pos.offset;
+ } else if (mobj->getType() == MEM_OBJ_CLONES) {
+ obj = &((*(CloneTable *)mobj)._table[idx]);
+ objpos.offset = idx;
+ valid = ((CloneTable *)mobj)->isValidEntry(idx);
+ }
+
+ if (valid) {
+ const char *objname = obj_get_name(s, objpos);
+ if (!strcmp(objname, str_objname)) {
+ // Found a match!
+ if ((index < 0) && (times_found > 0)) {
+ if (times_found == 1) {
+ // First time we realized the ambiguity
+ printf("Ambiguous:\n");
+ printf(" %3x: [%04x:%04x] %s\n", 0, PRINT_REG(*dest), str_objname);
+ }
+ printf(" %3x: [%04x:%04x] %s\n", times_found, PRINT_REG(objpos), str_objname);
+ }
+ if (index < 0 || times_found == index)
+ *dest = objpos;
+ ++times_found;
+ }
+ }
+ ++idx;
+ }
+
+ }
+
+ if (!times_found)
+ return 1;
+
+ if (times_found > 1 && index < 0) {
+ printf("Ambiguous: Aborting.\n");
+ return 1; // Ambiguous
+ }
+
+ if (times_found <= index)
+ return 1; // Not found
+
+ offsetting = str_suffix;
+ if (offsetting)
+ *str_suffix = suffchar;
+ rel_offsetting = 1;
+ } else {
+ char *colon = (char *)strchr(str, ':');
+
+ if (!colon) {
+ offsetting = str;
+ dest->segment = 0;
+ } else {
+ *colon = 0;
+ offsetting = colon + 1;
+
+ dest->segment = strtol(str, &endptr, 16);
+ if (*endptr)
+ return 1;
+ }
+ }
+ if (offsetting) {
+ int val = strtol(offsetting, &endptr, 16);
+
+ if (rel_offsetting)
+ dest->offset += val;
+ else
+ dest->offset = val;
+
+ if (*endptr)
+ return 1;
+ }
+
+ return 0;
+}
+
+const char *selector_name(EngineState *s, int selector) {
+ if (selector >= 0 && selector < (int)s->_kernel->getSelectorNamesSize())
+ return s->_kernel->getSelectorName(selector).c_str();
+ else
+ return "--INVALID--";
+}
+
+void Console::printList(List *l) {
+ reg_t pos = l->first;
+ reg_t my_prev = NULL_REG;
+
+ DebugPrintf("\t<\n");
+
+ while (!pos.isNull()) {
+ Node *node;
+ NodeTable *nt = (NodeTable *)GET_SEGMENT(*g_EngineState->seg_manager, pos.segment, MEM_OBJ_NODES);
+
+ if (!nt || !nt->isValidEntry(pos.offset)) {
+ DebugPrintf(" WARNING: %04x:%04x: Doesn't contain list node!\n",
+ PRINT_REG(pos));
+ return;
+ }
+
+ node = &(nt->_table[pos.offset]);
+
+ DebugPrintf("\t%04x:%04x : %04x:%04x -> %04x:%04x\n", PRINT_REG(pos), PRINT_REG(node->key), PRINT_REG(node->value));
+
+ if (my_prev != node->pred)
+ DebugPrintf(" WARNING: current node gives %04x:%04x as predecessor!\n",
+ PRINT_REG(node->pred));
+
+ my_prev = pos;
+ pos = node->succ;
+ }
+
+ if (my_prev != l->last)
+ DebugPrintf(" WARNING: Last node was expected to be %04x:%04x, was %04x:%04x!\n",
+ PRINT_REG(l->last), PRINT_REG(my_prev));
+ DebugPrintf("\t>\n");
+}
+
+int Console::printNode(reg_t addr) {
+ MemObject *mobj = GET_SEGMENT(*g_EngineState->seg_manager, addr.segment, MEM_OBJ_LISTS);
+
+ if (mobj) {
+ ListTable *lt = (ListTable *)mobj;
+ List *list;
+
+ if (!lt->isValidEntry(addr.offset)) {
+ DebugPrintf("Address does not contain a list\n");
+ return 1;
+ }
+
+ list = &(lt->_table[addr.offset]);
+
+ DebugPrintf("%04x:%04x : first x last = (%04x:%04x, %04x:%04x)\n", PRINT_REG(addr), PRINT_REG(list->first), PRINT_REG(list->last));
+ } else {
+ NodeTable *nt;
+ Node *node;
+ mobj = GET_SEGMENT(*g_EngineState->seg_manager, addr.segment, MEM_OBJ_NODES);
+
+ if (!mobj) {
+ DebugPrintf("Segment #%04x is not a list or node segment\n", addr.segment);
+ return 1;
+ }
+
+ nt = (NodeTable *)mobj;
+
+ if (!nt->isValidEntry(addr.offset)) {
+ DebugPrintf("Address does not contain a node\n");
+ return 1;
+ }
+ node = &(nt->_table[addr.offset]);
+
+ DebugPrintf("%04x:%04x : prev x next = (%04x:%04x, %04x:%04x); maps %04x:%04x -> %04x:%04x\n",
+ PRINT_REG(addr), PRINT_REG(node->pred), PRINT_REG(node->succ), PRINT_REG(node->key), PRINT_REG(node->value));
+ }
+
+ return 0;
+}
+
+int printObject(EngineState *s, reg_t pos) {
+ Object *obj = obj_get(s, pos);
+ Object *var_container = obj;
+ int i;
+
+ if (!obj) {
+ sciprintf("[%04x:%04x]: Not an object.", PRINT_REG(pos));
+ return 1;
+ }
+
+ // Object header
+ sciprintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(pos), obj_get_name(s, pos),
+ obj->_variables.size(), obj->methods_nr);
+
+ if (!(obj->_variables[SCRIPT_INFO_SELECTOR].offset & SCRIPT_INFO_CLASS))
+ var_container = obj_get(s, obj->_variables[SCRIPT_SUPERCLASS_SELECTOR]);
+ sciprintf(" -- member variables:\n");
+ for (i = 0; (uint)i < obj->_variables.size(); i++) {
+ sciprintf(" ");
+ if (i < var_container->variable_names_nr) {
+ sciprintf("[%03x] %s = ", VM_OBJECT_GET_VARSELECTOR(var_container, i), selector_name(s, VM_OBJECT_GET_VARSELECTOR(var_container, i)));
+ } else
+ sciprintf("p#%x = ", i);
+
+ reg_t val = obj->_variables[i];
+ sciprintf("%04x:%04x", PRINT_REG(val));
+
+ Object *ref = obj_get(s, val);
+ if (ref)
+ sciprintf(" (%s)", obj_get_name(s, val));
+
+ sciprintf("\n");
+ }
+ sciprintf(" -- methods:\n");
+ for (i = 0; i < obj->methods_nr; i++) {
+ reg_t fptr = VM_OBJECT_READ_FUNCTION(obj, i);
+ sciprintf(" [%03x] %s = %04x:%04x\n", VM_OBJECT_GET_FUNCSELECTOR(obj, i), selector_name(s, VM_OBJECT_GET_FUNCSELECTOR(obj, i)), PRINT_REG(fptr));
+ }
+ if (s->seg_manager->_heap[pos.segment]->getType() == MEM_OBJ_SCRIPT)
+ sciprintf("\nOwner script:\t%d\n", s->seg_manager->getScript(pos.segment)->nr);
+
+ return 0;
+}
+
} // End of namespace Sci
diff --git a/engines/sci/console.h b/engines/sci/console.h
index c7c0d0fb22..107ed5f422 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -36,6 +36,7 @@ class SciEngine;
// Refer to the "addresses" command on how to pass address parameters
int parse_reg_t(EngineState *s, const char *str, reg_t *dest);
+int printObject(EngineState *s, reg_t pos);
class Console : public GUI::Debugger {
public:
@@ -100,19 +101,26 @@ private:
bool cmdGCNormalize(int argc, const char **argv);
bool cmdVMVarlist(int argc, const char **argv);
bool cmdStack(int argc, const char **argv);
+ bool cmdViewListNode(int argc, const char **argv);
bool cmdValueType(int argc, const char **argv);
+ bool cmdViewObject(int argc, const char **argv);
+ bool cmdViewActiveObject(int argc, const char **argv);
+ bool cmdViewAccumulatorObject(int argc, const char **argv);
bool cmdSleepFactor(int argc, const char **argv);
bool cmdIsSample(int argc, const char **argv);
bool cmdSfx01Header(int argc, const char **argv);
bool cmdSfx01Track(int argc, const char **argv);
bool cmdScriptSteps(int argc, const char **argv);
bool cmdSetAccumulator(int argc, const char **argv);
+ bool cmdBreakpointList(int argc, const char **argv);
+ bool cmdBreakpointDelete(int argc, const char **argv);
bool cmdExit(int argc, const char **argv);
bool cmdAddresses(int argc, const char **argv);
bool cmdStopSfx(int argc, const char **argv);
bool segmentInfo(int nr);
void printList(List *l);
+ int printNode(reg_t addr);
private:
SciEngine *_vm;
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index 86d05989fb..8aa2cd68ed 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -120,47 +120,7 @@ static const char *_debug_get_input() {
return inputbuf;
}
-static int show_node(EngineState *s, reg_t addr) {
- MemObject *mobj = GET_SEGMENT(*s->seg_manager, addr.segment, MEM_OBJ_LISTS);
-
- if (mobj) {
- ListTable *lt = (ListTable *)mobj;
- List *list;
-
- if (!lt->isValidEntry(addr.offset)) {
- sciprintf("Address does not contain a list\n");
- return 1;
- }
-
- list = &(lt->_table[addr.offset]);
-
- sciprintf("%04x:%04x : first x last = (%04x:%04x, %04x:%04x)\n", PRINT_REG(addr), PRINT_REG(list->first), PRINT_REG(list->last));
- } else {
- NodeTable *nt;
- Node *node;
- mobj = GET_SEGMENT(*s->seg_manager, addr.segment, MEM_OBJ_NODES);
-
- if (!mobj) {
- sciprintf("Segment #%04x is not a list or node segment\n", addr.segment);
- return 1;
- }
-
- nt = (NodeTable *)mobj;
-
- if (!nt->isValidEntry(addr.offset)) {
- sciprintf("Address does not contain a node\n");
- return 1;
- }
- node = &(nt->_table[addr.offset]);
-
- sciprintf("%04x:%04x : prev x next = (%04x:%04x, %04x:%04x); maps %04x:%04x -> %04x:%04x\n",
- PRINT_REG(addr), PRINT_REG(node->pred), PRINT_REG(node->succ), PRINT_REG(node->key), PRINT_REG(node->value));
- }
-
- return 0;
-}
-
-int objinfo(EngineState *s, reg_t pos);
+extern int printObject(EngineState *s, reg_t pos);
static int c_vr(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
reg_t reg = cmdParams[0].reg;
@@ -212,12 +172,15 @@ static int c_vr(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
case KSIG_NODE:
sciprintf("list node\n");
- show_node(s, reg);
+ // TODO: printNode has been moved to console.cpp
+ /*
+ printNode(s, reg);
+ */
break;
case KSIG_OBJECT:
sciprintf("object\n");
- objinfo(s, reg);
+ printObject(s, reg);
break;
case KSIG_REF: {
@@ -259,22 +222,6 @@ static int c_vr(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
return 0;
}
-int c_debuginfo(EngineState *s) {
- if (!_debugstate_valid) {
- sciprintf("Not in debug state\n");
- return 1;
- }
-
- sciprintf("acc=%04x:%04x prev=%04x:%04x &rest=%x\n", PRINT_REG(s->r_acc), PRINT_REG(s->r_prev), *p_restadjust);
-
- if (!s->_executionStack.empty()) {
- sciprintf("pc=%04x:%04x obj=%04x:%04x fp=ST:%04x sp=ST:%04x\n", PRINT_REG(*p_pc), PRINT_REG(*p_objp), PRINT_STK(*p_pp), PRINT_STK(*p_sp));
- } else
- sciprintf("<no execution stack: pc,obj,fp omitted>\n");
-
- return 0;
-}
-
int c_step(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
_debugstate_valid = 0;
if (cmdParams.size() && (cmdParams[0].val > 0))
@@ -452,12 +399,7 @@ int c_parse(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
return 0;
}
-const char *selector_name(EngineState *s, int selector) {
- if (selector >= 0 && selector < (int)s->_kernel->getSelectorNamesSize())
- return s->_kernel->getSelectorName(selector).c_str();
- else
- return "--INVALID--";
-}
+extern const char *selector_name(EngineState *s, int selector);
int prop_ofs_to_id(EngineState *s, int prop_ofs, reg_t objp) {
Object *obj = obj_get(s, objp);
@@ -1211,68 +1153,6 @@ static void viewobjinfo(EngineState *s, HeapPtr pos) {
#endif
#undef GETRECT
-int objinfo(EngineState *s, reg_t pos) {
- Object *obj = obj_get(s, pos);
- Object *var_container = obj;
- int i;
-
- if (!obj) {
- sciprintf("[%04x:%04x]: Not an object.", PRINT_REG(pos));
- return 1;
- }
-
- // Object header
- sciprintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(pos), obj_get_name(s, pos),
- obj->_variables.size(), obj->methods_nr);
-
- if (!(obj->_variables[SCRIPT_INFO_SELECTOR].offset & SCRIPT_INFO_CLASS))
- var_container = obj_get(s, obj->_variables[SCRIPT_SUPERCLASS_SELECTOR]);
- sciprintf(" -- member variables:\n");
- for (i = 0; (uint)i < obj->_variables.size(); i++) {
- sciprintf(" ");
- if (i < var_container->variable_names_nr) {
- sciprintf("[%03x] %s = ", VM_OBJECT_GET_VARSELECTOR(var_container, i), selector_name(s, VM_OBJECT_GET_VARSELECTOR(var_container, i)));
- } else
- sciprintf("p#%x = ", i);
-
- reg_t val = obj->_variables[i];
- sciprintf("%04x:%04x", PRINT_REG(val));
-
- Object *ref = obj_get(s, val);
- if (ref)
- sciprintf(" (%s)", obj_get_name(s, val));
-
- sciprintf("\n");
- }
- sciprintf(" -- methods:\n");
- for (i = 0; i < obj->methods_nr; i++) {
- reg_t fptr = VM_OBJECT_READ_FUNCTION(obj, i);
- sciprintf(" [%03x] %s = %04x:%04x\n", VM_OBJECT_GET_FUNCSELECTOR(obj, i), selector_name(s, VM_OBJECT_GET_FUNCSELECTOR(obj, i)), PRINT_REG(fptr));
- }
- if (s->seg_manager->_heap[pos.segment]->getType() == MEM_OBJ_SCRIPT)
- sciprintf("\nOwner script:\t%d\n", s->seg_manager->getScript(pos.segment)->nr);
-
- return 0;
-}
-
-int c_vo(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
- return objinfo(s, cmdParams[0].reg);
-}
-
-int c_obj(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
- return objinfo(s, *p_objp);
-}
-
-int c_accobj(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
- return objinfo(s, s->r_acc);
-}
-
-int c_shownode(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
- reg_t addr = cmdParams[0].reg;
-
- return show_node(s, addr);
-}
-
// Breakpoint commands
static Breakpoint *bp_alloc(EngineState *s) {
@@ -1323,74 +1203,6 @@ int c_bpe(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
return 0;
}
-int c_bplist(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
- Breakpoint *bp;
- int i = 0;
- int bpdata;
-
- bp = s->bp_list;
- while (bp) {
- sciprintf(" #%i: ", i);
- switch (bp->type) {
- case BREAK_SELECTOR:
- sciprintf("Execute %s\n", bp->data.name);
- break;
- case BREAK_EXPORT:
- bpdata = bp->data.address;
- sciprintf("Execute script %d, export %d\n", bpdata >> 16, bpdata & 0xFFFF);
- break;
- }
-
- bp = bp->next;
- i++;
- }
-
- return 0;
-}
-
-int c_bpdel(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
- Breakpoint *bp, *bp_next, *bp_prev;
- int i = 0, found = 0;
- int type;
-
- // Find breakpoint with given index
- bp_prev = NULL;
- bp = s->bp_list;
- while (bp && i < cmdParams [0].val) {
- bp_prev = bp;
- bp = bp->next;
- i++;
- }
- if (!bp) {
- sciprintf("Invalid breakpoint index %i\n", cmdParams [0].val);
- return 1;
- }
-
- // Delete it
- bp_next = bp->next;
- type = bp->type;
- if (type == BREAK_SELECTOR) free(bp->data.name);
- free(bp);
- if (bp_prev)
- bp_prev->next = bp_next;
- else
- s->bp_list = bp_next;
-
- // Check if there are more breakpoints of the same type. If not, clear
- // the respective bit in s->have_bp.
- for (bp = s->bp_list; bp; bp = bp->next) {
- if (bp->type == type) {
- found = 1;
- break;
- }
- }
-
- if (!found)
- s->have_bp &= ~type;
-
- return 0;
-}
-
int c_se(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
stop_on_event = 1;
_debugstate_valid = 0;
@@ -1487,8 +1299,7 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t *
p_vars = variables;
p_var_max = variables_nr;
p_var_base = variables_base;
-
- c_debuginfo(s);
+
sciprintf("Step #%d\n", script_step_counter);
disassemble(s, *pc, 0, 1);
@@ -1509,10 +1320,6 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t *
" c<x> : Disassemble <x> bytes\n"
" bc : Print bytecode\n\n");
con_hook_command(c_disasm, "disasm", "!as", "Disassembles a method by name\n\nUSAGE\n\n disasm <obj> <method>\n\n");
- con_hook_command(c_obj, "obj", "!", "Displays information about the\n currently active object/class.\n"
- "\n\nSEE ALSO\n\n vo.1, accobj.1");
- con_hook_command(c_accobj, "accobj", "!", "Displays information about an\n object or class at the\n"
- "address indexed by acc.\n\nSEE ALSO\n\n obj.1, vo.1");
con_hook_command(c_backtrace, "bt", "", "Dumps the send/self/super/call/calle/callb stack");
con_hook_command(c_snk, "snk", "s*", "Steps forward until it hits the next\n callk operation.\n"
" If invoked with a parameter, it will\n look for that specific callk.\n");
@@ -1523,8 +1330,6 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t *
" bpx ego::doit\n\n May also be used to set a breakpoint\n that applies whenever an object\n"
" of a specific type is touched:\n bpx foo::\n");
con_hook_command(c_bpe, "bpe", "ii", "Sets a breakpoint on the execution of specified exported function.\n");
- con_hook_command(c_bplist, "bplist", "", "Lists all breakpoints.\n");
- con_hook_command(c_bpdel, "bpdel", "i", "Deletes a breakpoint with specified index.");
con_hook_command(c_go, "go", "", "Executes the script.\n");
con_hook_command(c_parse, "parse", "s", "Parses a sequence of words and prints\n the resulting parse tree.\n"
" The word sequence must be provided as a\n single string.");
@@ -1541,19 +1346,12 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t *
con_hook_command(c_gfx_draw_viewobj, "draw_viewobj", "i", "Draws the nsRect and brRect of a\n dynview object.\n\n nsRect is green, brRect\n"
" is blue.\n");
#endif
- con_hook_command(c_vo, "vo", "!a",
- "Examines an object\n\n"
- "SEE ALSO\n\n"
- " addresses.3, type.1");
con_hook_command(c_vr, "vr", "!aa*",
"Examines an arbitrary reference\n\n");
con_hook_command(c_sg, "sg", "!i",
"Steps until the global variable with the\n"
"specified index is modified.\n\nSEE ALSO\n\n"
" s.1, snk.1, so.1, bpx.1");
- con_hook_command(c_shownode, "shownode", "!a",
- "Prints information about a list node\n"
- " or list base.\n\n");
/*
con_hook_int(&script_abort_flag, "script_abort_flag", "Set != 0 to abort execution\n");
*/
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index 355c2b8ee2..4a4ba8126a 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -1994,7 +1994,7 @@ static EngineState *_game_run(EngineState *s, int restoring) {
return s;
}
-int objinfo(EngineState *s, reg_t pos);
+int printObject(EngineState *s, reg_t pos);
int game_run(EngineState **_s) {
EngineState *s = *_s;
@@ -2004,7 +2004,7 @@ int game_run(EngineState **_s) {
// Now: Register the first element on the execution stack-
if (!send_selector(s, s->game_obj, s->game_obj, s->stack_base, 2, s->stack_base)) {
- objinfo(s, s->game_obj);
+ printObject(s, s->game_obj);
sciprintf("Failed to run the game! Aborting...\n");
return 1;
}