summaryrefslogtreecommitdiff
path: root/ld/objdump86.c
diff options
context:
space:
mode:
Diffstat (limited to 'ld/objdump86.c')
-rw-r--r--ld/objdump86.c681
1 files changed, 681 insertions, 0 deletions
diff --git a/ld/objdump86.c b/ld/objdump86.c
new file mode 100644
index 0000000..a5dbf44
--- /dev/null
+++ b/ld/objdump86.c
@@ -0,0 +1,681 @@
+/*
+ * This is a combination of three tools for decoding information from
+ * Dev86/ELKS object files and executables.
+ *
+ * This executable can be given the names:
+ *
+ * objdump86: Dumps detailed information about a binary file.
+ * size86: Summary sizes of the data in a binary file.
+ * nm86: The symbol table of the binary file.
+ *
+ * None of these programs have any options, neither can they currently deal
+ * with archive files. This may be a minor problem with nm86.
+ */
+
+#include <stdio.h>
+#include <malloc.h>
+#include <string.h>
+
+FILE * ifd = stdin;
+char * ifname;
+
+#ifdef __STDC__
+#define _(x) x
+#else
+#define _(x) ()
+#endif
+
+long get_long _((void));
+long get_sized _((int sz));
+unsigned int get_word _((void));
+int main _((int argc, char**argv));
+void do_file _((char * fname));
+int error _((char * str));
+int read_objheader _((void));
+int read_sectheader _((void));
+int read_syms _((void));
+void read_databytes _((void));
+void hex_output _((int ch));
+void fetch_aout_hdr _((void));
+void dump_aout _((void));
+void size_aout _((void));
+void nm_aout _((void));
+
+int sections;
+long segsizes[16];
+long textoff, textlen;
+long str_off, str_len;
+
+char ** symnames;
+char * symtab;
+
+int display_mode = 0;
+int multiple_files = 0;
+int byte_order = 0;
+
+long size_text, size_data, size_bss;
+
+int
+main(argc, argv)
+int argc;
+char ** argv;
+{
+ int ar;
+ char * p;
+
+ p = strrchr(argv[0], '/');
+ if(p) p++; else p=argv[0];
+
+ if( p[0] == 's' ) display_mode = 1;
+ if( p[0] == 'n' ) display_mode = 2;
+
+ if( display_mode == 1 )
+ printf("text\tdata\tbss\tdec\thex\tfilename\n");
+
+ multiple_files = (argc>2);
+
+ for(ar=1; ar<argc; ar++)
+ do_file(argv[ar]);
+
+ return (argc<=1);
+}
+
+void
+do_file(fname)
+char * fname;
+{
+ int modno, i, ch;
+
+ size_text = size_data = size_bss = 0;
+ byte_order = 0;
+
+ if( !display_mode )
+ printf("OBJECTFILE '%s'\n", fname);
+
+ ifname = fname;
+ if( (ifd=fopen(fname, "rb")) == 0 )
+ {
+ error("Cannot open file");
+ return;
+ }
+
+ switch( read_objheader() )
+ {
+ case 0: /* as86 object file */
+
+ for(modno=1; modno<=sections; modno++)
+ {
+ if( modno != 1 && !display_mode )
+ printf("OBJECTSECTION %d\n", modno);
+ if( read_sectheader() < 0 ) break;
+
+ for(i=0; i<16; i++)
+ {
+ if( i<3 ) size_text += segsizes[i];
+ else size_data += segsizes[i];
+ }
+
+ if( read_syms() < 0 ) break;
+
+ if( display_mode == 0 )
+ printf("text\tdata\tbss\tdec\thex\tfilename\n");
+ if( display_mode != 2 )
+ printf("%ld\t%ld\t%ld\t%ld\t%lx\t%s\n",
+ size_text, size_data, size_bss,
+ size_text+ size_data+ size_bss,
+ size_text+ size_data+ size_bss,
+ ifname);
+
+ if( sections == 1 && display_mode != 0 )
+ break;
+
+ read_databytes();
+ }
+ if( !display_mode )
+ {
+ i=0;
+ while( (ch=getc(ifd)) != EOF )
+ {
+ if( i == 0 )
+ {
+ printf("TRAILER\n");
+ i=1;
+ }
+ hex_output(ch);
+ }
+ hex_output(EOF);
+ }
+ break;
+
+ case 1: /* ELKS executable */
+ fseek(ifd, 0L, 0);
+
+ switch(display_mode)
+ {
+ case 0: dump_aout(); break;
+ case 1: size_aout(); break;
+ case 2: nm_aout(); break;
+ }
+ break;
+ }
+ fclose(ifd);
+
+ if( symtab ) free(symtab);
+ if( symnames ) free(symnames);
+ symtab = 0;
+ symnames = 0;
+}
+
+int
+error(str)
+char * str;
+{
+ switch( display_mode )
+ {
+ case 1: fprintf(stderr, "size: %s: %s\n", ifname, str); break;
+ case 2: fprintf(stderr, "nm: %s: %s\n", ifname, str); break;
+ default:
+ printf("Error: %s\n", str);
+ break;
+ }
+ return -1;
+}
+
+int
+read_objheader()
+{
+ unsigned char buf[5];
+
+ if( fread(buf, 1, 5, ifd) != 5 )
+ return error("Cannot read object header");
+
+ if( buf[0] != 0xA3 || buf[1] != 0x86 )
+ {
+ if( buf[0] == 1 && buf[1] == 3 )
+ {
+ sections = 1;
+ return 1;
+ }
+ return error("Bad magic number");
+ }
+
+ if( (unsigned char)(buf[0] + buf[1] + buf[2] + buf[3]) != buf[4] )
+ return error("Bad header checksum");
+
+ sections= buf[2]+256*buf[3];
+
+ return 0;
+}
+
+int
+read_sectheader()
+{
+ long ssenc, cpos;
+ int i, ver;
+
+ textoff = get_long(); textlen = get_long();
+ str_len=get_word(); str_off=textoff-str_len;
+ ver = get_word();
+
+ symtab = malloc((unsigned int)str_len+1);
+ if( symtab == 0 ) return error("Out of memory");
+
+ cpos = ftell(ifd);
+ fseek(ifd, str_off, 0);
+ fread(symtab, 1, (int)str_len, ifd);
+ fseek(ifd, cpos, 0);
+
+ if( !display_mode )
+ {
+ printf("MODULE '%s'\n", symtab);
+ printf("BYTEPOS %08lx\n", textoff);
+ printf("BINLEN %08lx\n", textlen);
+ printf("STRINGS %04lx +%04lx\n", str_off, str_len);
+ printf("VERSION %d.%d\n", ver/256, ver%256);
+ }
+
+ (void)get_long(); /* Ignore fives */
+ ssenc=get_long();
+
+ for(i=0; i<16; i++)
+ {
+ int ss;
+ ss = (i^3);
+ ss = ((ssenc>>(2*(15-ss)))&3);
+ segsizes[i] = get_sized(ss);
+ if( segsizes[i] && !display_mode )
+ printf("SEG%x %08lx\n", i, segsizes[i]);
+ }
+ if( !display_mode )
+ printf("\n");
+
+ return 0;
+}
+
+int
+read_syms()
+{
+ int syms, i;
+
+ syms=get_word();
+
+ if( !display_mode ) printf("SYMS %u\n", syms);
+ if( syms < 0 ) return error("Bad symbol table");
+
+ symnames = malloc(syms*sizeof(char*)+1);
+ if( symnames == 0 ) return error("Out of memory");
+
+ if(display_mode == 2 && multiple_files)
+ printf("\n%s:\n", ifname);
+
+ for(i=0; i<syms; i++)
+ {
+ long offset=0;
+ unsigned int nameoff, symtype;
+
+ nameoff = get_word();
+ symtype = get_word();
+ offset = get_sized((symtype>>14)&3);
+ symtype &= 0x3FFF;
+ symnames[i] = symtab+nameoff;
+
+ if( !display_mode )
+ {
+ printf("SYM %-4d %08lx ", i, offset);
+
+ printf("%s", (symtype&0x2000)?"C":".");
+ printf("%s", (symtype&0x0100)?"N":".");
+ printf("%s", (symtype&0x0080)?"E":".");
+ printf("%s", (symtype&0x0040)?"I":".");
+ printf("%c", "T12D456789abcdeUAhijklmnopqrstuv"[symtype&0x1F]);
+ if( symtype &0x1E20 )
+ printf(" %04x", symtype);
+ printf(" %s\n", symnames[i]);
+ }
+ if( display_mode == 2 )
+ {
+ if( symtype == 0x004f || symtype == 0x0040 )
+ printf(" ");
+ else
+ printf("%08lx ", offset);
+ switch(symtype)
+ {
+ case 0x004F: putchar('U'); break;
+ case 0x0000: putchar('t'); break;
+ case 0x0003: putchar('d'); break;
+ case 0x2003: putchar('b'); break;
+ case 0x0043: putchar('C'); break;
+ case 0x0083: putchar('D'); break;
+ case 0x0080: putchar('T'); break;
+ case 0x0040: putchar('T'); break;
+ case 0x0180: putchar('N'); break;
+ case 0x0010: putchar('a'); break;
+ case 0x0090: putchar('A'); break;
+ default: putchar('?'); break;
+ }
+ printf(" %s\n", symnames[i]);
+ }
+
+ if( symtype == 0x43 || symtype == 0x2003 )
+ size_bss += offset;
+ }
+ if( !display_mode )
+ printf("\n");
+
+ return 0;
+}
+
+void
+read_databytes()
+{
+static char * relstr[] = {"ERR", "DB", "DW", "DD"};
+ long l;
+ int ch, i;
+ int curseg = 0;
+ int relsize = 0;
+ fseek(ifd, textoff, 0);
+
+ printf("\nBYTECODE\n");
+ for(;;)
+ {
+ if( (ch=getc(ifd)) == EOF ) break;
+
+ if( ch == 0 ) break;
+
+ switch( ch & 0xC0 )
+ {
+ case 0x00: switch(ch & 0xF0)
+ {
+ case 0x00: /* Relocator size */
+ printf("RELSZ %d\n", relsize= (ch&0xF));
+ if(relsize>3) relsize=3;
+ break;
+ case 0x10: /* Skip bytes */
+ printf("SKP %ld\n", get_sized(ch&0xF));
+ break;
+ case 0x20: /* Segment */
+ printf("SEG %x\n", curseg= (ch&0xF));
+ break;
+ default: printf("CODE %02x - unknown\n", ch);
+ return ;
+ }
+ break;
+ case 0x40: /* Raw bytes */
+ {
+ int abscnt = (ch&0x3F);
+ if( abscnt == 0 ) abscnt = 64;
+ for( i=0; i<abscnt; i++ )
+ {
+ if( (ch=getc(ifd)) == EOF ) break;
+ hex_output(ch);
+ }
+ hex_output(EOF);
+
+ if( ch == EOF ) return;
+ }
+ break;
+ case 0x80: /* Relocator - simple */
+ l = get_sized(relsize);
+ printf("%s SEG%x%s%s", relstr[relsize],
+ (ch&0xF),
+ (ch&0x20)?"-PC":"",
+ (ch&0x10)?"+?":"");
+ if(l)
+ printf("+0x%04lx", l);
+ putchar('\n');
+ break;
+ case 0xC0: /* Relocator - symbol relative */
+ if( ch & 0x18 )
+ {
+ printf("CODE %02x - unknown\n", ch);
+ return;
+ }
+ if( ch & 4 ) i = get_word();
+ else i = getc(ifd);
+ l = get_sized(ch&3);
+
+ printf("%s %s%s%s", relstr[relsize],
+ symnames[i],
+ (ch&0x20)?"-PC":"",
+ (ch&0x18)?"+?":"");
+ if(l)
+ printf("+0x%04lx", l);
+ putchar('\n');
+ break;
+ }
+ }
+ printf("\n");
+}
+
+long
+get_sized(sz)
+int sz;
+{
+ switch(sz)
+ {
+ case 0: return 0;
+ case 1: return getc(ifd);
+ case 2: return get_word();
+ case 3: return get_long();
+ }
+ return -1;
+}
+
+long
+get_long()
+{
+ long retv = 0;
+ int i;
+ for(i=0; i<32; i+=16)
+ {
+ unsigned int v = get_word();
+ if( byte_order & 2 )
+ retv += ((long)v<<(16-i));
+ else
+ retv += ((long)v<<i);
+ }
+ return retv;
+}
+
+unsigned int
+get_word()
+{
+ long retv = 0;
+ int i;
+ for(i=0; i<16; i+=8)
+ {
+ int v = getc(ifd);
+ if( v == EOF ) return -1;
+ if( byte_order & 1 )
+ retv += (v<<(8-i));
+ else
+ retv += (v<<i);
+ }
+ return retv;
+}
+
+void
+hex_output(ch)
+int ch;
+{
+static char linebuf[80];
+static char buf[20];
+static int pos = 0;
+
+ if( ch == EOF )
+ {
+ if(pos)
+ printf(": %.66s\n", linebuf);
+ pos = 0;
+ }
+ else
+ {
+ if(!pos)
+ memset(linebuf, ' ', sizeof(linebuf));
+ sprintf(buf, "%02x", ch&0xFF);
+ memcpy(linebuf+pos*3+(pos>7), buf, 2);
+ if( ch > ' ' && ch <= '~' ) linebuf[50+pos] = ch;
+ else linebuf[50+pos] = '.';
+ pos = ((pos+1) & 0xF);
+ if( pos == 0 )
+ {
+ printf(": %.66s\n", linebuf);
+ memset(linebuf, ' ', sizeof(linebuf));
+ }
+ }
+}
+
+/************************************************************************/
+/* ELKS a.out versions
+ */
+
+long header[12];
+int h_len, h_flgs, h_cpu;
+
+void
+fetch_aout_hdr()
+{
+ int i;
+
+ header[0] = get_long();
+ header[1] = get_long();
+ byte_order = ((header[0]>>24) & 3);
+
+ h_len = (header[1] & 0xFF);
+ h_flgs = ((header[0]>>16) & 0xFF);
+ h_cpu = ((header[0]>>24) & 0xFF);
+
+ for(i=2; i<8; i++)
+ {
+ if( i*4 <= h_len )
+ header[i] = get_long();
+ else
+ header[i] = 0;
+ }
+}
+
+void
+dump_aout()
+{
+static char * cpu[] = { "unknown", "8086", "m68k", "ns16k", "i386", "sparc" };
+static char * byteord[] = { "LITTLE_ENDIAN", "(2143)","(3412)","BIG_ENDIAN" };
+ int i;
+ long l;
+
+ if( display_mode == 0 ) fetch_aout_hdr();
+
+ if( h_cpu > 0x17 ) h_cpu &= 3;
+
+ printf("HLEN %d\n", h_len);
+ printf("CPU %s %s\n", cpu[h_cpu>>2], byteord[h_cpu&3]);
+
+ printf("FLAGS:");
+ if( h_flgs & 0x01 ) printf(" A_UZP");
+ if( h_flgs & 0x02 ) printf(" A_PAL");
+ if( h_flgs & 0x04 ) printf(" A_NSYM");
+ if( h_flgs & 0x08 ) printf(" FLG-08");
+ if( h_flgs & 0x10 ) printf(" A_EXEC");
+ if( h_flgs & 0x20 ) printf(" A_SEP");
+ if( h_flgs & 0x40 ) printf(" A_PURE");
+ if( h_flgs & 0x80 ) printf(" A_TOVLY");
+ printf("\n");
+
+ if( header[5] )
+ printf("a_entry = 0x%08lx\n", header[5]);
+ printf("a_total = 0x%08lx\n", header[6]);
+ if( header[7] )
+ printf("a_syms = 0x%08lx\n", header[7]);
+
+ if( h_len >= 36 )
+ printf("a_trsize = 0x%08lx\n", header[8]);
+ if( h_len >= 40 )
+ printf("a_drsize = 0x%08lx\n", header[9]);
+ if( h_len >= 44 )
+ printf("a_tbase = 0x%08lx\n", header[10]);
+ if( h_len >= 48 )
+ printf("a_dbase = 0x%08lx\n", header[11]);
+ printf("\n");
+
+ size_aout();
+ printf("\n");
+
+ if( header[7] )
+ {
+ printf("SYMBOLS\n");
+ nm_aout();
+ }
+ else
+ printf("NO SYMBOLS\n");
+ printf("\n");
+
+ printf("TEXTSEG\n");
+ fseek(ifd, (long)h_len, 0);
+ for(l=0; l<header[2]; l++)
+ {
+ if( (i=getc(ifd)) == EOF ) break;
+ hex_output(i);
+ }
+ hex_output(EOF);
+
+ printf("DATASEG\n");
+ fseek(ifd, (long)h_len+header[2], 0);
+ for(l=0; l<header[3]; l++)
+ {
+ if( (i=getc(ifd)) == EOF ) break;
+ hex_output(i);
+ }
+ hex_output(EOF);
+}
+
+void
+size_aout()
+{
+ if( display_mode == 1 ) fetch_aout_hdr();
+
+ if( display_mode == 0 )
+ printf("text\tdata\tbss\tdec\thex\tfilename\n");
+
+ printf("%ld\t%ld\t%ld\t%ld\t%lx\t%s\n",
+ header[2], header[3], header[4],
+ header[2]+ header[3]+ header[4],
+ header[2]+ header[3]+ header[4],
+ ifname);
+}
+
+void
+nm_aout()
+{
+ char n_name[10];
+ long n_value;
+ int n_sclass, n_numaux, n_type;
+ long bytes_left;
+
+ if( display_mode == 2 ) fetch_aout_hdr();
+
+ fseek(ifd, h_len+header[2]+header[3]+header[8]+header[9], 0);
+
+ if( h_flgs & 4 ) { error("Executable has new format symtab\n"); return; }
+
+ bytes_left = header[7];
+
+ if( bytes_left == 0 )
+ printf("No symbols in '%s'\n", ifname);
+ else if(multiple_files)
+ printf("\n%s:\n", ifname);
+
+ while(bytes_left > 16)
+ {
+ if( fread(n_name, 1, 8, ifd) != 8 ) return;
+ n_name[8] = 0;
+ n_value = get_long();
+ if( (n_sclass = getc(ifd)) == EOF ) return;
+ if( (n_numaux = getc(ifd)) == EOF ) return;
+ n_type = get_word();
+
+ printf("%08lx ", n_value);
+ switch(n_sclass)
+ {
+ case 0x01: printf("a "); break;
+ case 0x12: printf("T "); break;
+ case 0x13: printf("D "); break;
+ case 0x14: printf("C "); break;
+ case 0x1a: printf("t "); break;
+ case 0x1b: printf("d "); break;
+ case 0x1c: printf("b "); break;
+ default: if( display_mode )
+ {
+ printf("? "); break;
+ }
+
+ printf("n_sclass=");
+ switch(n_sclass>>3)
+ {
+ case 0: printf("C_NULL,"); break;
+ case 2: printf("C_EXT,"); break;
+ case 3: printf("C_STAT,"); break;
+ default: printf("%04o,", n_sclass&0xF8);
+ }
+ switch(n_sclass&7)
+ {
+ case 0: printf("N_UNDF "); break;
+ case 1: printf("N_ABS "); break;
+ case 2: printf("N_TEXT "); break;
+ case 3: printf("N_DATA "); break;
+ case 4: printf("N_BSS "); break;
+ case 5: printf("N_COMM "); break;
+ default: printf("%o ", n_sclass&7); break;
+ }
+ break;
+ }
+
+ if( display_mode == 0 )
+ {
+ if( n_numaux )
+ printf("n_numaux=%02x ", n_numaux);
+ if( n_type )
+ printf("n_type=%04x ", n_type);
+ }
+
+ printf("%s\n", n_name);
+ }
+}