1 /* todo: copyright/gpl stuff. */
4 #error "use it on your own risk"
12 #include <sys/types.h>
18 typedef unsigned char u8;
19 typedef unsigned short u16;
20 typedef unsigned int u32;
21 typedef unsigned long long u64;
24 static u8 *data, *data_start;
25 static u32 base_data, base_code, size_code;
27 static char *imm_chw[] = {
28 "b", /* 08 bits */ "w", /* 16 bits */
29 "d", /* 32 bits */ "q", /* 64 bits */
30 "n" /* unsigned int. hax */ ,
31 "sn" /* signed int. hax */
34 static char *vm_reg[] = {
35 "FLAGS", "IP", "RESERVED", "RESERVED",
36 "RESERVED", "RESERVED", "RESERVED", "RESERVED"
39 static void print_debug(const char *s)
41 fprintf(stderr, PS "0x%08x (0x%04x)\n", s, (u32) data,
45 static void pspace(void) { printf(" "); }
47 static void pcomma(void) { printf(", "); }
49 static void preg(u8 reg)
51 if (reg > 7) { assert(0); }
55 static void pvmreg(u8 reg)
57 if (reg > 7) { assert(0); }
58 printf("%s", vm_reg[reg]);
61 static void pdref(u8 x)
63 printf("%s", x ? "@" : "");
66 #define PIMM_READ(size) \
67 static void pimm##size(void) \
69 printf(size != 64 ? "%x" : "%llx", *((u##size *) data)); \
70 data += sizeof (u##size); \
78 static void pimm(u8 mod)
81 case 1: pimm16(); break;
82 case 2: pimm32(); break;
83 case 3: pimm64(); break;
84 case 0: default: assert(0);
88 static void pimmc(u8 imm_type)
90 if (imm_type > 5) { assert(0); }
91 printf("%s", imm_chw[imm_type]);
94 static void pflags(u8 flag)
97 case 0x0: printf("eq"); break;
98 case 0x1: printf("lte"); break;
99 case 0x2: printf("gte"); break;
100 case 0x3: printf("ulte"); break;
101 case 0x4: printf("ugte"); break;
105 static const char *breakopts[] = {
106 "Runaway program break",
107 "Get virtual machine version",
108 "undefined. WTF?", // "Skip"?
112 "Set compiler version"
115 static void pbreak(void)
119 if (i > 6) { printf("unknown break!"); assert(0);
120 } else printf("\"%s\"", breakopts[i]);
123 static void pinsn(void)
126 u8 opc = insn & 0x3f;
129 case 0x00: printf("BREAK"); pbreak(); break;
130 case 0x01: case 0x03:{
131 u8 opindex = insn & 0x80;
132 u8 c3264 = insn & 0x40;
137 u8 ebcnative = b1 & 0x20;
138 u8 relabs = b1 & 0x10;
143 printf("JMP%d%s", c3264 ? 64 : 32,
144 cond ? (flag ? "cs" : "cc") : "");
145 } else if (opc == 0x03) {
146 printf("CALL%d%s", c3264 ? 64 : 32,
147 ebcnative ? "EX" : "");
149 printf("%s", relabs ? "a" : ""); pspace();
151 if (!c3264) { // 32bit
163 u8 cond = insn & 0x80;
164 u8 flag = insn & 0x40;
165 printf("JMP8%s", cond ? (flag ? "cs" : "cc") : "");
169 case 0x04: printf("RET"); data++; break;
171 u8 opindex = insn & 0x80;
172 u8 c3264 = insn & 0x40;
176 u8 op2 = (b1 & 0x70) >> 4;
177 u8 dref2 = b1 & 0x80;
179 printf("CMP%d", !c3264 ? 32 : 64);
180 pflags(opc - 0x05); pspace();
182 pdref(dref2); preg(op2);
189 u8 opindex = insn & 0x80;
190 u8 c3264 = insn & 0x40;
195 u8 op2 = (b1 & 0x70) >> 4;
196 u8 dref2 = b1 & 0x80;
198 case 0x0a: printf("NOT"); break;
199 case 0x0b: printf("NEG"); break;
200 case 0x0c: printf("ADD"); break;
201 case 0x0d: printf("SUB"); break;
202 case 0x0e: printf("MUL"); break;
203 case 0x0f: printf("MULU"); break;
204 case 0x10: printf("DIV"); break;
205 case 0x11: printf("DIVU"); break;
206 case 0x12: printf("MOD"); break;
207 case 0x13: printf("MODU"); break;
208 case 0x14: printf("AND"); break;
209 case 0x15: printf("OR"); break;
210 case 0x16: printf("XOR"); break;
211 case 0x17: printf("SHL"); break;
212 case 0x18: printf("SHR"); break;
213 case 0x19: printf("ASHR"); break;
215 printf("\nopcode: %x\n", opc);
218 printf("%d", c3264 ? 64 : 32); pspace();
219 pdref(dref1); preg(op1); pcomma();
220 pdref(dref2); preg(op2);
227 u8 opindex = insn & 0x80;
228 u8 c3264 = insn & 0x40;
229 u8 opmod = opc - 0x1a; // 0b, 1w, 2d
234 u8 op2 = (b1 & 0x70) >> 4;
235 u8 dref2 = b1 & 0x80;
237 printf("EXTND"); pimmc(opmod);
238 printf("%d", c3264 ? 64 : 32); pspace();
239 pdref(dref1); preg(op1); pcomma();
240 pdref(dref2); preg(op2);
249 u8 op2 = (b1 & 0x70) >> 4;
251 printf("STORESP"); pspace();
252 preg(op1); pcomma(); pvmreg(op2);
256 u8 c3264 = insn & 0x40;
257 u8 i1632 = !!(insn & 0x80);
262 u8 op1index = b1 & 0x10;
264 printf("CMPI%d", !c3264 ? 32 : 64);
266 pflags(opc - 0x2d); pspace();
267 pdref(dref1); preg(op1);
281 case 0x1d: op1mod = 0; op2mod = 1; break; // MOVbw
282 case 0x1e: op1mod = 1; op2mod = 1; break; // MOVww
283 case 0x1f: op1mod = 2; op2mod = 1; break; // MOVdw
284 case 0x20: op1mod = 3; op2mod = 1; break; // MOVqw
285 case 0x21: op1mod = 0; op2mod = 2; break; // MOVbd
286 case 0x22: op1mod = 1; op2mod = 2; break; // MOVwd
287 case 0x23: op1mod = 2; op2mod = 2; break; // MOVdd
288 case 0x24: op1mod = 3; op2mod = 2; break; // MOVqd
290 case 0x25: op1mod = 5; op2mod = 1; break; // MOVsnw
291 case 0x26: op1mod = 5; op2mod = 2; break; // MOVsnq
293 case 0x28: op1mod = 3; op2mod = 3; break; // MOVqq
295 case 0x32: op1mod = 4; op2mod = 1; break; // MOVnw
296 case 0x33: op1mod = 4; op2mod = 2; break; // MOVnd
298 fprintf(stderr, "wtfopcode: %x\n", opc);
301 u8 mod = (insn & 0xc0) >> 6;
302 u8 op1index = mod & 0x2;
303 u8 op2index = mod & 0x1;
308 u8 op2 = (b1 & 0x70) >> 4;
309 u8 dref2 = b1 & 0x80;
311 printf("MOV"); pimmc(op1mod); pimmc(op2mod); pspace();
312 pdref(dref1); preg(op1);
313 // op2mod defines index width for *both* indexes
315 pspace(); pimm(op2mod);
317 pcomma(); pdref(dref2); preg(op2);
319 pspace(); pimm(op2mod);
324 u8 mod = (insn & 0xc0) >> 6;
328 u8 width = (b1 & 0x30) >> 4;
329 u8 op1index = b1 & 0x40;
331 printf("MOVI"); pimmc(width); pimmc(mod); pspace();
332 pdref(dref); preg(op1);
340 u8 mod = (insn & 0xc0) >> 6;
345 u8 op1index = (b1 & 0x40) >> 6;
347 printf("MOVIn"); pimmc(mod); pspace();
348 pdref(dref); preg(op1);
356 u8 mod = (insn & 0xc0) >> 6;
360 u8 op1index = b1 & 0x40;
362 printf("MOVREL"); pimmc(mod); pspace();
363 pdref(dref); preg(op1);
371 fprintf(stderr, "\nunknown opcode: 0x%02x\n", opc);
376 static void pheader(void)
378 printf("\n%08x: ", data - data_start);
381 int main(int argc, const char **argv)
384 fprintf(stderr, "usage: %s <pe-ebc>\n", argv[0]);
388 int fd = open(argv[1], O_RDONLY);
389 file_len = lseek(fd, 0, SEEK_END);
390 data_start = data = mmap(0, file_len, PROT_READ, MAP_SHARED, fd, 0);
393 if (memcmp(data, "MZ", 2) != 0) {
394 fprintf(stderr, "wrong DOS header: %c%c\n", *data, *(data + 1));
401 while (!found && ++data < (data + file_len)) {
402 if (memcmp(data, "PE", 2) == 0) {
409 fprintf(stderr, "no PE header found\n");
414 if (memcmp(data, "\xbc\x0e", 2) != 0) { // read '0xebc'
415 fprintf(stderr, "not an EBC image: 0x%02x%02x\n", *data,
421 while (!found && ++data < (data + file_len)) {
422 if (memcmp(data, "\x0b\x01", 2) == 0) { // read '0x10b'
423 print_debug("PE-opt");
429 fprintf(stderr, "no PE-opt header found\n");
433 fprintf(stderr, PS "0x%04x\n", "magic", *((u16 *) data));
436 fprintf(stderr, PS "0x%02x\n", "majorver", *((u8 *) data));
438 fprintf(stderr, PS "0x%02x\n", "minorver", *((u8 *) data));
441 // TODO: not sure if this is correct :/
442 size_code = *((u32 *) data);
443 print_debug("size_code");
444 fprintf(stderr, PS "0x%08x\n", "size_code", size_code);
445 data += 4 + 4 + 4; //u32, u32, u32
447 fprintf(stderr, PS "0x%08x\n", "entry_point", *((u32 *) data));
450 base_code = *((u32 *) data);
451 print_debug("base_code");
452 fprintf(stderr, PS "0x%08x\n", "base_code", base_code);
454 base_data = *((u32 *) data);
455 print_debug("base_data");
456 fprintf(stderr, PS "0x%08x\n", "base_data", base_data);
459 fprintf(stderr, PS "0x%08x\n", "???", *((u32 *) data));
461 data = data_start + base_code;
462 while (data <= (data_start + size_code)) {