# HG changeset patch
# User lost
# Date 1232764465 0
# Node ID 8272b46b5a34bb5c5d50366160852fb6631d8616
# Parent 3476629ee0ced0a3a977fc5be2f200fcd13dfaba
Added lwobjdump for debugging object files
diff -r 3476629ee0ce -r 8272b46b5a34 src/Makefile.am
--- a/src/Makefile.am Sat Jan 24 02:22:13 2009 +0000
+++ b/src/Makefile.am Sat Jan 24 02:34:25 2009 +0000
@@ -1,3 +1,4 @@
-bin_PROGRAMS = lwlink
+bin_PROGRAMS = lwlink lwobjdump
lwlink_SOURCES = main.c lwlink.c util.c readfiles.c expr.c script.c link.c output.c
+lwobjdump_SOURCES = objdump.c util.c
EXTRA_DIST = lwlink.h util.h expr.h
diff -r 3476629ee0ce -r 8272b46b5a34 src/objdump.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/objdump.c Sat Jan 24 02:34:25 2009 +0000
@@ -0,0 +1,303 @@
+/*
+objdump.c
+Copyright © 2009 William Astle
+
+This file is part of LWLINK
+
+LWLINK is free software: you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free Software
+Foundation, either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+more details.
+
+You should have received a copy of the GNU General Public License along with
+this program. If not, see .
+
+
+A standalone program to dump an object file in a text form to stdout
+
+*/
+
+#include
+#include
+
+#include "util.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+void read_lwobj16v0(unsigned char *filedata, long filesize);
+
+/*
+The logic of reading the entire file into memory is simple. All the symbol
+names in the file are NUL terminated strings and can be used directly without
+making additional copies.
+*/
+int main(int argc, char **argv)
+{
+ int i;
+ long size;
+ FILE *f;
+ long bread;
+ unsigned char *filedata;
+
+ if (argc != 2)
+ {
+ fprintf(stderr, "Must specify exactly one input file.\n");
+ exit(1);
+ }
+
+ f = fopen(argv[1], "rb");
+ if (!f)
+ {
+ fprintf(stderr, "Can't open file %s:", argv[1]);
+ perror("");
+ exit(1);
+ }
+ fseek(f, 0, SEEK_END);
+ size = ftell(f);
+ rewind(f);
+
+ filedata = lw_malloc(size);
+
+ bread = fread(filedata, 1, size, f);
+ if (bread < size)
+ {
+ fprintf(stderr, "Short read on file %s (%ld/%ld):", argv[1], bread, size);
+ perror("");
+ exit(1);
+ }
+
+ fclose(f);
+
+ if (!memcmp(filedata, "LWOBJ16", 8))
+ {
+ // read v0 LWOBJ16 file
+ read_lwobj16v0(filedata, size);
+ }
+ else
+ {
+ fprintf(stderr, "%s: unknown file format\n", argv[1]);
+ exit(1);
+ }
+ exit(0);
+}
+
+// this macro is used to bail out if we run off the end of the file data
+// while parsing - it keeps the code below cleaner
+#define NEXTBYTE() do { cc++; if (cc > filesize) { fprintf(stderr, "***invalid file format\n"); exit(1); } } while (0)
+// this macro is used to refer to the current byte in the stream
+#define CURBYTE() (filedata[cc < filesize ? cc : filesize - 1])
+// this one will leave the input pointer past the trailing NUL
+#define CURSTR() read_lwobj16v0_str(&cc, &filedata, filesize)
+unsigned char *read_lwobj16v0_str(long *cc1, unsigned char **filedata1, long filesize)
+{
+ int cc = *cc1;
+ unsigned char *filedata = *filedata1;
+ unsigned char *fp;
+ fp = &CURBYTE();
+ while (CURBYTE())
+ NEXTBYTE();
+ NEXTBYTE();
+ *cc1 = cc;
+ *filedata1 = filedata;
+ return fp;
+}
+// the function below can be switched to dealing with data coming from a
+// source other than an in-memory byte pool by adjusting the input data
+// in "fn" and the above two macros
+void read_lwobj16v0(unsigned char *filedata, long filesize)
+{
+ unsigned char *fp;
+ long cc;
+ int val;
+ int bss;
+
+ static char *opernames[] = {
+ "?",
+ "PLUS",
+ "MINUS",
+ "TIMES",
+ "DIVIDE",
+ "MOD",
+ "INTDIV",
+ "BWAND",
+ "BWOR",
+ "BWXOR",
+ "AND",
+ "OR",
+ "NEG",
+ "COM"
+ };
+ static const int numopers = 13;
+
+ // start reading *after* the magic number
+ cc = 8;
+
+ while (1)
+ {
+ bss = 0;
+
+ // bail out if no more sections
+ if (!(CURBYTE()))
+ break;
+
+ fp = CURSTR();
+
+ printf("SECTION %s\n", fp);
+
+ // read flags
+ while (CURBYTE())
+ {
+ switch (CURBYTE())
+ {
+ case 0x01:
+ printf(" FLAG: BSS\n");
+ bss = 1;
+ break;
+
+ default:
+ printf(" FLAG: %02X (unknown)\n", CURBYTE());
+ break;
+ }
+ NEXTBYTE();
+ }
+ // skip NUL terminating flags
+ NEXTBYTE();
+
+ printf(" Local symbols:\n");
+ // now parse the local symbol table
+ while (CURBYTE())
+ {
+ fp = CURSTR();
+
+ // fp is the symbol name
+ val = (CURBYTE()) << 8;
+ NEXTBYTE();
+ val |= (CURBYTE());
+ NEXTBYTE();
+ // val is now the symbol value
+
+ printf(" %s=%04X\n", fp, val);
+
+ }
+ // skip terminating NUL
+ NEXTBYTE();
+
+ printf(" Exported symbols\n");
+
+ // now parse the exported symbol table
+ while (CURBYTE())
+ {
+ fp = CURSTR();
+
+ // fp is the symbol name
+ val = (CURBYTE()) << 8;
+ NEXTBYTE();
+ val |= (CURBYTE());
+ NEXTBYTE();
+ // val is now the symbol value
+
+ printf(" %s=%04X\n", fp, val);
+ }
+ // skip terminating NUL
+ NEXTBYTE();
+
+ // now parse the incomplete references and make a list of
+ // external references that need resolution
+ printf(" Incomplete references\n");
+ while (CURBYTE())
+ {
+ printf(" (");
+ // parse the expression
+ while (CURBYTE())
+ {
+ int tt = CURBYTE();
+ NEXTBYTE();
+ switch (tt)
+ {
+ case 0x01:
+ // 16 bit integer
+ tt = CURBYTE() << 8;
+ NEXTBYTE();
+ tt |= CURBYTE();
+ NEXTBYTE();
+ // normalize for negatives...
+ if (tt > 0x7fff)
+ tt -= 0x10000;
+ printf(" I16=%d", tt);
+ break;
+
+ case 0x02:
+ // external symbol reference
+ printf(" ES=%s", CURSTR());
+ break;
+
+ case 0x03:
+ // internal symbol reference
+ printf(" IS=%s", CURSTR());
+ break;
+
+ case 0x04:
+ // operator
+ if (CURBYTE() > 0 && CURBYTE() <= numopers)
+ printf(" OP=%s", opernames[CURBYTE()]);
+ else
+ printf(" OP=?");
+ NEXTBYTE();
+ break;
+
+ case 0x05:
+ // section base reference (NULL internal reference is
+ // the section base address
+ printf(" SB");
+ break;
+
+ default:
+ printf(" ERR");
+ }
+ }
+ // skip the NUL
+ NEXTBYTE();
+
+ // fetch the offset
+ val = CURBYTE() << 8;
+ NEXTBYTE();
+ val |= CURBYTE() & 0xff;
+ NEXTBYTE();
+ printf(" ) @ %04X\n", val);
+ }
+ // skip the NUL terminating the relocations
+ NEXTBYTE();
+
+ // now set code location and size and verify that the file
+ // contains data going to the end of the code (if !SECTION_BSS)
+ val = CURBYTE() << 8;
+ NEXTBYTE();
+ val |= CURBYTE();
+ NEXTBYTE();
+
+ printf(" CODE %04X bytes", val);
+
+ // skip the code if we're not in a BSS section
+ if (!bss)
+ {
+ int i;
+ for (i = 0; i < val; i++)
+ {
+ if (! (i % 16))
+ {
+ printf("\n %04X ", i);
+ }
+ printf("%02X", CURBYTE());
+ NEXTBYTE();
+ }
+ }
+ printf("\n");
+ }
+}