This is dis.c in view mode; [Download] [Up]
/* NeXT disassembly tool
Copyright (C) 1989 by Bill Spitzak.
See Copyright notice in makefile
*/
#include "dis.h"
char *objectfile; /* name of the object file */
char *map; /* the file, mapped into memory with neat Mach stuff */
/* Disassembly switches: */
int decimalrange=127;/* -d */
flag globalscode; /* -g */
int printpass=100; /* -p n */
flag xlabels; /* -x */
flag onlysymbols; /* -t */
flag noextern; /* -e */
long filelength(int handle) {
long ltmp, ltmp2;
ltmp=lseek(handle,0L,1);
ltmp2=lseek(handle,0L,2);
lseek(handle,ltmp,0);
return(ltmp2);
}
/* This is part of main() - see if file is an archive, and if so
map one of the archive entries: */
int archeck(int i, char *objname, char *libname) {
struct { /* the header for an archive entry */
char name[16];
char date[12];
char uid[6];
char gid[6];
char mode[8];
char size[10];
char fmag[2];
} ar;
int size;
/* see if magic string is at the start: */
read(i,&ar,8); if (strncmp(ar.name,"!<arch>\n",8)) return(FALSE);
if (!objname) {printf("%s is a library.\n",libname); goto FAIL;}
while (read(i,&ar,sizeof(ar)) == sizeof(ar)) {
if (strncmp(ar.fmag,"`\n",2)) break; /* perhaps junk at eof? */
size = atoi(ar.size);
if (!strncmp(ar.name,"__.SYMDEF",9));
else if (!strncmp(objname,ar.name,strlen(objname))) {
map_fd(i,lseek(i,0,1),&map,TRUE,size);
return(TRUE);
}
if (size&1) size++;
lseek(i,size,1);
}
printf("%s not found in library %s.\n",objname,libname);
FAIL:
printf("Recommend you do the following to find a symbol:\n"
" nm -gop %s | grep <symbol>\n",libname);
exit(1);
return(FALSE); /* make cc not complain */
}
int main(int argc, char **argv) {
int i,fd;
char *c;
for (i=1; c = argv[i++];) {
if (*c=='-') for (;*++c;) {
switch(*c) {
case 'd': decimalrange = atoi(argv[i++]); break;
case 'e': noextern = TRUE; break;
case 'g': globalscode = TRUE; break;
case 'G': globalscode = 2; break;
case 'p': printpass = atoi(argv[i++]); break;
case 't': onlysymbols = TRUE; break;
case 'x': xlabels = TRUE; break;
}
}
else break;
}
if (!c) {
puts(" dis: the Mach-O/NeXT disassembler.\n"
" Written by Bill Spitzak (SPITZAK@MCIMAIL.COM) Sep 1989\n"
" This software is distributed FREE and may not be sold.\n"
"\n"
"dis {-xxx} name\t\t: disassemble executable\n"
"dis {-xxx} name.o\t: disassemble object\n"
"dis {-xxx} lib.a name.o\t: disassemble object in library\n"
"\n"
"switches:\n"
"-d #\t: print constants larger than # in hex (default=127)\n"
"-e\t: don't print .globl declarations for externals\n"
"-g\t: assumme all globals in .text segment are code\n"
"-G\t: assumme everything in .text is code\n"
"-p #\t: print during pass # (0 is first pass)\n"
"-t\t: print only the symbols, no code\n"
"-x\t: print address in hex before each line\n"
"\n");
return(1);
}
fd = open(c,0);
if (fd<0) {printf("Can't open %s, %s\n",c,strerror()); return(1);}
if (archeck(fd,argv[i],c)) objectfile = argv[i];
else {objectfile = c; map_fd(fd,0,&map,TRUE,filelength(fd));}
close(fd);
disasmmappedfile();
/* we could go on to do multiple files here... */
return(0);
}
/*======================= print routines ========================*/
/* These routines are called to print all the output. So they and the
calling routines can be identified if we ever improve this to produce
graphical output.
*/
flag printit; /* if false, disable printing for pre-passes */
static flag linestarted; /* multiple \n preventer */
void startline(long unsigned address) {
if (!printit) return;
if (linestarted) putchar('\n');
if (xlabels) printf("%7x ",address);
linestarted = TRUE;
}
void startlinenoaddress(void) {
if (!printit) return;
if (linestarted) putchar('\n');
if (xlabels) printf(" ");
linestarted = TRUE;
}
void endline(void) { /* this only needs to be called at eof! */
if (linestarted) putchar('\n');
linestarted = FALSE;
}
void cprint(int c) {if (printit) putchar(c);}
void sprint(char *s) {if (printit) printf("%s",s);}
void fprint(f,i1,i2,i3) {if (printit) printf((char *)f,i1,i2,i3);}
/*==================================================================*/
symbol *sourcesymtab; /* points to symbol list, for items that index it */
char *symnametable; /* the source file symbol name table */
struct section *sectiontable[50]; /* note that index of 1 is location 0! */
disasmmappedfile() {
/* do exactly one, already mapped, object file */
int i,j,sectn;
unsigned startaddress=1;
struct segment_command *p;
struct section *q;
symbol *n;
int pass;
extern int newlabels;
extern flag incode;
struct mach_header *header = (struct mach_header *)map;
if (header->magic != 0xfeedface) {
printf("%s is not a Mach-O file (bad magic number)!\n",objectfile);
exit(1);
}
if (header->cputype != 6)
printf("Cputype is %d (MC68030==6 so disassembly may be wrong)\n",header->cputype);
if (header->cpusubtype != 1)
printf("Wrong machine (cpusubtype is %d, NeXT==1)?\n",header->cpusubtype);
sectn = 0;
for (i=0, p = (struct segment_command*)(header+1); i<header->ncmds; i++) {
switch(p->cmd) {
case 1: /* a segment load command, get all the sections: */
for (j=0,q=(struct section *)(p+1); j<p->nsects; q++,j++) {
sectiontable[sectn++] = q;
}
break;
case 2: /* load the symbol table, sort it: */
sourcesymtab = n =
(symbol *)(map+((struct symtab_command*)p)->symoff);
symnametable = map+((struct symtab_command*)p)->stroff;
for (j = ((struct symtab_command*)p)->nsyms; j>0; j--,n++) {
if (n->name) n->name = symnametable+(int)n->name;
if ((n->type&-2)==N_ABS && !n->section) n->section=sectn+1;
addsymbol(n);
}
break;
case 5: /* a unix-thread thing */
startaddress = ((struct unixthread *)p)->pc;
break;
}
p = (struct segment_command *)((void *)p + p->cmdsize);
}
if (startaddress != 1) {
n = findlabel(startaddress);
if (n) n->desc = CODE;
else createlabel(startaddress,1,CODE,"start");
}
sortreltables();
/* do non-printing passes until no more symbols: */
printit = FALSE;
for (pass=0; pass<printpass; pass++) {
newlabels = 0;
sectn=0;
for (i=0, p = (struct segment_command*)(header+1);
i<header->ncmds; i++,
p = (struct segment_command *)((void *)p + p->cmdsize)
) if (p->cmd==1) { /* for each section */
for (j=0,q=(struct section *)(p+1); j<p->nsects; q++,j++) {
sectn++; /* for each segment */
incode = sectn==1;
disasmblock(q->vmaddr,q->vmaddr+q->vmsize,p->vmaddr,
q->fileoff ? p->vmaddr+p->vmsize:0,
(unsigned)map+p->fileoff-p->vmaddr,
(struct relocation_info *)(map+q->reloff),
q->nreloc,sectn);
}
}
if (!newlabels) break;
printf("| Pass %d, %d new labels\n",pass,newlabels);
}
startaddress = 0;
printit = TRUE;
sectn=0;
if (!onlysymbols)
for (i=0, p = (struct segment_command*)(header+1);
i<header->ncmds; i++,
p = (struct segment_command *)((void *)p + p->cmdsize)
) if (p->cmd==1) { /* for each section */
for (j=0,q=(struct section *)(p+1); j<p->nsects; q++,j++) {
if (!j) disasmsymbols(startaddress,q->vmaddr,FALSE);
startaddress = q->vmaddr+q->vmsize;
sectn++; /* for each segment */
incode = sectn==1;
if (!strcmp(q->sectname,"__text") ||
!strcmp(q->sectname,"__data") ||
!strcmp(q->sectname,"__bss")) {
if (!q->vmsize) continue;
startline(q->vmaddr);
cprint('.'); sprint(q->sectname+2);
}
else {
startline(q->vmaddr);
fprint(".segment %s; .section %s:",
q->segname,q->sectname);
}
disasmblock(q->vmaddr,q->vmaddr+q->vmsize,p->vmaddr,
q->fileoff ? p->vmaddr+p->vmsize:0,
(unsigned)map+p->fileoff-p->vmaddr,
(struct relocation_info *)(map+q->reloff),
q->nreloc,sectn);
}
}
disasmsymbols(startaddress,0,TRUE);
endline();
}
sortreltables() {
int sectn;
struct section *q;
struct relocation_info *r,*s,temp;
char *p; char *sym; int off;
int i,j;
for (sectn = 0; q = sectiontable[sectn]; sectn++) {
/* sort into descending order: */
for (i=0, r=(struct relocation_info *)(map+q->reloff);
i<q->nreloc; i++) {
for (j=i-1; j>=0 && r[j].address<r[i].address; j--);
j++;
if (j<i) {
temp = r[i];
movmem(r+j,r+j+1,(i-j)*sizeof(struct relocation_info));
r[j] = temp;
}
}
}
}
disasmsymbols(
unsigned start, /* address to start at */
unsigned end, /* address to end at */
int rest) /* ignore end, print all of them */
{
symbol *n;
extern unsigned symaddress;
n = firstsymbol(start);
while (n && (rest || symaddress<end)) {
printsymbol(n);
n = nextsymbol();
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.