ftp.nice.ch/pub/next/unix/hack/hackkit.2.N.bs.tar.gz#/freebies/source/dis/dis.c

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.