enhanced ebc disassembler
[dis-ebc.git] / dis-ebc.c
1 /* todo: copyright/gpl stuff. */
2
3 #ifndef __i386__
4 #error "use it on your own risk"
5 #endif
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdarg.h>
10 #include <stdint.h>
11 #include <unistd.h>
12 #include <sys/mman.h>
13 #include <fcntl.h>
14 #include <sys/types.h>
15 #include <string.h>
16 #include <assert.h>
17
18 #define PS "%-10s: "
19
20
21 typedef unsigned char u8;
22 typedef signed char s8;
23 typedef uint16_t u16;
24 typedef int16_t s16;
25 typedef uint32_t u32;
26 typedef int32_t s32;
27 typedef uint64_t u64;
28 typedef int64_t s64;
29
30
31 #define MAX_STRING_LEN 100
32 #define MAX_INSTRUCTION_LEN 40
33
34 typedef struct _instruction {
35         int offsetInFile;
36         int offsetInCode;
37
38         u8 bytes[MAX_INSTRUCTION_LEN];
39         int bytePos;
40
41         char string[MAX_STRING_LEN];
42         int stringPos;
43
44         int isJump;
45         int jumpAddress;
46
47         int isCall;
48         int callAddress;
49
50         int isCallTarget;
51         int isJumpTarget;
52
53         int callLabel;
54         int jumpLabel;
55
56         struct _instruction *next;
57 } instruction;
58
59 typedef struct _statistics {
60         int maxInstructionLen;
61 } statistics;
62
63 static instruction* instruction_new(int offsetInFile, int offsetInCode) {
64         instruction *inst = malloc(sizeof(instruction));
65         assert(inst != NULL);
66
67         memset(inst, 0, sizeof(instruction));
68
69         inst->offsetInFile = offsetInFile;
70         inst->offsetInCode = offsetInCode;
71
72         return inst;
73 }
74
75 static void instruction_print(instruction *inst, const char *c) {
76         int len = strlen(c);
77         assert((inst->stringPos+len) < MAX_STRING_LEN);
78         for (int i=0; i<len; i++)
79                 inst->string[inst->stringPos++] = c[i];
80 }
81
82 static void instruction_push_byte(instruction *inst, u8 byte) {
83         assert((inst->bytePos+1) < MAX_INSTRUCTION_LEN);
84         inst->bytes[inst->bytePos++] = byte;
85 }
86
87 static instruction *first_instruction;
88 static instruction *current_instruction;
89 static int current_call_label=0;
90 static int current_jump_label=0;
91 static statistics stat;
92 static int entry_point;
93
94
95 /* 
96  * BEGIN - interface functions
97  */
98 static void i_begin(int offsetInFile, int offsetInCode) {
99         if (first_instruction == NULL) {
100                 first_instruction = current_instruction = instruction_new(offsetInFile, offsetInCode);
101         } else {
102                 assert(current_instruction->next == 0);
103                 current_instruction->next = instruction_new(offsetInFile, offsetInCode);
104                 current_instruction = current_instruction->next;
105         }
106 }
107
108 static void i_print(const char *fmt, ...) {
109         assert(current_instruction != NULL);
110
111         va_list args;
112         char str[MAX_STRING_LEN];
113
114         memset(str, 0, MAX_STRING_LEN);
115
116         va_start(args, fmt);
117         vsprintf(str, fmt, args);
118         instruction_print(current_instruction, str);
119         va_end(args);
120 }
121
122 static u8 i_push(u8 byte) {
123         assert(current_instruction != NULL);
124         instruction_push_byte(current_instruction, byte);
125         return byte;
126 }
127
128 static void i_set_relative_call(int relAddr) {
129         current_instruction->isCall=1;
130         current_instruction->callAddress = current_instruction->offsetInCode + current_instruction->bytePos + relAddr;
131         /*i_print("[call to 0x%08x] ", current_instruction->callAddress);*/
132 }
133
134 static void i_set_relative_jmp(int relAddr) {
135         current_instruction->isJump=1;
136         // FIXME: is this correct ?
137         current_instruction->jumpAddress = current_instruction->offsetInCode + current_instruction->bytePos + relAddr;
138         /*current_instruction->jumpAddress = current_instruction->offsetInCode + relAddr;*/
139         /*i_print("[jump to 0x%08x] ", current_instruction->jumpAddress);*/
140 }
141
142 static int i_get_jump_label(int absoluteCodeOffset) {
143         instruction *i = first_instruction;
144         while (i != NULL) {
145                 if (i->offsetInCode == absoluteCodeOffset && i->isJumpTarget) 
146                         return i->jumpLabel;
147                 i = i->next;
148         }
149         return -1;
150 }
151 static int i_get_call_label(int absoluteCodeOffset) {
152         instruction *i = first_instruction;
153         while (i != NULL) {
154                 if (i->offsetInCode == absoluteCodeOffset && i->isCallTarget) 
155                         return i->callLabel;
156                 i = i->next;
157         }
158         return -1;
159 }
160
161 static void i_dump() {
162         int k;
163
164         instruction *i = first_instruction;
165         while (i != NULL) {
166                 if (i->offsetInCode == entry_point)
167                         printf("\n\nENTRY_POINT:\n");
168                 if (i->isCallTarget) 
169                         printf("\n\nfunction%d:\n", i->callLabel);
170                 if (i->isJumpTarget) 
171                         printf("label%d: \n", i->jumpLabel);
172
173                 printf("\t0x%08x:", i->offsetInCode);
174                 for (k=0; k<stat.maxInstructionLen; k++) {
175                         if (k<i->bytePos) 
176                                 printf(" %02x", i->bytes[k]);
177                         else
178                                 printf("   ");
179                 }
180                 if (i->isCall) 
181                         printf(" %s [call function%d]\n", i->string, i_get_call_label(i->callAddress));
182                 else if (i->isJump)
183                         printf(" %s [jump label%d]\n", i->string, i_get_jump_label(i->jumpAddress));
184                 else
185                         printf(" %s\n", i->string);
186                 i = i->next;
187         }
188 }
189
190 static void i_mark_jump_target(int absoluteCodeOffset) {
191         // search in list for address and set isJumpTarget = true
192         instruction *i = first_instruction;
193         while (i != NULL) {
194                 if (i->offsetInCode == absoluteCodeOffset) {
195                         i->isJumpTarget++;
196                         return;
197                 }
198                 i = i->next;
199         }
200         assert(0);
201 }
202 static void i_mark_call_target(int absoluteCodeOffset) {
203         // search in list for address and set isCallTarget = true
204         instruction *i = first_instruction;
205         while (i != NULL) {
206                 if (i->offsetInCode == absoluteCodeOffset) {
207                         i->isCallTarget++;
208                         return;
209                 }
210                 i = i->next;
211         }
212         assert(0);
213 }
214
215 static void i_mark_jump_targets() {
216         // search the whole list for jumps and call
217         // i_mark_jump_target() for every of them 
218         instruction *i = first_instruction;
219         while (i != NULL) {
220                 if (i->isJump) 
221                         i_mark_jump_target(i->jumpAddress);
222                 i = i->next;
223         }
224 }
225
226 static void i_mark_call_targets() {
227         // search the whole list for calls and call
228         // i_mark_call_target() for every of them 
229         instruction *i = first_instruction;
230         while (i != NULL) {
231                 if (i->isCall) 
232                         i_mark_call_target(i->callAddress);
233                 i = i->next;
234         }
235 }
236
237 static void i_enumerate_jump_targets() {
238         instruction *i = first_instruction;
239         while (i != NULL) {
240                 if (i->isJumpTarget) 
241                         i->jumpLabel = current_jump_label++;
242                 i = i->next;
243         }
244 }
245
246 static void i_enumerate_call_targets() {
247         instruction *i = first_instruction;
248         while (i != NULL) {
249                 if (i->isCallTarget) 
250                         i->callLabel = current_call_label++;
251                 i = i->next;
252         }
253 }
254
255 static void i_make_statistics() {
256         instruction *i = first_instruction;
257         while (i != NULL) {
258                 if (i->bytePos > stat.maxInstructionLen) {
259                         stat.maxInstructionLen = i->bytePos;
260                 }
261                 i = i->next;
262         }
263 }
264
265 static void i_end() {
266         i_mark_jump_targets();
267         i_mark_call_targets();
268
269         i_enumerate_jump_targets();
270         i_enumerate_call_targets();
271
272         i_make_statistics();
273 }
274
275 static void i_cleanup() {
276         instruction *current_inst = first_instruction;
277         instruction *next;
278
279         first_instruction = NULL;
280         while (current_inst != NULL) {
281                 next = current_inst->next;
282                 free(current_inst);
283                 current_inst = next;
284         }
285 }
286
287 /* 
288  * END - interface functions
289  */
290
291 static int file_len;
292 static u8 *data, *data_start;
293 static u32 base_data, base_code, size_code;
294
295 static char *imm_chw[] = {
296         "b", /* 08 bits */ "w", /* 16 bits */
297         "d", /* 32 bits */ "q", /* 64 bits */
298         "n" /* unsigned int. hax */ ,
299         "sn" /* signed int. hax */
300 };
301
302 static char *vm_reg[] = {
303         "FLAGS", "IP", "RESERVED", "RESERVED",
304         "RESERVED", "RESERVED", "RESERVED", "RESERVED"
305 };
306
307 static void print_debug(const char *s)
308 {
309         fprintf(stderr, PS "0x%08x (0x%04x)\n", s, (u32) data,
310                 data - data_start);
311 }
312
313 static void pspace(void) { i_print(" "); }
314 static void pcomma(void) { i_print(", "); }
315
316 static void preg(u8 reg)
317 {
318         if (reg > 7) { assert(0); }
319         i_print("r%1d", reg);
320 }
321
322 static void pvmreg(u8 reg)
323 {
324         if (reg > 7) { assert(0); }
325         i_print("%s", vm_reg[reg]);
326 }
327
328 static void pdref(u8 x)
329 {
330         i_print("%s", x ? "@" : "");
331 }
332
333 #define PIMM_READ(size) \
334         static void pimm##size(void) \
335         { \
336                 i_print(size != 64 ? "%x" : "%llx", *((u##size *) data)); \
337                 for (int i=0; i<size/8; i++) \
338                         i_push(*data++); \
339         }
340
341 PIMM_READ(8);
342 PIMM_READ(16);
343 PIMM_READ(32);
344 PIMM_READ(64);
345
346 static void pimm(u8 mod)
347 {
348         switch (mod) {
349         case 1: pimm16(); break;
350         case 2: pimm32(); break;
351         case 3: pimm64(); break;
352         case 0: default: assert(0);
353         }
354 }
355
356 #define PIDX_READ(size) \
357         static void pidx##size(void) \
358         { \
359                 u##size d = *((u##size *)data); \
360                 u##size sign = (d >> (size-1))&1; \
361                 u##size nat_bits = ((d>>(size-4))&0x7) * (size/8);\
362                 u##size c_bits = size - nat_bits - 4;\
363                 u##size c = (d>>nat_bits)&((1ULL<<c_bits)-1);\
364                 u##size n = d & ((1ULL<<nat_bits)-1);\
365                 i_print(size != 64 ? "{%c %dn %dc}" : "{%c %lldn %lldc}", sign ? '-' : '+', n, c); \
366                 for (int i=0; i<size/8; i++) \
367                         i_push(*data++); \
368         }
369
370 PIDX_READ(8);
371 PIDX_READ(16);
372 PIDX_READ(32);
373 PIDX_READ(64);
374 static void pidx(u8 mod)
375 {
376         switch (mod) {
377         case 1: pidx16(); break;
378         case 2: pidx32(); break;
379         case 3: pidx64(); break;
380         case 0: default: assert(0);
381         }
382 }
383
384 static void pimmc(u8 imm_type)
385 {
386         if (imm_type > 5) { assert(0); }
387         i_print("%s", imm_chw[imm_type]);
388 }
389
390 static void pflags(u8 flag)
391 {
392         switch (flag) {
393         case 0x0: i_print("eq"); break;
394         case 0x1: i_print("lte"); break;
395         case 0x2: i_print("gte"); break;
396         case 0x3: i_print("ulte"); break;
397         case 0x4: i_print("ugte"); break;
398         }
399 }
400
401 static const char *breakopts[] = {
402         "Runaway program break",
403         "Get virtual machine version",
404         "undefined. WTF?",      // "Skip"?
405         "Debug breakpoint",
406         "System call",
407         "Create thunk",
408         "Set compiler version"
409 };
410
411 static void pbreak(void)
412 {
413         u8 i = i_push(*data++);
414         pspace();
415         if (i > 6) { fprintf(stderr, "unknown break!"); assert(0);
416         } else i_print("\"%s\"", breakopts[i]);
417 }
418
419 static void pinsn(void)
420 {
421         u8 insn = i_push(*data++);
422         u8 opc = insn & 0x3f;
423
424         switch (opc) {
425         case 0x00: i_print("BREAK"); pbreak(); break;
426         case 0x01: case 0x03:{
427                         u8 opindex = insn & 0x80;
428                         u8 c3264 = insn & 0x40;
429
430                         u8 b1 = i_push(*data++);
431                         u8 cond = b1 & 0x80;
432                         u8 flag = b1 & 0x40;
433                         u8 ebcnative = b1 & 0x20;
434                         u8 relabs = b1 & 0x10;
435                         u8 op1 = b1 & 0x7;
436                         u8 dref1 = b1 & 0x8;
437
438                         if (opc == 0x01) {
439                                 i_print("JMP%d%s", c3264 ? 64 : 32,
440                                        cond ? (flag ? "cs" : "cc") : "");
441                         } else if (opc == 0x03) {
442                                 i_print("CALL%d%s", c3264 ? 64 : 32,
443                                        ebcnative ? "EX" : "");
444                         }
445                         i_print("%s", relabs ? "a" : ""); pspace();
446
447                         if (!c3264) {   // 32bit
448                                 pdref(dref1);
449                                 preg(op1);
450                                 if (opindex) {
451                                         pspace();
452                                         if (op1==0) { // relative/absolute call/jmp
453                                                 u32 imm32 = *(u32*)data;
454                                                 i_push(*data++);
455                                                 i_push(*data++);
456                                                 i_push(*data++);
457                                                 i_push(*data++);
458                                                 if (relabs) { // relative call
459                                                         if (opc == 0x03) 
460                                                                 i_set_relative_call(imm32);
461                                                         else
462                                                                 i_set_relative_jmp(imm32);
463                                                 } else { // absolute call
464                                                         i_print("FIXME %s.%d", __FUNCTION__, __LINE__);
465                                                 }
466                                         } else {
467                                                 pidx32();
468                                                 /*pimm32();*/
469                                         }
470                                 }
471                         } else {        // 64bit
472                                 pimm64();
473                         }
474                         /*i_print("   msk: offset=%d", (data-startOfInstruction));*/
475                 }
476                 break;
477         case 0x02:{
478                         u8 cond = insn & 0x80;
479                         u8 flag = insn & 0x40;
480                         i_print("JMP8%s", cond ? (flag ? "cs" : "cc") : "");
481                         pspace(); 
482                         //pimm8();
483                         int relOffset = 2*((int)(s8)i_push(*data++));
484
485                         i_set_relative_jmp(relOffset);
486             /*
487                          *i_print("   msk-offset=%x", 2*(*data) + (data-startOfInstruction));
488                          *i_print("   msk-offset=%08x", (startOfInstruction-data_start) + 2*(*data) + (data-startOfInstruction));
489              */
490                 }
491                 break;
492         case 0x04: i_print("RET"); i_push(*data++); break;
493         case 0x05 ... 0x09:{
494                         u8 opindex = insn & 0x80;
495                         u8 c3264 = insn & 0x40;
496
497                         u8 b1 = i_push(*data++);
498                         u8 op1 = b1 & 0x7;
499                         u8 op2 = (b1 & 0x70) >> 4;
500                         u8 dref2 = b1 & 0x80;
501
502                         i_print("CMP%d", !c3264 ? 32 : 64);
503                         pflags(opc - 0x05); pspace();
504                         preg(op1); pcomma();
505                         pdref(dref2); preg(op2);
506                         if (opindex) {
507                                 pspace(); pimm16();
508                         }
509                 }
510                 break;
511         case 0x0a ... 0x19:{
512                         u8 opindex = insn & 0x80;
513                         u8 c3264 = insn & 0x40;
514
515                         u8 b1 = i_push(*data++);
516                         u8 op1 = b1 & 0x7;
517                         u8 dref1 = b1 & 0x8;
518                         u8 op2 = (b1 & 0x70) >> 4;
519                         u8 dref2 = b1 & 0x80;
520                         switch (opc) {
521                         case 0x0a: i_print("NOT"); break;
522                         case 0x0b: i_print("NEG"); break;
523                         case 0x0c: i_print("ADD"); break;
524                         case 0x0d: i_print("SUB"); break;
525                         case 0x0e: i_print("MUL"); break;
526                         case 0x0f: i_print("MULU"); break;
527                         case 0x10: i_print("DIV"); break;
528                         case 0x11: i_print("DIVU"); break;
529                         case 0x12: i_print("MOD"); break;
530                         case 0x13: i_print("MODU"); break;
531                         case 0x14: i_print("AND"); break;
532                         case 0x15: i_print("OR"); break;
533                         case 0x16: i_print("XOR"); break;
534                         case 0x17: i_print("SHL"); break;
535                         case 0x18: i_print("SHR"); break;
536                         case 0x19: i_print("ASHR"); break;
537                         default:
538                                 fprintf(stderr, "\nopcode: %x\n", opc);
539                                 assert(0);
540                         }
541                         i_print("%d", c3264 ? 64 : 32); pspace();
542                         pdref(dref1); preg(op1); pcomma();
543                         pdref(dref2); preg(op2);
544                         if (opindex) {
545                                 pspace(); pimm16();
546                         }
547                 }
548                 break;
549         case 0x1a ... 0x1c:{
550                         u8 opindex = insn & 0x80;
551                         u8 c3264 = insn & 0x40;
552                         u8 opmod = opc - 0x1a;  // 0b, 1w, 2d
553
554                         u8 b1 = i_push(*data++);
555                         u8 op1 = b1 & 0x7;
556                         u8 dref1 = b1 & 0x8;
557                         u8 op2 = (b1 & 0x70) >> 4;
558                         u8 dref2 = b1 & 0x80;
559
560                         i_print("EXTND"); pimmc(opmod);
561                         i_print("%d", c3264 ? 64 : 32); pspace();
562                         pdref(dref1); preg(op1); pcomma();
563                         pdref(dref2); preg(op2);
564                         if (opindex) {
565                                 pspace(); pimm16();
566                         }
567                 }
568                 break;
569         case 0x2a:{
570                         u8 b1 = i_push(*data++);
571                         u8 op1 = b1 & 0x7;
572                         u8 op2 = (b1 & 0x70) >> 4;
573
574                         i_print("STORESP"); pspace();
575                         preg(op1); pcomma(); pvmreg(op2);
576                 }
577                 break;
578         case 0x2d ... 0x31:{
579                         u8 c3264 = insn & 0x40;
580                         u8 i1632 = !!(insn & 0x80);
581
582                         u8 b1 = i_push(*data++);
583                         u8 op1 = b1 & 0x7;
584                         u8 dref1 = b1 & 0x8;
585                         u8 op1index = b1 & 0x10;
586
587                         i_print("CMPI%d", !c3264 ? 32 : 64);
588                         pimmc(i1632 + 1);
589                         pflags(opc - 0x2d); pspace();
590                         pdref(dref1); preg(op1);
591                         if (op1index) {
592                                 pspace(); pimm16();
593                         }
594                         pcomma();
595                         if (i1632) pimm32();
596                         else pimm16();
597                 }
598                 break;
599         case 0x1d ... 0x28:
600         case 0x32 ... 0x33:{
601                         u8 op1mod = 0;
602                         u8 op2mod = 0;
603                         switch (opc) {
604                         case 0x1d: op1mod = 0; op2mod = 1; break;       // MOVbw
605                         case 0x1e: op1mod = 1; op2mod = 1; break;       // MOVww
606                         case 0x1f: op1mod = 2; op2mod = 1; break;       // MOVdw
607                         case 0x20: op1mod = 3; op2mod = 1; break;       // MOVqw
608                         case 0x21: op1mod = 0; op2mod = 2; break;       // MOVbd
609                         case 0x22: op1mod = 1; op2mod = 2; break;       // MOVwd
610                         case 0x23: op1mod = 2; op2mod = 2; break;       // MOVdd
611                         case 0x24: op1mod = 3; op2mod = 2; break;       // MOVqd
612
613                         case 0x25: op1mod = 5; op2mod = 1; break;       // MOVsnw
614                         case 0x26: op1mod = 5; op2mod = 2; break;       // MOVsnq
615
616                         case 0x28: op1mod = 3; op2mod = 3; break;       // MOVqq
617
618                         case 0x32: op1mod = 4; op2mod = 1; break;       // MOVnw
619                         case 0x33: op1mod = 4; op2mod = 2; break;       // MOVnd
620                         default:
621                                 fprintf(stderr, "wtfopcode: %x\n", opc);
622                                 assert(0);
623                         }
624                         u8 mod = (insn & 0xc0) >> 6;
625                         u8 op1index = mod & 0x2;
626                         u8 op2index = mod & 0x1;
627
628                         u8 b1 = i_push(*data++);
629                         u8 op1 = b1 & 0x7;
630                         u8 dref1 = b1 & 0x8;
631                         u8 op2 = (b1 & 0x70) >> 4;
632                         u8 dref2 = b1 & 0x80;
633
634                         i_print("MOV"); pimmc(op1mod); pimmc(op2mod); pspace();
635                         pdref(dref1); preg(op1);
636                         // op2mod defines index width for *both* indexes
637                         if (op1index) {
638                                 pspace(); pidx(op2mod);
639                         }
640                         pcomma(); pdref(dref2); preg(op2);
641                         if (op2index) {
642                                 pspace(); pidx(op2mod);
643                         }
644                 }
645                 break;
646         case 0x37:{
647                         u8 mod = (insn & 0xc0) >> 6;
648                         u8 b1 = i_push(*data++);
649                         u8 op1 = b1 & 0x7;
650                         u8 dref = b1 & 0x8;
651                         u8 width = (b1 & 0x30) >> 4;
652                         u8 op1index = b1 & 0x40;
653
654                         i_print("MOVI"); pimmc(width); pimmc(mod); pspace();
655                         pdref(dref); preg(op1);
656                         if (op1index) {
657                                 pspace(); pidx16();
658                         }
659                         pcomma(); pimm(mod);
660                 }
661                 break;
662         case 0x38:{
663                         u8 mod = (insn & 0xc0) >> 6;
664
665                         u8 b1 = i_push(*data++);
666                         u8 op1 = b1 & 0x7;
667                         u8 dref = b1 & 0x8;
668                         u8 op1index = (b1 & 0x40) >> 6;
669
670                         i_print("MOVIn"); pimmc(mod); pspace();
671                         pdref(dref); preg(op1);
672                         if (op1index) {
673                                 pspace(); pidx16();
674                         }
675                         pcomma(); pimm(mod);
676                 }
677                 break;
678         case 0x39:{
679                         u8 mod = (insn & 0xc0) >> 6;
680                         u8 b1 = i_push(*data++);
681                         u8 op1 = b1 & 0x7;
682                         u8 dref = b1 & 0x8;
683                         u8 op1index = b1 & 0x40;
684
685                         i_print("MOVREL"); pimmc(mod); pspace();
686                         pdref(dref); preg(op1);
687                         if (op1index) {
688                                 pspace(); pidx16();
689                         }
690                         pcomma(); pimm(mod);
691                 }
692                 break;
693         default:
694                 fprintf(stderr, "\nunknown opcode: 0x%02x\n", opc);
695                 assert(0);
696         }
697 }
698
699 static void pheader(void)
700 {
701         /*printf("\n%08x: ", data - data_start);*/
702         /*i_print("\n");*/
703 }
704
705 int main(int argc, const char **argv)
706 {
707         if (argc != 2) {
708                 fprintf(stderr, "usage: %s <pe-ebc>\n", argv[0]);
709                 exit(1);
710         }
711
712         int fd = open(argv[1], O_RDONLY);
713         file_len = lseek(fd, 0, SEEK_END);
714         data_start = data = mmap(0, file_len, PROT_READ, MAP_SHARED, fd, 0);
715         close(fd);
716
717         if (memcmp(data, "MZ", 2) != 0) {
718                 fprintf(stderr, "wrong DOS header: %c%c\n", *data, *(data + 1));
719                 exit(2);
720         } else {
721                 print_debug("data");
722         }
723
724         int found = 0;
725         while (!found && ++data < (data + file_len)) {
726                 if (memcmp(data, "PE", 2) == 0) {
727                         print_debug("PE");
728                         found = 1;
729                 }
730         }
731
732         if (!found) {
733                 fprintf(stderr, "no PE header found\n");
734                 exit(3);
735         }
736
737         data += 4;
738         if (memcmp(data, "\xbc\x0e", 2) != 0) { // read '0xebc'
739                 fprintf(stderr, "not an EBC image: 0x%02x%02x\n", *data,
740                         *(data + 1));
741                 exit(4);
742         }
743
744         found = 0;
745         while (!found && ++data < (data + file_len)) {
746                 if (memcmp(data, "\x0b\x01", 2) == 0) { // read '0x10b'
747                         print_debug("PE-opt");
748                         found = 1;
749                 }
750         }
751
752         if (!found) {
753                 fprintf(stderr, "no PE-opt header found\n");
754                 exit(3);
755         }
756
757         fprintf(stderr, PS "0x%04x\n", "magic", *((u16 *) data));
758         data += 2;              //u16
759
760         fprintf(stderr, PS "0x%02x\n", "majorver", *((u8 *) data));
761         data++;                 //u8
762         fprintf(stderr, PS "0x%02x\n", "minorver", *((u8 *) data));
763         data++;                 //u8
764
765         // TODO: not sure if this is correct :/
766         size_code = *((u32 *) data);
767         print_debug("size_code");
768         fprintf(stderr, PS "0x%08x\n", "size_code", size_code);
769         data += 4 + 4 + 4;      //u32, u32, u32
770
771         entry_point = *((u32 *) data) - *((u32 *)(data+4));
772         fprintf(stderr, PS "0x%08x\n", "entry_point", entry_point);
773         data += 4;              //u32
774
775         base_code = *((u32 *) data);
776         print_debug("base_code");
777         fprintf(stderr, PS "0x%08x\n", "base_code", base_code);
778         data += 4;
779         base_data = *((u32 *) data);
780         print_debug("base_data");
781         fprintf(stderr, PS "0x%08x\n", "base_data", base_data);
782
783         data += 4;              //u32
784         fprintf(stderr, PS "0x%08x\n", "???", *((u32 *) data));
785
786         data = data_start + base_code;
787         while (data <= (data_start + base_code + size_code)) {
788                 i_begin((int)(data-data_start), (int)(data-data_start-base_code));
789
790                 pheader();
791                 pinsn();
792         }
793         printf("\n");
794         i_end();
795         i_dump();
796         i_cleanup();
797
798         return 0;
799 }
800