This is dis.m in view mode; [Download] [Up]
/* NeXT disassembly tool
Copyright (C) 1989 by Bill Spitzak.
See Copyright notice in makefile
*/
/* $Log: dis.m,v $
Revision 1.3 94/08/24 22:42:48 ediger
changed a comment
Revision 1.2 94/08/22 22:32:31 ediger
added some comments
Revision 1.1 94/05/31 22:06:37 ediger
Initial revision
* */
static char rcsident[] = "$Id: dis.m,v 1.3 94/08/24 22:42:48 ediger Exp Locker: ediger $";
#include <dis.h>
#include <sys/stat.h>
#import <MappedFile.h>
/* Disassembly switches: */
int decimalrange = 127; /* -d */
flag globalscode = FALSE; /* -g */
int printpass = 100; /* -p n */
flag xlabels = FALSE; /* -x */
flag onlysymbols = FALSE; /* -t */
flag noextern = FALSE; /* -e */
flag printit;
/* fwd declarations of functions in this file */
long filelength(int);
void endline(void);
int main(int, char **);
long
filelength(int handle)
{
struct stat sStat;
assert(handle >= 0);
if (fstat(handle, &sStat) < 0)
perror("finding file size");
return sStat.st_size;
}
extern int optind;
extern char *optarg;
void usage(void);
int
main(int argc, char **argv)
{
int iOption;
MappedFile *oMappedFile;
while ((iOption = getopt(argc, argv, "d:egGtxp:")) != EOF)
{
switch (iOption)
{
case 'd':
decimalrange = atoi(optarg);
break;
case 'e':
noextern = TRUE;
break;
case 'g':
globalscode = TRUE;
break;
case 'G':
globalscode = 2;
break;
case 'p':
printpass = atoi(optarg);
break;
case 't':
onlysymbols = TRUE;
break;
case 'x':
xlabels = TRUE;
break;
default:
usage();
break;
}
}
if (argv[optind] == NULL)
usage();
oMappedFile = [[[MappedFile alloc] init] filename:argv[optind]];
if (oMappedFile == NULL)
{
fprintf(stderr, "Failed to memory-map \"%s\"\n", argv[optind]);
exit(33);
} else if (![oMappedFile map]) {
fprintf(stderr, "Failed to memory-map \"%s\": %s\n", argv[optind],
[oMappedFile errorString]);
[oMappedFile free];
exit(33);
}
disasmmappedfile([oMappedFile address]);
/* we could go on to do multiple files here... */
if (![oMappedFile unmap])
fprintf(stderr, "Failed to UNmemory-map \"%s\": %s\n", argv[optind],
[oMappedFile errorString]);
[oMappedFile free];
return (0);
}
/* do exactly one, already mapped, object file */
void
disasmmappedfile(char *map)
{
int i, j, sectn = 0;
unsigned startaddress = 1;
struct segment_command *p;
struct section *q;
struct nlist *n;
int pass;
extern int newlabels;
extern flag incode;
struct mach_header *header = (struct mach_header *)map;
check_header(header);
/*
* This next for/switch combo appears to be order of section dependent.
* That is, loading the symbol table correctly means having the section
* total count correct.
*/
p = (struct segment_command *)(header + 1);
for (i = 0; i < header->ncmds; i++)
{
switch (p->cmd)
{
case LC_SEGMENT: /* a segment load command, get all the sections: */
sectn = set_sections(p);
break;
case LC_SYMTAB: /* load the symbol table */
load_symbol_table(map, (struct symtab_command *)p, sectn);
break;
case LC_THREAD: /* a thread thing */
case LC_UNIXTHREAD: /* a unix-thread thing */
startaddress = thread_prog_counter(p);
break;
case LC_LOADFVMLIB:
/* should pick up the symbols out of this thing */
break;
}
p = (struct segment_command *) ((void *)p + p->cmdsize);
}
if (startaddress != 1)
{
n = findlabel(startaddress);
if (n)
n->n_desc = CODE;
else
createlabel(startaddress, 1, CODE, "start");
}
/* have to sort the relocation info because getlabel() looks
* in the current relocation info table (rtab global) to find
* a label for the address passed in */
sortreltables(map);
/* do non-printing passes until no more symbols: */
printit = FALSE;
for (pass = 0; pass < printpass; pass++)
{
newlabels = 0;
sectn = 0;
p = (struct segment_command *) (header + 1);
for (i = 0; i < header->ncmds; i++)
{
if (p->cmd == LC_SEGMENT)
{ /* for each section */
q = (struct section *)(p + 1);
for (j = 0; j < p->nsects; q++, j++)
{
sectn++; /* for each segment */
incode = (sectn == 1);
disasmblock(p, q, sectn, map);
}
}
p = (struct segment_command *)((void *)p + p->cmdsize);
}
if (!newlabels)
break;
printf("| Pass %d, %d new labels\n", pass, newlabels);
}
startaddress = 0;
printit = TRUE;
sectn = 0;
if (!onlysymbols)
{
p = (struct segment_command *)(header + 1);
for (i = 0; i < header->ncmds; i++)
{
if (p->cmd == LC_SEGMENT)
{ /* for each section */
q = (struct section *)(p + 1);
for (j = 0; j < p->nsects; q++, j++)
{
if (j == 0)
disasmsymbols(startaddress, q->addr, FALSE);
startaddress = q->addr + q->size;
sectn++; /* for each segment */
incode = sectn == 1;
if (!strcmp(q->sectname, "__text") ||
!strcmp(q->sectname, "__data") ||
!strcmp(q->sectname, "__bss"))
{
if (!q->size)
continue;
startline(q->addr);
cprint('.');
sprint(q->sectname + 2);
} else {
startline(q->addr);
fprint(".segment %s; .section %s:",
q->segname, q->sectname);
}
disasmblock(p, q, sectn, map);
}
}
p = (struct segment_command *)((void *)p + p->cmdsize);
}
}
disasmsymbols(startaddress, 0, TRUE);
endline();
}
void
disasmsymbols(
unsigned start, /* address to start at */
unsigned end, /* address to end at */
int rest /* ignore end, print all of them */
)
{
struct nlist *n;
extern unsigned symaddress;
n = firstsymbol(start);
while (n && (rest || symaddress < end))
{
printsymbol(n);
n = nextsymbol();
}
}
unsigned int
thread_prog_counter(struct segment_command *spSegmentCmd)
{
struct thread_command *spThreadCmd;
struct thread_state_flavor *spThreadStateFlavor;
unsigned long lNextAddress;
unsigned int irPC = -1;
assert(NULL != spSegmentCmd);
spThreadCmd = (struct thread_command *)spSegmentCmd;
spThreadStateFlavor =
(struct thread_state_flavor *)(spThreadCmd + 1);
lNextAddress = (unsigned long)(spThreadStateFlavor + 1);
switch(spThreadStateFlavor->flavor)
{
case M68K_THREAD_STATE_REGS:
irPC = ((struct m68k_thread_state_regs *)lNextAddress)->pc;
break;
case M68K_THREAD_STATE_68882:
irPC = ((struct m68k_thread_state_68882 *)lNextAddress)->iar;
break;
case M68K_THREAD_STATE_USER_REG:
irPC = ((struct m68k_thread_state_user_reg *)lNextAddress)->user_reg;
break;
case i386_THREAD_STATE:
irPC = ((i386_thread_state_t *)lNextAddress)->eip;
break;
}
return irPC;
}
void
check_header(struct mach_header *header)
{
if (header->magic != MH_MAGIC)
{
printf("Not a Mach-O file (bad magic number 0x%x)!\n", header->magic);
exit(1);
}
if (header->cputype != CPU_TYPE_MC680x0)
printf("Cputype is %d (Not MC68030 so disassembly may be wrong)\n",
header->cputype);
if (header->cpusubtype != CPU_SUBTYPE_MC680x0_ALL)
printf("Wrong machine (cpusubtype is %d, MC680x0 is 1)?\n",
header->cpusubtype);
}
void
usage()
{
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: assume all globals in .text segment are code\n"
"-G\t: assume 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");
exit (1);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.