From: Martin Kustermann Date: Tue, 30 Aug 2011 20:11:59 +0000 (+0200) Subject: enhanced ebc disassembler X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=dis-ebc.git;a=commitdiff_plain;h=HEAD enhanced ebc disassembler enhancements: * get jump/call targets * print raw data and asm-instructions * decode indices todo: * not all instructions use the index-decoding functionality * ... --- diff --git a/dis-ebc.c b/dis-ebc.c index b96ec15..a590972 100644 --- a/dis-ebc.c +++ b/dis-ebc.c @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include #include @@ -15,10 +17,276 @@ #define PS "%-10s: " + typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long long u64; +typedef signed char s8; +typedef uint16_t u16; +typedef int16_t s16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef int64_t s64; + + +#define MAX_STRING_LEN 100 +#define MAX_INSTRUCTION_LEN 40 + +typedef struct _instruction { + int offsetInFile; + int offsetInCode; + + u8 bytes[MAX_INSTRUCTION_LEN]; + int bytePos; + + char string[MAX_STRING_LEN]; + int stringPos; + + int isJump; + int jumpAddress; + + int isCall; + int callAddress; + + int isCallTarget; + int isJumpTarget; + + int callLabel; + int jumpLabel; + + struct _instruction *next; +} instruction; + +typedef struct _statistics { + int maxInstructionLen; +} statistics; + +static instruction* instruction_new(int offsetInFile, int offsetInCode) { + instruction *inst = malloc(sizeof(instruction)); + assert(inst != NULL); + + memset(inst, 0, sizeof(instruction)); + + inst->offsetInFile = offsetInFile; + inst->offsetInCode = offsetInCode; + + return inst; +} + +static void instruction_print(instruction *inst, const char *c) { + int len = strlen(c); + assert((inst->stringPos+len) < MAX_STRING_LEN); + for (int i=0; istring[inst->stringPos++] = c[i]; +} + +static void instruction_push_byte(instruction *inst, u8 byte) { + assert((inst->bytePos+1) < MAX_INSTRUCTION_LEN); + inst->bytes[inst->bytePos++] = byte; +} + +static instruction *first_instruction; +static instruction *current_instruction; +static int current_call_label=0; +static int current_jump_label=0; +static statistics stat; +static int entry_point; + + +/* + * BEGIN - interface functions + */ +static void i_begin(int offsetInFile, int offsetInCode) { + if (first_instruction == NULL) { + first_instruction = current_instruction = instruction_new(offsetInFile, offsetInCode); + } else { + assert(current_instruction->next == 0); + current_instruction->next = instruction_new(offsetInFile, offsetInCode); + current_instruction = current_instruction->next; + } +} + +static void i_print(const char *fmt, ...) { + assert(current_instruction != NULL); + + va_list args; + char str[MAX_STRING_LEN]; + + memset(str, 0, MAX_STRING_LEN); + + va_start(args, fmt); + vsprintf(str, fmt, args); + instruction_print(current_instruction, str); + va_end(args); +} + +static u8 i_push(u8 byte) { + assert(current_instruction != NULL); + instruction_push_byte(current_instruction, byte); + return byte; +} + +static void i_set_relative_call(int relAddr) { + current_instruction->isCall=1; + current_instruction->callAddress = current_instruction->offsetInCode + current_instruction->bytePos + relAddr; + /*i_print("[call to 0x%08x] ", current_instruction->callAddress);*/ +} + +static void i_set_relative_jmp(int relAddr) { + current_instruction->isJump=1; + // FIXME: is this correct ? + current_instruction->jumpAddress = current_instruction->offsetInCode + current_instruction->bytePos + relAddr; + /*current_instruction->jumpAddress = current_instruction->offsetInCode + relAddr;*/ + /*i_print("[jump to 0x%08x] ", current_instruction->jumpAddress);*/ +} + +static int i_get_jump_label(int absoluteCodeOffset) { + instruction *i = first_instruction; + while (i != NULL) { + if (i->offsetInCode == absoluteCodeOffset && i->isJumpTarget) + return i->jumpLabel; + i = i->next; + } + return -1; +} +static int i_get_call_label(int absoluteCodeOffset) { + instruction *i = first_instruction; + while (i != NULL) { + if (i->offsetInCode == absoluteCodeOffset && i->isCallTarget) + return i->callLabel; + i = i->next; + } + return -1; +} + +static void i_dump() { + int k; + + instruction *i = first_instruction; + while (i != NULL) { + if (i->offsetInCode == entry_point) + printf("\n\nENTRY_POINT:\n"); + if (i->isCallTarget) + printf("\n\nfunction%d:\n", i->callLabel); + if (i->isJumpTarget) + printf("label%d: \n", i->jumpLabel); + + printf("\t0x%08x:", i->offsetInCode); + for (k=0; kbytePos) + printf(" %02x", i->bytes[k]); + else + printf(" "); + } + if (i->isCall) + printf(" %s [call function%d]\n", i->string, i_get_call_label(i->callAddress)); + else if (i->isJump) + printf(" %s [jump label%d]\n", i->string, i_get_jump_label(i->jumpAddress)); + else + printf(" %s\n", i->string); + i = i->next; + } +} + +static void i_mark_jump_target(int absoluteCodeOffset) { + // search in list for address and set isJumpTarget = true + instruction *i = first_instruction; + while (i != NULL) { + if (i->offsetInCode == absoluteCodeOffset) { + i->isJumpTarget++; + return; + } + i = i->next; + } + assert(0); +} +static void i_mark_call_target(int absoluteCodeOffset) { + // search in list for address and set isCallTarget = true + instruction *i = first_instruction; + while (i != NULL) { + if (i->offsetInCode == absoluteCodeOffset) { + i->isCallTarget++; + return; + } + i = i->next; + } + assert(0); +} + +static void i_mark_jump_targets() { + // search the whole list for jumps and call + // i_mark_jump_target() for every of them + instruction *i = first_instruction; + while (i != NULL) { + if (i->isJump) + i_mark_jump_target(i->jumpAddress); + i = i->next; + } +} + +static void i_mark_call_targets() { + // search the whole list for calls and call + // i_mark_call_target() for every of them + instruction *i = first_instruction; + while (i != NULL) { + if (i->isCall) + i_mark_call_target(i->callAddress); + i = i->next; + } +} + +static void i_enumerate_jump_targets() { + instruction *i = first_instruction; + while (i != NULL) { + if (i->isJumpTarget) + i->jumpLabel = current_jump_label++; + i = i->next; + } +} + +static void i_enumerate_call_targets() { + instruction *i = first_instruction; + while (i != NULL) { + if (i->isCallTarget) + i->callLabel = current_call_label++; + i = i->next; + } +} + +static void i_make_statistics() { + instruction *i = first_instruction; + while (i != NULL) { + if (i->bytePos > stat.maxInstructionLen) { + stat.maxInstructionLen = i->bytePos; + } + i = i->next; + } +} + +static void i_end() { + i_mark_jump_targets(); + i_mark_call_targets(); + + i_enumerate_jump_targets(); + i_enumerate_call_targets(); + + i_make_statistics(); +} + +static void i_cleanup() { + instruction *current_inst = first_instruction; + instruction *next; + + first_instruction = NULL; + while (current_inst != NULL) { + next = current_inst->next; + free(current_inst); + current_inst = next; + } +} + +/* + * END - interface functions + */ static int file_len; static u8 *data, *data_start; @@ -42,32 +310,32 @@ static void print_debug(const char *s) data - data_start); } -static void pspace(void) { printf(" "); } - -static void pcomma(void) { printf(", "); } +static void pspace(void) { i_print(" "); } +static void pcomma(void) { i_print(", "); } static void preg(u8 reg) { if (reg > 7) { assert(0); } - printf("r%1d", reg); + i_print("r%1d", reg); } static void pvmreg(u8 reg) { if (reg > 7) { assert(0); } - printf("%s", vm_reg[reg]); + i_print("%s", vm_reg[reg]); } static void pdref(u8 x) { - printf("%s", x ? "@" : ""); + i_print("%s", x ? "@" : ""); } #define PIMM_READ(size) \ static void pimm##size(void) \ { \ - printf(size != 64 ? "%x" : "%llx", *((u##size *) data)); \ - data += sizeof (u##size); \ + i_print(size != 64 ? "%x" : "%llx", *((u##size *) data)); \ + for (int i=0; i> (size-1))&1; \ + u##size nat_bits = ((d>>(size-4))&0x7) * (size/8);\ + u##size c_bits = size - nat_bits - 4;\ + u##size c = (d>>nat_bits)&((1ULL< 5) { assert(0); } - printf("%s", imm_chw[imm_type]); + i_print("%s", imm_chw[imm_type]); } static void pflags(u8 flag) { switch (flag) { - case 0x0: printf("eq"); break; - case 0x1: printf("lte"); break; - case 0x2: printf("gte"); break; - case 0x3: printf("ulte"); break; - case 0x4: printf("ugte"); break; + case 0x0: i_print("eq"); break; + case 0x1: i_print("lte"); break; + case 0x2: i_print("gte"); break; + case 0x3: i_print("ulte"); break; + case 0x4: i_print("ugte"); break; } } @@ -114,24 +410,24 @@ static const char *breakopts[] = { static void pbreak(void) { - u8 i = *data++; + u8 i = i_push(*data++); pspace(); - if (i > 6) { printf("unknown break!"); assert(0); - } else printf("\"%s\"", breakopts[i]); + if (i > 6) { fprintf(stderr, "unknown break!"); assert(0); + } else i_print("\"%s\"", breakopts[i]); } static void pinsn(void) { - u8 insn = *data++; + u8 insn = i_push(*data++); u8 opc = insn & 0x3f; switch (opc) { - case 0x00: printf("BREAK"); pbreak(); break; + case 0x00: i_print("BREAK"); pbreak(); break; case 0x01: case 0x03:{ u8 opindex = insn & 0x80; u8 c3264 = insn & 0x40; - u8 b1 = *data++; + u8 b1 = i_push(*data++); u8 cond = b1 & 0x80; u8 flag = b1 & 0x40; u8 ebcnative = b1 & 0x20; @@ -140,43 +436,70 @@ static void pinsn(void) u8 dref1 = b1 & 0x8; if (opc == 0x01) { - printf("JMP%d%s", c3264 ? 64 : 32, + i_print("JMP%d%s", c3264 ? 64 : 32, cond ? (flag ? "cs" : "cc") : ""); } else if (opc == 0x03) { - printf("CALL%d%s", c3264 ? 64 : 32, + i_print("CALL%d%s", c3264 ? 64 : 32, ebcnative ? "EX" : ""); } - printf("%s", relabs ? "a" : ""); pspace(); + i_print("%s", relabs ? "a" : ""); pspace(); if (!c3264) { // 32bit pdref(dref1); preg(op1); if (opindex) { - pspace(); pimm32(); + pspace(); + if (op1==0) { // relative/absolute call/jmp + u32 imm32 = *(u32*)data; + i_push(*data++); + i_push(*data++); + i_push(*data++); + i_push(*data++); + if (relabs) { // relative call + if (opc == 0x03) + i_set_relative_call(imm32); + else + i_set_relative_jmp(imm32); + } else { // absolute call + i_print("FIXME %s.%d", __FUNCTION__, __LINE__); + } + } else { + pidx32(); + /*pimm32();*/ + } } } else { // 64bit pimm64(); } + /*i_print(" msk: offset=%d", (data-startOfInstruction));*/ } break; case 0x02:{ u8 cond = insn & 0x80; u8 flag = insn & 0x40; - printf("JMP8%s", cond ? (flag ? "cs" : "cc") : ""); - pspace(); pimm8(); + i_print("JMP8%s", cond ? (flag ? "cs" : "cc") : ""); + pspace(); + //pimm8(); + int relOffset = 2*((int)(s8)i_push(*data++)); + + i_set_relative_jmp(relOffset); + /* + *i_print(" msk-offset=%x", 2*(*data) + (data-startOfInstruction)); + *i_print(" msk-offset=%08x", (startOfInstruction-data_start) + 2*(*data) + (data-startOfInstruction)); + */ } break; - case 0x04: printf("RET"); data++; break; + case 0x04: i_print("RET"); i_push(*data++); break; case 0x05 ... 0x09:{ u8 opindex = insn & 0x80; u8 c3264 = insn & 0x40; - u8 b1 = *data++; + u8 b1 = i_push(*data++); u8 op1 = b1 & 0x7; u8 op2 = (b1 & 0x70) >> 4; u8 dref2 = b1 & 0x80; - printf("CMP%d", !c3264 ? 32 : 64); + i_print("CMP%d", !c3264 ? 32 : 64); pflags(opc - 0x05); pspace(); preg(op1); pcomma(); pdref(dref2); preg(op2); @@ -189,33 +512,33 @@ static void pinsn(void) u8 opindex = insn & 0x80; u8 c3264 = insn & 0x40; - u8 b1 = *data++; + u8 b1 = i_push(*data++); u8 op1 = b1 & 0x7; u8 dref1 = b1 & 0x8; u8 op2 = (b1 & 0x70) >> 4; u8 dref2 = b1 & 0x80; switch (opc) { - case 0x0a: printf("NOT"); break; - case 0x0b: printf("NEG"); break; - case 0x0c: printf("ADD"); break; - case 0x0d: printf("SUB"); break; - case 0x0e: printf("MUL"); break; - case 0x0f: printf("MULU"); break; - case 0x10: printf("DIV"); break; - case 0x11: printf("DIVU"); break; - case 0x12: printf("MOD"); break; - case 0x13: printf("MODU"); break; - case 0x14: printf("AND"); break; - case 0x15: printf("OR"); break; - case 0x16: printf("XOR"); break; - case 0x17: printf("SHL"); break; - case 0x18: printf("SHR"); break; - case 0x19: printf("ASHR"); break; + case 0x0a: i_print("NOT"); break; + case 0x0b: i_print("NEG"); break; + case 0x0c: i_print("ADD"); break; + case 0x0d: i_print("SUB"); break; + case 0x0e: i_print("MUL"); break; + case 0x0f: i_print("MULU"); break; + case 0x10: i_print("DIV"); break; + case 0x11: i_print("DIVU"); break; + case 0x12: i_print("MOD"); break; + case 0x13: i_print("MODU"); break; + case 0x14: i_print("AND"); break; + case 0x15: i_print("OR"); break; + case 0x16: i_print("XOR"); break; + case 0x17: i_print("SHL"); break; + case 0x18: i_print("SHR"); break; + case 0x19: i_print("ASHR"); break; default: - printf("\nopcode: %x\n", opc); + fprintf(stderr, "\nopcode: %x\n", opc); assert(0); } - printf("%d", c3264 ? 64 : 32); pspace(); + i_print("%d", c3264 ? 64 : 32); pspace(); pdref(dref1); preg(op1); pcomma(); pdref(dref2); preg(op2); if (opindex) { @@ -228,14 +551,14 @@ static void pinsn(void) u8 c3264 = insn & 0x40; u8 opmod = opc - 0x1a; // 0b, 1w, 2d - u8 b1 = *data++; + u8 b1 = i_push(*data++); u8 op1 = b1 & 0x7; u8 dref1 = b1 & 0x8; u8 op2 = (b1 & 0x70) >> 4; u8 dref2 = b1 & 0x80; - printf("EXTND"); pimmc(opmod); - printf("%d", c3264 ? 64 : 32); pspace(); + i_print("EXTND"); pimmc(opmod); + i_print("%d", c3264 ? 64 : 32); pspace(); pdref(dref1); preg(op1); pcomma(); pdref(dref2); preg(op2); if (opindex) { @@ -244,11 +567,11 @@ static void pinsn(void) } break; case 0x2a:{ - u8 b1 = *data++; + u8 b1 = i_push(*data++); u8 op1 = b1 & 0x7; u8 op2 = (b1 & 0x70) >> 4; - printf("STORESP"); pspace(); + i_print("STORESP"); pspace(); preg(op1); pcomma(); pvmreg(op2); } break; @@ -256,12 +579,12 @@ static void pinsn(void) u8 c3264 = insn & 0x40; u8 i1632 = !!(insn & 0x80); - u8 b1 = *data++; + u8 b1 = i_push(*data++); u8 op1 = b1 & 0x7; u8 dref1 = b1 & 0x8; u8 op1index = b1 & 0x10; - printf("CMPI%d", !c3264 ? 32 : 64); + i_print("CMPI%d", !c3264 ? 32 : 64); pimmc(i1632 + 1); pflags(opc - 0x2d); pspace(); pdref(dref1); preg(op1); @@ -302,36 +625,36 @@ static void pinsn(void) u8 op1index = mod & 0x2; u8 op2index = mod & 0x1; - u8 b1 = *data++; + u8 b1 = i_push(*data++); u8 op1 = b1 & 0x7; u8 dref1 = b1 & 0x8; u8 op2 = (b1 & 0x70) >> 4; u8 dref2 = b1 & 0x80; - printf("MOV"); pimmc(op1mod); pimmc(op2mod); pspace(); + i_print("MOV"); pimmc(op1mod); pimmc(op2mod); pspace(); pdref(dref1); preg(op1); // op2mod defines index width for *both* indexes if (op1index) { - pspace(); pimm(op2mod); + pspace(); pidx(op2mod); } pcomma(); pdref(dref2); preg(op2); if (op2index) { - pspace(); pimm(op2mod); + pspace(); pidx(op2mod); } } break; case 0x37:{ u8 mod = (insn & 0xc0) >> 6; - u8 b1 = *data++; + u8 b1 = i_push(*data++); u8 op1 = b1 & 0x7; u8 dref = b1 & 0x8; u8 width = (b1 & 0x30) >> 4; u8 op1index = b1 & 0x40; - printf("MOVI"); pimmc(width); pimmc(mod); pspace(); + i_print("MOVI"); pimmc(width); pimmc(mod); pspace(); pdref(dref); preg(op1); if (op1index) { - pspace(); pimm16(); + pspace(); pidx16(); } pcomma(); pimm(mod); } @@ -339,30 +662,30 @@ static void pinsn(void) case 0x38:{ u8 mod = (insn & 0xc0) >> 6; - u8 b1 = *data++; + u8 b1 = i_push(*data++); u8 op1 = b1 & 0x7; u8 dref = b1 & 0x8; u8 op1index = (b1 & 0x40) >> 6; - printf("MOVIn"); pimmc(mod); pspace(); + i_print("MOVIn"); pimmc(mod); pspace(); pdref(dref); preg(op1); if (op1index) { - pspace(); pimm16(); + pspace(); pidx16(); } pcomma(); pimm(mod); } break; case 0x39:{ u8 mod = (insn & 0xc0) >> 6; - u8 b1 = *data++; + u8 b1 = i_push(*data++); u8 op1 = b1 & 0x7; u8 dref = b1 & 0x8; u8 op1index = b1 & 0x40; - printf("MOVREL"); pimmc(mod); pspace(); + i_print("MOVREL"); pimmc(mod); pspace(); pdref(dref); preg(op1); if (op1index) { - pspace(); pimm16(); + pspace(); pidx16(); } pcomma(); pimm(mod); } @@ -375,7 +698,8 @@ static void pinsn(void) static void pheader(void) { - printf("\n%08x: ", data - data_start); + /*printf("\n%08x: ", data - data_start);*/ + /*i_print("\n");*/ } int main(int argc, const char **argv) @@ -444,7 +768,8 @@ int main(int argc, const char **argv) fprintf(stderr, PS "0x%08x\n", "size_code", size_code); data += 4 + 4 + 4; //u32, u32, u32 - fprintf(stderr, PS "0x%08x\n", "entry_point", *((u32 *) data)); + entry_point = *((u32 *) data) - *((u32 *)(data+4)); + fprintf(stderr, PS "0x%08x\n", "entry_point", entry_point); data += 4; //u32 base_code = *((u32 *) data); @@ -459,11 +784,17 @@ int main(int argc, const char **argv) fprintf(stderr, PS "0x%08x\n", "???", *((u32 *) data)); data = data_start + base_code; - while (data <= (data_start + size_code)) { + while (data <= (data_start + base_code + size_code)) { + i_begin((int)(data-data_start), (int)(data-data_start-base_code)); + pheader(); pinsn(); } printf("\n"); + i_end(); + i_dump(); + i_cleanup(); return 0; } +