2 * This is a combination of three tools for decoding information from
3 * Dev86/ELKS object files and executables.
5 * This executable can be given the names:
7 * objdump86: Dumps detailed information about a binary file.
8 * size86: Summary sizes of the data in a binary file.
9 * nm86: The symbol table of the binary file.
11 * None of these programs have any options.
12 * This may be a minor problem with nm86.
14 * Copyright (c) 1999 by Greg Haerr <greg@censoft.com>
15 * Added archive file reading capabilties
38 long get_long
_((void));
39 long get_sized
_((int sz
));
40 unsigned int get_word
_((void));
41 int get_byte
_((void));
42 int main
_((int argc
, char**argv
));
43 void do_file
_((char * fname
));
44 long read_arheader
_((char *archentry
));
45 void do_module
_((char * fname
, char *archive
));
46 int error
_((char * str
));
47 int read_objheader
_((void));
48 int read_sectheader
_((void));
49 int read_syms
_((void));
50 void disp_sectheader
_((void));
51 int disp_syms
_((void));
52 void read_databytes
_((void));
53 void hex_output
_((int ch
));
54 void fetch_aout_hdr
_((void));
55 void dump_aout
_((void));
56 void size_aout
_((void));
57 void nm_aout
_((void));
74 unsigned int nameoff
, symtype
;
79 int multiple_files
= 0;
84 long size_text
, size_data
, size_bss
;
85 long tot_size_text
=0, tot_size_data
=0, tot_size_bss
=0;
95 ifd
= stdin
; /* In Libc6 stdin is weird */
97 p
= strrchr(argv
[0], '/');
98 if(p
) p
++; else p
=argv
[0];
100 if( p
[0] == 's' ) display_mode
= 1;
101 if( p
[0] == 'n' ) display_mode
= 2;
104 for(ar
=1; ar
<argc
; ar
++)
106 if( argv
[ar
][0] == '-' ) switch(argv
[ar
][1])
108 case 's': display_mode
= 1; break;
109 case 'n': display_mode
= 2; break;
110 case 'o': opt_o
++; break;
116 if( !multiple_files
) exit(1);
118 multiple_files
= (multiple_files
>1);
120 if( display_mode
== 1 )
121 printf("text\tdata\tbss\tdec\thex\tfilename\n");
123 for(ar
=1; ar
<argc
; ar
++) if(argv
[ar
][0] != '-')
126 if( display_mode
== 1 && multiple_files
)
127 printf("%ld\t%ld\t%ld\t%ld\t%lx\tTotal\n",
128 tot_size_text
, tot_size_data
, tot_size_bss
,
129 tot_size_text
+ tot_size_data
+ tot_size_bss
,
130 tot_size_text
+ tot_size_data
+ tot_size_bss
);
141 char archentry
[sizeof(struct ar_hdr
)]; /* sizeof ar_hdr.ar_name*/
142 char filemagic
[SARMAG
];
145 if( (ifd
=fopen(fname
, "rb")) == 0 )
147 error("Cannot open file");
152 /* check if file is an archive*/
153 if(fread(filemagic
, sizeof(filemagic
), 1, ifd
) == 1
154 && strncmp(filemagic
, ARMAG
, sizeof filemagic
) == 0)
157 while((filelength
= read_arheader(archentry
)) > 0)
159 filepos
+= sizeof(struct ar_hdr
);
163 fseek(ifd
, filepos
, 0);
164 do_module(archentry
, fname
);
166 else if(magic
== 0x3C21 ) /* "!<" */
168 filepos
+= ld_roundup(filelength
, 2, long);
169 fseek(ifd
, filepos
, 0);
175 do_module(fname
, NULL
);
180 /* read archive header and return length */
182 read_arheader(archentry
)
186 struct ar_hdr arheader
;
188 if(fread((char *)&arheader
, sizeof(arheader
), 1, ifd
) != 1)
190 strncpy(archentry
, arheader
.ar_name
, sizeof(arheader
.ar_name
));
191 archentry
[sizeof(arheader
.ar_name
)] = 0;
192 endptr
= archentry
+ sizeof(arheader
.ar_name
);
196 } while(endptr
> archentry
&& (*endptr
== ' ' || *endptr
== '/'));
197 return strtoul(arheader
.ar_size
, (char **)NULL
, 0);
201 do_module(fname
, archive
)
207 size_text
= size_data
= size_bss
= 0;
213 printf("ARCHIVEFILE '%s'\n", archive
);
214 printf("OBJECTFILE '%s'\n", fname
);
217 switch( read_objheader() )
219 case 0: /* as86 object file */
221 for(modno
=1; modno
<=sections
; modno
++)
223 if( modno
!= 1 && !display_mode
)
224 printf("OBJECTSECTION %d\n", modno
);
225 if( read_sectheader() < 0 ) break;
227 /* segments 0, 4-E are text, 1-3 are data*/
231 size_text
+= segsizes
[i
];
232 else size_data
+= segsizes
[i
];
235 if( read_syms() < 0 ) break;
237 strtab
= malloc((unsigned int)str_len
+1);
238 if( strtab
== 0 ) { error("Out of memory"); break; }
239 str_off
= ftell(ifd
);
240 fread(strtab
, 1, (unsigned int)str_len
, ifd
);
245 if( display_mode
== 0 )
246 printf("text\tdata\tbss\tdec\thex\tfilename\n");
247 if( display_mode
!= 2 )
249 printf("%ld\t%ld\t%ld\t%ld\t%lx\t",
250 size_text
, size_data
, size_bss
,
251 size_text
+ size_data
+ size_bss
,
252 size_text
+ size_data
+ size_bss
);
254 if(archive
) printf("%s(%s)\n", archive
, fname
);
255 else printf("%s\n", fname
);
257 tot_size_text
+= size_text
;
258 tot_size_data
+= size_data
;
259 tot_size_bss
+= size_bss
;
262 if( sections
== 1 && display_mode
!= 0 )
269 case 1: /* ELKS executable */
275 case 0: dump_aout(); break;
276 case 1: size_aout(); break;
277 case 2: nm_aout(); break;
282 if( strtab
) free(strtab
);
283 if( symnames
) free(symnames
);
292 switch( display_mode
)
294 case 1: fprintf(stderr
, "size: %s: %s\n", ifname
, str
); break;
295 case 2: fprintf(stderr
, "nm: %s: %s\n", ifname
, str
); break;
297 printf("Error: %s\n", str
);
306 unsigned char buf
[5];
308 if( fread(buf
, 1, 5, ifd
) != 5 )
309 return error("Cannot read object header");
311 if( buf
[0] != 0xA3 || buf
[1] != 0x86 )
313 if( buf
[0] == 1 && buf
[1] == 3 )
318 return error("Bad magic number");
321 if( (unsigned char)(buf
[0] + buf
[1] + buf
[2] + buf
[3]) != buf
[4] )
322 return error("Bad header checksum");
324 sections
= buf
[2]+256*buf
[3];
335 textoff
= get_long(); /* Offset of bytecode in file */
336 textlen
= get_long(); /* Length of text+data (no bss) in memory */
337 str_len
= get_word(); /* Length of string table in file */
338 obj_ver
= get_word(); /* 0.0 */
340 (void)get_long(); /* Ignore fives */
341 ssenc
= get_long(); /* Sixteen segment size sizes */
347 ss
= ((ssenc
>>(2*(15-ss
)))&3);
348 segsizes
[i
] = get_sized(ss
);
351 num_syms
= get_word(); /* Number of symbol codes */
360 if( display_mode
) return;
362 printf("MODULE '%s'\n", strtab
);
363 printf("BYTEPOS %08lx\n", textoff
);
364 printf("BINLEN %08lx\n", textlen
);
365 printf("STRINGS %04lx +%04lx\n", str_off
, str_len
);
366 printf("VERSION %d.%d\n", obj_ver
/256, obj_ver
%256);
370 printf("SEG%x %08lx\n", i
, segsizes
[i
]);
373 printf("SYMS %u\n", num_syms
);
381 if( num_syms
< 0 ) return error("Bad symbol table");
383 symnames
= malloc(num_syms
*sizeof(char*)+1);
384 if( symnames
== 0 ) return error("Out of memory");
386 symtab
= calloc(num_syms
, sizeof(*symtab
));
387 if( symtab
== 0 ) return error("Out of memory");
389 for(i
=0; i
<num_syms
; i
++)
391 unsigned int symtype
;
393 symtab
[i
].nameoff
= get_word();
394 symtab
[i
].symtype
= get_word();
395 symtype
= (symtab
[i
].symtype
& 0x3FFF);
397 if (symtab
[i
].nameoff
== -1 || symtab
[i
].symtype
== -1) {
398 printf("!!! EOF in symbol table\n");
401 symtab
[i
].offset
= get_sized((symtab
[i
].symtype
>>14)&3);
403 if( symtype
== 0x43 || symtype
== 0x2003 )
404 size_bss
+= symtab
[i
].offset
;
415 if(display_mode
== 2 && multiple_files
&& !opt_o
)
416 printf("\n%s:\n", ifname
);
418 for(i
=0; i
<num_syms
; i
++)
421 unsigned int nameoff
, symtype
;
423 nameoff
= symtab
[i
].nameoff
;
424 symtype
= symtab
[i
].symtype
;
425 offset
= symtab
[i
].offset
;
428 if (nameoff
> str_len
|| nameoff
< 0)
429 symnames
[i
] = strtab
+ str_len
;
431 symnames
[i
] = strtab
+nameoff
;
435 printf("SYM %-4d %08lx ", i
, offset
);
437 printf("%s", (symtype
&0x2000)?"C":".");
438 printf("%s", (symtype
&0x0100)?"N":".");
439 printf("%s", (symtype
&0x0080)?"E":".");
440 printf("%s", (symtype
&0x0040)?"I":".");
441 printf("%c", "T12D456789abcdeUAhijklmnopqrstuv"[symtype
&0x1F]);
442 if( symtype
&0x1E20 )
443 printf(" %04x", symtype
);
444 printf(" %s\n", symnames
[i
]);
446 if( display_mode
== 2 )
449 printf("%s: ", ifname
);
450 if( symtype
== 0x004f || symtype
== 0x0040 )
453 printf("%08lx ", offset
);
456 case 0x004F: putchar('U'); break;
457 case 0x0000: putchar('t'); break;
458 case 0x0003: putchar('d'); break;
459 case 0x2003: putchar('b'); break;
460 case 0x0043: putchar('C'); break;
461 case 0x0083: putchar('D'); break;
462 case 0x0080: putchar('T'); break;
463 case 0x0040: putchar('T'); break;
464 case 0x0180: putchar('N'); break;
465 case 0x0010: putchar('a'); break;
466 case 0x0090: putchar('A'); break;
468 if((symtype
& ~0xF) == 0x40 )
470 else if((symtype
& ~0xF) == 0x80 )
471 printf("%c", "T12D456789abcdeU"[symtype
&0xF]);
476 printf(" %s\n", symnames
[i
]);
488 static char * relstr
[] = {"ERR", "DB", "DW", "DD"};
495 fseek(ifd
, filepos
+textoff
, 0);
497 printf("\nBYTECODE\n");
500 if( (ch
=get_byte()) == -1 ) break;
506 case 0x00: switch(ch
& 0xF0)
508 case 0x00: /* Relocator size */
509 printf("RELSZ %d\n", relsize
= (ch
&0xF));
510 if(relsize
>3) relsize
=3;
512 case 0x10: /* Skip bytes */
513 printf("SKP %ld\n", get_sized(ch
&0xF));
515 case 0x20: /* Segment */
516 printf("SEG %x\n", curseg
= (ch
&0xF));
518 default: printf("CODE %02x - unknown\n", ch
);
522 case 0x40: /* Raw bytes */
524 int abscnt
= (ch
&0x3F);
525 if( abscnt
== 0 ) abscnt
= 64;
526 for( i
=0; i
<abscnt
; i
++ )
528 if( (ch
=get_byte()) == -1 ) break;
533 if( ch
== -1 ) goto break_break
;
536 case 0x80: /* Relocator - simple */
537 l
= get_sized(relsize
);
538 printf("%s SEG%x%s%s", relstr
[relsize
],
543 printf("+0x%04lx", l
);
546 case 0xC0: /* Relocator - symbol relative */
549 printf("CODE %02x - unknown\n", ch
);
552 if( ch
& 4 ) i
= get_word();
556 printf("%s %s%s%s", relstr
[relsize
],
561 printf("+0x%04lx", l
);
578 case 1: return get_byte();
579 case 2: return get_word();
580 case 3: return get_long();
590 for(i
=0; i
<32; i
+=16)
592 unsigned int v
= get_word();
594 retv
+= ((long)v
<<(16-i
));
596 retv
+= ((long)v
<<i
);
609 if( v
== EOF
) return -1;
623 if (v
== EOF
) return -1;
632 static char linebuf
[80];
639 printf(": %.66s\n", linebuf
);
645 memset(linebuf
, ' ', sizeof(linebuf
));
646 sprintf(buf
, "%02x", ch
&0xFF);
647 memcpy(linebuf
+pos
*3+(pos
>7), buf
, 2);
648 if( ch
> ' ' && ch
<= '~' ) linebuf
[50+pos
] = ch
;
649 else linebuf
[50+pos
] = '.';
650 pos
= ((pos
+1) & 0xF);
653 printf(": %.66s\n", linebuf
);
654 memset(linebuf
, ' ', sizeof(linebuf
));
659 /************************************************************************/
660 /* ELKS a.out versions
664 int h_len
, h_flgs
, h_cpu
;
671 header
[0] = get_long();
672 header
[1] = get_long();
673 byte_order
= ((header
[0]>>24) & 3);
675 h_len
= (header
[1] & 0xFF);
676 h_flgs
= ((header
[0]>>16) & 0xFF);
677 h_cpu
= ((header
[0]>>24) & 0xFF);
682 header
[i
] = get_long();
691 static char * cpu
[] = { "unknown", "8086", "m68k", "ns16k", "i386", "sparc" };
692 static char * byteord
[] = { "LITTLE_ENDIAN", "(2143)","(3412)","BIG_ENDIAN" };
696 if( h_cpu
> 0x17 ) h_cpu
&= 3;
698 printf("HLEN %d\n", h_len
);
699 printf("CPU %s %s\n", cpu
[h_cpu
>>2], byteord
[h_cpu
&3]);
702 if( h_flgs
& 0x01 ) printf(" A_UZP");
703 if( h_flgs
& 0x02 ) printf(" A_PAL");
704 if( h_flgs
& 0x04 ) printf(" A_NSYM");
705 if( h_flgs
& 0x08 ) printf(" FLG-08");
706 if( h_flgs
& 0x10 ) printf(" A_EXEC");
707 if( h_flgs
& 0x20 ) printf(" A_SEP");
708 if( h_flgs
& 0x40 ) printf(" A_PURE");
709 if( h_flgs
& 0x80 ) printf(" A_TOVLY");
713 printf("a_entry = 0x%08lx\n", header
[5]);
714 printf("a_total = 0x%08lx\n", header
[6]);
716 printf("a_syms = 0x%08lx\n", header
[7]);
719 printf("a_trsize = 0x%08lx\n", header
[8]);
721 printf("a_drsize = 0x%08lx\n", header
[9]);
723 printf("a_tbase = 0x%08lx\n", header
[10]);
725 printf("a_dbase = 0x%08lx\n", header
[11]);
737 printf("NO SYMBOLS\n");
741 fseek(ifd
, (long)h_len
, 0);
742 for(l
=0; l
<header
[2]; l
++)
744 if( (i
=getc(ifd
)) == EOF
) break;
750 fseek(ifd
, (long)h_len
+header
[2], 0);
751 for(l
=0; l
<header
[3]; l
++)
753 if( (i
=getc(ifd
)) == EOF
) break;
762 if( display_mode
== 0 )
763 printf("text\tdata\tbss\tdec\thex\tfilename\n");
765 printf("%ld\t%ld\t%ld\t%ld\t%lx\t%s\n",
766 header
[2], header
[3], header
[4],
767 header
[2]+ header
[3]+ header
[4],
768 header
[2]+ header
[3]+ header
[4],
771 tot_size_text
+= header
[2];
772 tot_size_data
+= header
[3];
773 tot_size_bss
+= header
[4];
781 int n_sclass
, n_numaux
, n_type
;
785 fseek(ifd
, h_len
+header
[2]+header
[3]+header
[8]+header
[9], 0);
788 { error("Executable has new format symbol table.\n"); return; }
790 bytes_left
= header
[7];
792 if( bytes_left
== 0 )
793 printf("No symbols in '%s'\n", ifname
);
794 else if(multiple_files
&& !opt_o
)
795 printf("\n%s:\n", ifname
);
797 while(bytes_left
> 16)
799 if( fread(n_name
, 1, 8, ifd
) != 8 ) break;
801 n_value
= get_long();
802 if( (n_sclass
= getc(ifd
)) == EOF
) break;
803 if( (n_numaux
= getc(ifd
)) == EOF
) break;
806 if( pending_nl
&& n_sclass
== 0 )
808 printf("%s", n_name
);
812 if( pending_nl
) putchar('\n');
814 printf("%s: ", ifname
);
815 if( n_sclass
== 0x10 )
818 printf("%08lx ", n_value
);
821 case 0x01: printf("a "); break;
822 case 0x12: printf("T "); break;
823 case 0x13: printf("D "); break;
824 case 0x14: printf("C "); break;
825 case 0x1a: printf("t "); break;
826 case 0x1b: printf("d "); break;
827 case 0x1c: printf("b "); break;
828 case 0x10: printf("U "); break;
829 default: if( display_mode
)
837 case 0: printf("C_NULL,"); break;
838 case 2: printf("C_EXT,"); break;
839 case 3: printf("C_STAT,"); break;
840 default: printf("%04o,", n_sclass
&0xF8);
844 case 0: printf("N_UNDF "); break;
845 case 1: printf("N_ABS "); break;
846 case 2: printf("N_TEXT "); break;
847 case 3: printf("N_DATA "); break;
848 case 4: printf("N_BSS "); break;
849 case 5: printf("N_COMM "); break;
850 default: printf("%o ", n_sclass
&7); break;
855 if( display_mode
== 0 )
858 printf("n_numaux=%02x ", n_numaux
);
860 printf("n_type=%04x ", n_type
);
863 printf("%s", n_name
);
868 if( pending_nl
) putchar('\n');