/* * Dump information about a program, optionally disassembling it. */ #include "std.h" #include "lpc_incl.h" #include "efuns_incl.h" #include "simul_efun.h" #include "comm.h" #include "swap.h" #include "lex.h" #include "file.h" #ifdef F_DUMP_PROG void dump_prog PROT((program_t *, char *, int)); static void disassemble PROT((FILE *, char *, int, int, program_t *)); static char *disassem_string PROT((char *)); static int short_compare PROT((unsigned short *, unsigned short *)); static void dump_line_numbers PROT((FILE *, program_t *)); void f_dump_prog PROT((void)) { program_t *prog; char *where; int d; object_t *ob; if (st_num_arg == 2) { ob = sp[-1].u.ob; d = sp->u.number; where = 0; } else if (st_num_arg == 3) { ob = sp[-2].u.ob; d = sp[-1].u.number; where = (sp->type == T_STRING) ? sp->u.string : 0; } else { ob = sp->u.ob; d = 0; where = 0; } pop_n_elems(st_num_arg); if (!(prog = ob->prog)) { error("No program for object.\n"); } else { if (!where) { where = "/PROG_DUMP"; } dump_prog(prog, where, d); } } /* Current flags: * 1 - do disassembly * 2 - dump line number table */ void dump_prog P3(program_t *, prog, char *, fn, int, flags) { char *fname; FILE *f; int i, j; fname = check_valid_path(fn, current_object, "dumpallobj", 1); if (!fname) { error("Invalid path '%s' for writing.\n", fn); return; } f = fopen(fname, "w"); if (!f) { error("Unable to open '/%s' for writing.\n", fname); return; } fprintf(f, "NAME: /%s\n", prog->name); fprintf(f, "INHERITS:\n"); fprintf(f, "\tname fio vio\n"); fprintf(f, "\t---------------- --- ---\n"); for (i = 0; i < (int) prog->num_inherited; i++) fprintf(f, "\t%-20s %5d %5d\n", prog->inherit[i].prog->name, (int)prog->inherit[i].function_index_offset, (int)prog->inherit[i].variable_index_offset ); fprintf(f, "PROGRAM:"); for (i = 0; i < (int) prog->program_size; i++) { if (i % 16 == 0) fprintf(f, "\n\t%04x: ", (unsigned int) i); fprintf(f, "%02d ", (unsigned char) prog->program[i]); } fputc('\n', f); fprintf(f, "FUNCTIONS:\n"); fprintf(f, " name offset fio flags # locals # args\n"); fprintf(f, " ----------- ------ --- ------- -------- ------\n"); for (i = 0; i < (int) prog->num_functions; i++) { char sflags[8]; int flags; flags = prog->functions[i].flags; sflags[6] = '\0'; sflags[0] = (flags & NAME_INHERITED) ? 'i' : '-'; sflags[1] = (flags & NAME_UNDEFINED) ? 'u' : '-'; sflags[2] = (flags & NAME_STRICT_TYPES) ? 's' : '-'; sflags[3] = (flags & NAME_PROTOTYPE) ? 'p' : '-'; sflags[4] = (flags & NAME_DEF_BY_INHERIT) ? 'd' : '-'; sflags[5] = (flags & NAME_ALIAS) ? 'a' : '-'; fprintf(f, "%4d: %-12s %5d %5d %7s %8d %6d\n", i, prog->functions[i].name, (int)prog->functions[i].offset, prog->functions[i].function_index_offset, sflags, prog->functions[i].num_local, prog->functions[i].num_arg ); } fprintf(f, "VARIABLES:\n"); for (i = 0; i < (int) prog->num_variables; i++) fprintf(f, "%4d: %-12s\n", i, prog->variable_names[i].name); fprintf(f, "STRINGS:\n"); for (i = 0; i < (int) prog->num_strings; i++) { fprintf(f, "%4d: ", i); for (j = 0; j < 32; j++) { char c; if (!(c = prog->strings[i][j])) break; else if (c == '\n') fprintf(f, "\\n"); else fputc(c, f); } fputc('\n', f); } if (flags & 1) { fprintf(f, "\n;;; *** Disassembly ***\n"); disassemble(f, prog->program, 0, prog->program_size, prog); } if (flags & 2) { fprintf(f, "\n;;; *** Line Number Info ***\n"); dump_line_numbers(f, prog); } fclose(f); } static char *disassem_string P1(char *, str) { static char buf[30]; char *b; int i; if (!str) return "0"; b = buf; for (i = 0; i < 29; i++) { if (!str[i]) break; if (str[i] == '\n') { *b++ = '\\'; *b++ = 'n'; } else { *b++ = str[i]; } } *b++ = 0; return buf; } #define FUNS prog->functions #define NUM_FUNS prog->num_functions #define VARS prog->variable_names #define NUM_VARS prog->num_variables #define STRS prog->strings #define NUM_STRS prog->num_strings #define CLSS prog->classes static int short_compare P2(unsigned short *, a, unsigned short *, b) { return (int) (*a - *b); } static char *pushes[] = { "string", "number", "global", "local" }; static void disassemble P5(FILE *, f, char *, code, int, start, int, end, program_t *, prog) { int i, j, instr, iarg, is_efun; unsigned short sarg; unsigned short offset; char *pc, buff[256]; int next_func; short *offsets; if (start == 0) { /* sort offsets of functions */ offsets = (short *) malloc(NUM_FUNS * 2 * sizeof(short)); for (i = 0; i < (int) NUM_FUNS; i++) { if (!FUNS[i].offset || (FUNS[i].flags & (NAME_ALIAS | NAME_INHERITED))) offsets[i * 2] = end + 1; else offsets[i * 2] = FUNS[i].offset; offsets[i * 2 + 1] = i; } #ifdef _SEQUENT_ qsort((void *) &offsets[0], #else qsort((char *) &offsets[0], #endif NUM_FUNS, sizeof(short) * 2, (int (*) ()) short_compare); next_func = 0; } else { offsets = 0; next_func = -1; } pc = code + start; while ((pc - code) < end) { fprintf(f, "%04x: ", (unsigned) (pc - code)); is_efun = (instr = EXTRACT_UCHAR(pc)) >= BASE; pc++; buff[0] = 0; sarg = 0; switch (instr) { case F_PUSH: fprintf(f, "push "); i = EXTRACT_UCHAR(pc++); while (i--) { j = EXTRACT_UCHAR(pc++); fprintf(f, "%s %i", pushes[(j & PUSH_WHAT) >> 6], j & PUSH_MASK); if (i) fprintf(f, ", "); else break; } fprintf(f, "\n"); continue; /* Single numeric arg */ case F_BRANCH_NE: case F_BRANCH_GE: case F_BRANCH_LE: case F_BRANCH_EQ: case F_BRANCH: case F_BRANCH_WHEN_ZERO: case F_BRANCH_WHEN_NON_ZERO: #ifdef F_LOR case F_LOR: case F_LAND: #endif COPY_SHORT(&sarg, pc); offset = (pc - code) + (unsigned short) sarg; sprintf(buff, "%04x (%04x)", (unsigned) sarg, (unsigned) offset); pc += 2; break; case F_NEXT_FOREACH: case F_BBRANCH_LT: COPY_SHORT(&sarg, pc); offset = (pc - code) - (unsigned short) sarg; sprintf(buff, "%04x (%04x)", (unsigned) sarg, (unsigned) offset); pc += 2; break; case F_FOREACH: { char tmp[32]; int flags = EXTRACT_UCHAR(pc++); sprintf(buff, "(%s) %s %i", (flags & 4) ? "mapping" : "array", (flags & 1) ? "global" : "local", EXTRACT_UCHAR(pc++)); if (flags & 4) { sprintf(tmp, ", %s %i", (flags & 2) ? "global" : "local", EXTRACT_UCHAR(pc++)); strcat(buff, tmp); } break; } case F_BBRANCH_WHEN_ZERO: case F_BBRANCH_WHEN_NON_ZERO: case F_BBRANCH: COPY_SHORT(&sarg, pc); offset = (pc - code) - (unsigned short) sarg; sprintf(buff, "%04x (%04x)", (unsigned) sarg, (unsigned) offset); pc += 2; break; #ifdef F_JUMP case F_JUMP: #endif #ifdef F_JUMP_WHEN_ZERO case F_JUMP_WHEN_ZERO: case F_JUMP_WHEN_NON_ZERO: #endif case F_CATCH: COPY_SHORT(&sarg, pc); sprintf(buff, "%04x", (unsigned) sarg); pc += 2; break; case F_AGGREGATE: case F_AGGREGATE_ASSOC: COPY_SHORT(&sarg, pc); sprintf(buff, "%d", (int)sarg); pc += 2; break; case F_MEMBER: case F_MEMBER_LVALUE: sprintf(buff, "%d", (int)EXTRACT_UCHAR(pc++)); break; case F_EXPAND_VARARGS: { int which = EXTRACT_UCHAR(pc++); if (which) { sprintf(buff, "%d from top of stack", which); } else { strcpy(buff, "top of stack"); } } break; case F_NEW_CLASS: { int which = EXTRACT_UCHAR(pc++); sprintf(buff, "class %s", STRS[CLSS[which].name]); break; } case F_CALL_FUNCTION_BY_ADDRESS: COPY_SHORT(&sarg, pc); pc += 3; if (sarg < NUM_FUNS) sprintf(buff, "%-12s %5d", FUNS[sarg].name, (int)sarg); else sprintf(buff, "<out of range %d>", (int)sarg); break; case F_CALL_INHERITED: { program_t *newprog; newprog = (prog->inherit + EXTRACT_UCHAR(pc++))->prog; COPY_SHORT(&sarg, pc); pc += 3; if (sarg < newprog->num_functions) sprintf(buff, "%30s::%-12s %5d", newprog->name, newprog->functions[sarg].name, (int) sarg); else sprintf(buff, "<out of range in %30s - %d>", newprog->name, (int) sarg); break; } case F_GLOBAL_LVALUE: case F_GLOBAL: if ((unsigned) (iarg = EXTRACT_UCHAR(pc)) < NUM_VARS) sprintf(buff, "%s", VARS[iarg].name); else sprintf(buff, "<out of range %d>", iarg); pc++; break; case F_LOOP_INCR: sprintf(buff, "LV%d", EXTRACT_UCHAR(pc)); pc++; break; case F_WHILE_DEC: COPY_SHORT(&sarg, pc + 1); offset = (pc - code) - (unsigned short) sarg; sprintf(buff, "LV%d--, branch %04x (%04x)", EXTRACT_UCHAR(pc), (unsigned) sarg, (unsigned) offset); pc += 3; break; case F_TRANSFER_LOCAL: case F_LOCAL: case F_LOCAL_LVALUE: case F_VOID_ASSIGN_LOCAL: sprintf(buff, "LV%d", EXTRACT_UCHAR(pc)); pc++; break; case F_LOOP_COND_NUMBER: i = EXTRACT_UCHAR(pc++); COPY_INT(&iarg, pc); pc += 4; COPY_SHORT(&sarg, pc); offset = (pc - code) - (unsigned short) sarg; pc += 2; sprintf(buff, "LV%d < %d bbranch_when_non_zero %04x (%04x)", i, iarg, sarg, offset); break; case F_LOOP_COND_LOCAL: i = EXTRACT_UCHAR(pc++); iarg = *pc++; COPY_SHORT(&sarg, pc); offset = (pc - code) - (unsigned short) sarg; pc += 2; sprintf(buff, "LV%d < LV%d bbranch_when_non_zero %04x (%04x)", i, iarg, sarg, offset); break; case F_STRING: COPY_SHORT(&sarg, pc); if (sarg < NUM_STRS) sprintf(buff, "\"%s\"", disassem_string(STRS[sarg])); else sprintf(buff, "<out of range %d>", (int)sarg); pc += 2; break; case F_SHORT_STRING: if (EXTRACT_UCHAR(pc) < NUM_STRS) sprintf(buff, "\"%s\"", disassem_string(STRS[EXTRACT_UCHAR(pc)])); else sprintf(buff, "<out of range %d>", EXTRACT_UCHAR(pc)); pc++; break; case F_SIMUL_EFUN: COPY_SHORT(&sarg, pc); sprintf(buff, "\"%s\" %d", simuls[sarg]->name, pc[2]); pc += 3; break; case F_FUNCTION_CONSTRUCTOR: switch (EXTRACT_UCHAR(pc++)) { case FP_SIMUL: LOAD_SHORT(sarg, pc); sprintf(buff, "<simul_efun> \"%s\"", simuls[sarg]->name); break; case FP_EFUN: LOAD_SHORT(sarg, pc); sprintf(buff, "<efun> %s", instrs[sarg].name); break; case FP_LOCAL: LOAD_SHORT(sarg, pc); if (sarg < NUM_FUNS) sprintf(buff, "<local_fun> %s", FUNS[sarg].name); else sprintf(buff, "<local_fun> <out of range %d>", (int)sarg); break; case FP_FUNCTIONAL: case FP_FUNCTIONAL | FP_NOT_BINDABLE: sprintf(buff, "<functional, %d args>\nCode:", (int)pc[0]); pc += 3; break; case FP_ANONYMOUS: COPY_SHORT(&sarg, &pc[2]); sprintf(buff, "<anonymous function, %d args, %d locals, ends at %04x>\nCode:", (int)pc[0], (int)pc[1], (int) (pc + 3 + sarg - code)); pc += 4; break; } break; case F_NUMBER: COPY_INT(&iarg, pc); sprintf(buff, "%d", iarg); pc += 4; break; case F_REAL: { float farg; COPY_FLOAT(&farg, pc); sprintf(buff, "%f", farg); pc += 4; break; } case F_SSCANF: case F_PARSE_COMMAND: case F_BYTE: sprintf(buff, "%d", EXTRACT_UCHAR(pc)); pc++; break; case F_NBYTE: sprintf(buff, "-%d", EXTRACT_UCHAR(pc)); pc++; break; case F_SWITCH: { unsigned char ttype; unsigned short stable, etable, def; char *parg; ttype = EXTRACT_UCHAR(pc); ((char *) &stable)[0] = pc[1]; ((char *) &stable)[1] = pc[2]; ((char *) &etable)[0] = pc[3]; ((char *) &etable)[1] = pc[4]; ((char *) &def)[0] = pc[5]; ((char *) &def)[1] = pc[6]; fprintf(f, "switch\n"); fprintf(f, " type: %02x table: %04x-%04x deflt: %04x\n", (unsigned) ttype, (unsigned) stable, (unsigned) etable, (unsigned) def); /* recursively disassemble stuff in switch */ disassemble(f, code, pc - code + 7, stable, prog); /* now print out table - ugly... */ fprintf(f, " switch table (for %04x)\n", (unsigned) (pc - code - 1)); if (ttype == 0xfe) ttype = 0; /* direct lookup */ else if (ttype >> 4 == 0xf) ttype = 1; /* normal int */ else ttype = 2; /* string */ pc = code + stable; if (ttype == 0) { i = 0; while (pc < code + etable - 4) { COPY_SHORT(&sarg, pc); fprintf(f, "\t%2d: %04x\n", i++, (unsigned) sarg); pc += 2; } COPY_INT(&iarg, pc); fprintf(f, "\tminval = %d\n", iarg); pc += 4; } else { while (pc < code + etable) { COPY_PTR(&parg, pc); COPY_SHORT(&sarg, pc + SIZEOF_PTR); if (ttype == 1 || !parg) { fprintf(f, "\t%-4d\t%04x\n",(int)parg, (unsigned) sarg); } else { fprintf(f, "\t\"%s\"\t%04x\n", disassem_string(parg), (unsigned) sarg); } pc += 2 + SIZEOF_PTR; } } continue; } case F_EFUNV: sprintf(buff, "%d", EXTRACT_UCHAR(pc++)); instr = EXTRACT_UCHAR(pc++) + ONEARG_MAX; break; case F_EFUN0: case F_EFUN1: case F_EFUN2: case F_EFUN3: if (instrs[instr].min_arg != instrs[instr].max_arg) { sprintf(buff, "%d", instr - F_EFUN0); } instr = EXTRACT_UCHAR(pc++) + ONEARG_MAX; break; } fprintf(f, "%s %s\n", get_f_name(instr), buff); if ((next_func >= 0) && ((pc - code) >= offsets[next_func])) { fprintf(f, "\n;; Function %s\n", FUNS[offsets[next_func + 1]].name); next_func += 2; if (next_func >= ((int) NUM_FUNS * 2)) next_func = -1; } } if (offsets) free(offsets); } #define INCLUDE_DEPTH 10 static void dump_line_numbers P2(FILE *, f, program_t *, prog) { unsigned short *fi; unsigned char *li_start; unsigned char *li_end; unsigned char *li; int addr; int sz; short s; if (!prog->line_info) { load_line_numbers(prog); if (!prog->line_info) { fprintf(f, "Failed to load line numbers\n"); return; } } fi = prog->file_info; li_end = (unsigned char *)(((char *)fi) + fi[0]); li_start = (unsigned char *)(fi + fi[1]); fi += 2; fprintf(f, "\nabsolute line -> (file, line) table:\n"); while (fi < (unsigned short *)li_start) { fprintf(f, "%i lines from %i [%s]\n", (int)fi[0], (int)fi[1], prog->strings[fi[1]-1]); fi += 2; } li = li_start; addr = 0; fprintf(f,"\naddress -> absolute line table:\n"); while (li < li_end) { sz = *li++; COPY_SHORT(&s, li); li += 2; fprintf(f, "%4x-%4x: %i\n", addr, addr + sz - 1, (int)s); addr += sz; } } #endif