1 /****************************************************************************
2 * Copyright (C) 2012 by Matteo Franchin *
3 * *
4 * This file is part of Box. *
5 * *
6 * Box is free software: you can redistribute it and/or modify it *
7 * under the terms of the GNU Lesser General Public License as published *
8 * by the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * Box is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU Lesser General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU Lesser General Public *
17 * License along with Box. If not, see <http://www.gnu.org/licenses/>. *
18 ****************************************************************************/
19
20 #include <stdio.h>
21 #include <assert.h>
22
23 #include "types.h"
24 #include "strutils.h"
25
26 #include "vm_priv.h"
27 #include "vmdasm_priv.h"
28
29
30 /**
31 * Structure used to pass arguments to My_Op_Dasm.
32 */
33 typedef struct {
34 BoxVMWord *bytecode;
35 FILE *output;
36 } MyDasmData;
37
38
39 static void
My_Arg_To_Str(char * out,size_t out_size,int arg_format,BoxTypeId args_type,BoxInt arg_value)40 My_Arg_To_Str(char *out, size_t out_size,
41 int arg_format, BoxTypeId args_type, BoxInt arg_value) {
42 BoxInt arg_abs_value = abs(arg_value);
43 char reg_char = "vr"[arg_value >= 0],
44 type_char = "cirpo"[args_type];
45 switch(arg_format) {
46 case BOXCONTCATEG_GREG:
47 sprintf(out, "g%c%c" SInt, reg_char, type_char, arg_abs_value);
48 break;
49 case BOXCONTCATEG_LREG:
50 sprintf(out, "%c%c" SInt, reg_char, type_char, arg_abs_value);
51 break;
52 case BOXCONTCATEG_PTR:
53 if (arg_value < 0)
54 sprintf(out, "%c[ro0 - " SInt "]", type_char, arg_abs_value);
55 else if (arg_value == 0)
56 sprintf(out, "%c[ro0]", type_char);
57 else
58 sprintf(out, "%c[ro0 + " SInt "]", type_char, arg_abs_value);
59 break;
60 case BOXCONTCATEG_IMM:
61 if (args_type == BOXTYPEID_CHAR)
62 arg_value = (BoxInt) ((BoxChar) arg_value);
63 sprintf(out, SInt, arg_value);
64 break;
65 default:
66 abort();
67 }
68 }
69
70 static void
My_Data_To_Str(char * out,size_t out_size,BoxTypeId t,void * data)71 My_Data_To_Str(char *out, size_t out_size, BoxTypeId t, void *data) {
72 switch (t) {
73 case BOXTYPEID_CHAR:
74 sprintf(out, SChar, *((BoxChar *) data));
75 break;
76 case BOXTYPEID_INT:
77 sprintf(out, SInt, *((BoxInt *) data));
78 break;
79 case BOXTYPEID_REAL:
80 sprintf(out, SReal, *((BoxReal *) data));
81 break;
82 case BOXTYPEID_POINT:
83 sprintf(out, SPoint,
84 ((BoxPoint *) data)->x, ((BoxPoint *) data)->y);
85 break;
86 default:
87 sprintf(out, "???");
88 break;
89 }
90 }
91
92 static BoxTask
My_Op_Dasm(BoxVMDasm * dasm,void * pass)93 My_Op_Dasm(BoxVMDasm *dasm, void *pass) {
94 MyDasmData *data = pass;
95 FILE *output = data->output;
96 BoxOp *op = & dasm->op;
97 const char *op_name;
98 const size_t arg_buf_size = 64;
99 char arg_buf[BOX_OP_MAX_NUM_ARGS + 1][arg_buf_size];
100 int num_written_bufs;
101 int num_args;
102
103 if (dasm->op_desc) {
104 op_name = dasm->op_desc->name; /* op name */
105 num_args = dasm->op_desc->num_args; /* num. of args */
106
107 } else {
108 op_name = "???";
109 num_args = 0;
110 }
111
112 /* First we do arguments pre-processing. */
113 switch (op->id) {
114 case BOXOP_JMP_I:
115 case BOXOP_JC_I:
116 op->args[0] += dasm->op_pos;
117 op->args[0] *= sizeof(BoxVMWord);
118 break;
119 default:
120 break;
121 }
122
123 /* Now we convert the arguments to string. */
124 num_written_bufs = 0;
125 if (num_args > 0) {
126 BoxTypeId t = dasm->op_desc->t_id;
127 int i;
128
129 assert(num_args <= BOX_OP_MAX_NUM_ARGS);
130
131 for (i = 0; i < num_args; i++)
132 My_Arg_To_Str(arg_buf[i], arg_buf_size,
133 (op->args_forms >> (2*i)) & 0x3, t, op->args[i]);
134
135 if (op->has_data)
136 My_Data_To_Str(arg_buf[i++], arg_buf_size, t, op->data);
137
138 num_written_bufs = i;
139 }
140
141 /* Finally we compose the instruction string, starting from its name... */
142 fprintf(output, SUInt "\t", (BoxUInt) (dasm->op_pos * sizeof(BoxVMWord)));
143 if (dasm->vm->attr.hexcode)
144 fprintf(output, BoxVMWord_Fmt"\t", data->bytecode[dasm->op_pos]);
145 fprintf(output, "%s", op_name);
146
147 /* ...and the arguments. */
148 {
149 int i;
150 char *sep = " ";
151
152 for (i = 0; i < num_written_bufs; i++, sep = ", ")
153 fprintf(output, "%s%s", sep, arg_buf[i]);
154 }
155
156 /* Now we do any post-processing of the stringified arguments. */
157 switch (op->id) {
158 case BOXOP_CALL_I:
159 case BOXOP_CALL_Iimm:
160 {
161 BoxVMProcTable *pt = & dasm->vm->proc_table;
162 BoxInt call_num = ((op->id == BOXOP_CALL_I) ?
163 op->args[0] : *((BoxInt *) op->data));
164
165 if (call_num >= 1 || call_num <= BoxArr_Num_Items(& pt->installed)) {
166 BoxVMProcInstalled *p = BoxArr_Item_Ptr(& pt->installed, call_num);
167 char *call_name, *trunc_name;
168
169 call_name = (p->desc) ? p->desc : p->name;
170 trunc_name = (call_name) ? Str_Cut(call_name, 40, 85) : NULL;
171 fprintf(output, " ('%.40s')", (trunc_name) ? trunc_name : "?");
172 Box_Mem_Free(trunc_name);
173 }
174 }
175 break;
176
177 case BOXOP_CREATE_I:
178 case BOXOP_TYPEOF_I:
179 {
180 BoxTypeId type_id = op->args[0];
181 BoxType *type = BoxVM_Get_Installed_Type(dasm->vm, type_id);
182 if (type) {
183 char *type_repr = BoxType_Get_Repr(type);
184 if (type_repr) {
185 char *trunc_type_repr = Str_Cut(type_repr, 40, 85);
186
187 if (trunc_type_repr) {
188 Box_Mem_Free(type_repr);
189 type_repr = trunc_type_repr;
190 }
191
192 fprintf(output, " ('%.40s')", type_repr);
193 Box_Mem_Free(type_repr);
194 }
195 }
196 }
197 break;
198
199 default:
200 break;
201 }
202
203 fprintf(output, "\n");
204
205 /* Print the remaining instruction words in hex. */
206 if (dasm->vm->attr.hexcode) {
207 size_t i;
208 for (i = 1; i < op->next; i++)
209 fprintf(output, "\t"BoxVMWord_Fmt"\n",
210 data->bytecode[dasm->op_pos + i]);
211 }
212
213 return BOXTASK_OK;
214 }
215
216 /* Traduce il codice binario della VM, in formato testo.
217 * prog e' il puntatore all'inizio del codice, dim e' la dimensione del codice
218 * da tradurre (espresso in "numero di BoxVMWord").
219 */
220 BoxTask
BoxVM_Disassemble(BoxVM * vm,FILE * output,const void * prog,size_t dim)221 BoxVM_Disassemble(BoxVM *vm, FILE *output, const void *prog, size_t dim) {
222 MyDasmData data;
223 data.output = output;
224 data.bytecode = (void *) prog;
225 return BoxVM_Disassemble_Block(vm, prog, dim, My_Op_Dasm, & data);
226 }
227