[PATCH 1/4] Move common symbol loading code to separate file |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/hatari-devel Archives
]
- Subject: [PATCH 1/4] Move common symbol loading code to separate file
- From: Thorsten Otto <admin@xxxxxxxxxxx>
- Date: Wed, 31 Mar 2021 18:46:01 +0200
---
src/debug/symbols-common.c | 841 +++++++++++++++++++++++++++++++++++++
src/debug/symbols.c | 779 +---------------------------------
tools/debugger/gst2ascii.c | 763 +--------------------------------
3 files changed, 863 insertions(+), 1520 deletions(-)
create mode 100644 src/debug/symbols-common.c
diff --git a/src/debug/symbols-common.c b/src/debug/symbols-common.c
new file mode 100644
index 00000000..f36025c4
--- /dev/null
+++ b/src/debug/symbols-common.c
@@ -0,0 +1,841 @@
+/*
+ * Hatari - symbols-common.c
+ *
+ * Copyright (C) 2010-2019 by Eero Tamminen
+ *
+ * This file is distributed under the GNU General Public License, version 2
+ * or at your option any later version. Read the file gpl.txt for details.
+ *
+ * symbols-common.c - Hatari debugger symbol/address handling; parsing, sorting,
+ * matching, TAB completion support etc.
+ * This code is shared between the internal debug "symbols" command
+ * and the standalone gst2asciii tool.
+ */
+
+
+typedef struct {
+ char *name;
+ uint32_t address;
+ symtype_t type;
+} symbol_t;
+
+typedef struct {
+ int symbols; /* initial symbol count */
+ int namecount; /* final symbol count */
+ int codecount; /* TEXT symbol address count */
+ int datacount; /* DATA/BSS symbol address count */
+ symbol_t *addresses; /* TEXT + DATA/BSS items sorted by address */
+ symbol_t *names; /* all items sorted by symbol name */
+ char *strtab;
+} symbol_list_t;
+
+typedef struct {
+ uint32_t offset;
+ uint32_t end;
+} prg_section_t;
+
+/* Magic used to denote different symbol table formats */
+#define SYMBOL_FORMAT_GNU 0x474E555f /* "MiNT" */
+#define SYMBOL_FORMAT_MINT 0x4D694E54 /* "GNU_" */
+#define SYMBOL_FORMAT_DRI 0x0
+
+/* Magic identifying Atari programs */
+#define ATARI_PROGRAM_MAGIC 0x601A
+
+
+/* ------------------ load and free functions ------------------ */
+
+/**
+ * return true if given symbol name is object/library/file name
+ */
+static bool is_obj_file(const char *name)
+{
+ int len = strlen(name);
+ /* object (.a or .o) / file name? */
+ if (len > 2 && ((name[len-2] == '.' && (name[len-1] == 'a' || name[len-1] == 'o')) || strchr(name, '/'))) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * compare function for qsort() to sort according to
+ * symbol type & address. Text section symbols will
+ * be sorted first.
+ */
+static int symbols_by_address(const void *s1, const void *s2)
+{
+ const symbol_t *sym1 = (const symbol_t*)s1;
+ const symbol_t *sym2 = (const symbol_t*)s2;
+
+ /* separate TEXT type addresses from others */
+ if (sym1->type != sym2->type) {
+ if (sym1->type == SYMTYPE_TEXT) {
+ return -1;
+ }
+ if (sym2->type == SYMTYPE_TEXT) {
+ return 1;
+ }
+ }
+ /* then sort by address */
+ if (sym1->address < sym2->address) {
+ return -1;
+ }
+ if (sym1->address > sym2->address) {
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * compare function for qsort() to sort according to
+ * symbol name & address
+ */
+static int symbols_by_name(const void *s1, const void *s2)
+{
+ const symbol_t *sym1 = (const symbol_t*)s1;
+ const symbol_t *sym2 = (const symbol_t*)s2;
+ int ret;
+
+ /* first by name */
+ ret = strcmp(sym1->name, sym2->name);
+ if (ret) {
+ return ret;
+ }
+ /* then by address */
+ return (sym1->address - sym2->address);
+}
+
+/**
+ * Check for duplicate addresses in symbol list
+ * (called separately for TEXT & non-TEXT symbols)
+ * Return number of duplicates
+ */
+static int symbols_check_addresses(const symbol_t *syms, int count)
+{
+ int i, j, dups = 0;
+
+ for (i = 0; i < (count - 1); i++)
+ {
+ /* absolute symbols have values, not addresses */
+ if (syms[i].type == SYMTYPE_ABS) {
+ continue;
+ }
+ for (j = i + 1; j < count && syms[i].address == syms[j].address; j++) {
+ if (syms[j].type == SYMTYPE_ABS) {
+ continue;
+ }
+ /* ASCII symbol files contain also object file addresses,
+ * those will often have the same address as the first symbol
+ * in given object -> no point warning about them
+ */
+ if (is_obj_file(syms[i].name) || is_obj_file(syms[j].name)) {
+ continue;
+ }
+ fprintf(stderr, "WARNING: symbols '%s' & '%s' have the same 0x%x address.\n",
+ syms[i].name, syms[j].name, syms[i].address);
+ dups++;
+ i = j;
+ }
+ }
+ return dups;
+}
+
+/**
+ * Check for duplicate names in symbol list
+ * Return number of duplicates
+ */
+static int symbols_check_names(const symbol_t *syms, int count)
+{
+ int i, j, dups = 0;
+
+ for (i = 0; i < (count - 1); i++)
+ {
+ for (j = i + 1; j < count && strcmp(syms[i].name, syms[j].name) == 0; j++) {
+ /* this is common case for object files having different sections */
+ if (syms[i].type != syms[j].type && is_obj_file(syms[i].name)) {
+ continue;
+ }
+ fprintf(stderr, "WARNING: addresses 0x%x & 0x%x have the same '%s' name.\n",
+ syms[i].address, syms[j].address, syms[i].name);
+ dups++;
+ i = j;
+ }
+ }
+ return dups;
+}
+
+/**
+ * Allocate symbol list & names for given number of items.
+ * Return allocated list or NULL on failure.
+ */
+static symbol_list_t* symbol_list_alloc(int symbols)
+{
+ symbol_list_t *list;
+
+ if (!symbols) {
+ return NULL;
+ }
+ list = calloc(1, sizeof(symbol_list_t));
+ if (list) {
+ list->names = malloc(symbols * sizeof(symbol_t));
+ if (!list->names) {
+ free(list);
+ list = NULL;
+ }
+ }
+ return list;
+}
+
+/**
+ * Free symbol list & names.
+ */
+static void symbol_list_free(symbol_list_t *list)
+{
+ if (list) {
+ if (list->names) {
+ free(list->names);
+ }
+ free(list);
+ }
+}
+
+/**
+ * Return symbol type identifier char
+ */
+static char symbol_char(int type)
+{
+ switch (type) {
+ case SYMTYPE_TEXT: return 'T';
+ case SYMTYPE_DATA: return 'D';
+ case SYMTYPE_BSS: return 'B';
+ case SYMTYPE_ABS: return 'A';
+ default: return '?';
+ }
+}
+
+/**
+ * Return true if symbol name matches internal GCC symbol name,
+ * or is object / file name.
+ */
+static bool symbol_remove_obj(const char *name)
+{
+ static const char *gcc_sym[] = {
+ "___gnu_compiled_c",
+ "gcc2_compiled."
+ };
+ int i;
+
+ if (is_obj_file(name)) {
+ return true;
+ }
+ /* useless symbols GCC (v2) seems to add to every object? */
+ for (i = 0; i < ARRAY_SIZE(gcc_sym); i++) {
+ if (strcmp(name, gcc_sym[i]) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/**
+ * Load symbols of given type and the symbol address addresses from
+ * DRI/GST format symbol table, and add given offsets to the addresses:
+ * http://toshyp.atari.org/en/005005.html
+ * Return symbols list or NULL for failure.
+ */
+static symbol_list_t* symbols_load_dri(FILE *fp, prg_section_t *sections, symtype_t gettype, uint32_t tablesize, bool no_local, bool no_obj)
+{
+ int i, count, symbols, invalid;
+ int notypes, dtypes, locals, ofiles;
+ prg_section_t *section;
+ symbol_list_t *list;
+ symtype_t symtype;
+#define DRI_ENTRY_SIZE 14
+ char name[23];
+ uint16_t symid;
+ uint32_t address;
+
+ if (tablesize % DRI_ENTRY_SIZE || !tablesize) {
+ fprintf(stderr, "ERROR: invalid DRI/GST symbol table size %d!\n", tablesize);
+ return NULL;
+ }
+ symbols = tablesize / DRI_ENTRY_SIZE;
+ if (!(list = symbol_list_alloc(symbols))) {
+ return NULL;
+ }
+
+ invalid = dtypes = notypes = ofiles = locals = count = 0;
+ for (i = 1; i <= symbols; i++) {
+ /* read DRI symbol table slot */
+ if (fread(name, 8, 1, fp) != 1 ||
+ fread(&symid, sizeof(symid), 1, fp) != 1 ||
+ fread(&address, sizeof(address), 1, fp) != 1) {
+ break;
+ }
+ address = SDL_SwapBE32(address);
+ symid = SDL_SwapBE16(symid);
+
+ /* GST extended DRI symbol format? */
+ if ((symid & 0x0048)) {
+ /* next slot is rest of name */
+ i += 1;
+ if (fread(name+8, 14, 1, fp) != 1) {
+ break;
+ }
+ name[22] = '\0';
+ } else {
+ name[8] = '\0';
+ }
+
+ /* check section */
+ switch (symid & 0xf00) {
+ case 0x0200:
+ symtype = SYMTYPE_TEXT;
+ section = &(sections[0]);
+ break;
+ case 0x0400:
+ symtype = SYMTYPE_DATA;
+ section = &(sections[1]);
+ break;
+ case 0x0100:
+ symtype = SYMTYPE_BSS;
+ section = &(sections[2]);
+ break;
+ default:
+ if ((symid & 0xe000) == 0xe000) {
+ dtypes++;
+ continue;
+ }
+ if ((symid & 0x4000) == 0x4000) {
+ symtype = SYMTYPE_ABS;
+ section = NULL;
+ break;
+ }
+ fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %d of unknown type 0x%x.\n", name, i, symid);
+ invalid++;
+ continue;
+ }
+ if (!(gettype & symtype)) {
+ notypes++;
+ continue;
+ }
+ if (no_local) {
+ if (name[0] == '.' && name[1] == 'L') {
+ locals++;
+ continue;
+ }
+ }
+ if (no_obj) {
+ if (symbol_remove_obj(name)) {
+ ofiles++;
+ continue;
+ }
+ }
+ if (section) {
+ address += section->offset;
+ if (address > section->end) {
+ fprintf(stderr, "WARNING: ignoring symbol '%s' of type %c in slot %d with invalid offset 0x%x (>= 0x%x).\n",
+ name, symbol_char(symtype), i, address, section->end);
+ invalid++;
+ continue;
+ }
+ }
+ list->names[count].address = address;
+ list->names[count].type = symtype;
+ list->names[count].name = strdup(name);
+ assert(list->names[count].name);
+ count++;
+ }
+ if (i <= symbols) {
+ perror("ERROR: reading symbol failed");
+ symbol_list_free(list);
+ return NULL;
+ }
+ list->symbols = symbols;
+ list->namecount = count;
+
+ if (invalid) {
+ fprintf(stderr, "NOTE: ignored %d invalid symbols.\n", invalid);
+ }
+ if (dtypes) {
+ fprintf(stderr, "NOTE: ignored %d debugging symbols.\n", dtypes);
+ }
+ if (notypes) {
+ fprintf(stderr, "NOTE: ignored %d other unwanted symbol types.\n", notypes);
+ }
+ if (locals) {
+ fprintf(stderr, "NOTE: ignored %d unnamed / local symbols (= name starts with '.L').\n", locals);
+ }
+ if (ofiles) {
+ /* object file path names most likely get truncated and
+ * as result cause unnecessary symbol name conflicts in
+ * addition to object file addresses conflicting with
+ * first symbol in the object file.
+ */
+ fprintf(stderr, "NOTE: ignored %d object symbols (= name has '/', ends in '.[ao]' or is GCC internal).\n", ofiles);
+ }
+ return list;
+}
+
+
+/**
+ * Load symbols of given type and the symbol address addresses from
+ * a.out format symbol table, and add given offsets to the addresses.
+ * Return symbols list or NULL for failure.
+ */
+static symbol_list_t* symbols_load_gnu(FILE *fp, prg_section_t *sections, symtype_t gettype, uint32_t tablesize, Uint32 stroff, Uint32 strsize, bool no_local, bool no_obj)
+{
+ size_t slots = tablesize / SIZEOF_STRUCT_NLIST;
+ size_t i;
+ size_t strx;
+ unsigned char *p;
+ char *name;
+ symbol_t *sym;
+ symtype_t symtype;
+ uint32_t address;
+ uint32_t nread;
+ symbol_list_t *list;
+ unsigned char n_type;
+ unsigned char n_other;
+ unsigned short n_desc;
+ static char dummy[] = "<invalid>";
+ int dtypes, locals, ofiles, count, notypes, invalid, weak;
+ prg_section_t *section;
+
+ if (!(list = symbol_list_alloc(slots))) {
+ return NULL;
+ }
+
+ list->strtab = (char *)malloc(tablesize + strsize);
+
+ if (list->strtab == NULL)
+ {
+ symbol_list_free(list);
+ return NULL;
+ }
+
+ nread = fread(list->strtab, tablesize + strsize, 1, fp);
+ if (nread != 1)
+ {
+ perror("ERROR: reading symbols failed");
+ symbol_list_free(list);
+ return NULL;
+ }
+
+ p = (unsigned char *)list->strtab;
+ sym = list->names;
+
+ weak = invalid = dtypes = notypes = ofiles = locals = count = 0;
+ for (i = 0; i < slots; i++)
+ {
+ strx = SDL_SwapBE32(*(Uint32*)p);
+ p += 4;
+ n_type = *p++;
+ n_other = *p++;
+ n_desc = SDL_SwapBE16(*(Uint16*)p);
+ p += 2;
+ address = SDL_SwapBE32(*(Uint32*)p);
+ p += 4;
+ name = dummy;
+ if (!strx) {
+ invalid++;
+ continue;
+ }
+ if (strx >= strsize) {
+ fprintf(stderr, "symbol name index %x out of range\n", (unsigned int)strx);
+ invalid++;
+ continue;
+ }
+ name = list->strtab + strx + stroff;
+
+ if (n_type & N_STAB)
+ {
+ dtypes++;
+ continue;
+ }
+ section = NULL;
+ switch (n_type & (N_TYPE|N_EXT))
+ {
+ case N_UNDF:
+ case N_UNDF|N_EXT:
+ /* shouldn't happen here */
+ weak++;
+ continue;
+ case N_ABS:
+ case N_ABS|N_EXT:
+ symtype = SYMTYPE_ABS;
+ break;
+ case N_TEXT:
+ case N_TEXT|N_EXT:
+ symtype = SYMTYPE_TEXT;
+ section = &(sections[0]);
+ break;
+ case N_DATA:
+ case N_DATA|N_EXT:
+ symtype = SYMTYPE_DATA;
+ section = &(sections[1]);
+ break;
+ case N_BSS:
+ case N_BSS|N_EXT:
+ case N_COMM:
+ case N_COMM|N_EXT:
+ symtype = SYMTYPE_BSS;
+ section = &(sections[2]);
+ break;
+ case N_FN: /* filenames, not object addresses? */
+ dtypes++;
+ continue;
+ case N_SIZE:
+ case N_WARNING:
+ case N_SETA:
+ case N_SETT:
+ case N_SETD:
+ case N_SETB:
+ case N_SETV:
+ dtypes++;
+ continue;
+ case N_WEAKU:
+ case N_WEAKT:
+ case N_WEAKD:
+ case N_WEAKB:
+ weak++;
+ continue;
+ default:
+ fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %u of unknown type 0x%x.\n", name, (unsigned int)i, n_type);
+ invalid++;
+ continue;
+ }
+ /*
+ * the value of a common symbol is its size, not its address:
+ */
+ if (((n_type & N_TYPE) == N_COMM) ||
+ (((n_type & N_EXT) && (n_type & N_TYPE) == N_UNDF && address != 0)))
+ {
+ /* if we ever want to know a symbols size, get that here */
+ fprintf(stderr, "WARNING: ignoring common symbol '%s' in slot %u.\n", name, (unsigned int)i);
+ dtypes++;
+ continue;
+ }
+ if (!(gettype & symtype)) {
+ notypes++;
+ continue;
+ }
+ if (no_local) {
+ if (name[0] == '.' && name[1] == 'L') {
+ locals++;
+ continue;
+ }
+ }
+ if (no_obj) {
+ if (symbol_remove_obj(name)) {
+ ofiles++;
+ continue;
+ }
+ }
+ if (section) {
+ address += sections[0].offset; /* all GNU symbol addresses are TEXT relative */
+ if (address > section->end) {
+ fprintf(stderr, "WARNING: ignoring symbol '%s' of type %c in slot %u with invalid offset 0x%x (>= 0x%x).\n",
+ name, symbol_char(symtype), (unsigned int)i, address, section->end);
+ invalid++;
+ continue;
+ }
+ }
+ sym->address = address;
+ sym->type = symtype;
+ sym->name = name;
+ sym++;
+ count++;
+ (void) n_desc;
+ (void) n_other;
+ }
+ list->symbols = slots;
+ list->namecount = count;
+
+ if (invalid) {
+ fprintf(stderr, "NOTE: ignored %d invalid symbols.\n", invalid);
+ }
+ if (dtypes) {
+ fprintf(stderr, "NOTE: ignored %d debugging symbols.\n", dtypes);
+ }
+ if (weak) {
+ fprintf(stderr, "NOTE: ignored %d weak / undefined symbols.\n", weak);
+ }
+ if (notypes) {
+ fprintf(stderr, "NOTE: ignored %d other unwanted symbol types.\n", notypes);
+ }
+ if (locals) {
+ fprintf(stderr, "NOTE: ignored %d unnamed / local symbols (= name starts with '.L').\n", locals);
+ }
+ if (ofiles) {
+ /* object file path names most likely get truncated and
+ * as result cause unnecessary symbol name conflicts in
+ * addition to object file addresses conflicting with
+ * first symbol in the object file.
+ */
+ fprintf(stderr, "NOTE: ignored %d object symbols (= name has '/', ends in '.[ao]' or is GCC internal).\n", ofiles);
+ }
+
+ return list;
+}
+
+
+/**
+ * Print program header information.
+ * Return false for unrecognized symbol table type.
+ */
+static bool symbols_print_prg_info(Uint32 tabletype, Uint32 prgflags, Uint16 relocflag)
+{
+ static const struct {
+ Uint32 flag;
+ const char *name;
+ } flags[] = {
+ { 0x0001, "FASTLOAD" },
+ { 0x0002, "TTRAMLOAD" },
+ { 0x0004, "TTRAMMEM" },
+ { 0x0008, "MINIMUM" }, /* MagiC */
+ { 0x1000, "SHAREDTEXT" }
+ };
+ const char *info;
+ int i;
+
+ switch (tabletype) {
+ case SYMBOL_FORMAT_MINT: /* "MiNT" */
+ info = "GCC/MiNT executable, GST symbol table";
+ break;
+ case SYMBOL_FORMAT_GNU: /* "GNU_" */
+ info = "GCC/MiNT executable, a.out symbol table";
+ break;
+ case SYMBOL_FORMAT_DRI:
+ info = "TOS executable, DRI / GST symbol table";
+ break;
+ default:
+ fprintf(stderr, "ERROR: unknown executable type 0x%x!\n", tabletype);
+ return false;
+ }
+ fprintf(stderr, "%s, reloc=%d, program flags:", info, relocflag);
+ /* bit flags */
+ for (i = 0; i < ARRAY_SIZE(flags); i++) {
+ if (prgflags & flags[i].flag) {
+ fprintf(stderr, " %s", flags[i].name);
+ }
+ }
+ /* memory protection flags */
+ switch((prgflags >> 4) & 3) {
+ case 0: info = "PRIVATE"; break;
+ case 1: info = "GLOBAL"; break;
+ case 2: info = "SUPER"; break;
+ case 3: info = "READONLY"; break;
+ }
+ fprintf(stderr, " %s (0x%x)\n", info, prgflags);
+ return true;
+}
+
+/**
+ * Parse program header and use symbol table format specific
+ * loader function to load the symbols.
+ * Return symbols list or NULL for failure.
+ */
+static symbol_list_t* symbols_load_binary(FILE *fp, symtype_t gettype)
+{
+ Uint32 textlen, datalen, bsslen, tablesize, tabletype, prgflags;
+ prg_section_t sections[3];
+ int offset, reads = 0;
+ Uint16 relocflag;
+ symbol_list_t* symbols;
+ Uint32 symoff = 0;
+ Uint32 stroff = 0;
+ Uint32 strsize = 0;
+#ifdef SYMBOLS_IN_HATARI
+ Uint32 start;
+#endif
+
+ /* get TEXT, DATA & BSS section sizes */
+ fseek(fp, 2, SEEK_SET);
+ reads += fread(&textlen, sizeof(textlen), 1, fp);
+ textlen = SDL_SwapBE32(textlen);
+ reads += fread(&datalen, sizeof(datalen), 1, fp);
+ datalen = SDL_SwapBE32(datalen);
+ reads += fread(&bsslen, sizeof(bsslen), 1, fp);
+ bsslen = SDL_SwapBE32(bsslen);
+
+ /* get symbol table size & type and check that all reads succeeded */
+ reads += fread(&tablesize, sizeof(tablesize), 1, fp);
+ tablesize = SDL_SwapBE32(tablesize);
+ reads += fread(&tabletype, sizeof(tabletype), 1, fp);
+ tabletype = SDL_SwapBE32(tabletype);
+
+ /* get program header and whether there's reloc table */
+ reads += fread(&prgflags, sizeof(prgflags), 1, fp);
+ prgflags = SDL_SwapBE32(prgflags);
+ reads += fread(&relocflag, sizeof(relocflag), 1, fp);
+ relocflag = SDL_SwapBE32(relocflag);
+
+ if (reads != 7) {
+ fprintf(stderr, "ERROR: program header reading failed!\n");
+ return NULL;
+ }
+ /*
+ * check for GNU-style symbol table in aexec header
+ */
+ if (tabletype == SYMBOL_FORMAT_MINT) { /* MiNT */
+ Uint32 magic1, magic2;
+ Uint32 dummy;
+ Uint32 a_text, a_data, a_bss, a_syms, a_entry, a_trsize, a_drsize;
+ Uint32 g_tparel_pos, g_tparel_size, g_stkpos, g_symbol_format;
+
+ reads = fread(&magic1, sizeof(magic1), 1, fp);
+ magic1 = SDL_SwapBE32(magic1);
+ reads += fread(&magic2, sizeof(magic2), 1, fp);
+ magic2 = SDL_SwapBE32(magic2);
+ if (reads == 2 &&
+ ((magic1 == 0x283a001a && magic2 == 0x4efb48fa) || /* Original binutils: move.l 28(pc),d4; jmp 0(pc,d4.l) */
+ (magic1 == 0x203a001a && magic2 == 0x4efb08fa))) { /* binutils >= 2.18-mint-20080209: move.l 28(pc),d0; jmp 0(pc,d0.l) */
+ reads += fread(&dummy, sizeof(dummy), 1, fp); /* skip a_info */
+ reads += fread(&a_text, sizeof(a_text), 1, fp);
+ a_text = SDL_SwapBE32(a_text);
+ reads += fread(&a_data, sizeof(a_data), 1, fp);
+ a_data = SDL_SwapBE32(a_data);
+ reads += fread(&a_bss, sizeof(a_bss), 1, fp);
+ a_bss = SDL_SwapBE32(a_bss);
+ reads += fread(&a_syms, sizeof(a_syms), 1, fp);
+ a_syms = SDL_SwapBE32(a_syms);
+ reads += fread(&a_entry, sizeof(a_entry), 1, fp);
+ a_entry = SDL_SwapBE32(a_entry);
+ reads += fread(&a_trsize, sizeof(a_trsize), 1, fp);
+ a_trsize = SDL_SwapBE32(a_trsize);
+ reads += fread(&a_drsize, sizeof(a_drsize), 1, fp);
+ a_drsize = SDL_SwapBE32(a_drsize);
+ reads += fread(&g_tparel_pos, sizeof(g_tparel_pos), 1, fp);
+ g_tparel_pos = SDL_SwapBE32(g_tparel_pos);
+ reads += fread(&g_tparel_size, sizeof(g_tparel_size), 1, fp);
+ g_tparel_size = SDL_SwapBE32(g_tparel_size);
+ reads += fread(&g_stkpos, sizeof(g_stkpos), 1, fp);
+ g_stkpos = SDL_SwapBE32(g_stkpos);
+ reads += fread(&g_symbol_format, sizeof(g_symbol_format), 1, fp);
+ g_symbol_format = SDL_SwapBE32(g_symbol_format);
+ if (g_symbol_format == 0)
+ {
+ tabletype = SYMBOL_FORMAT_GNU;
+ }
+ if ((a_text + (256 - 28)) != textlen)
+ fprintf(stderr, "warning: inconsistent text segment size %08x != %08x\n", textlen, a_text + (256 - 28));
+ if (a_data != datalen)
+ fprintf(stderr, "warning: inconsistent data segment size %08x != %08x\n", datalen, a_data);
+ if (a_bss != bsslen)
+ fprintf(stderr, "warning: inconsistent bss segment size %08x != %08x\n", bsslen, a_bss);
+ /*
+ * the symbol table size in the GEMDOS header includes the string table,
+ * the symbol table size in the exec header does not.
+ */
+ if (tabletype == SYMBOL_FORMAT_GNU)
+ {
+ strsize = tablesize - a_syms;
+ tablesize = a_syms;
+ stroff = a_syms;
+ }
+
+ textlen = a_text + (256 - 28);
+ datalen = a_data;
+ bsslen = a_bss;
+ symoff = 0x100 + /* sizeof(extended exec header) */
+ a_text +
+ a_data +
+ a_trsize +
+ a_drsize;
+ }
+ }
+ if (!symbols_print_prg_info(tabletype, prgflags, relocflag)) {
+ return NULL;
+ }
+#ifndef SYMBOLS_IN_HATARI
+ fprintf(stderr, "Program section sizes:\n- text: %d\n- data: %d\n- bss: %d\n",
+ textlen, datalen, bsslen);
+#endif
+
+ if (!tablesize) {
+ fprintf(stderr, "ERROR: symbol table missing from the program!\n");
+ return NULL;
+ }
+#ifndef SYMBOLS_IN_HATARI
+ fprintf(stderr, "- syms: %d\n", tablesize);
+#endif
+
+#ifdef SYMBOLS_IN_HATARI
+ /* offsets & max sizes for running program TEXT/DATA/BSS section symbols */
+ start = DebugInfo_GetTEXT();
+ if (!start) {
+ fprintf(stderr, "ERROR: no valid program basepage!\n");
+ return NULL;
+ }
+ sections[0].offset = start;
+ sections[0].end = start + textlen;
+ if (DebugInfo_GetTEXTEnd() != sections[0].end) {
+ fprintf(stderr, "ERROR: given program TEXT section size differs from one in RAM!\n");
+ return NULL;
+ }
+
+ start = DebugInfo_GetDATA();
+ sections[1].offset = start;
+ sections[1].end = start + datalen;
+
+ start = DebugInfo_GetBSS();
+ sections[2].offset = start;
+ sections[2].end = start + bsslen;
+
+ if (sections[0].end != sections[1].offset) {
+ fprintf(stderr, "WARNING: DATA start doesn't match TEXT start + size!\n");
+ }
+ if (sections[1].end != sections[2].offset) {
+ fprintf(stderr, "WARNING: BSS start doesn't match DATA start + size!\n");
+ }
+#else
+
+ /* symbols already have suitable offsets, so only acceptable end position needs to be calculated */
+ sections[0].offset = 0;
+ sections[0].end = textlen;
+ sections[1].offset = textlen;
+ sections[1].end = textlen + datalen;
+ sections[2].offset = textlen + datalen;
+ sections[2].end = textlen + datalen + bsslen;
+
+#endif
+
+ if (tabletype == SYMBOL_FORMAT_GNU) {
+ /* go to start of symbol table */
+ offset = symoff;
+ if (fseek(fp, offset, SEEK_SET) < 0) {
+ perror("ERROR: seeking to symbol table failed");
+ return NULL;
+ }
+ fprintf(stderr, "Trying to load symbol table at offset 0x%x...\n", offset);
+#ifdef SYMBOLS_IN_HATARI
+ symbols = symbols_load_gnu(fp, sections, gettype, tablesize, stroff, strsize, true, true);
+#else
+ symbols = symbols_load_gnu(fp, sections, gettype, tablesize, stroff, strsize, Options.no_local, Options.no_obj);
+#endif
+ } else {
+ /* go to start of symbol table */
+ offset = 0x1C + textlen + datalen;
+ if (fseek(fp, offset, SEEK_SET) < 0) {
+ perror("ERROR: seeking to symbol table failed");
+ return NULL;
+ }
+ fprintf(stderr, "Trying to load symbol table at offset 0x%x...\n", offset);
+#ifdef SYMBOLS_IN_HATARI
+ symbols = symbols_load_dri(fp, sections, gettype, tablesize, true, true);
+#else
+ symbols = symbols_load_dri(fp, sections, gettype, tablesize, Options.no_local, Options.no_obj);
+#endif
+ }
+#ifndef SYMBOLS_IN_HATARI
+ if (!symbols) {
+ fprintf(stderr, "\n\n*** Try with 'nm -n <program>' (Atari/cross-compiler tool) instead ***\n\n");
+ return NULL;
+ }
+ fprintf(stderr, "Load the listed symbols to Hatari debugger with 'symbols <filename> TEXT'.\n");
+#endif
+ return symbols;
+}
diff --git a/src/debug/symbols.c b/src/debug/symbols.c
index bd60e7e9..982f88bf 100644
--- a/src/debug/symbols.c
+++ b/src/debug/symbols.c
@@ -36,38 +36,13 @@ const char Symbols_fileid[] = "Hatari symbols.c";
#include "configuration.h"
#include "a.out.h"
-typedef struct {
- char *name;
- Uint32 address;
- symtype_t type;
-} symbol_t;
-
-typedef struct {
- int symbols; /* initial symbol count */
- int namecount; /* final symbol count */
- int codecount; /* TEXT symbol address count */
- int datacount; /* DATA/BSS symbol address count */
- symbol_t *addresses; /* TEXT + DATA/BSS items sorted by address */
- symbol_t *names; /* all items sorted by symbol name */
- char *strtab;
-} symbol_list_t;
-
-typedef struct {
- Uint32 offset;
- Uint32 end;
-} prg_section_t;
-
-
/* how many characters the symbol name can have.
* NOTE: change also sscanf width arg if you change this!!!
*/
#define MAX_SYM_SIZE 32
-/* Magic used to denote different symbol table formats */
-#define SYMBOL_FORMAT_GNU 0x474E555f /* "MiNT" */
-#define SYMBOL_FORMAT_MINT 0x4D694E54 /* "GNU_" */
-#define SYMBOL_FORMAT_DRI 0x0
-
+#define SYMBOLS_IN_HATARI 1
+#include "symbols-common.c"
/* TODO: add symbol name/address file names to configuration? */
static symbol_list_t *CpuSymbolsList;
@@ -81,756 +56,6 @@ static bool SymbolsAreForProgram;
static bool AutoLoadFailed;
-/* ------------------ load and free functions ------------------ */
-
-/**
- * return true if given symbol name is object/library/file name
- */
-static bool is_obj_file(const char *name)
-{
- int len = strlen(name);
- /* object (.a or .o) / file name? */
- if (len > 2 && ((name[len-2] == '.' && (name[len-1] == 'a' || name[len-1] == 'o')) || strchr(name, '/'))) {
- return true;
- }
- return false;
-}
-
-/**
- * compare function for qsort() to sort according to
- * symbol type & address. Text section symbols will
- * be sorted first.
- */
-static int symbols_by_address(const void *s1, const void *s2)
-{
- const symbol_t *sym1 = (const symbol_t*)s1;
- const symbol_t *sym2 = (const symbol_t*)s2;
-
- /* separate TEXT type addresses from others */
- if (sym1->type != sym2->type) {
- if (sym1->type == SYMTYPE_TEXT) {
- return -1;
- }
- if (sym2->type == SYMTYPE_TEXT) {
- return 1;
- }
- }
- /* then sort by address */
- if (sym1->address < sym2->address) {
- return -1;
- }
- if (sym1->address > sym2->address) {
- return 1;
- }
- return 0;
-}
-
-/**
- * compare function for qsort() to sort according to
- * symbol name & address
- */
-static int symbols_by_name(const void *s1, const void *s2)
-{
- const symbol_t *sym1 = (const symbol_t*)s1;
- const symbol_t *sym2 = (const symbol_t*)s2;
- int ret;
-
- /* first by name */
- ret = strcmp(sym1->name, sym2->name);
- if (ret) {
- return ret;
- }
- /* then by address */
- return (sym1->address - sym2->address);
-}
-
-/**
- * Check for duplicate addresses in symbol list
- * (called separately for TEXT & non-TEXT symbols)
- * Return number of duplicates
- */
-static int symbols_check_addresses(const symbol_t *syms, int count)
-{
- int i, j, dups = 0;
-
- for (i = 0; i < (count - 1); i++)
- {
- /* absolute symbols have values, not addresses */
- if (syms[i].type == SYMTYPE_ABS) {
- continue;
- }
- for (j = i + 1; j < count && syms[i].address == syms[j].address; j++) {
- if (syms[j].type == SYMTYPE_ABS) {
- continue;
- }
- /* ASCII symbol files contain also object file addresses,
- * those will often have the same address as the first symbol
- * in given object -> no point warning about them
- */
- if (is_obj_file(syms[i].name) || is_obj_file(syms[j].name)) {
- continue;
- }
- fprintf(stderr, "WARNING: symbols '%s' & '%s' have the same 0x%x address\n",
- syms[i].name, syms[j].name, syms[i].address);
- dups++;
- i = j;
- }
- }
- return dups;
-}
-
-/**
- * Check for duplicate names in symbol list
- * Return number of duplicates
- */
-static int symbols_check_names(const symbol_t *syms, int count)
-{
- int i, j, dups = 0;
-
- for (i = 0; i < (count - 1); i++)
- {
- for (j = i + 1; j < count && strcmp(syms[i].name, syms[j].name) == 0; j++) {
- /* this is common case for object files having different sections */
- if (syms[i].type != syms[j].type && is_obj_file(syms[i].name)) {
- continue;
- }
- fprintf(stderr, "WARNING: addresses 0x%x & 0x%x have the same '%s' name\n",
- syms[i].address, syms[j].address, syms[i].name);
- dups++;
- i = j;
- }
- }
- return dups;
-}
-
-/**
- * Allocate symbol list & names for given number of items.
- * Return allocated list or NULL on failure.
- */
-static symbol_list_t* symbol_list_alloc(int symbols)
-{
- symbol_list_t *list;
-
- if (!symbols) {
- return NULL;
- }
- list = calloc(1, sizeof(symbol_list_t));
- if (list) {
- list->names = malloc(symbols * sizeof(symbol_t));
- if (!list->names) {
- free(list);
- list = NULL;
- }
- }
- return list;
-}
-
-/**
- * Free symbol list & names.
- */
-static void symbol_list_free(symbol_list_t *list)
-{
- if (list) {
- if (list->names) {
- free(list->names);
- }
- free(list);
- }
-}
-
-/**
- * Return symbol type identifier char
- */
-static char symbol_char(int type)
-{
- switch (type) {
- case SYMTYPE_TEXT: return 'T';
- case SYMTYPE_DATA: return 'D';
- case SYMTYPE_BSS: return 'B';
- case SYMTYPE_ABS: return 'A';
- default: return '?';
- }
-}
-
-/**
- * Return true if symbol name matches internal GCC symbol name,
- * or is object / file name.
- */
-static bool symbol_remove_obj(const char *name)
-{
- static const char *gcc_sym[] = {
- "___gnu_compiled_c",
- "gcc2_compiled."
- };
- int i;
-
- if (is_obj_file(name)) {
- return true;
- }
- /* useless symbols GCC (v2) seems to add to every object? */
- for (i = 0; i < ARRAY_SIZE(gcc_sym); i++) {
- if (strcmp(name, gcc_sym[i]) == 0) {
- return true;
- }
- }
- return false;
-}
-
-
-/**
- * Load symbols of given type and the symbol address addresses from
- * DRI/GST format symbol table, and add given offsets to the addresses:
- * http://toshyp.atari.org/en/005005.html
- * Return symbols list or NULL for failure.
- */
-static symbol_list_t* symbols_load_dri(FILE *fp, prg_section_t *sections, symtype_t gettype, Uint32 tablesize)
-{
- int i, count, symbols, invalid;
- int notypes, dtypes, locals, ofiles;
- prg_section_t *section;
- symbol_list_t *list;
- symtype_t symtype;
-#define DRI_ENTRY_SIZE 14
- char name[23];
- Uint16 symid;
- Uint32 address;
-
- if (tablesize % DRI_ENTRY_SIZE || !tablesize) {
- fprintf(stderr, "ERROR: invalid DRI/GST symbol table size %d!\n", tablesize);
- return NULL;
- }
- symbols = tablesize / DRI_ENTRY_SIZE;
- if (!(list = symbol_list_alloc(symbols))) {
- return NULL;
- }
-
- invalid = dtypes = notypes = ofiles = locals = count = 0;
- for (i = 1; i <= symbols; i++) {
- /* read DRI symbol table slot */
- if (fread(name, 8, 1, fp) != 1 ||
- fread(&symid, sizeof(symid), 1, fp) != 1 ||
- fread(&address, sizeof(address), 1, fp) != 1) {
- break;
- }
- address = SDL_SwapBE32(address);
- symid = SDL_SwapBE16(symid);
-
- /* GST extended DRI symbol format? */
- if ((symid & 0x0048)) {
- /* next slot is rest of name */
- i += 1;
- if (fread(name+8, 14, 1, fp) != 1) {
- break;
- }
- name[22] = '\0';
- } else {
- name[8] = '\0';
- }
-
- /* check section */
- switch (symid & 0xf00) {
- case 0x0200:
- symtype = SYMTYPE_TEXT;
- section = &(sections[0]);
- break;
- case 0x0400:
- symtype = SYMTYPE_DATA;
- section = &(sections[1]);
- break;
- case 0x0100:
- symtype = SYMTYPE_BSS;
- section = &(sections[2]);
- break;
- default:
- if ((symid & 0xe000) == 0xe000) {
- dtypes++;
- continue;
- }
- if ((symid & 0x4000) == 0x4000) {
- symtype = SYMTYPE_ABS;
- section = NULL;
- break;
- }
- fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %d of unknown type 0x%x.\n", name, i, symid);
- invalid++;
- continue;
- }
- if (!(gettype & symtype)) {
- notypes++;
- continue;
- }
- if (name[0] == '.' && name[1] == 'L') {
- locals++;
- continue;
- }
- if (symbol_remove_obj(name)) {
- ofiles++;
- continue;
- }
- if (section) {
- address += section->offset;
- if (address > section->end) {
- fprintf(stderr, "WARNING: ignoring symbol '%s' of type %c in slot %d with invalid offset 0x%x (>= 0x%x).\n",
- name, symbol_char(symtype), i, address, section->end);
- invalid++;
- continue;
- }
- }
- list->names[count].address = address;
- list->names[count].type = symtype;
- list->names[count].name = strdup(name);
- assert(list->names[count].name);
- count++;
- }
- if (i <= symbols) {
- perror("ERROR: reading symbol failed");
- symbol_list_free(list);
- return NULL;
- }
- list->symbols = symbols;
- list->namecount = count;
-
- if (invalid) {
- fprintf(stderr, "NOTE: ignored %d invalid symbols.\n", invalid);
- }
- if (dtypes) {
- fprintf(stderr, "NOTE: ignored %d debugging symbols.\n", dtypes);
- }
- if (notypes) {
- fprintf(stderr, "NOTE: ignored %d other unwanted symbol types.\n", notypes);
- }
- if (locals) {
- fprintf(stderr, "NOTE: ignored %d unnamed / local symbols (= name starts with '.L').\n", locals);
- }
- if (ofiles) {
- /* object file path names most likely get truncated and
- * as result cause unnecessary symbol name conflicts in
- * addition to object file addresses conflicting with
- * first symbol in the object file.
- */
- fprintf(stderr, "NOTE: ignored %d object symbols (= name has '/', ends in '.[ao]' or is GCC internal).\n", ofiles);
- }
- return list;
-}
-
-
-/**
- * Load symbols of given type and the symbol address addresses from
- * a.out format symbol table, and add given offsets to the addresses.
- * Return symbols list or NULL for failure.
- */
-static symbol_list_t* symbols_load_gnu(FILE *fp, prg_section_t *sections, symtype_t gettype, Uint32 tablesize, Uint32 stroff, Uint32 strsize)
-{
- size_t slots = tablesize / SIZEOF_STRUCT_NLIST;
- size_t i;
- size_t strx;
- unsigned char *p;
- char *name;
- symbol_t *sym;
- symtype_t symtype;
- uint32_t address;
- uint32_t nread;
- symbol_list_t *list;
- unsigned char n_type;
- unsigned char n_other;
- unsigned short n_desc;
- static char dummy[] = "<invalid>";
- int dtypes, locals, ofiles, count, notypes, invalid, weak;
- prg_section_t *section;
-
- if (!(list = symbol_list_alloc(slots))) {
- return NULL;
- }
-
- list->strtab = (char *)malloc(tablesize + strsize);
-
- if (list->strtab == NULL)
- {
- symbol_list_free(list);
- return NULL;
- }
-
- nread = fread(list->strtab, tablesize + strsize, 1, fp);
- if (nread != 1)
- {
- perror("ERROR: reading symbols failed");
- symbol_list_free(list);
- return NULL;
- }
-
- p = (unsigned char *)list->strtab;
- sym = list->names;
-
- weak = invalid = dtypes = notypes = ofiles = locals = count = 0;
- for (i = 0; i < slots; i++)
- {
- strx = SDL_SwapBE32(*(Uint32*)p);
- p += 4;
- n_type = *p++;
- n_other = *p++;
- n_desc = SDL_SwapBE16(*(Uint16*)p);
- p += 2;
- address = SDL_SwapBE32(*(Uint32*)p);
- p += 4;
- name = dummy;
- if (!strx) {
- invalid++;
- continue;
- }
- if (strx >= strsize) {
- fprintf(stderr, "symbol name index %x out of range\n", (unsigned int)strx);
- invalid++;
- continue;
- }
- name = list->strtab + strx + stroff;
-
- if (n_type & N_STAB)
- {
- dtypes++;
- continue;
- }
- section = NULL;
- switch (n_type & (N_TYPE|N_EXT))
- {
- case N_UNDF:
- case N_UNDF|N_EXT:
- /* shouldn't happen here */
- weak++;
- continue;
- case N_ABS:
- case N_ABS|N_EXT:
- symtype = SYMTYPE_ABS;
- break;
- case N_TEXT:
- case N_TEXT|N_EXT:
- symtype = SYMTYPE_TEXT;
- section = &(sections[0]);
- break;
- case N_DATA:
- case N_DATA|N_EXT:
- symtype = SYMTYPE_DATA;
- section = &(sections[1]);
- break;
- case N_BSS:
- case N_BSS|N_EXT:
- case N_COMM:
- case N_COMM|N_EXT:
- symtype = SYMTYPE_BSS;
- section = &(sections[2]);
- break;
- case N_FN: /* filenames, not object addresses? */
- dtypes++;
- continue;
- case N_SIZE:
- case N_WARNING:
- case N_SETA:
- case N_SETT:
- case N_SETD:
- case N_SETB:
- case N_SETV:
- dtypes++;
- continue;
- case N_WEAKU:
- case N_WEAKT:
- case N_WEAKD:
- case N_WEAKB:
- weak++;
- continue;
- default:
- fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %u of unknown type 0x%x.\n", name, (unsigned int)i, n_type);
- invalid++;
- continue;
- }
- /*
- * the value of a common symbol is its size, not its address:
- */
- if (((n_type & N_TYPE) == N_COMM) ||
- (((n_type & N_EXT) && (n_type & N_TYPE) == N_UNDF && address != 0)))
- {
- /* if we ever want to know a symbols size, get that here */
- fprintf(stderr, "WARNING: ignoring common symbol '%s' in slot %u.\n", name, (unsigned int)i);
- dtypes++;
- continue;
- }
- if (!(gettype & symtype)) {
- notypes++;
- continue;
- }
- if (name[0] == '.' && name[1] == 'L') {
- locals++;
- continue;
- }
- if (symbol_remove_obj(name)) {
- ofiles++;
- continue;
- }
- if (section) {
- address += sections[0].offset; /* all GNU symbol addresses are TEXT relative */
- if (address > section->end) {
- fprintf(stderr, "WARNING: ignoring symbol '%s' of type %c in slot %u with invalid offset 0x%x (>= 0x%x).\n",
- name, symbol_char(symtype), (unsigned int)i, address, section->end);
- invalid++;
- continue;
- }
- }
- sym->address = address;
- sym->type = symtype;
- sym->name = name;
- sym++;
- count++;
- (void) n_desc;
- (void) n_other;
- }
- list->symbols = slots;
- list->namecount = count;
-
- if (invalid) {
- fprintf(stderr, "NOTE: ignored %d invalid symbols.\n", invalid);
- }
- if (dtypes) {
- fprintf(stderr, "NOTE: ignored %d debugging symbols.\n", dtypes);
- }
- if (weak) {
- fprintf(stderr, "NOTE: ignored %d weak / undefined symbols.\n", weak);
- }
- if (notypes) {
- fprintf(stderr, "NOTE: ignored %d other unwanted symbol types.\n", notypes);
- }
- if (locals) {
- fprintf(stderr, "NOTE: ignored %d unnamed / local symbols (= name starts with '.L').\n", locals);
- }
- if (ofiles) {
- /* object file path names most likely get truncated and
- * as result cause unnecessary symbol name conflicts in
- * addition to object file addresses conflicting with
- * first symbol in the object file.
- */
- fprintf(stderr, "NOTE: ignored %d object symbols (= name has '/', ends in '.[ao]' or is GCC internal).\n", ofiles);
- }
- return list;
-}
-
-
-/**
- * Print program header information.
- * Return false for unrecognized symbol table type.
- */
-static bool symbols_print_prg_info(Uint32 tabletype, Uint32 prgflags, Uint16 relocflag)
-{
- static const struct {
- Uint32 flag;
- const char *name;
- } flags[] = {
- { 0x0001, "FASTLOAD" },
- { 0x0002, "TTRAMLOAD" },
- { 0x0004, "TTRAMMEM" },
- { 0x0008, "MINIMUM" }, /* MagiC */
- { 0x1000, "SHAREDTEXT" }
- };
- const char *info;
- int i;
-
- switch (tabletype) {
- case SYMBOL_FORMAT_MINT: /* "MiNT" */
- info = "GCC/MiNT executable, GST symbol table";
- break;
- case SYMBOL_FORMAT_GNU: /* "GNU_" */
- info = "GCC/MiNT executable, a.out symbol table";
- break;
- case SYMBOL_FORMAT_DRI:
- info = "TOS executable, DRI / GST symbol table";
- break;
- default:
- fprintf(stderr, "ERROR: unknown executable type 0x%x!\n", tabletype);
- return false;
- }
- fprintf(stderr, "%s, reloc=%d, program flags:", info, relocflag);
- /* bit flags */
- for (i = 0; i < ARRAY_SIZE(flags); i++) {
- if (prgflags & flags[i].flag) {
- fprintf(stderr, " %s", flags[i].name);
- }
- }
- /* memory protection flags */
- switch((prgflags >> 4) & 3) {
- case 0: info = "PRIVATE"; break;
- case 1: info = "GLOBAL"; break;
- case 2: info = "SUPER"; break;
- case 3: info = "READONLY"; break;
- }
- fprintf(stderr, " %s (0x%x)\n", info, prgflags);
- return true;
-}
-
-/**
- * Parse program header and use symbol table format specific
- * loader function to load the symbols.
- * Return symbols list or NULL for failure.
- */
-static symbol_list_t* symbols_load_binary(FILE *fp, symtype_t gettype)
-{
- Uint32 textlen, datalen, bsslen, start, tablesize, tabletype, prgflags;
- prg_section_t sections[3];
- int offset, reads = 0;
- Uint16 relocflag;
- symbol_list_t* symbols;
- Uint32 symoff = 0;
- Uint32 stroff = 0;
- Uint32 strsize = 0;
-
- /* get TEXT, DATA & BSS section sizes */
- fseek(fp, 2, SEEK_SET);
- reads += fread(&textlen, sizeof(textlen), 1, fp);
- textlen = SDL_SwapBE32(textlen);
- reads += fread(&datalen, sizeof(datalen), 1, fp);
- datalen = SDL_SwapBE32(datalen);
- reads += fread(&bsslen, sizeof(bsslen), 1, fp);
- bsslen = SDL_SwapBE32(bsslen);
-
- /* get symbol table size & type and check that all reads succeeded */
- reads += fread(&tablesize, sizeof(tablesize), 1, fp);
- tablesize = SDL_SwapBE32(tablesize);
- reads += fread(&tabletype, sizeof(tabletype), 1, fp);
- tabletype = SDL_SwapBE32(tabletype);
-
- /* get program header and whether there's reloc table */
- reads += fread(&prgflags, sizeof(prgflags), 1, fp);
- prgflags = SDL_SwapBE32(prgflags);
- reads += fread(&relocflag, sizeof(relocflag), 1, fp);
- relocflag = SDL_SwapBE32(relocflag);
-
- if (reads != 7) {
- fprintf(stderr, "ERROR: program header reading failed!\n");
- return NULL;
- }
- /*
- * check for GNU-style symbol table in aexec header
- */
- if (tabletype == SYMBOL_FORMAT_MINT) { /* MiNT */
- Uint32 magic1, magic2;
- Uint32 dummy;
- Uint32 a_text, a_data, a_bss, a_syms, a_entry, a_trsize, a_drsize;
- Uint32 g_tparel_pos, g_tparel_size, g_stkpos, g_symbol_format;
-
- reads = fread(&magic1, sizeof(magic1), 1, fp);
- magic1 = SDL_SwapBE32(magic1);
- reads += fread(&magic2, sizeof(magic2), 1, fp);
- magic2 = SDL_SwapBE32(magic2);
- if (reads == 2 &&
- ((magic1 == 0x283a001a && magic2 == 0x4efb48fa) || /* Original binutils: move.l 28(pc),d4; jmp 0(pc,d4.l) */
- (magic1 == 0x203a001a && magic2 == 0x4efb08fa))) { /* binutils >= 2.18-mint-20080209: move.l 28(pc),d0; jmp 0(pc,d0.l) */
- reads += fread(&dummy, sizeof(dummy), 1, fp); /* skip a_info */
- reads += fread(&a_text, sizeof(a_text), 1, fp);
- a_text = SDL_SwapBE32(a_text);
- reads += fread(&a_data, sizeof(a_data), 1, fp);
- a_data = SDL_SwapBE32(a_data);
- reads += fread(&a_bss, sizeof(a_bss), 1, fp);
- a_bss = SDL_SwapBE32(a_bss);
- reads += fread(&a_syms, sizeof(a_syms), 1, fp);
- a_syms = SDL_SwapBE32(a_syms);
- reads += fread(&a_entry, sizeof(a_entry), 1, fp);
- a_entry = SDL_SwapBE32(a_entry);
- reads += fread(&a_trsize, sizeof(a_trsize), 1, fp);
- a_trsize = SDL_SwapBE32(a_trsize);
- reads += fread(&a_drsize, sizeof(a_drsize), 1, fp);
- a_drsize = SDL_SwapBE32(a_drsize);
- reads += fread(&g_tparel_pos, sizeof(g_tparel_pos), 1, fp);
- g_tparel_pos = SDL_SwapBE32(g_tparel_pos);
- reads += fread(&g_tparel_size, sizeof(g_tparel_size), 1, fp);
- g_tparel_size = SDL_SwapBE32(g_tparel_size);
- reads += fread(&g_stkpos, sizeof(g_stkpos), 1, fp);
- g_stkpos = SDL_SwapBE32(g_stkpos);
- reads += fread(&g_symbol_format, sizeof(g_symbol_format), 1, fp);
- g_symbol_format = SDL_SwapBE32(g_symbol_format);
- if (g_symbol_format == 0)
- {
- tabletype = SYMBOL_FORMAT_GNU;
- }
- if ((a_text + (256 - 28)) != textlen)
- fprintf(stderr, "warning: inconsistent text segment size %08x != %08x\n", textlen, a_text + (256 - 28));
- if (a_data != datalen)
- fprintf(stderr, "warning: inconsistent data segment size %08x != %08x\n", datalen, a_data);
- if (a_bss != bsslen)
- fprintf(stderr, "warning: inconsistent bss segment size %08x != %08x\n", bsslen, a_bss);
- /*
- * the symbol table size in the GEMDOS header includes the string table,
- * the symbol table size in the exec header does not.
- */
- if (tabletype == SYMBOL_FORMAT_GNU)
- {
- strsize = tablesize - a_syms;
- tablesize = a_syms;
- stroff = a_syms;
- }
-
- textlen = a_text + (256 - 28);
- datalen = a_data;
- bsslen = a_bss;
- symoff = 0x100 + /* sizeof(extended exec header) */
- a_text +
- a_data +
- a_trsize +
- a_drsize;
- }
- }
- if (!symbols_print_prg_info(tabletype, prgflags, relocflag)) {
- return NULL;
- }
- if (!tablesize) {
- fprintf(stderr, "ERROR: symbol table missing from the program!\n");
- return NULL;
- }
-
- /* offsets & max sizes for running program TEXT/DATA/BSS section symbols */
- start = DebugInfo_GetTEXT();
- if (!start) {
- fprintf(stderr, "ERROR: no valid program basepage!\n");
- return NULL;
- }
- sections[0].offset = start;
- sections[0].end = start + textlen;
- if (DebugInfo_GetTEXTEnd() != sections[0].end) {
- fprintf(stderr, "ERROR: given program TEXT section size differs from one in RAM!\n");
- return NULL;
- }
-
- start = DebugInfo_GetDATA();
- sections[1].offset = start;
- sections[1].end = start + datalen;
-
- start = DebugInfo_GetBSS();
- sections[2].offset = start;
- sections[2].end = start + bsslen;
-
- if (sections[0].end != sections[1].offset) {
- fprintf(stderr, "WARNING: DATA start doesn't match TEXT start + size!\n");
- }
- if (sections[1].end != sections[2].offset) {
- fprintf(stderr, "WARNING: BSS start doesn't match DATA start + size!\n");
- }
-
- if (tabletype == SYMBOL_FORMAT_GNU) {
- /* go to start of symbol table */
- offset = symoff;
- if (fseek(fp, offset, SEEK_SET) < 0) {
- perror("ERROR: seeking to symbol table failed");
- return NULL;
- }
- fprintf(stderr, "Trying to load symbol table at offset 0x%x...\n", offset);
- symbols = symbols_load_gnu(fp, sections, gettype, tablesize, stroff, strsize);
- } else {
- /* go to start of symbol table */
- offset = 0x1C + textlen + datalen;
- if (fseek(fp, offset, SEEK_SET) < 0) {
- perror("ERROR: seeking to symbol table failed");
- return NULL;
- }
- fprintf(stderr, "Trying to load symbol table at offset 0x%x...\n", offset);
- symbols = symbols_load_dri(fp, sections, gettype, tablesize);
- }
- return symbols;
-}
-
/**
* Load symbols of given type and the symbol address addresses from
* the given ASCII file and add given offsets to the addresses.
diff --git a/tools/debugger/gst2ascii.c b/tools/debugger/gst2ascii.c
index 8572a93f..efeb197f 100644
--- a/tools/debugger/gst2ascii.c
+++ b/tools/debugger/gst2ascii.c
@@ -34,33 +34,16 @@ typedef enum {
SYMTYPE_ABS = 8
} symtype_t;
-typedef struct {
- char *name;
- uint32_t address;
- symtype_t type;
-} symbol_t;
-
-typedef struct {
- int count; /* final symbol count */
- int symbols; /* initial symbol count */
- symbol_t *addresses; /* items sorted by address */
- symbol_t *names; /* items sorted by symbol name */
- char *strtab;
-} symbol_list_t;
-
-typedef struct {
- uint32_t offset;
- uint32_t end;
-} prg_section_t;
-
-/* Magic used to denote different symbol table formats */
-#define SYMBOL_FORMAT_GNU 0x474E555f /* "MiNT" */
-#define SYMBOL_FORMAT_MINT 0x4D694E54 /* "GNU_" */
-#define SYMBOL_FORMAT_DRI 0x0
+#define ARRAY_SIZE(x) (int)(sizeof(x)/sizeof(x[0]))
-/* Magic identifying Atari programs */
-#define ATARI_PROGRAM_MAGIC 0x601A
+static struct {
+ symtype_t notypes;
+ bool no_local;
+ bool no_obj;
+ bool sort_name;
+} Options;
+#include "../../src/debug/symbols-common.c"
/* ------------------ options & usage ------------------ */
@@ -70,17 +53,8 @@ typedef struct {
#define PATHSEP '/'
#endif
-#define ARRAY_SIZE(x) (int)(sizeof(x)/sizeof(x[0]))
-
static const char *PrgPath;
-static struct {
- symtype_t notypes;
- bool no_local;
- bool no_obj;
- bool sort_name;
-} Options;
-
/*
* Show program usage, given error message, and exit
*/
@@ -129,703 +103,6 @@ static void usage(const char *msg)
exit(msg != NULL);
}
-/* ------------------ load and free functions ------------------ */
-
-/**
- * compare function for qsort() to sort according to symbol address
- */
-static int symbols_by_address(const void *s1, const void *s2)
-{
- uint32_t addr1 = ((const symbol_t*)s1)->address;
- uint32_t addr2 = ((const symbol_t*)s2)->address;
-
- if (addr1 < addr2) {
- return -1;
- }
- if (addr1 > addr2) {
- return 1;
- }
- return 0;
-}
-
-/**
- * compare function for qsort() to sort according to symbol name
- */
-static int symbols_by_name(const void *s1, const void *s2)
-{
- const char* name1 = ((const symbol_t*)s1)->name;
- const char* name2 = ((const symbol_t*)s2)->name;
- int ret;
-
- ret = strcmp(name1, name2);
- return ret;
-}
-
-/**
- * check for duplicate addresses in symbol list
- */
-static void symbols_check_addresses(const symbol_t *syms, int count)
-{
- int i, j;
-
- for (i = 0; i < (count - 1); i++)
- {
- /* absolute symbols have values, not addresses */
- if (syms[i].type == SYMTYPE_ABS) {
- continue;
- }
- for (j = i + 1; j < count && syms[i].address == syms[j].address; j++) {
- if (syms[j].type == SYMTYPE_ABS) {
- continue;
- }
- fprintf(stderr, "WARNING: symbols '%s' & '%s' have the same 0x%x address.\n",
- syms[i].name, syms[j].name, syms[i].address);
- i = j;
- }
- }
-}
-
-/**
- * check for duplicate names in symbol list
- */
-static void symbols_check_names(const symbol_t *syms, int count)
-{
- int i, j;
-
- for (i = 0; i < (count - 1); i++)
- {
- for (j = i + 1; j < count && strcmp(syms[i].name, syms[j].name) == 0; j++) {
- fprintf(stderr, "WARNING: addresses 0x%x & 0x%x have the same '%s' name.\n",
- syms[i].address, syms[j].address, syms[i].name);
- i = j;
- }
- }
-}
-
-/**
- * Allocate symbol list & names for given number of items.
- * Return allocated list or NULL on failure.
- */
-static symbol_list_t* symbol_list_alloc(int symbols)
-{
- symbol_list_t *list;
-
- if (!symbols) {
- return NULL;
- }
- list = calloc(1, sizeof(symbol_list_t));
- if (list) {
- list->names = malloc(symbols * sizeof(symbol_t));
- if (!list->names) {
- free(list);
- list = NULL;
- }
- }
- return list;
-}
-
-/**
- * Free symbol list & names.
- */
-static void symbol_list_free(symbol_list_t *list)
-{
- if (list) {
- if (list->names) {
- free(list->names);
- }
- free(list);
- }
-}
-
-/**
- * Return symbol type identifier char
- */
-static char symbol_char(int type)
-{
- switch (type) {
- case SYMTYPE_TEXT: return 'T';
- case SYMTYPE_DATA: return 'D';
- case SYMTYPE_BSS: return 'B';
- case SYMTYPE_ABS: return 'A';
- default: return '?';
- }
-}
-
-/**
- * Return true if symbol name matches internal GCC symbol name,
- * or is object / file name.
- */
-static bool symbol_remove_obj(const char *name)
-{
- static const char *gcc_sym[] = {
- "___gnu_compiled_c",
- "gcc2_compiled."
- };
- int i, len = strlen(name);
- /* object (.a or .o) / file name? */
- if (len > 2 && ((name[len-2] == '.' && (name[len-1] == 'a' || name[len-1] == 'o')) || strchr(name, '/'))) {
- return true;
- }
- /* useless symbols GCC (v2) seems to add to every object? */
- for (i = 0; i < ARRAY_SIZE(gcc_sym); i++) {
- if (strcmp(name, gcc_sym[i]) == 0) {
- return true;
- }
- }
- return false;
-}
-
-
-/**
- * Load symbols of given type and the symbol address addresses from
- * DRI/GST format symbol table, and add given offsets to the addresses:
- * http://toshyp.atari.org/en/005005.html
- * Return symbols list or NULL for failure.
- */
-static symbol_list_t* symbols_load_dri(FILE *fp, prg_section_t *sections, uint32_t tablesize)
-{
- int i, count, symbols, invalid;
- int notypes, dtypes, locals, ofiles;
- prg_section_t *section;
- symbol_list_t *list;
- symtype_t symtype;
-#define DRI_ENTRY_SIZE 14
- char name[23];
- uint16_t symid;
- uint32_t address;
-
- if (tablesize % DRI_ENTRY_SIZE) {
- fprintf(stderr, "ERROR: invalid DRI/GST symbol table size %d!\n", tablesize);
- return NULL;
- }
- symbols = tablesize / DRI_ENTRY_SIZE;
- if (!(list = symbol_list_alloc(symbols))) {
- return NULL;
- }
-
- invalid = dtypes = notypes = ofiles = locals = count = 0;
- for (i = 1; i <= symbols; i++) {
- /* read DRI symbol table slot */
- if (fread(name, 8, 1, fp) != 1 ||
- fread(&symid, sizeof(symid), 1, fp) != 1 ||
- fread(&address, sizeof(address), 1, fp) != 1) {
- break;
- }
- address = SDL_SwapBE32(address);
- symid = SDL_SwapBE16(symid);
-
- /* GST extended DRI symbol format? */
- if ((symid & 0x0048)) {
- /* next slot is rest of name */
- i += 1;
- if (fread(name+8, 14, 1, fp) != 1) {
- break;
- }
- name[22] = '\0';
- } else {
- name[8] = '\0';
- }
-
- /* check section */
- switch (symid & 0xf00) {
- case 0x0200:
- symtype = SYMTYPE_TEXT;
- section = &(sections[0]);
- break;
- case 0x0400:
- symtype = SYMTYPE_DATA;
- section = &(sections[1]);
- break;
- case 0x0100:
- symtype = SYMTYPE_BSS;
- section = &(sections[2]);
- break;
- default:
- if ((symid & 0xe000) == 0xe000) {
- dtypes++;
- continue;
- }
- if ((symid & 0x4000) == 0x4000) {
- symtype = SYMTYPE_ABS;
- section = NULL;
- break;
- }
- fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %d of unknown type 0x%x.\n", name, i, symid);
- invalid++;
- continue;
- }
- if (Options.notypes & symtype) {
- notypes++;
- continue;
- }
- if (Options.no_local) {
- if (name[0] == '.' && name[1] == 'L') {
- locals++;
- continue;
- }
- }
- if (Options.no_obj) {
- if (symbol_remove_obj(name)) {
- ofiles++;
- continue;
- }
- }
- if (section) {
- address += section->offset;
- if (address > section->end) {
- fprintf(stderr, "WARNING: ignoring symbol '%s' of type %c in slot %d with invalid offset 0x%x (>= 0x%x).\n",
- name, symbol_char(symtype), i, address, section->end);
- invalid++;
- continue;
- }
- }
- list->names[count].address = address;
- list->names[count].type = symtype;
- list->names[count].name = strdup(name);
- assert(list->names[count].name);
- count++;
- }
- if (i <= symbols) {
- perror("ERROR: reading symbol failed");
- symbol_list_free(list);
- return NULL;
- }
- if (invalid) {
- fprintf(stderr, "NOTE: ignored %d invalid symbols.\n", invalid);
- }
- if (dtypes) {
- fprintf(stderr, "NOTE: ignored %d debugging symbols.\n", dtypes);
- }
- if (notypes) {
- fprintf(stderr, "NOTE: ignored %d other unwanted symbol types.\n", notypes);
- }
- if (locals) {
- fprintf(stderr, "NOTE: ignored %d unnamed / local symbols (= name starts with '.L').\n", locals);
- }
- if (ofiles) {
- /* object file path names most likely get truncated and
- * as result cause unnecessary symbol name conflicts in
- * addition to object file addresses conflicting with
- * first symbol in the object file.
- */
- fprintf(stderr, "NOTE: ignored %d object symbols (= name has '/', ends in '.[ao]' or is GCC internal).\n", ofiles);
- }
- list->symbols = symbols;
- list->count = count;
- return list;
-}
-
-
-/**
- * Load symbols of given type and the symbol address addresses from
- * a.out format symbol table, and add given offsets to the addresses:
- * Return symbols list or NULL for failure.
- */
-static symbol_list_t* symbols_load_gnu(FILE *fp, prg_section_t *sections, Uint32 tablesize, Uint32 stroff, Uint32 strsize)
-{
- size_t slots = tablesize / SIZEOF_STRUCT_NLIST;
- size_t i;
- size_t strx;
- unsigned char *p;
- char *name;
- symbol_t *sym;
- symtype_t symtype;
- uint32_t address;
- uint32_t nread;
- symbol_list_t *list;
- unsigned char n_type;
- unsigned char n_other;
- unsigned short n_desc;
- static char dummy[] = "<invalid>";
- int dtypes, locals, ofiles, count, notypes, invalid, weak;
- prg_section_t *section;
-
- if (!(list = symbol_list_alloc(slots))) {
- return NULL;
- }
-
- list->strtab = (char *)malloc(tablesize + strsize);
-
- if (list->strtab == NULL)
- {
- symbol_list_free(list);
- return NULL;
- }
-
- nread = fread(list->strtab, tablesize + strsize, 1, fp);
- if (nread != 1)
- {
- perror("ERROR: reading symbols failed");
- symbol_list_free(list);
- return NULL;
- }
-
- p = (unsigned char *)list->strtab;
- sym = list->names;
-
- weak = invalid = dtypes = notypes = ofiles = locals = count = 0;
- for (i = 0; i < slots; i++)
- {
- strx = SDL_SwapBE32(*(Uint32*)p);
- p += 4;
- n_type = *p++;
- n_other = *p++;
- n_desc = SDL_SwapBE16(*(Uint16*)p);
- p += 2;
- address = SDL_SwapBE32(*(Uint32*)p);
- p += 4;
- name = dummy;
- if (!strx) {
- invalid++;
- continue;
- }
- if (strx >= strsize) {
- fprintf(stderr, "symbol name index %x out of range\n", (unsigned int)strx);
- invalid++;
- continue;
- }
- name = list->strtab + strx + stroff;
-
- if (n_type & N_STAB)
- {
- dtypes++;
- continue;
- }
- section = NULL;
- switch (n_type & (N_TYPE|N_EXT))
- {
- case N_UNDF:
- case N_UNDF|N_EXT:
- /* shouldn't happen here */
- weak++;
- continue;
- case N_ABS:
- case N_ABS|N_EXT:
- symtype = SYMTYPE_ABS;
- break;
- case N_TEXT:
- case N_TEXT|N_EXT:
- symtype = SYMTYPE_TEXT;
- section = &(sections[0]);
- break;
- case N_DATA:
- case N_DATA|N_EXT:
- symtype = SYMTYPE_DATA;
- section = &(sections[1]);
- break;
- case N_BSS:
- case N_BSS|N_EXT:
- case N_COMM:
- case N_COMM|N_EXT:
- symtype = SYMTYPE_BSS;
- section = &(sections[2]);
- break;
- case N_FN: /* filenames, not object addresses? */
- dtypes++;
- continue;
- case N_SIZE:
- case N_WARNING:
- case N_SETA:
- case N_SETT:
- case N_SETD:
- case N_SETB:
- case N_SETV:
- dtypes++;
- continue;
- case N_WEAKU:
- case N_WEAKT:
- case N_WEAKD:
- case N_WEAKB:
- weak++;
- continue;
- default:
- fprintf(stderr, "WARNING: ignoring symbol '%s' in slot %u of unknown type 0x%x.\n", name, (unsigned int)i, n_type);
- invalid++;
- continue;
- }
- /*
- * the value of a common symbol is its size, not its address:
- */
- if (((n_type & N_TYPE) == N_COMM) ||
- (((n_type & N_EXT) && (n_type & N_TYPE) == N_UNDF && address != 0)))
- {
- /* if we ever want to know a symbols size, get that here */
- fprintf(stderr, "WARNING: ignoring common symbol '%s' in slot %u.\n", sym->name, (unsigned int)i);
- dtypes++;
- continue;
- }
- if (Options.notypes & symtype) {
- notypes++;
- continue;
- }
- if (Options.no_local) {
- if (name[0] == '.' && name[1] == 'L') {
- locals++;
- continue;
- }
- }
- if (Options.no_obj) {
- if (symbol_remove_obj(name)) {
- ofiles++;
- continue;
- }
- }
- if (section) {
- address += sections[0].offset; /* all GNU symbol addresses are TEXT relative */
- if (address > section->end) {
- fprintf(stderr, "WARNING: ignoring symbol '%s' of type %c in slot %u with invalid offset 0x%x (>= 0x%x).\n",
- name, symbol_char(symtype), (unsigned int)i, address, section->end);
- invalid++;
- continue;
- }
- }
- sym->address = address;
- sym->type = symtype;
- sym->name = name;
- sym++;
- count++;
- (void) n_desc;
- (void) n_other;
- }
-
- if (invalid) {
- fprintf(stderr, "NOTE: ignored %d invalid symbols.\n", invalid);
- }
- if (dtypes) {
- fprintf(stderr, "NOTE: ignored %d debugging symbols.\n", dtypes);
- }
- if (weak) {
- fprintf(stderr, "NOTE: ignored %d weak / undefined symbols.\n", weak);
- }
- if (notypes) {
- fprintf(stderr, "NOTE: ignored %d other unwanted symbol types.\n", notypes);
- }
- if (locals) {
- fprintf(stderr, "NOTE: ignored %d unnamed / local symbols (= name starts with '.L').\n", locals);
- }
- if (ofiles) {
- /* object file path names most likely get truncated and
- * as result cause unnecessary symbol name conflicts in
- * addition to object file addresses conflicting with
- * first symbol in the object file.
- */
- fprintf(stderr, "NOTE: ignored %d object symbols (= name has '/', ends in '.[ao]' or is GCC internal).\n", ofiles);
- }
-
- list->symbols = slots;
- list->count = count;
- return list;
-}
-
-
-/**
- * Print program header information.
- * Return false for unrecognized symbol table type.
- */
-static bool symbols_print_prg_info(Uint32 tabletype, Uint32 prgflags, Uint16 relocflag)
-{
- static const struct {
- Uint32 flag;
- const char *name;
- } flags[] = {
- { 0x0001, "FASTLOAD" },
- { 0x0002, "TTRAMLOAD" },
- { 0x0004, "TTRAMMEM" },
- { 0x0008, "MINIMUM" }, /* MagiC */
- { 0x1000, "SHAREDTEXT" }
- };
- const char *info;
- int i;
-
- switch (tabletype) {
- case SYMBOL_FORMAT_MINT: /* "MiNT" */
- info = "GCC/MiNT executable, GST symbol table";
- break;
- case SYMBOL_FORMAT_GNU: /* "GNU_" */
- info = "GCC/MiNT executable, a.out symbol table";
- break;
- case SYMBOL_FORMAT_DRI:
- info = "TOS executable, DRI / GST symbol table";
- break;
- default:
- fprintf(stderr, "ERROR: unknown executable type 0x%x!\n", tabletype);
- return false;
- }
- fprintf(stderr, "%s, reloc=%d, program flags:", info, relocflag);
- /* bit flags */
- for (i = 0; i < ARRAY_SIZE(flags); i++) {
- if (prgflags & flags[i].flag) {
- fprintf(stderr, " %s", flags[i].name);
- }
- }
- /* memory protection flags */
- switch((prgflags >> 4) & 3) {
- case 0: info = "PRIVATE"; break;
- case 1: info = "GLOBAL"; break;
- case 2: info = "SUPER"; break;
- case 3: info = "READONLY"; break;
- }
- fprintf(stderr, " %s (0x%x)\n", info, prgflags);
- return true;
-}
-
-/**
- * Parse program header and use symbol table format specific loader
- * loader function to load the symbols.
- * Return symbols list or NULL for failure.
- */
-static symbol_list_t* symbols_load_binary(FILE *fp)
-{
- Uint32 textlen, datalen, bsslen, tablesize, tabletype, prgflags;
- prg_section_t sections[3];
- int offset, reads = 0;
- Uint16 relocflag;
- symbol_list_t* symbols;
- Uint32 symoff = 0;
- Uint32 stroff = 0;
- Uint32 strsize = 0;
-
- /* get TEXT, DATA & BSS section sizes */
- reads += fread(&textlen, sizeof(textlen), 1, fp);
- textlen = SDL_SwapBE32(textlen);
- reads += fread(&datalen, sizeof(datalen), 1, fp);
- datalen = SDL_SwapBE32(datalen);
- reads += fread(&bsslen, sizeof(bsslen), 1, fp);
- bsslen = SDL_SwapBE32(bsslen);
-
- /* get symbol table size & type and check that all reads succeeded */
- reads += fread(&tablesize, sizeof(tablesize), 1, fp);
- tablesize = SDL_SwapBE32(tablesize);
- reads += fread(&tabletype, sizeof(tabletype), 1, fp);
- tabletype = SDL_SwapBE32(tabletype);
-
- /* get program header and whether there's reloc table */
- reads += fread(&prgflags, sizeof(prgflags), 1, fp);
- prgflags = SDL_SwapBE32(prgflags);
- reads += fread(&relocflag, sizeof(relocflag), 1, fp);
- relocflag = SDL_SwapBE32(relocflag);
-
- if (reads != 7) {
- fprintf(stderr, "ERROR: program header reading failed!\n");
- return NULL;
- }
- /*
- * check for GNU-style symbol table in aexec header
- */
- if (tabletype == SYMBOL_FORMAT_MINT) { /* MiNT */
- Uint32 magic1, magic2;
- Uint32 dummy;
- Uint32 a_text, a_data, a_bss, a_syms, a_entry, a_trsize, a_drsize;
- Uint32 g_tparel_pos, g_tparel_size, g_stkpos, g_symbol_format;
-
- reads = fread(&magic1, sizeof(magic1), 1, fp);
- magic1 = SDL_SwapBE32(magic1);
- reads += fread(&magic2, sizeof(magic2), 1, fp);
- magic2 = SDL_SwapBE32(magic2);
- if (reads == 2 &&
- ((magic1 == 0x283a001a && magic2 == 0x4efb48fa) || /* Original binutils: move.l 28(pc),d4; jmp 0(pc,d4.l) */
- (magic1 == 0x203a001a && magic2 == 0x4efb08fa))) { /* binutils >= 2.18-mint-20080209: move.l 28(pc),d0; jmp 0(pc,d0.l) */
- reads += fread(&dummy, sizeof(dummy), 1, fp); /* skip a_info */
- reads += fread(&a_text, sizeof(a_text), 1, fp);
- a_text = SDL_SwapBE32(a_text);
- reads += fread(&a_data, sizeof(a_data), 1, fp);
- a_data = SDL_SwapBE32(a_data);
- reads += fread(&a_bss, sizeof(a_bss), 1, fp);
- a_bss = SDL_SwapBE32(a_bss);
- reads += fread(&a_syms, sizeof(a_syms), 1, fp);
- a_syms = SDL_SwapBE32(a_syms);
- reads += fread(&a_entry, sizeof(a_entry), 1, fp);
- a_entry = SDL_SwapBE32(a_entry);
- reads += fread(&a_trsize, sizeof(a_trsize), 1, fp);
- a_trsize = SDL_SwapBE32(a_trsize);
- reads += fread(&a_drsize, sizeof(a_drsize), 1, fp);
- a_drsize = SDL_SwapBE32(a_drsize);
- reads += fread(&g_tparel_pos, sizeof(g_tparel_pos), 1, fp);
- g_tparel_pos = SDL_SwapBE32(g_tparel_pos);
- reads += fread(&g_tparel_size, sizeof(g_tparel_size), 1, fp);
- g_tparel_size = SDL_SwapBE32(g_tparel_size);
- reads += fread(&g_stkpos, sizeof(g_stkpos), 1, fp);
- g_stkpos = SDL_SwapBE32(g_stkpos);
- reads += fread(&g_symbol_format, sizeof(g_symbol_format), 1, fp);
- g_symbol_format = SDL_SwapBE32(g_symbol_format);
- if (g_symbol_format == 0)
- {
- tabletype = SYMBOL_FORMAT_GNU;
- }
- if ((a_text + (256 - 28)) != textlen)
- fprintf(stderr, "warning: inconsistent text segment size %08x != %08x\n", textlen, a_text + (256 - 28));
- if (a_data != datalen)
- fprintf(stderr, "warning: inconsistent data segment size %08x != %08x\n", datalen, a_data);
- if (a_bss != bsslen)
- fprintf(stderr, "warning: inconsistent bss segment size %08x != %08x\n", bsslen, a_bss);
- /*
- * the symbol table size in the GEMDOS header includes the string table,
- * the symbol table size in the exec header does not.
- */
- if (tabletype == SYMBOL_FORMAT_GNU)
- {
- strsize = tablesize - a_syms;
- tablesize = a_syms;
- stroff = a_syms;
- }
-
- textlen = a_text + (256 - 28);
- datalen = a_data;
- bsslen = a_bss;
- symoff = 0x100 + /* sizeof(extended exec header) */
- a_text +
- a_data +
- a_trsize +
- a_drsize;
- }
- }
- if (!symbols_print_prg_info(tabletype, prgflags, relocflag)) {
- return NULL;
- }
- fprintf(stderr, "Program section sizes:\n- text: %d\n- data: %d\n- bss: %d\n",
- textlen, datalen, bsslen);
-
- if (!tablesize) {
- fprintf(stderr, "ERROR: symbol table missing from the program!\n");
- return NULL;
- }
- fprintf(stderr, "- syms: %d\n", tablesize);
-
- /* symbols already have suitable offsets, so only acceptable end position needs to be calculated */
- sections[0].offset = 0;
- sections[0].end = textlen;
- sections[1].offset = textlen;
- sections[1].end = textlen + datalen;
- sections[2].offset = textlen + datalen;
- sections[2].end = textlen + datalen + bsslen;
-
- if (tabletype == SYMBOL_FORMAT_GNU) {
- /* go to start of symbol table */
- offset = symoff;
- if (fseek(fp, offset, SEEK_SET) < 0) {
- perror("ERROR: seeking to symbol table failed");
- return NULL;
- }
- fprintf(stderr, "Trying to load symbol table at offset 0x%x...\n", offset);
- symbols = symbols_load_gnu(fp, sections, tablesize, stroff, strsize);
- } else {
- /* go to start of symbol table */
- offset = 0x1C + textlen + datalen;
- if (fseek(fp, offset, SEEK_SET) < 0) {
- perror("ERROR: seeking to symbol table failed");
- return NULL;
- }
- fprintf(stderr, "Trying to load symbol table at offset 0x%x...\n", offset);
- symbols = symbols_load_dri(fp, sections, tablesize);
- }
- if (!symbols) {
- fprintf(stderr, "\n\n*** Try with 'nm -n <program>' (Atari/cross-compiler tool) instead ***\n\n");
- return NULL;
- }
- fprintf(stderr, "Load the listed symbols to Hatari debugger with 'symbols <filename> TEXT'.\n");
- return symbols;
-}
-
/**
* Load symbols of given type and the symbol address addresses from
* the given file and add given offsets to the addresses.
@@ -848,36 +125,36 @@ static symbol_list_t* symbols_load(const char *filename)
if (SDL_SwapBE16(magic) != ATARI_PROGRAM_MAGIC) {
usage("file isn't an Atari program file");
}
- list = symbols_load_binary(fp);
+ list = symbols_load_binary(fp, ~Options.notypes);
fclose(fp);
if (!list) {
usage("no symbols, or reading them failed");
}
- if (list->count < list->symbols) {
- if (!list->count) {
+ if (list->namecount < list->symbols) {
+ if (!list->namecount) {
usage("no valid symbols in program, symbol table loading failed");
}
/* parsed less than there were "content" lines */
- list->names = realloc(list->names, list->count * sizeof(symbol_t));
+ list->names = realloc(list->names, list->namecount * sizeof(symbol_t));
assert(list->names);
}
/* copy name list to address list */
- list->addresses = malloc(list->count * sizeof(symbol_t));
+ list->addresses = malloc(list->namecount * sizeof(symbol_t));
assert(list->addresses);
- memcpy(list->addresses, list->names, list->count * sizeof(symbol_t));
+ memcpy(list->addresses, list->names, list->namecount * sizeof(symbol_t));
/* sort both lists, with different criteria */
- qsort(list->addresses, list->count, sizeof(symbol_t), symbols_by_address);
- qsort(list->names, list->count, sizeof(symbol_t), symbols_by_name);
+ qsort(list->addresses, list->namecount, sizeof(symbol_t), symbols_by_address);
+ qsort(list->names, list->namecount, sizeof(symbol_t), symbols_by_name);
/* check for duplicate addresses */
- symbols_check_addresses(list->addresses, list->count);
+ symbols_check_addresses(list->addresses, list->namecount);
/* check for duplicate names */
- symbols_check_names(list->names, list->count);
+ symbols_check_names(list->names, list->namecount);
return list;
}
@@ -903,13 +180,13 @@ static int symbols_show(symbol_list_t* list)
} else {
entries = list->addresses;
}
- for (entry = entries, i = 0; i < list->count; i++, entry++) {
+ for (entry = entries, i = 0; i < list->namecount; i++, entry++) {
symchar = symbol_char(entry->type);
fprintf(stdout, "0x%08x %c %s\n",
entry->address, symchar, entry->name);
}
- fprintf(stderr, "%d (unignored) symbols processed.\n", list->count);
+ fprintf(stderr, "%d (unignored) symbols processed.\n", list->namecount);
return 0;
}
--
2.24.0
--nextPart3945085.DFmjOQq6lO
Content-Disposition: attachment; filename="0003-For-DRI-style-symbol-tables-try-to-auto-detect-wheth.patch"
Content-Transfer-Encoding: 7Bit
Content-Type: text/x-patch; charset="UTF-8"; name="0003-For-DRI-style-symbol-tables-try-to-auto-detect-wheth.patch"