FreeCalypso > hg > freecalypso-reveng
view leo-obj/tool/disasm.c @ 133:daeaa5950d10
tiobjd: Thumb bl w/o reloc: find symbol if there is one
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Mon, 07 Apr 2014 01:22:09 +0000 |
parents | 87b82398a08b |
children | df432a4b1b84 |
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(); extern char *storage_class_to_string(); int auto_xlat_section_relocs = 1; static void find_better_symbol(sec, symp, addp) struct internal_scnhdr *sec; struct internal_syment **symp; unsigned *addp; { unsigned addr, delta; struct internal_syment *sym; unsigned n; addr = *addp; for (n = 0; n < sec->nsymbols; n++) { sym = sec->sorted_symbols[n]; if (sym->value > addr) return; if (sym->class != C_EXT && sym->class != C_STAT) continue; delta = addr - sym->value; if (sym->name[0] == '_' && !delta || sym->name[0] == '$' && delta <= 1) { *symp = sym; *addp = delta; } } } void disasm_reloc_target(sec, rel, addend) struct internal_scnhdr *sec; struct internal_reloc *rel; unsigned addend; { struct internal_syment *sym = rel->sym; if (sym) addend -= sym->value; if (auto_xlat_section_relocs && (!sym || sym->section && !strcmp(sym->name, sym->section->name))) find_better_symbol(sym ? sym->section : sec, &sym, &addend); if (sym) fputs(sym->name, stdout); else fputs(sec->name, stdout); if (addend >= 10) printf("+0x%x", addend); else if (addend) printf("+%u", addend); } 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_end_of_section(sec, symnum) struct internal_scnhdr *sec; unsigned symnum; { struct internal_syment *sym; char *sym_comment; putchar('\n'); while (symnum < sec->nsymbols) { sym = sec->sorted_symbols[symnum]; if (sym->value != sec->size) { printf("error: expecting symbol at end of section\n"); return; } switch (sym->class) { case C_EXT: sym_comment = "Global"; break; case C_STAT: sym_comment = "static"; break; case C_LABEL: sym_comment = "label"; break; default: sym_comment = "unexpected class!"; } printf("%s:\t; %s\n", sym->name, sym_comment); symnum++; } printf("%8x:\t<end of section>\n", sec->size); } 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; } if (pos & 1 || headroom < 2) { if (rel) { printf("error: reloc at byte pos, aborting\n"); return; } printf("%02x\n", filemap[sec->data_offset + pos]); incr = 1; 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; } } if (symnum < sec->nsymbols) disasm_end_of_section(sec, symnum); } void disasm_data_section(sec) struct internal_scnhdr *sec; { unsigned symnum, relnum; unsigned pos, incr, headroom; int linebrk = 0; struct internal_syment *sym; struct internal_reloc *rel; char *sym_comment; printf("Disassembling data 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"; 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) { if (rel->type != RTYPE_LONG) { printf("error: reloc other than word32 in data section\n"); return; } if (pos & 3) { printf("MISALIGNED pos for word32 reloc, aborting\n"); return; } disasm_word32_reloc(sec, rel); incr = 4; } else if (pos & 1 || headroom < 2) { printf("%02x\n", filemap[sec->data_offset + pos]); incr = 1; } else if (pos & 2 || headroom < 4) { printf("%04x\n", get_u16(filemap + sec->data_offset + pos)); incr = 2; } else { printf("%08x\n", get_u32(filemap + sec->data_offset + pos)); incr = 4; } linebrk = 0; if (incr > headroom) { printf("error: increment %u > headroom %u, aborting\n", incr, headroom); return; } } if (symnum < sec->nsymbols) disasm_end_of_section(sec, symnum); } void disasm_bss(sec) struct internal_scnhdr *sec; { unsigned m; struct internal_syment *sym; char classbuf[8]; putchar('\n'); for (m = 0; m < sec->nsymbols; m++) { sym = sec->sorted_symbols[m]; printf("%08X %-7s %s\n", sym->value, storage_class_to_string(sym->class, classbuf), sym->name); } printf("%08X <end of section>\n", sec->size); } void disasm_sec_by_type(sec) struct internal_scnhdr *sec; { switch (sec->disasm_mode) { case DISASM_MODE_CODE: disasm_text_section(sec); return; case DISASM_MODE_DATA: disasm_data_section(sec); return; case DISASM_MODE_BSS: disasm_bss(sec); return; default: printf("Unrecognized section type, skipped\n"); } } cmd_disasm(argc, argv) char **argv; { extern char *optarg; char *hintsfile = 0; struct internal_scnhdr *sec; unsigned secnum; int c; while ((c = getopt(argc, argv, "h:s")) != EOF) switch (c) { case 'h': hintsfile = optarg; continue; case 's': auto_xlat_section_relocs = 0; continue; default: /* error msg already printed */ exit(1); } printf("%s:\n", objfilename); dump_filehdr_info(); putchar('\n'); get_int_section_table(); get_int_symbol_table(); if (hintsfile) read_hints_file(hintsfile); extern_profile_report("Module"); sort_symbols_of_all_sec(); for (secnum = 0; secnum < nsections; secnum++) { sec = sections + secnum; printf("=== %s ===\n", sec->name); disasm_sec_by_type(sec); putchar('\n'); } exit(0); }