aboutsummaryrefslogtreecommitdiffstats
path: root/disas.c
diff options
context:
space:
mode:
Diffstat (limited to 'disas.c')
-rw-r--r--disas.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/disas.c b/disas.c
new file mode 100644
index 000000000..d3dcdffd1
--- /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 "";
+}