-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathdisassemble.c
More file actions
206 lines (183 loc) · 4.46 KB
/
disassemble.c
File metadata and controls
206 lines (183 loc) · 4.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include "agent.h"
#include "code.h"
#include "compiler.h"
#include "constant.h"
#include "disassemble.h"
#include "opcode.h"
#include "str.h"
#include "value.h"
void print_const_pool(struct cb_code *code)
{
for (int i = 0; i < code->nconsts; i += 1) {
struct cb_const *const_ = &code->const_pool[i];
if (const_->type == CB_CONST_MODULE) {
cb_str name = cb_agent_get_string(cb_modspec_name(
const_->val.as_module));
printf("\t%d: <module %s>\n", i, cb_strptr(&name));
continue;
}
struct cb_value val = cb_const_to_value(const_);
cb_str as_str = cb_value_to_string(val);
printf("\t%d: %s\n", i, cb_strptr(&as_str));
cb_str_free(as_str);
}
}
int cb_disassemble_recursive(struct cb_code *code)
{
int result = cb_disassemble(code);
putchar('\n');
for (int i = 0; i < code->nconsts; i += 1) {
struct cb_const *c = &code->const_pool[i];
size_t name_id;
struct cb_code *inner_code;
if (c->type == CB_CONST_FUNCTION) {
name_id = c->val.as_function->name;
inner_code = c->val.as_function->code;
} else if (c->type == CB_CONST_MODULE) {
name_id = cb_modspec_name(c->val.as_module);
inner_code = cb_modspec_code(c->val.as_module);
} else {
continue;
}
cb_str name = cb_agent_get_string(name_id);
printf("%s %s\n", cb_const_type_name(c->type),
cb_strptr(&name));
result |= cb_disassemble_recursive(inner_code);
}
return result;
}
int cb_disassemble(struct cb_code *code)
{
puts("constants:");
print_const_pool(code);
puts("");
for (size_t i = 0; i < code->bytecode_len; i++) {
if (cb_disassemble_one(code->bytecode[i], i))
return 1;
}
return 0;
}
int cb_disassemble_one(cb_instruction instruction, size_t offset)
{
union cb_op_encoding encoding;
enum cb_opcode op;
cb_str tmp_str;
encoding.as_size_t = instruction;
op = encoding.unary.op;
size_t arg = encoding.unary.arg,
arg1 = encoding.binary.arg1,
arg2 = encoding.binary.arg2;
printf("%4ld: ", offset);
switch (op) {
/* no args */
case OP_HALT:
case OP_CONST_TRUE:
case OP_CONST_FALSE:
case OP_CONST_NULL:
case OP_ADD:
case OP_SUB:
case OP_MUL:
case OP_DIV:
case OP_MOD:
case OP_EXP:
case OP_POP:
case OP_ARRAY_GET:
case OP_ARRAY_SET:
case OP_EQUAL:
case OP_NOT_EQUAL:
case OP_LESS_THAN:
case OP_LESS_THAN_EQUAL:
case OP_GREATER_THAN:
case OP_GREATER_THAN_EQUAL:
case OP_BITWISE_OR:
case OP_BITWISE_AND:
case OP_BITWISE_XOR:
case OP_BITWISE_NOT:
case OP_NOT:
case OP_NEG:
case OP_DUP:
case OP_DUP_2:
case OP_RETURN:
case OP_NEW_STRUCT:
case OP_ROT_2:
case OP_ROT_3:
case OP_ROT_4:
case OP_THROW:
case OP_POP_TRY:
case OP_CATCH:
case OP_INC:
case OP_DEC:
case OP_LOAD_THIS:
printf("%s\n", cb_opcode_name(op));
return 0;
/* one arg */
case OP_JUMP:
case OP_JUMP_IF_TRUE:
case OP_JUMP_IF_FALSE:
case OP_LOAD_LOCAL:
case OP_STORE_LOCAL:
case OP_LOAD_UPVALUE:
case OP_STORE_UPVALUE:
case OP_ALLOCATE_LOCALS:
case OP_NEW_ARRAY_WITH_VALUES:
case OP_CALL:
case OP_CALL_METHOD:
case OP_IMPORT_MODULE:
case OP_PUSH_TRY: {
printf("%s(%zu)\n", cb_opcode_name(op), arg);
return 0;
}
case OP_APPLY_DEFAULT_ARG: {
size_t param_num = arg1,
next_param_addr = arg2;
printf("%s(%zu, %zu)\n", cb_opcode_name(op), param_num,
next_param_addr);
return 0;
}
case OP_LOAD_CONST:
/* TODO: show constant value */
printf("%s(%zu)\n", cb_opcode_name(op), arg);
return 0;
case OP_LOAD_GLOBAL:
case OP_DECLARE_GLOBAL:
case OP_STORE_GLOBAL:
case OP_LOAD_STRUCT:
case OP_STORE_STRUCT:
case OP_ADD_STRUCT_FIELD:
case OP_CONST_STRING:
case OP_LOAD_METHOD:
tmp_str = cb_agent_get_string(arg);
printf("%s(\"%s\")\n", cb_opcode_name(op), cb_strptr(&tmp_str));
return 0;
case OP_BIND_LOCAL:
case OP_BIND_UPVALUE:
printf("%s(%zu, %zu)\n", cb_opcode_name(op), arg1, arg2);
return 0;
case OP_SET_METHOD:
tmp_str = cb_agent_get_string(arg2);
printf("%s(%zu, %s)\n", cb_opcode_name(op), arg1,
cb_strptr(&tmp_str));
return 0;
case OP_LOAD_FROM_MODULE: {
const cb_modspec *spec;
cb_str modname, import_name;
spec = cb_agent_get_modspec(arg1);
modname = cb_agent_get_string(cb_modspec_name(spec));
import_name = cb_agent_get_string(
cb_modspec_get_export_name(spec, arg2));
printf("%s(\"%s\", \"%s\")\n", cb_opcode_name(op),
cb_strptr(&modname), cb_strptr(&import_name));
return 0;
}
case OP_MAX:
break;
}
fprintf(stderr, "Unknown bytecode instruction %u\n", op);
return -1;
#undef NEXT
#undef NEXT_USIZE
}