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);
+}