FreeCalypso > hg > freecalypso-reveng
view ticoff/disasm.c @ 118:193926ccd1ec
tiobjd: better handling of section-relative relocs
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Thu, 03 Apr 2014 07:47:03 +0000 |
parents | f9fde7f36ae3 |
children | 4d8dfdbd2ea1 |
line wrap: on
line source
/* * Putting it all together: section-, symbol- and reloc-aware disassembly */ #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include "intstruct.h" #include "coffconst.h" #include "globals.h" extern unsigned get_u16(), get_u32(); static void find_better_symbol(symp, addp) struct internal_syment **symp; unsigned *addp; { struct internal_scnhdr *sec; unsigned addr; struct internal_syment *sym, *symsel; unsigned n; sec = (*symp)->section; addr = *addp; symsel = 0; for (n = 0; n < sec->nsymbols; n++) { sym = sec->sorted_symbols[n]; if (sym->value > addr) break; if (sym->class == C_EXT || sym->class == C_STAT) symsel = sym; } if (symsel) { *symp = symsel; *addp = addr - symsel->value; } } void disasm_reloc_target(sec, rel, addend) struct internal_scnhdr *sec; struct internal_reloc *rel; unsigned addend; { struct internal_syment *sym = rel->sym; addend -= sym->value; if (sym->section && !strcmp(sym->name, sym->section->name)) find_better_symbol(&sym, &addend); if (addend >= 10) printf("%s+0x%x", sym->name, addend); else if (addend) printf("%s+%u", sym->name, addend); else fputs(sym->name, stdout); } void disasm_word32_reloc(sec, rel) struct internal_scnhdr *sec; struct internal_reloc *rel; { unsigned word; word = get_u32(filemap + sec->data_offset + rel->location); printf("%08x R\t.word\t", word); disasm_reloc_target(sec, rel, word); putchar('\n'); } void disasm_text_section(sec) struct internal_scnhdr *sec; { unsigned symnum, relnum; unsigned pos, incr, headroom; int state = -1, linebrk = 0; struct internal_syment *sym; struct internal_reloc *rel; char *sym_comment; printf("Disassembling code section:\n"); if (sec->nsymbols) sort_symbols_of_sec(sec); if (sec->nreloc) get_relocs_of_sec(sec); symnum = relnum = 0; for (pos = 0; pos < sec->size; pos += incr) { headroom = sec->size - pos; while (symnum < sec->nsymbols) { sym = sec->sorted_symbols[symnum]; if (sym->value > pos) { if (sym->value - pos < headroom) headroom = sym->value - pos; break; } /* hit symbol */ if (!linebrk) { putchar('\n'); linebrk = 1; } switch (sym->class) { case C_EXT: sym_comment = "Global"; break; case C_STAT: sym_comment = "static"; break; case C_LABEL: sym_comment = "label"; if (!strcmp(sym->name, "$CODE16")) state = 1; else if (!strcmp(sym->name, "$CODE32")) state = 0; break; default: sym_comment = "unexpected class!"; } printf("%s:\t; %s\n", sym->name, sym_comment); symnum++; } if (relnum < sec->nreloc) { rel = sec->int_relocs + relnum; if (rel->location == pos) relnum++; /* it's ours */ else { if (rel->location - pos < headroom) headroom = rel->location - pos; rel = 0; /* no reloc for current pos */ } } else rel = 0; printf("%8x:\t", pos); if (rel && rel->type == RTYPE_LONG) { if (pos & 3) { printf("MISALIGNED pos for word32 reloc, aborting\n"); return; } disasm_word32_reloc(sec, rel); incr = 4; goto next; } switch (state) { case 0: /* ARM */ if (pos & 3) { printf("MISALIGNED pos in CODE32 state, aborting\n"); return; } if (rel) { if (rel->type != RTYPE_ARM_B) { printf("Wrong reloc type in CODE32 state, aborting\n"); return; } arm_branch_reloc(sec, rel); } else arm_disasm_line(sec, pos); incr = 4; break; case 1: /* Thumb */ if (pos & 1) { printf("MISALIGNED pos in CODE16 state, aborting\n"); return; } if (rel) { if (rel->type != RTYPE_THUMB_BL) { printf("Wrong reloc type in CODE16 state, aborting\n"); return; } thumb_bl_reloc(sec, rel); incr = 4; } else if (headroom >= 4 && thumb_check_bl(sec, pos)) incr = 4; else { thumb_disasm_line(sec, pos); incr = 2; } break; default: printf("UNKNOWN T state, aborting\n"); return; } next: linebrk = 0; if (incr > headroom) { printf("error: increment %u > headroom %u, aborting\n", incr, headroom); return; } } } void disasm_sectype_by_name(sec) struct internal_scnhdr *sec; { if (!strncmp(sec->name, ".text", 5)) disasm_text_section(sec); /* other section types to be added */ else printf("Unrecognized section type, skipped\n"); } cmd_disasm() { struct internal_scnhdr *sec; unsigned secnum; printf("%s:\n", objfilename); dump_filehdr_info(); putchar('\n'); get_int_section_table(); get_int_symbol_table(); extern_profile_report("Module"); sort_symbols_of_all_sec(); for (secnum = 0; secnum < nsections; secnum++) { sec = sections + secnum; printf("=== %s ===\n", sec->name); disasm_sectype_by_name(sec); putchar('\n'); } exit(0); }