diff options
Diffstat (limited to 'disas.c')
-rw-r--r-- | disas.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/disas.c b/disas.c new file mode 100644 index 0000000000..d3dcdffd1b --- /dev/null +++ b/disas.c @@ -0,0 +1,79 @@ +/* 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 ""; +} |