FreeCalypso > hg > freecalypso-reveng
diff leo-obj/tool/disasm.c @ 130:87b82398a08b
leo-obj project subtree started, tiobjd tool moved into it
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Sun, 06 Apr 2014 22:14:39 +0000 |
parents | ticoff/disasm.c@03f8a618689e |
children | daeaa5950d10 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/leo-obj/tool/disasm.c Sun Apr 06 22:14:39 2014 +0000 @@ -0,0 +1,414 @@ +/* + * 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(); + +static 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); +}