/* * SPL - The SPL Programming Language * Copyright (C) 2004, 2005 Clifford Wolf * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * dump.c: Dump the SPL VM state */ #include #include #include #ifdef ENABLE_PTHREAD_SUPPORT #include #endif #include "spl.h" static int dump_roof; static int dump_counter; static int dump_pass; static FILE *dump_file; static struct spl_vm *dump_vm_ptr; #ifdef ENABLE_PTHREAD_SUPPORT static pthread_mutex_t dump_lck = PTHREAD_MUTEX_INITIALIZER; #endif static void print_string(char *string) { unsigned char *ustring = (unsigned char *)string; fputc('(', dump_file); for (int i=0; ustring[i]; i++) switch (ustring[i]) { case 'a' ... 'z': case 'A' ... 'Z': case '0' ... '9': case ':': case '#': case '+': case '-': case '_': case ',': case '.': case ' ': fputc(ustring[i], dump_file); break; default: fprintf(dump_file, "%%%02X", ustring[i]); } fputc(')', dump_file); } static void print_data(unsigned char *data, int size) { fputc('{', dump_file); for (int i=0; idump_tag != 1) return; code->dump_tag = dump_counter++; } else { if (code->dump_tag == 1) return; code->dump_tag = 1; dump_roof++; } if ( dump_pass ) { fprintf(dump_file, "CODE=%d CODE_TYPE=%d SIZE=%d ID=", code->dump_tag, code->code_type, code->size); if ( code->id ) fprintf(dump_file, "(%s)", code->id); fprintf(dump_file, " SHAONE="); if ( (sha1=spl_code_sha1(code)) != 0 ) fprintf(dump_file, "(%s)", sha1); fprintf(dump_file, " CODE="); if ( sha1 && dump_vm_ptr->codecache_dir ) { int fn_size = strlen(dump_vm_ptr->codecache_dir) + 100; char fn[fn_size]; snprintf(fn, fn_size, "%s/%s.splb", dump_vm_ptr->codecache_dir, sha1); if (utime(fn, NULL) != 0) { FILE *f = fopen(fn, "wb"); if (f) { fwrite(code->code, code->size, 1, f); fclose(f); } else goto cant_open_code_dump_file; } } else { cant_open_code_dump_file:; if ( code->code ) print_data(code->code, code->size); } fprintf(dump_file, "\n"); } } static void dump_node(struct spl_node *node) { if ( !node ) return; if ( dump_pass ) { if (node->dump_tag != 1) return; node->dump_tag = dump_counter++; } else { if (node->dump_tag == 1) return; if (node->hnode_name) spl_hnode_dump(dump_vm_ptr, node); node->dump_tag = 1; dump_roof++; } dump_node(node->ctx); dump_node(node->cls); dump_code(node->code); struct spl_node_sub *s = node->subs_begin; while (s) { dump_node(s->node); s = s->next; } if ( dump_pass ) { fprintf(dump_file, "NODE=%d FLAGS=%d CLS=%d CTX=%d CTX_TYPE=%d CODE=%d CODE_IP=%d NIDX=%d SUBS=", node->dump_tag, node->flags, node->cls ? node->cls->dump_tag : 0, node->ctx ? node->ctx->dump_tag : 0, node->ctx_type, node->code ? node->code->dump_tag : 0, node->code_ip, node->subs_next_idx); for (s=node->subs_begin; s; s = s->next) { fprintf(dump_file, "%s%d", s == node->subs_begin ? "" : ",", s->node ? s->node->dump_tag : 0); if ( s->module ) { fprintf(dump_file, ":"); print_string(s->module); } if ( s->key ) print_string(s->key); } fprintf(dump_file, " VALUE="); if ( node->value ) print_string(spl_get_string(node)); fprintf(dump_file, " HOSTED="); if ( node->hnode_name ) print_string(node->hnode_name); fprintf(dump_file, " HDATA="); if ( node->hnode_dump ) print_string(node->hnode_dump); fprintf(dump_file, "\n"); } } static void dump_task(struct spl_task *task) { if ( dump_pass ) { if (task->dump_tag != 1) return; task->dump_tag = dump_counter++; } else { if (task->dump_tag == 1) return; task->dump_tag = 1; dump_roof++; } dump_node(task->ctx); dump_code(task->code); struct spl_node_stack *s = task->stack; while (s) { dump_node(s->node); s = s->next; } if ( dump_pass ) { fprintf(dump_file, "TASK=%d CTX=%d CODE=%d CODE_IP=%d FLAGS=%d ID=", task->dump_tag, task->ctx ? task->ctx->dump_tag : 0, task->code ? task->code->dump_tag : 0, task->code_ip, task->flags); if ( task->id ) print_string(task->id); fprintf(dump_file, " STACK="); for (s=task->stack; s; s = s->next) fprintf(dump_file, "%s%d", s == task->stack ? "" : ",", s->node ? s->node->dump_tag : 0); fprintf(dump_file, "\n"); } } static void dump_vm(struct spl_vm *vm) { if ( dump_pass ) { fprintf(dump_file, "IDS=0 VALUE=%d VALUE=", dump_roof); print_string(SPL_SIGNATURE); fprintf(dump_file, "\n"); } dump_node(vm->root); struct spl_task *t = vm->task_list; while (t) { dump_task(t); t = t->next; } if ( dump_pass ) { fprintf(dump_file, "VM=1 ROOT=%d\n", vm->root->dump_tag); struct spl_module *m = vm->module_list; while (m) { fprintf(dump_file, "MOD=1 NAME="); print_string(m->name); fprintf(dump_file, "\n"); m = m->next; } fprintf(dump_file, "END=1\n"); } } int spl_dump_ascii(struct spl_vm *vm, FILE *file) { if (vm->undumpable) fprintf(file, "VM State is undumpable: %s\n", vm->undumpable_info ? vm->undumpable_info : "NO UNUMPABLE INFO SET"); #ifdef ENABLE_PTHREAD_SUPPORT pthread_mutex_lock(&dump_lck); #endif dump_file = file; dump_vm_ptr = vm; dump_roof = dump_counter = 2; dump_pass = 0; dump_vm(vm); dump_pass = 1; dump_vm(vm); #ifdef ENABLE_PTHREAD_SUPPORT pthread_mutex_unlock(&dump_lck); #endif return vm->undumpable ? 1 : 0; }