home *** CD-ROM | disk | FTP | other *** search
- /* ScummC
- * Copyright (C) 2006 Alban Bedel
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
- /**
- * @file scvm_dbg.c
- * @ingroup scvm
- * @brief Debugger interface
- */
-
- #include "config.h"
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <inttypes.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <ctype.h>
-
- #ifdef HAVE_READLINE
- #include <readline/readline.h>
- #include <readline/history.h>
- #endif
-
- #include "scc_fd.h"
- #include "scc_util.h"
- #include "scc_param.h"
- #include "scc_cost.h"
- #include "scc_box.h"
- #include "scvm_res.h"
- #include "scvm_thread.h"
- #include "scvm.h"
-
- typedef struct scvm_debug_cmd {
- char* name, *full_name;
- int (*action)(scvm_t* vm, char* arg);
- void (*usage)(char* args);
- struct scvm_debug_cmd* next;
- } scvm_debug_cmd_t;
-
- static int dbg_interrupt = 0;
- static scvm_debug_cmd_t debug_cmd[];
-
- static void dbg_interrupt_handler(int sig) {
- printf("Kill debug\n");
- dbg_interrupt = 1;
- }
-
- static int check_interrupt(scvm_t* vm) {
- return dbg_interrupt;
- }
-
- static scvm_debug_cmd_t* scvm_find_debug_cmd(scvm_t* vm, char* line,
- scvm_debug_cmd_t* cmdtable,
- char** next_args, int* found) {
- char* cmd, *args, *cmd_end_pos, cmd_end;
- int i,len;
- if(next_args) *next_args = NULL;
- if(found) *found = 0;
- if(!line)
- return NULL;
- for(cmd = line ; isspace(cmd[0]) ; cmd++);
- if(!cmd[0])
- return NULL;
- for(args = cmd+1 ; args[0] && !isspace(args[0]) ; args++);
- cmd_end = args[0];
- cmd_end_pos = args;
- if(args[0]) {
- args[0] = 0;
- for(args++ ; isspace(args[0]) ; args++);
- }
- if(!args[0])
- args = NULL;
- len = strlen(cmd);
- for(i = 0 ; cmdtable[i].name ; i++)
- if(strncmp(cmd,cmdtable[i].name,len) == 0) {
- if(cmdtable[i].next) {
- scvm_debug_cmd_t* next_cmd;
- cmd_end_pos[0] = cmd_end;
- if(!args) {
- if(found && cmdtable[i].action) *found = 1;
- return cmdtable+i;
- }
- next_cmd = scvm_find_debug_cmd(vm,args,cmdtable[i].next,next_args,found);
- if(next_cmd && (!found || *found)) return next_cmd;
- // not found
- if(next_args) *next_args = args;
- return cmdtable+i;
- }
- if(next_args) *next_args = args;
- if(found) *found = 1;
- return cmdtable+i;
- }
- cmd_end_pos[0] = cmd_end;
- return NULL;
- }
-
- /////////////// breakpoint ///////////////////////////
-
- static void cmd_breakpoint_usage(char* args) {
- printf("Usage: breakpoint [room] script [pos]\n");
- }
-
-
- static int cmd_breakpoint(scvm_t* vm, char* args) {
- int arg[3], num, id;
- int room = 0, script = 0, pos = 0;
- if(!args) {
- cmd_breakpoint_usage(NULL);
- return 0;
- }
- num = sscanf(args,"%d %d %d",arg,arg+1,arg+2);
- if(num == 3)
- room = arg[0], script = arg[1], pos = arg[2];
- else if(num == 2)
- script = arg[0], pos = arg[1];
- else if(num == 1)
- script = arg[0];
- else {
- cmd_breakpoint_usage(NULL);
- return 0;
- }
- id = scvm_add_breakpoint(vm,room,script,pos);
- if(id < 0) {
- printf("Failed to create breakpoint.\n");
- return 0;
- }
- if(room)
- printf("Added breakpoint %d in room %d, script %d at 0x%X\n",
- id,room,script,pos);
- else
- printf("Added breakpoint %d in script %d at 0x%X\n",
- id,script,pos);
- return 1;
- }
-
- /////////////// help ///////////////////////////
-
- static void cmd_help_usage(char* args) {
- printf("Usage: help [ CMD ... ]\n");
- }
-
- static int cmd_help(scvm_t* vm, char* args) {
- scvm_debug_cmd_t* cmdtable = debug_cmd, *cmd;
- char* next_args;
- int i;
- if(args && (cmd = scvm_find_debug_cmd(vm,args,debug_cmd,&next_args,NULL))) {
- if(cmd->next) {
- // print subcmd list
- printf("Usage: %s SUBCMD ...\n"
- "where SUBCMD is one of:\n",cmd->full_name);
- cmdtable = cmd->next;
- } else if(cmd->usage) {
- cmd->usage(next_args);
- return 1;
- } else {
- printf("Command is missing a help message.\n");
- return 0;
- }
- } else {
- if(args)
- printf("Unknown command: %s\n",args);
- printf("Commands:\n");
- }
-
- for(i = 0 ; cmdtable[i].name ; i++)
- printf(" %-20s -\n",cmdtable[i].name);
- return 1;
- }
-
- /////////////// quit ///////////////////////////
-
- static void cmd_quit_usage(char* args) {
- printf("Usage: quit\n");
- }
-
- static int cmd_quit(scvm_t* vm, char* args) {
- // kill the vm ?
- return -1;
- }
-
- ///////////// show actor ///////////////////////
-
- static void cmd_show_actor_usage(char* args) {
- printf("Usage: show actor [ actor-addr ]\n");
- }
-
- static int cmd_show_actor(scvm_t* vm, char* args) {
- int a;
- scvm_actor_t* actor;
- if(args) {
- if(sscanf(args,"%d",&a) != 1) {
- cmd_show_actor_usage(NULL);
- return 0;
- }
- if(a <= 0 || a >= vm->num_actor) {
- printf("Invalid actor address: %d\n",a);
- return 0;
- }
- actor = &vm->actor[a];
- } else if(!vm->current_actor) {
- printf("Current actor is not set.\n");
- return 0;
- } else
- actor = vm->current_actor;
-
- printf("Actor %d:\n",actor->id);
- printf(" Name : %s\n",actor->name);
- if(actor->costdec.cost)
- printf(" Costume : %d\n",actor->costdec.cost->id);
- if(actor->costdec.anim)
- printf(" Animation : %d\n",actor->costdec.anim_id);
- printf(" Room : %d\n",actor->room);
- printf(" Position : %dx%d\n",actor->x,actor->y);
- printf(" Size : %dx%d\n",actor->width,actor->height);
- printf(" Direction : %d\n",actor->direction);
- printf(" Scaling : %dx%d\n",actor->scale_x,actor->scale_y);
- printf(" Layer : %d\n",actor->layer);
- printf(" Elevation : %d\n",actor->elevation);
- printf(" Follow boxes : %s\n",
- (actor->flags & SCVM_ACTOR_IGNORE_BOXES) ? "No" : "Yes");
- if(!(actor->flags & SCVM_ACTOR_IGNORE_BOXES))
- printf(" Box : %d\n",actor->box);
- printf("\n");
- // flags
- printf(" Anim speed : %d\n",actor->anim_speed);
- printf(" Anim cycle : %d\n",actor->anim_cycle);
- printf(" Walk speed : %dx%d\n",actor->walk_speed_x,
- actor->walk_speed_y);
- printf(" Walk script : %d\n",actor->walk_script);
- printf(" Walk state : %d\n",actor->walking);
- if(actor->walking) {
- printf(" Walk destination : %dx%d (box %d)\n",
- actor->walk_to_x,actor->walk_to_y,actor->walk_to_box);
- printf(" Walk waypoint : %dx%d (box %d)\n",
- actor->dstX,actor->dstY,actor->dst_box);
- }
- printf("\n");
- printf(" Init frame : %d\n",actor->init_frame);
- printf(" Walk frame : %d\n",actor->walk_frame);
- printf(" Talk start frame : %d\n",actor->talk_start_frame);
- printf(" Talk end frame : %d\n",actor->talk_end_frame);
- printf(" Stand frame : %d\n",actor->stand_frame);
- printf("\n");
- printf(" Talk color : %d\n",actor->talk_color);
- printf(" Talk position : %dx%d\n",actor->talk_x,actor->talk_y);
- printf(" Talk script : %d\n",actor->talk_script);
- return 1;
- }
-
- ///////////// show array ///////////////////////
-
- static void cmd_show_array_usage(char* args) {
- printf("Usage: show array array-addr\n");
- }
-
- static int cmd_show_array(scvm_t* vm, char* args) {
- int i, a, val;
- if(!args || sscanf(args,"%d",&a) != 1) {
- cmd_show_array_usage(NULL);
- return 0;
- }
- if(a <= 0 || a >= vm->num_array ||
- vm->array[a].size == 0) {
- printf("Invalid array address: %d\n",a);
- return 0;
- }
-
- printf("Array %d = { ",a);
- for(i = 0 ; i < vm->array[a].size ; i++)
- if(!scvm_read_array(vm,a,i,0,&val))
- printf("%s%d",i > 0 ? ", " : "",val);
- printf(" }\n");
- return 1;
- }
-
- ///////////// show avar ///////////////////////
-
- static void cmd_show_avar_usage(char* args) {
- printf("Usage: show avar var-addr\n");
- }
-
- static int cmd_show_avar(scvm_t* vm, char* args) {
- int i, var, a, val;
- if(sscanf(args,"local %d",&var) == 1) {
- var &= 0x3FFF;
- var |= 0x4000;
- } else if(sscanf(args,"%d",&var) != 1) {
- cmd_show_avar_usage(NULL);
- return 0;
- }
- if(scvm_thread_read_var(vm,vm->current_thread,var,&a)) {
- printf("Invalid address: %d\n",var);
- return 0;
- }
- if(a <= 0 || a >= vm->num_array ||
- vm->array[a].size == 0) {
- printf("Invalid array address: %d\n",a);
- return 0;
- }
-
- printf("Array %d = { ",a);
- for(i = 0 ; i < vm->array[a].size ; i++)
- if(!scvm_read_array(vm,a,i,0,&val))
- printf("%s%d",i > 0 ? ", " : "",val);
- printf(" }\n");
- return 1;
- }
-
- ///////////// show costume ////////////////////
- static void cmd_show_costume_usage(char* args) {
- printf("Usage: show costume costume-addr\n");
- }
-
- static int cmd_show_costume(scvm_t* vm, char* args) {
- int id;
- scc_cost_t* cost;
- scc_cost_anim_t* ani;
- if(!args || sscanf(args,"%d",&id) != 1) {
- cmd_show_costume_usage(NULL);
- return 0;
- }
- if(!(cost = scvm_load_res(vm,SCVM_RES_COSTUME,id)))
- return 0;
- printf("Costume %d:\n",cost->id);
- printf(" Format : 0x%X\n",cost->format);
- printf(" Colors : %d\n",cost->pal_size);
- printf(" Anims :");
- for(ani = cost->anims ; ani ; ani = ani->next)
- printf(" %d",ani->id);
- printf("\n");
- return 1;
- }
-
- ///////////// show costume ////////////////////
- static void cmd_show_object_usage(char* args) {
- printf("Usage: show object object-addr\n");
- }
-
- static int cmd_show_object(scvm_t* vm, char* args) {
- int id,n = 0;
- scvm_object_t* obj;
- if(!args || sscanf(args,"%d",&id) != 1) {
- cmd_show_object_usage(NULL);
- return 0;
- }
- if(!(obj = scvm_load_res(vm,SCVM_RES_OBJECT,id)))
- return 0;
-
- printf("Object %d:\n",obj->id);
- printf(" Name : %s\n",obj->pdata->name);
- printf(" Class mask : 0x%X\n",obj->pdata->klass);
- printf(" Owner : %d\n",obj->pdata->owner);
- printf(" State : %d\n",obj->pdata->state);
- printf(" Position : %dx%d\n",obj->x,obj->y);
- printf(" Size : %dx%d\n",obj->width,obj->height);
- printf(" Images : %d\n",obj->num_image);
- printf(" Z planes : %d\n",obj->num_zplane);
- printf(" Hotspots :");
- for(n = 0 ; n < obj->num_hotspot ; n++)
- printf(" %dx%d",obj->hotspot[n<<1],obj->hotspot[(n<<1)+1]);
- printf("\n");
- if(obj->parent)
- printf(" Parent : %d\n",obj->parent->id);
- printf(" Direction : %d\n",obj->actor_dir);
- printf(" Verbs :");
- for(n = 0 ; n < obj->num_verb_entries ; n++)
- printf(" %d",obj->verb_entries[n<<1]);
- printf("\n");
- return 1;
- }
-
- ///////////// show room ///////////////////////
-
- static void cmd_show_room_usage(char* args) {
- printf("Usage: show room [ room-addr ]\n");
- }
-
- static int cmd_show_room(scvm_t* vm, char* args) {
- int id;
- scvm_room_t* room;
- if(args) {
- if(sscanf(args,"%d",&id) != 1) {
- cmd_show_avar_usage(NULL);
- return 0;
- }
- if(!(room = scvm_load_res(vm,SCVM_RES_ROOM,id)))
- return 0;
- } else if(!vm->room) {
- printf("No current room.\n");
- return 0;
- } else
- room = vm->room;
-
- printf("Room %d:\n",room->id);
- printf(" Size : %dx%d\n",room->width,room->height);
- printf(" Z planes : %d\n",room->num_zplane);
- printf(" Palettes : %d\n",room->num_palette);
- printf(" Cycles : %d\n",room->num_cycle);
- printf(" Transparent color : %d\n",room->trans);
- printf(" Entry script : %s\n",room->entry ? "yes" : "no");
- printf(" Exit script : %s\n",room->exit ? "yes" : "no");
- printf(" Scripts : %d\n",room->num_script);
- printf(" Objects :");
- for(id = 0 ; id < room->num_object ; id++)
- if(room->object[id])
- printf(" %d",room->object[id]->id);
- printf("\n");
- return 1;
- }
-
-
- /////////////// show thread ///////////////////////////
-
- static void show_thread(scvm_thread_t* t) {
- printf("Thread %d\n",t->id);
- printf(" State : %s\n",scvm_thread_state_name(t->state));
- if(t->parent)
- printf(" Parent thread : %d\n",t->parent->id);
- if(!t->state)
- return;
- if(t->next_state)
- printf(" Next VM state : %s\n",scvm_state_name(t->next_state));
- if(t->flags) {
- char flags[1024];
- scvm_thread_flags_name(t->flags,flags,sizeof(flags));
- printf(" Flags : %s\n",flags);
- }
- printf(" Cycle : %d\n",t->cycle);
- if(t->delay)
- printf(" Delay : %d ms\n",t->delay);
- if(t->script && (t->script->id & 0x0FFF0000) == 0x0ECD0000)
- printf(" Script : %s\n",
- t->script->id == 0x0ECD0000 ? "entry" : "exit");
- else
- printf(" Script : %d\n",t->script ? t->script->id : -1);
- printf(" Code pointer : %d - 0x%X\n",t->code_ptr,t->code_ptr);
- printf(" OP start : %d - 0x%X\n",t->op_start,t->code_ptr);
- }
-
- static void cmd_show_thread_usage(char* args) {
- printf("Usage: show thread [ id ... ]\n");
- }
-
- static int cmd_show_thread(scvm_t* vm, char* args) {
- int t;
- if(!args) {
- for(t = 0 ; t < vm->num_thread ; t++)
- if(vm->thread[t].state > SCVM_THREAD_STOPPED)
- show_thread(&vm->thread[t]);
- return 1;
- }
- while(1) {
- char* end = args;
- while(isspace(args[0])) args++;
- if(!args[0]) break;
- t = strtol(args,&end,0);
- if(end == args)
- return 0;
- show_thread(&vm->thread[t]);
- args = end;
- }
- return 1;
- }
-
- /////////////// show var ///////////////////////////
-
- static void cmd_show_var_usage(char* args) {
- printf("Usage: show var [ local | bit ] var-addr\n");
- }
-
- static int cmd_show_var(scvm_t* vm, char* args) {
- int var,val;
- if(!args) {
- cmd_show_var_usage(NULL);
- return 0;
- }
- if(sscanf(args,"local %d",&var) == 1) {
- var &= 0x3FFF;
- var |= 0x4000;
- } else if(sscanf(args,"bit %d",&var) == 1) {
- var &= 0x7FFF;
- var |= 0x8000;
- } else if(sscanf(args,"%d",&var) != 1) {
- cmd_show_var_usage(NULL);
- return 0;
- }
- if(scvm_thread_read_var(vm,vm->current_thread,var,&val)) {
- printf("Invalid address: %d\n",var);
- return 0;
- }
- return 1;
- }
-
- /////////////// show vm ///////////////////////////
-
- static void cmd_show_vm_usage(char* args) {
- printf("Usage: show vm\n");
- }
-
- static int cmd_show_vm(scvm_t* vm, char* args) {
- printf("VM:\n");
- printf(" Data path : %s\n",vm->path);
- printf(" Basename : %s\n",vm->basename);
- printf(" File key : 0x%02x\n",vm->file_key);
- printf(" Data files : %d\n",vm->num_file);
- printf("\n");
- printf(" Global variables : %d\n",vm->num_var);
- printf(" Bit variables : %d\n",vm->num_bitvar);
- printf(" Arrays : %d\n",vm->num_array);
- printf(" Stack : %d/%d\n",vm->stack_ptr,vm->stack_size);
- printf("\n");
- printf(" State : %s\n",scvm_state_name(vm->state));
- printf(" Cycle : %d\n",vm->cycle);
- if(vm->room)
- printf(" Room : %d\n",vm->room->id);
- if(vm->current_thread)
- printf(" Thread : %d\n",vm->current_thread->id);
- if(vm->current_actor)
- printf(" Actor : %d\n",vm->current_actor->id);
- return 1;
- }
-
- /////////////// show xxx ///////////////////////////
-
- #define SHOW_CMD(name) \
- { #name, "show" #name, cmd_show_##name, cmd_show_##name##_usage }
-
- static scvm_debug_cmd_t show_cmd[] = {
- SHOW_CMD(actor),
- SHOW_CMD(array),
- SHOW_CMD(avar),
- SHOW_CMD(costume),
- SHOW_CMD(object),
- SHOW_CMD(room),
- SHOW_CMD(thread),
- SHOW_CMD(var),
- SHOW_CMD(vm),
- { NULL }
- };
-
-
- /////////////// thread ///////////////////////////
-
- static void cmd_thread_usage(char* args) {
- printf("Usage: thread [ id ]\n");
- }
-
- static int cmd_thread(scvm_t* vm, char* args) {
- if(!args) {
- if(!vm->current_thread) {
- printf("No thread is currently scheduled.\n");
- return 0;
- }
- printf("Current thread is %d.\n",vm->current_thread->id);
- return 1;
- }
- // TODO: switch thread
- return 0;
- }
-
-
- /////////////// run ///////////////////////////
-
- static void cmd_run_usage(char* args) {
- printf("Usage: run [ boot-param ]\n");
- }
-
- static int cmd_run(scvm_t* vm, char* args) {
- sig_t oldsig;
- // todo: reset the vm
- dbg_interrupt = 0;
- oldsig = signal(SIGINT,dbg_interrupt_handler);
- scvm_run(vm);
- signal(SIGINT,oldsig);
- return 1;
- }
-
- ////////////////// root commands /////////////////////
-
- #define DBG_CMD(name) \
- { #name, #name, cmd_##name, cmd_##name##_usage }
- #define DBG_SUBCMD(name) \
- { #name, #name, NULL, NULL, name##_cmd }
-
- static scvm_debug_cmd_t debug_cmd[] = {
- DBG_CMD(breakpoint),
- DBG_CMD(help),
- DBG_CMD(quit),
- DBG_CMD(run),
- DBG_SUBCMD(show),
- DBG_CMD(thread),
- { NULL }
- };
-
- #ifndef HAVE_READLINE
- char* readline(const char* prompt) {
- char* line = malloc(512);
- printf("%s",prompt);
- if(!fgets(line,512,stdin)) {
- free(line);
- return NULL;
- }
- return line;
- }
-
- void add_history(const char* line) {
- }
- #endif
-
- int scvm_debugger(scvm_t* vm) {
- char* line = NULL, *ptr, *args;
- scvm_debug_cmd_t* cmd;
- int r = 1, found;
-
- if(!vm->dbg)
- vm->dbg = calloc(1,sizeof(scvm_debug_t));
-
- vm->dbg->check_interrupt = check_interrupt;
-
- do {
- if(line) free(line);
- if(!(line = readline("(scvm) ")))
- continue;
- for(ptr = line ; isspace(ptr[0]) ; ptr++);
- if(!ptr[0]) continue;
- add_history(ptr);
- cmd = scvm_find_debug_cmd(vm,ptr,debug_cmd,&args,&found);
- if(!found) {
- if(cmd) {
- if(args)
- printf("Unknown command: %s\n",ptr);
- else
- printf("Incomplete command: %s\n",ptr);
- }
- cmd_help(vm,ptr);
- r = 0;
- continue;
- }
- r = cmd->action(vm,args);
- } while(r >= 0);
- return r;
- }
-