diff options
author | Filippos Karapetis | 2009-06-02 23:29:58 +0000 |
---|---|---|
committer | Filippos Karapetis | 2009-06-02 23:29:58 +0000 |
commit | 2ce6cca98b2b92d84f7956ecf78042ee566fe392 (patch) | |
tree | 088ca72968cddea5caec4748615f46edaab63db2 | |
parent | d94f920d5003e9ada2f903066d4988cb16725c21 (diff) | |
download | scummvm-rg350-2ce6cca98b2b92d84f7956ecf78042ee566fe392.tar.gz scummvm-rg350-2ce6cca98b2b92d84f7956ecf78042ee566fe392.tar.bz2 scummvm-rg350-2ce6cca98b2b92d84f7956ecf78042ee566fe392.zip |
Moved some more console commands to ScummVM's debug console
svn-id: r41129
-rw-r--r-- | engines/sci/console.cpp | 667 | ||||
-rw-r--r-- | engines/sci/console.h | 8 | ||||
-rw-r--r-- | engines/sci/engine/scriptdebug.cpp | 218 | ||||
-rw-r--r-- | engines/sci/engine/vm.cpp | 4 |
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; } |