aboutsummaryrefslogtreecommitdiffstats
path: root/disassemble.c
diff options
context:
space:
mode:
authornop <nop>1997-03-03 03:44:59 +0000
committernop <nop>1997-03-03 03:44:59 +0000
commita515162931c35db517995e3427cb41cee2a63a0a (patch)
tree8e3f82edf617adebc676d878af284c0678dad555 /disassemble.c
downloadmoo-cvs-a515162931c35db517995e3427cb41cee2a63a0a.tar.gz
moo-cvs-a515162931c35db517995e3427cb41cee2a63a0a.tar.xz
moo-cvs-a515162931c35db517995e3427cb41cee2a63a0a.zip
Initial revision
Diffstat (limited to 'disassemble.c')
-rw-r--r--disassemble.c496
1 files changed, 496 insertions, 0 deletions
diff --git a/disassemble.c b/disassemble.c
new file mode 100644
index 0000000..d67e9ef
--- /dev/null
+++ b/disassemble.c
@@ -0,0 +1,496 @@
+/******************************************************************************
+ Copyright (c) 1994, 1995, 1996 Xerox Corporation. All rights reserved.
+ Portions of this code were written by Stephen White, aka ghond.
+ Use and copying of this software and preparation of derivative works based
+ upon this software are permitted. Any distribution of this software or
+ derivative works must comply with all applicable United States export
+ control laws. This software is made available AS IS, and Xerox Corporation
+ makes no warranty about the software, its performance or its conformity to
+ any specification. Any person obtaining a copy of this software is requested
+ to send their name and post office or electronic mail address to:
+ Pavel Curtis
+ Xerox PARC
+ 3333 Coyote Hill Rd.
+ Palo Alto, CA 94304
+ Pavel@Xerox.Com
+ *****************************************************************************/
+
+#include "my-stdio.h"
+
+#include "bf_register.h"
+#include "config.h"
+#include "db.h"
+#include "functions.h"
+#include "list.h"
+#include "opcode.h"
+#include "program.h"
+#include "storage.h"
+#include "streams.h"
+#include "unparse.h"
+#include "utils.h"
+#include "verbs.h"
+
+const char *mnemonics[256], *ext_mnemonics[256];
+
+struct mapping {
+ unsigned value;
+ const char *name;
+};
+
+struct mapping mappings[] = {
+ {OP_IF, "IF"},
+ {OP_WHILE, "WHILE"},
+ {OP_EIF, "ELSEIF"},
+ {OP_FORK, "FORK"},
+ {OP_FORK_WITH_ID, "FORK_NAMED"},
+ {OP_FOR_LIST, "FOR_LIST"},
+ {OP_FOR_RANGE, "FOR_RANGE"},
+ {OP_INDEXSET, "INDEXSET"},
+ {OP_PUSH_GET_PROP, "PUSH_GET_PROP"},
+ {OP_GET_PROP, "GET_PROP"},
+ {OP_CALL_VERB, "CALL_VERB"},
+ {OP_PUT_PROP, "PUT_PROP"},
+ {OP_BI_FUNC_CALL, "CALL_FUNC"},
+ {OP_IF_QUES, "IF_EXPR"},
+ {OP_REF, "INDEX"},
+ {OP_RANGE_REF, "RANGE"},
+ {OP_MAKE_SINGLETON_LIST, "MAKE_SINGLETON_LIST"},
+ {OP_CHECK_LIST_FOR_SPLICE, "CHECK_LIST_FOR_SPLICE"},
+ {OP_MULT, "MULTIPLY"},
+ {OP_DIV, "DIVIDE"},
+ {OP_MOD, "MOD"},
+ {OP_ADD, "ADD"},
+ {OP_MINUS, "SUBTRACT"},
+ {OP_EQ, "EQ"},
+ {OP_NE, "NE"},
+ {OP_LT, "LT"},
+ {OP_LE, "LE"},
+ {OP_GT, "GT"},
+ {OP_GE, "GE"},
+ {OP_IN, "IN"},
+ {OP_AND, "AND"},
+ {OP_OR, "OR"},
+ {OP_UNARY_MINUS, "NEGATE"},
+ {OP_NOT, "NOT"},
+ {OP_G_PUT, "PUT"},
+ {OP_G_PUSH, "PUSH"},
+ {OP_IMM, "PUSH_LITERAL"},
+ {OP_MAKE_EMPTY_LIST, "MAKE_EMPTY_LIST"},
+ {OP_LIST_ADD_TAIL, "LIST_ADD_TAIL"},
+ {OP_LIST_APPEND, "LIST_APPEND"},
+ {OP_PUSH_REF, "PUSH_INDEX"},
+ {OP_PUT_TEMP, "PUT_TEMP"},
+ {OP_PUSH_TEMP, "PUSH_TEMP"},
+ {OP_JUMP, "JUMP"},
+ {OP_RETURN, "RETURN"},
+ {OP_RETURN0, "RETURN 0"},
+ {OP_DONE, "DONE"},
+ {OP_POP, "POP"}};
+
+struct mapping ext_mappings[] = {
+ {EOP_RANGESET, "RANGESET"},
+ {EOP_LENGTH, "LENGTH"},
+ {EOP_PUSH_LABEL, "PUSH_LABEL"},
+ {EOP_SCATTER, "SCATTER"},
+ {EOP_EXP, "EXPONENT"},
+ {EOP_CATCH, "CATCH"},
+ {EOP_END_CATCH, "END_CATCH"},
+ {EOP_TRY_EXCEPT, "TRY_EXCEPT"},
+ {EOP_END_EXCEPT, "END_EXCEPT"},
+ {EOP_TRY_FINALLY, "TRY_FINALLY"},
+ {EOP_END_FINALLY, "END_FINALLY"},
+ {EOP_CONTINUE, "CONTINUE"},
+ {EOP_WHILE_ID, "WHILE_ID"},
+ {EOP_EXIT, "EXIT"},
+ {EOP_EXIT_ID, "EXIT_ID"}};
+
+static void
+initialize_tables(void)
+{
+ static int tables_initialized = 0;
+ unsigned i;
+
+ if (tables_initialized)
+ return;
+
+ for (i = 0; i < 256; i++) {
+ mnemonics[i] = "*** Unknown opcode ***";
+ ext_mnemonics[i] = "*** Unknown extended opcode ***";
+ }
+
+ for (i = 0; i < Arraysize(mappings); i++)
+ mnemonics[mappings[i].value] = mappings[i].name;
+
+ for (i = 0; i < Arraysize(ext_mappings); i++)
+ ext_mnemonics[ext_mappings[i].value] = ext_mappings[i].name;
+
+ tables_initialized = 1;
+}
+
+typedef void (*Printer)(const char *, void *);
+static Printer print;
+static void *print_data;
+static int bytes_width, max_bytes_width;
+
+static void
+output(Stream *s)
+{
+ (*print)(reset_stream(s), print_data);
+}
+
+static void
+new_insn(Stream *s, unsigned pc)
+{
+ stream_printf(s, "%3d:", pc);
+ bytes_width = max_bytes_width;
+}
+
+static unsigned
+add_bytes(Stream *s, Byte *vector, unsigned pc, unsigned length)
+{
+ unsigned arg = 0, b;
+
+ while (length--) {
+ if (bytes_width == 0) {
+ output(s);
+ stream_add_string(s, " ");
+ bytes_width = max_bytes_width;
+ }
+ b = vector[pc++];
+ stream_printf(s, " %03d", b);
+ arg = (arg << 8) + b;
+ bytes_width--;
+ }
+
+ return arg;
+}
+
+static void
+finish_insn(Stream *s, Stream *insn)
+{
+ while (bytes_width--)
+ stream_add_string(s, " ");
+ stream_add_string(s, reset_stream(insn));
+ output(s);
+}
+
+static void
+disassemble(Program *prog, Printer p, void *data)
+{
+ Stream *s = new_stream(100);
+ Stream *insn = new_stream(50);
+ int i, l;
+ unsigned pc;
+ Bytecodes bc;
+ const char *ptr;
+ const char **names = prog->var_names;
+ unsigned tmp, num_names = prog->num_var_names;
+# define NAMES(i) (tmp = i, \
+ tmp < num_names ? names[tmp] \
+ : "*** Unknown variable ***")
+ Var *literals = prog->literals;
+
+ initialize_tables();
+ print = p;
+ print_data = data;
+ stream_printf(s, "Language version number: %d", (int) prog->version);
+ output(s);
+ stream_printf(s, "First line number: %d", prog->first_lineno);
+ output(s);
+
+ for (i = -1; i < 0 || i < prog->fork_vectors_size; i++) {
+ output(s);
+ if (i == -1) {
+ stream_printf(s, "Main code vector:");
+ output(s);
+ stream_printf(s, "=================");
+ output(s);
+ bc = prog->main_vector;
+ } else {
+ stream_printf(s, "Forked code vector %d:", i);
+ l = stream_length(s);
+ output(s);
+ while (l--)
+ stream_add_char(s, '=');
+ output(s);
+ bc = prog->fork_vectors[i];
+ }
+
+ stream_printf(s, "[Bytes for labels = %d, literals = %d, ",
+ bc.numbytes_label, bc.numbytes_literal);
+ stream_printf(s, "forks = %d, variables = %d, stack refs = %d]",
+ bc.numbytes_fork, bc.numbytes_var_name,
+ bc.numbytes_stack);
+ output(s);
+ stream_printf(s, "[Maximum stack size = %d]", bc.max_stack);
+ output(s);
+
+ max_bytes_width = 5;
+
+ for (pc = 0; pc < bc.size;) {
+ Byte b;
+ unsigned arg;
+# define ADD_BYTES(n) (arg = add_bytes(s, bc.vector, pc, n), \
+ pc += n, \
+ arg)
+ unsigned a1, a2;
+
+ new_insn(s, pc);
+ b = add_bytes(s, bc.vector, pc++, 1);
+ if (b != OP_EXTENDED)
+ stream_add_string(insn, COUNT_TICK(b) ? " * " : " ");
+ if (IS_OPTIM_NUM_OPCODE(b))
+ stream_printf(insn, "NUM %d", OPCODE_TO_OPTIM_NUM(b));
+ else if (IS_PUSH_n(b))
+ stream_printf(insn, "PUSH %s", NAMES(PUSH_n_INDEX(b)));
+ else if (IS_PUT_n(b))
+ stream_printf(insn, "PUT %s", NAMES(PUT_n_INDEX(b)));
+ else if (b == OP_EXTENDED) {
+ b = ADD_BYTES(1);
+ stream_add_string(insn, COUNT_EOP_TICK(b) ? " * " : " ");
+ stream_add_string(insn, ext_mnemonics[b]);
+ switch ((Extended_Opcode) b) {
+ case EOP_WHILE_ID:
+ a1 = ADD_BYTES(bc.numbytes_var_name);
+ a2 = ADD_BYTES(bc.numbytes_label);
+ stream_printf(insn, " %s %d", NAMES(a1), a2);
+ break;
+ case EOP_EXIT_ID:
+ stream_printf(insn, " %s",
+ NAMES(ADD_BYTES(bc.numbytes_var_name)));
+ /* fall thru */
+ case EOP_EXIT:
+ a1 = ADD_BYTES(bc.numbytes_stack);
+ a2 = ADD_BYTES(bc.numbytes_label);
+ stream_printf(insn, " %d %d", a1, a2);
+ break;
+ case EOP_PUSH_LABEL: case EOP_END_CATCH:
+ case EOP_END_EXCEPT: case EOP_TRY_FINALLY:
+ stream_printf(insn, " %d", ADD_BYTES(bc.numbytes_label));
+ break;
+ case EOP_TRY_EXCEPT:
+ stream_printf(insn, " %d", ADD_BYTES(1));
+ break;
+ case EOP_LENGTH:
+ stream_printf(insn, " %d", ADD_BYTES(bc.numbytes_stack));
+ break;
+ case EOP_SCATTER:
+ {
+ int i, nargs = ADD_BYTES(1);
+
+ a1 = ADD_BYTES(1);
+ a2 = ADD_BYTES(1);
+ stream_printf(insn, " %d/%d/%d:", nargs, a1, a2);
+ for (i = 0; i < nargs; i++) {
+ a1 = ADD_BYTES(bc.numbytes_var_name);
+ a2 = ADD_BYTES(bc.numbytes_label);
+ stream_printf(insn, " %s/%d", NAMES(a1), a2);
+ }
+ stream_printf(insn, " %d",
+ ADD_BYTES(bc.numbytes_label));
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ stream_add_string(insn, mnemonics[b]);
+ switch ((Opcode) b) {
+ case OP_IF: case OP_IF_QUES: case OP_EIF:
+ case OP_AND: case OP_OR: case OP_JUMP:
+ case OP_WHILE:
+ stream_printf(insn, " %d", ADD_BYTES(bc.numbytes_label));
+ break;
+ case OP_FORK:
+ stream_printf(insn, " %d", ADD_BYTES(bc.numbytes_fork));
+ break;
+ case OP_FORK_WITH_ID:
+ a1 = ADD_BYTES(bc.numbytes_fork);
+ a2 = ADD_BYTES(bc.numbytes_var_name);
+ stream_printf(insn, " %d %s", a1, NAMES(a2));
+ break;
+ case OP_FOR_LIST:
+ case OP_FOR_RANGE:
+ a1 = ADD_BYTES(bc.numbytes_var_name);
+ a2 = ADD_BYTES(bc.numbytes_label);
+ stream_printf(insn, " %s %d", NAMES(a1), a2);
+ break;
+ case OP_G_PUSH:
+ case OP_G_PUT:
+ stream_printf(insn, " %s",
+ NAMES(ADD_BYTES(bc.numbytes_var_name)));
+ break;
+ case OP_IMM:
+ {
+ Var v;
+
+ v = literals[ADD_BYTES(bc.numbytes_literal)];
+ switch (v.type) {
+ case TYPE_OBJ:
+ stream_printf(insn, " #%d", v.v.obj);
+ break;
+ case TYPE_INT:
+ stream_printf(insn, " %d", v.v.num);
+ break;
+ case TYPE_STR:
+ stream_add_string(insn, " \"");
+ for (ptr = v.v.str; *ptr; ptr++) {
+ if (*ptr == '"' || *ptr == '\\')
+ stream_add_char(insn, '\\');
+ stream_add_char(insn, *ptr);
+ }
+ stream_add_char(insn, '"');
+ break;
+ case TYPE_ERR:
+ stream_printf(insn, " %s", error_name(v.v.err));
+ break;
+ default:
+ stream_printf(insn, " <literal type = %d>",
+ v.type);
+ break;
+ }
+ }
+ break;
+ case OP_BI_FUNC_CALL:
+ stream_printf(insn, " %s", name_func_by_num(ADD_BYTES(1)));
+ default:
+ break;
+ }
+ }
+
+ finish_insn(s, insn);
+ }
+ }
+
+ free_stream(s);
+ free_stream(insn);
+}
+
+static void
+print_line(const char *line, void *data)
+{
+ FILE *f = data;
+
+ fprintf(f, "%s\n", line);
+}
+
+void
+disassemble_to_file(FILE *fp, Program *prog)
+{
+ disassemble(prog, print_line, fp);
+}
+
+void
+disassemble_to_stderr(Program *prog)
+{
+ disassemble_to_file(stderr, prog);
+}
+
+struct data {
+ char **lines;
+ int used, max;
+};
+
+static void
+add_line(const char *line, void *data)
+{
+ struct data *d = data;
+
+ if (d->used >= d->max) {
+ int new_max = (d->max == 0 ? 20 : d->max * 2);
+ char **new = mymalloc(sizeof(char **) * new_max, M_DISASSEMBLE);
+ int i;
+
+ for (i = 0; i < d->used; i++)
+ new[i] = d->lines[i];
+ if (d->lines)
+ myfree(d->lines, M_DISASSEMBLE);
+ d->lines = new;
+ d->max = new_max;
+ }
+
+ d->lines[d->used++] = str_dup(line);
+}
+
+static package
+bf_disassemble(Var arglist, Byte next, void *vdata, Objid progr)
+{
+ Objid oid = arglist.v.list[1].v.obj;
+ Var desc = arglist.v.list[2];
+ db_verb_handle h;
+ struct data data;
+ Var r;
+ int i;
+ enum error e;
+
+ if ((e = validate_verb_descriptor(desc)) != E_NONE
+ || (e = E_INVARG, !valid(oid))) {
+ free_var(arglist);
+ return make_error_pack(e);
+ }
+
+ h = find_described_verb(oid, desc);
+ free_var(arglist);
+
+ if (!h.ptr)
+ return make_error_pack(E_VERBNF);
+ if (!db_verb_allows(h, progr, VF_READ))
+ return make_error_pack(E_PERM);
+
+ data.lines = 0;
+ data.used = data.max = 0;
+ disassemble(db_verb_program(h), add_line, &data);
+ r = new_list(data.used);
+ for (i = 1; i <= data.used; i++) {
+ r.v.list[i].type = TYPE_STR;
+ r.v.list[i].v.str = data.lines[i - 1];
+ }
+ if (data.lines)
+ myfree(data.lines, M_DISASSEMBLE);
+ return make_var_pack(r);
+}
+
+void
+register_disassemble(void)
+{
+ register_function("disassemble", 2, 2, bf_disassemble, TYPE_OBJ, TYPE_ANY);
+}
+
+char rcsid_disassemble[] = "$Id";
+
+/* $Log$
+/* Revision 1.1 1997/03/03 03:44:59 nop
+/* Initial revision
+/*
+ * Revision 2.6 1996/04/08 01:09:40 pavel
+ * Added missing mnemonic-table entry for EOP_PUSH_LABEL. Release 1.8.0p3.
+ *
+ * Revision 2.5 1996/02/08 07:15:40 pavel
+ * Added support for exponentiation expression, named WHILE loop, and BREAK
+ * and CONTINUE statements. Removed redundant error-value unparsing code.
+ * Added printing of language version number. Added support for EOPs that
+ * cost ticks. Renamed TYPE_NUM to TYPE_INT. Added disassemble_to_file().
+ * Updated copyright notice for 1996. Release 1.8.0beta1.
+ *
+ * Revision 2.4 1996/01/16 07:16:38 pavel
+ * Add EOP_SCATTER handling. Added support for line-wrapping in the display
+ * of the bytes of an instruction. Release 1.8.0alpha6.
+ *
+ * Revision 2.3 1995/12/31 00:07:49 pavel
+ * Added support for EOP_LENGTH and stack references in general.
+ * Release 1.8.0alpha4.
+ *
+ * Revision 2.2 1995/12/28 00:31:29 pavel
+ * Added support for numeric verb descriptors in disassemble() built-in.
+ * Release 1.8.0alpha3.
+ *
+ * Revision 2.1 1995/12/11 08:10:32 pavel
+ * Accounted for verb programs never being NULL any more.
+ * Release 1.8.0alpha2.
+ *
+ * Revision 2.0 1995/11/30 05:00:54 pavel
+ * New baseline version, corresponding to release 1.8.0alpha1.
+ *
+ * Revision 1.1 1995/11/30 05:00:43 pavel
+ * Initial revision
+ */