| /* General "disassemble this chunk" code. Used for debugging. */ |
| #include "dis-asm.h" |
| #include "disas.h" |
| #include "elf.h" |
| |
| /* Filled in by elfload.c. Simplistic, but will do for now. */ |
| unsigned int disas_num_syms; |
| void *disas_symtab; |
| const char *disas_strtab; |
| |
| /* Disassemble this for me please... (debugging). */ |
| void disas(FILE *out, void *code, unsigned long size, enum disas_type type) |
| { |
| uint8_t *pc; |
| int count; |
| struct disassemble_info disasm_info; |
| int (*print_insn)(bfd_vma pc, disassemble_info *info); |
| |
| INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf); |
| |
| disasm_info.buffer = code; |
| disasm_info.buffer_vma = (unsigned long)code; |
| disasm_info.buffer_length = size; |
| |
| if (type == DISAS_TARGET) { |
| #ifdef WORDS_BIGENDIAN |
| disasm_info.endian = BFD_ENDIAN_BIG; |
| #else |
| disasm_info.endian = BFD_ENDIAN_LITTLE; |
| #endif |
| #ifdef __i386__ |
| disasm_info.mach = bfd_mach_i386_i386; |
| print_insn = print_insn_i386; |
| #elif defined(__powerpc__) |
| print_insn = print_insn_ppc; |
| #else |
| fprintf(out, "Asm output not supported on this arch\n"); |
| return; |
| #endif |
| } else { |
| /* Currently only source supported in x86. */ |
| disasm_info.endian = BFD_ENDIAN_LITTLE; |
| if (type == DISAS_I386_I386) |
| disasm_info.mach = bfd_mach_i386_i386; |
| else |
| disasm_info.mach = bfd_mach_i386_i8086; |
| print_insn = print_insn_i386; |
| } |
| |
| for (pc = code; pc < (uint8_t *)code + size; pc += count) { |
| fprintf(out, "0x%08lx: ", (long)pc); |
| count = print_insn((long)pc, &disasm_info); |
| fprintf(out, "\n"); |
| if (count < 0) |
| break; |
| } |
| } |
| |
| /* Look up symbol for debugging purpose. Returns "" if unknown. */ |
| const char *lookup_symbol(void *orig_addr) |
| { |
| unsigned int i; |
| /* Hack, because we know this is x86. */ |
| Elf32_Sym *sym = disas_symtab; |
| |
| for (i = 0; i < disas_num_syms; i++) { |
| if (sym[i].st_shndx == SHN_UNDEF |
| || sym[i].st_shndx >= SHN_LORESERVE) |
| continue; |
| |
| if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC) |
| continue; |
| |
| if ((long)orig_addr >= sym[i].st_value |
| && (long)orig_addr < sym[i].st_value + sym[i].st_size) |
| return disas_strtab + sym[i].st_name; |
| } |
| return ""; |
| } |