FreeCalypso > hg > freecalypso-reveng
view leo-obj/tool/disasm.c @ 193:37f78f986a0a
grokdsn: tree dump implemented
author | Michael Spacefalcon <falcon@ivan.Harhan.ORG> |
---|---|
date | Wed, 07 Jan 2015 08:09:30 +0000 |
parents | fcf1ef773a57 |
children | 71e25510f5af |
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; int disasm_richsym, disasm_lineno; extern int richsym_print_bitsize; 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'); } static void handle_symbol(sym, statep, linebrkp) struct internal_syment *sym; int *statep, *linebrkp; { char *sym_comment, *cpref; if (sym->class == C_FCN && !strcmp(sym->name, ".ef")) { printf("; End function\n"); return; } if (!*linebrkp) { putchar('\n'); *linebrkp = 1; } if (sym->class == C_FCN && !strcmp(sym->name, ".bf")) { printf("; Begin function\n"); if (disasm_richsym) if (richsym_function_locals(sym)) putchar('\n'); return; } switch (sym->class) { case C_EXT: sym_comment = "Global"; cpref = "; "; break; case C_STAT: sym_comment = "static"; cpref = "; static "; break; case C_LABEL: sym_comment = "label"; if (!strcmp(sym->name, "$CODE16")) *statep = 1; else if (!strcmp(sym->name, "$CODE32")) *statep = 0; break; default: sym_comment = "unexpected class!"; } printf("%s:\t; %s\n", sym->name, sym_comment); if (!disasm_richsym || sym->class != C_EXT && sym->class != C_STAT) return; if (!sym->aux || sym->name[0] != '_' && sym->name[0] != '$') return; richsym_print_in_c(cpref, sym, 0); } void disasm_emit_asciz(sec, pos, len) struct internal_scnhdr *sec; unsigned pos, len; { int c; unsigned endpos = pos + len; fputs("\t.asciz\t\"", stdout); for (; pos < endpos; pos++) { c = filemap[sec->data_offset + pos]; switch (c) { case '\b': fputs("\\b", stdout); continue; case '\t': fputs("\\t", stdout); continue; case '\n': fputs("\\n", stdout); continue; case '\r': fputs("\\r", stdout); continue; case '"': fputs("\\\"", stdout); continue; case '\\': fputs("\\\\", stdout); continue; } if (c >= ' ' && c <= '~') putchar(c); else printf("\\%03o", c); } putchar('"'); putchar('\n'); } void disasm_codedata_section(sec) struct internal_scnhdr *sec; { unsigned symnum, relnum; unsigned pos, incr, headroom; int state = -1, linebrk = 0, gothint; struct internal_syment *sym; struct internal_reloc *rel; struct hint *hint = sec->hints; u_char *asciz_end; unsigned asciz_len; unsigned *lineno_arr; unsigned lineno_cur, lineno_total; if (sec->nreloc) get_relocs_of_sec(sec); if (disasm_lineno && sec->nlineent) get_lineno_addrs(sec, &lineno_arr, &lineno_total); else { lineno_arr = 0; lineno_total = 0; } symnum = relnum = 0; lineno_cur = 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 */ handle_symbol(sym, &state, &linebrk); 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; if (hint) { if (pos >= hint->pos) gothint++; else { gothint = 0; if (hint->pos - pos < headroom) headroom = hint->pos - pos; } } else gothint = 0; if (gothint && pos == hint->pos && hint->linebrk) putchar('\n'); if (lineno_cur < lineno_total) { if (pos >= lineno_arr[lineno_cur]) { puts("; line"); lineno_cur++; } else { if (lineno_arr[lineno_cur] - pos < headroom) headroom = lineno_arr[lineno_cur] - pos; } } printf("%8x:\t", pos); if (gothint && hint->type) { if (rel) { printf("error: hint/reloc conflict\n"); return; } switch (hint->type) { case HINT_D8: printf("%02x\n", filemap[sec->data_offset + pos]); incr = 1; break; case HINT_D16: printf("%04x\n", get_u16(filemap+sec->data_offset+pos)); incr = 2; break; case HINT_D32: printf("%08x\n", get_u32(filemap+sec->data_offset+pos)); incr = 4; break; case HINT_ASCIZ: asciz_end = memchr(filemap+sec->data_offset+pos, 0, headroom); if (!asciz_end) { printf("bad asciz hint: no 0 found\n"); return; } asciz_len = asciz_end - filemap - sec->data_offset - pos; disasm_emit_asciz(sec, pos, asciz_len); incr = asciz_len + 1; } goto next; } if (rel) { if (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; } else if (sec->disasm_mode == DISASM_MODE_DATA) { printf("error: reloc other than word32 in data section\n"); return; } } 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; } if (sec->disasm_mode == DISASM_MODE_DATA) { 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; } 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 (hint && pos >= hint->endpos) hint = hint->next; } while (symnum < sec->nsymbols) { sym = sec->sorted_symbols[symnum]; if (sym->value != sec->size) { printf("error: expecting symbol at end of section\n"); return; } handle_symbol(sym, &state, &linebrk); symnum++; } if (linebrk) printf("%8x:\t<end of section>\n", sec->size); if (lineno_arr) free(lineno_arr); } void disasm_bss(sec) struct internal_scnhdr *sec; { unsigned m; struct internal_syment *sym; char classbuf[8], *cpref; 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); if (!disasm_richsym || !sym->aux || sym->name[0] != '_') continue; switch (sym->class) { case C_EXT: cpref = "; "; break; case C_STAT: cpref = "; static "; break; default: continue; } richsym_print_in_c(cpref, sym, 0); } 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: printf("Disassembling code section:\n"); disasm_codedata_section(sec); return; case DISASM_MODE_DATA: printf("Disassembling data section:\n"); disasm_codedata_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, "bgh:ls")) != EOF) switch (c) { case 'b': richsym_print_bitsize++; continue; case 'g': disasm_richsym++; continue; case 'h': hintsfile = optarg; continue; case 'l': disasm_lineno++; 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(); if (disasm_richsym) richsym_initial_preen(); for (secnum = 0; secnum < nsections; secnum++) { sec = sections + secnum; printf("=== %s ===\n", sec->name); disasm_sec_by_type(sec); putchar('\n'); } exit(0); }