File:  [MW Coherent from dump] / coherent / b / bin / cdmp.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:36 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * cdmp.c
 * 3/24/93
 * Requires libmisc functions: cc cdmp.c -lmisc
 * Read and print COFF files.
 * Usage: cdmp [ -adlrsx ] filename ...
 * Options:
 * 	-a	supress symbol aux entries
 * 	-d	supress data dumps
 * 	-l	supress line numbers
 * 	-r	supress relocation entries
 * 	-s	supress symbol entries
 *	-V	print version number
 *	-x	dump aux entries in hex
 *	-?	print usage info and exit
 * Does not know all there is to know about aux entry structure yet.
 */

#include <misc.h>		/* misc useful stuff */
#include <coff.h>
#include <errno.h>

#define	VERSION	"V2.2"
#define VHSZ	48		/* line size in vertical hex dump */
typedef	char	SECNAME[9];	/* NUL-terminated 8 character section name */

/* Some shortcut display stuff. */
#define showFlag(flag, msg) if (fh.f_flags & flag) printf("\t" msg "\n");
#define showCase(x)	showDesc(x, #x)
#define	showDesc(x, d)	case x: printf(d); break;
#define showVal(x)	case x: printf(#x "\tvalue=%ld ", se->n_value); break;
#define showHexVal(x)	case x: printf(#x "\tvalue=0x%lX ", se->n_value); break;

/* Externals. */
extern	long	ftell();
extern	char	*optarg;

/* Forward. */
void	fatal();
char	*checkStr();
void	optHeader();
void	readHeaders();
void	shrLib();
void	readSection();
void	readStrings();
void	readSymbols();
void	print_aux();
void	print_sym();
void	dump();
int	clean();
void	outc();
int	hex();

/* Globals. */
char	aswitch;		/* Suppress aux entry dumps		*/
char	buf[VHSZ];		/* Buffer for hex dump			*/
char	dswitch;		/* Suppress data dumps			*/
FILE	*fp;			/* COFF file pointer			*/
char	lswitch;		/* Suppress line number dumps		*/
long	num_sections;		/* Number of sections			*/
long	num_symbols;		/* Number of symbols			*/
char	rswitch;		/* Suppress reloc dumps			*/
SECNAME	*sec_name;		/* Section names			*/
long	section_seek;		/* Seek to seek start of section	*/
char	sswitch;		/* Suppress symbol dumps		*/
char	*str_tab;		/* String char array			*/
long	symptr;			/* File pointer to symbol table entries	*/
char	xswitch;		/* Dump aux entries in hex		*/

/*
 * Print fatal error message and die.
 */
/* VARARGS */
void
fatal(s) char *s;
{
	register int save;

	save = errno;
	fprintf(stderr, "cdmp: %r\n", &s);
	if (0 != (errno = save))
		perror("errno reports");
	exit(1);
}

/*
 * Return a printable version of string s,
 * massaging nonprintable characters if necessary.
 */
char *
checkStr(s) unsigned char *s;
{
	register unsigned char *p, c;
	register int ct, badct;
	static char *work = NULL;

	for (badct = 0, ct = 1, p = s; c = *p++; ct++)
		if ((c <= ' ') || (c > '~'))
			badct += 2;	/* not printable as is */

	if (!badct)
		return s;		/* ok as is */

	if (NULL != work)
		free(work);		/* free previous */

	work = alloc(badct + ct);
	for (p = work; c = *s++;) {
		if (c > '~') {
			*p++ = '~';
			c &= 0x7f;
		}
		if (c <= ' ') {
			*p++ = '^';
			c |= '@';
		}
		*p++ = c;
	}
	return work;
}

/*
 * Process optional file header.
 */
void
optHeader(size) unsigned int size;
{
	register AOUTHDR *ohp;
	register unsigned int tail;

	if ((tail = size - sizeof(*ohp)) < 0)
		fatal("optional header too small -- %d bytes", size);
	ohp = alloc(size);

	if (1 != fread(ohp, size, 1, fp))
		fatal("error reading optional header");

	printf("\nOPTIONAL HEADER VALUES\n");
	printf("magic            = 0x%X\n",	ohp->magic);
	printf("version stamp    = %d\n",	ohp->vstamp);
	printf("text size        = 0x%lX\n",	ohp->tsize);
	printf("init data size   = 0x%lX\n",	ohp->dsize);
	printf("uninit data size = 0x%lX\n",	ohp->bsize);
	printf("entry point      = 0x%lX\n",	ohp->entry);
	printf("text start       = 0x%lX\n",	ohp->text_start);
	printf("data start       = 0x%lX\n",	ohp->data_start);

	/* Print extra info, if any. */
	if (tail) {
		printf("\n EXTRA OPTIONAL HEADER INFO\n");
		dump(ohp + 1, tail);
	}
	free(ohp);
}

/*
 * Process file header.
 */
void
readHeaders(fn) char *fn;
{
	FILEHDR	fh;

	fp = xopen(fn, "rb");

	if (1 != fread(&fh, sizeof(fh), 1, fp))
		fatal("error reading COFF header");

	printf("FILE %s HEADER VALUES\n",	fn);
	printf("magic number   = 0x%X\n",	fh.f_magic);
	printf("sections       = %ld\n",	num_sections = fh.f_nscns);
	printf("file date      = %s",		ctime(&fh.f_timdat));
	printf("symbol ptr     = 0x%lX\n",	symptr = fh.f_symptr);
	printf("symbols        = %ld\n",	num_symbols = fh.f_nsyms);
	printf("sizeof(opthdr) = %d\n",		fh.f_opthdr);
	printf("flags          = 0x%X\n",	fh.f_flags);

	showFlag(F_RELFLG,	"Relocation info stripped from file");
	showFlag(F_EXEC,	"File is executable");
	showFlag(F_LNNO,	"Line numbers stripped from file");
	showFlag(F_LSYMS,	"Local symbols stripped from file");
	showFlag(F_MINMAL,	"Minimal object file");

	/*
	 * Allocate section name array.
	 */
	if (num_sections != 0)
		sec_name = (SECNAME *)alloc(((int)num_sections) * (sizeof(SECNAME)));

	if (fh.f_opthdr)
		optHeader(fh.f_opthdr);		/* optional header */
	section_seek = sizeof(FILEHDR) + fh.f_opthdr;
}

/*
 * Process shared library.
 */
void
shrLib()
{
	SHRLIB shr;
	register long i;
	register char *pathn;

	if (1 != fread(&shr, sizeof(shr), 1, fp))
		fatal("error reading library section");

	if (shr.pathndx -= 2) {
		long j;
		printf("\nExtra Library info:\n");

		for (j = shr.pathndx * 4;
		     j && (i = fread(buf, 1, ((j > VHSZ) ? VHSZ : (int)j), fp));
		     j -= i) {
			if (!i)
				fatal("unexpected EOF in .lib data");
			dump(buf, (int)i);
		}
	}

	pathn = alloc(i = (shr.entsz - 2) * 4);
	if (1 != fread(pathn, i, 1, fp))
		fatal("error reading library name");
	printf("\nReferences %s\n", pathn);
	free(pathn);
}

/*
 * Process sections.
 */
void
readSection(n) register int n;
{
	SCNHDR	sh;
	register long i;

	fseek(fp, section_seek, 0);
	if (1 != fread(&sh, sizeof(SCNHDR), 1, fp))
		fatal("error reading section header");

	section_seek += sizeof(SCNHDR);
	fseek(fp, sh.s_scnptr, 0);

	strncpy(sec_name[n], checkStr(sh.s_name), sizeof(SECNAME) - 1);
	printf("\n%s - SECTION HEADER -\n",	sec_name[n]);
	printf("physical address    = 0x%lX\n", sh.s_paddr);
	printf("virtual address     = 0x%lX\n", sh.s_vaddr);
	printf("section size        = 0x%lX\n", sh.s_size);
	printf("file ptr to data    = 0x%lX\n", sh.s_scnptr);
	printf("file ptr to relocs  = 0x%lX\n", sh.s_relptr);
	printf("file ptr to lines   = 0x%lX\n", sh.s_lnnoptr);
	printf("relocation entries  = %u\n",	sh.s_nreloc);
	printf("line number entries = %u\n",	sh.s_nlnno);
	printf("flags               = 0x%lX\t", sh.s_flags);
	switch((int)sh.s_flags) {

	showDesc(STYP_GROUP,	"grouped section")
	showDesc(STYP_PAD,	"padding section")
	showDesc(STYP_COPY,	"copy section")
	showDesc(STYP_INFO,	"comment section")
	showDesc(STYP_OVER,	"overlay section")
	showDesc(STYP_TEXT,	"text only")
	showDesc(STYP_DATA,	"data only")
	showDesc(STYP_BSS,	"bss only")

	case STYP_LIB:
		printf(".lib section\n");
		shrLib();
		return;

	default:
		printf("unrecognized section");
		break;
	}
	putchar('\n');

	/* Print raw data. */
	if (!dswitch && strcmp(sh.s_name, ".bss")) { /* don't output bss */
		register long j;

		fseek(fp, sh.s_scnptr, 0);
		printf("\nRAW DATA\n");

		for (j = sh.s_size;
		     j && (i = fread(buf, 1, ((j > VHSZ) ? VHSZ : (int)j), fp));
		     j -= i) {
			if (!i)
				fatal("unexpected EOF in %.8s data",
				      checkStr(sh.s_name));
			dump(buf, (int)i);
		}
	}

	/* Print relocs. */
	if (!rswitch && sh.s_nreloc) {
		fseek(fp, sh.s_relptr, 0);
		printf("\nRELOCATION ENTRIES\n");
		for (i = 0; i < sh.s_nreloc; i++) {
			RELOC	re;	/* Relocation entry structure */

			if (1 != fread(&re, RELSZ, 1, fp))
				fatal("error reading relocation entry");

			printf("address=0x%lX\tindex=%ld \ttype=",
				re.r_vaddr, re.r_symndx);
			switch(re.r_type) {
			showCase(R_DIR8)
			showCase(R_DIR16)
			showCase(R_DIR32)
			showCase(R_RELBYTE)
			showCase(R_RELWORD)
			showCase(R_RELLONG)
			showCase(R_PCRBYTE)
			showCase(R_PCRWORD)
			showCase(R_PCRLONG)
			showCase(R_NONREL)
			default:
				fatal("unexpected relocation type 0x%X",
					re.r_type);
				break;
			}
			putchar('\n');
		}
	}

	/* Print line numbers. */
	if (!lswitch && sh.s_nlnno) {
		fseek(fp, sh.s_lnnoptr, 0);
		printf("\nLINE NUMBER ENTRIES\n");

		for (i = 0; i < sh.s_nlnno; i++) {
			LINENO	le;	/* Line number entry structure */

			if (1 != fread(&le, LINESZ, 1, fp))
				fatal("error reading line number entry");

			if (le.l_lnno)
				printf("address=0x%lX\tline=%d\n",
					le.l_addr.l_paddr, le.l_lnno);
			else
				printf("function=%d\n", le.l_addr.l_symndx);
		}
	}
}

/*
 * Read the string table into memory.
 * This allows readSymbols() to work.
 */
void
readStrings()
{
	register unsigned char *str_ptr, c;
	long str_seek;
	unsigned long str_length;
	unsigned len;

	str_seek = symptr + (SYMESZ * num_symbols);
	fseek(fp, str_seek, 0);

	if (1 != fread(&str_length, sizeof(str_length), 1, fp))
		str_length = 0;

	if (str_length == 0) {
		printf("\nNO STRING TABLE\n");
		return;
	}
	printf("\nSTRING TABLE DUMP\n");
	len = str_length -= 4;
	if (len != str_length)
		fatal("bad string table length %ld", str_length);
	str_tab = alloc(len);
	if (1 != fread(str_tab, len, 1, fp))
		fatal("error reading string table %lX %d", ftell(fp), len);

	for (str_ptr = str_tab; str_ptr < str_tab + str_length; ) {
		putchar('\t');
		while (c = *str_ptr++) {
			if (c > '~') {
				c &= 0x7f;
				putchar('~');
			}
			if (c < ' ') {
				c |= '@';
				putchar('^');
			}
			putchar(c);
		}
		putchar('\n');
	}
}

/*
 * Process symbol table.
 */
void
readSymbols()
{
	SYMENT se;
	register long i, j, naux;

	if (sswitch)
		return;
	fseek(fp, symptr, 0);
	printf("\nSYMBOL TABLE ENTRIES\n");
	for (i = 0; i < num_symbols; i++) {
		if (1 != fread(&se, SYMESZ, 1, fp))
			fatal("error reading symbol entry");
		print_sym(&se, i);
		naux = se.n_numaux;
		for (j = 0; j < naux; j++)
			print_aux(i+j+1, &se);
		i += naux;
		if (i >= num_symbols)
			fatal("inconsistant sym table");
	}
}

#define showNe(x, d) if(l = ae.x) printf("\t" d "=%ld", l)
/*
 * Process a symbol aux entry.
 * This is still pretty ad hoc, it may not do all entries correctly yet.
 * Does not print 0-valued fields.
 */
void
print_aux(n, sep) int n; register SYMENT *sep;
{
	AUXENT ae;
	register int type, class;
	register long l;
	int has_fsize, has_fcn;
	unsigned short *sp;
	char fname[FILNMLEN + 1];

	if (1 != fread(&ae, AUXESZ, 1, fp))
		fatal("error reading symbol aux entry");
	if (aswitch)
		return;					/* suppressed */
	printf("%4ld\t", n);				/* symbol number */
	if (xswitch) {					/* dump in hex */
		printf("\tAUX ENTRY DUMP\n");
		dump(&ae, sizeof(ae));
		return;
	}

	class = sep->n_sclass;
	type = sep->n_type;

	if (class == C_FILE) {				/* .file */
		strncpy(fname, ae.ae_fname, FILNMLEN);
		fname[FILNMLEN] = '\0';
		printf("\tfilename=%s\n", checkStr(fname));
		return;
	} else if (class == C_STAT && type == T_NULL) {	/* section name */
		printf("\tlength=%lX\trelocs=%d\tlinenos=%d\n",
			ae.ae_scnlen,
			ae.ae_nreloc,
			ae.ae_nlinno);
		return;
	}

	/*
	 * In cases not handled above,
	 * the AUXENT is an x_sym which must be decyphered.
	 * Flags tell which members of unions to dump.
	 * The flag setting might not be quite right yet.
	 */
	has_fsize = has_fcn = 0;
	if (class == C_STRTAG || class == C_UNTAG || class == C_ENTAG
	 || class == C_BLOCK)		/* tag definitions or .bb or .eb */
		++has_fcn;
	if (ISFCN(type)) {
		++has_fsize;
		++has_fcn;
	}

	/* Print tag index. */
	showNe(ae_tagndx, "tag");

	/* Print fsize or lnsz info. */
	if (has_fsize) {
		showNe(ae_fsize, "fsize");
	} else {
		showNe(ae_lnno, "lnno");
		showNe(ae_size, "size");
	}

	/* Print fcn or ary info. */
	if (has_fcn) {
		if (l = ae.ae_lnnoptr)
			printf("\tlnnoptr=0x%lX", l);
		showNe(ae_endndx, "end");
	} else {
		sp = ae.ae_dimen;
		if (*sp != 0) {
			printf("\tdims=< ");
			while (sp < &ae.ae_dimen[DIMNUM] && *sp)
				printf("%d ", *sp++);
			putchar('>');
		}
	}

	/* Print tv index. */
	showNe(ae_tvndx, "tv");
	putchar('\n');
}
#undef showNe

/*
 * Process symbol table entry.
 */
void
print_sym(se, n) register SYMENT *se; register long n;
{
	register int i, c, flag, derived;
	
	if (se->n_sclass == C_FILE && n > 0)
		putchar('\n');			/* for readability */
	printf("%4ld\t", n);			/* index number */
	if (se->n_zeroes != 0) {		/* name in place */
		for (flag = i = 0; i < SYMNMLEN; i++) {
			if (flag)
				;
			else if ((' ' < (c = se->n_name[i])) && ('~' >= c))
				putchar(c);
			else
				flag = c ? 1 : -1;
		}
		putchar('\t');
	} else					/* name in string table */
		printf("%s ", checkStr(str_tab + se->n_offset - 4));

	/* Print section. */
	i = se->n_scnum;
	printf("section=");
	if (i >= 1 && i <= num_sections)
		printf("%s", sec_name[i-1]);
	else
		switch(i) {
		showCase(N_UNDEF)
		showCase(N_ABS)
		showCase(N_DEBUG)
		default:
			printf("%d?", i);
			break;
		}

	/* Print the type. */
	printf("\ttype=");

	/* Print derived types. */
	derived = 0;
	for (i = se->n_type; i & N_TMASK; i >>= N_TSHIFT) {
		if (derived++ == 0)
			putchar('<');
		switch((i & N_TMASK) >> N_BTSHFT) {
		showCase(DT_PTR)
		showCase(DT_FCN)
		showCase(DT_ARY)
		case DT_NON:
		default:
			fatal("unexpected derived type 0x%X", i & N_TMASK);
		}
		putchar(' ');
	}

	switch (c = (se->n_type & N_BTMASK)) {	/* base type */
	showDesc(T_NULL, "none")
	showCase(T_CHAR)
	showCase(T_SHORT)
	showCase(T_INT)
	showCase(T_LONG)
	showCase(T_FLOAT)
	showCase(T_DOUBLE)
	showCase(T_STRUCT)
	showCase(T_UNION)
	showCase(T_ENUM)
	showCase(T_MOE)
	showCase(T_UCHAR)
	showCase(T_USHORT)
	showCase(T_UINT)
	showCase(T_ULONG)

	case T_ARG:		/* What has base type (not storage class) ARG? */
	default:
		fatal("unexpected base type 0x%X", c);

	}
	if (derived)
		putchar('>');

	/* Print the storage class. */
	printf("\tclass=");
	switch (i = se->n_sclass) {

	showVal(C_EFCN)
	showVal(C_NULL)
	showVal(C_AUTO)
	showHexVal(C_STAT)
	showVal(C_REG)
	showVal(C_EXTDEF)
	showVal(C_LABEL)
	showVal(C_ULABEL)
	showVal(C_MOS)
	showVal(C_ARG)
	showVal(C_STRTAG)
	showVal(C_MOU)
	showVal(C_UNTAG)
	showVal(C_TPDEF)
	showVal(C_ENTAG)
	showVal(C_MOE)
	showVal(C_REGPARM)
	showVal(C_FIELD)
	showVal(C_BLOCK)
	showVal(C_FCN)
	showVal(C_EOS)
	showVal(C_FILE)

	case C_EXT:
		if (se->n_scnum != N_UNDEF)
			printf("C_EXT\tvalue=0x%lX", se->n_value);
		else if (se->n_value != 0)
			printf("Common\tlength=%ld", se->n_value);
		else
			printf("External");
		break;

	case C_USTATIC:			/* What is an undefined static? */
		fatal("unexpected storage class 0x%X", i);

	default:
		printf("0x%X", i);

	}

#if	0
	if (se->n_numaux)
		printf("\tnaux=%d", se->n_numaux);
#endif
	putchar('\n');

	if (1 == flag) {
		printf("*** Bad data in name **\n");
		dump(se, SYMESZ);
	}
}

/*
 * Vertical hex dump of p bytes from buffer buf.
 */
void
dump(buf, p) register char *buf; register int p;
{
	register int i;

	/* Offset. */
	printf ("\n%6lX\t", ftell(fp) - p);

	/* Printable version of character. */
	for (i = 0; i < p; i++ )
		outc(clean(buf[i]), i, ' ');
	printf("\n\t");

	/* High hex digit. */
	for (i = 0; i < p; i++)
		outc(hex((buf[i] >> 4) & 0x0f), i, '.');
	printf("\n\t");

	/* Low hex digit. */
	for (i = 0; i < p; i++)
		outc(hex(buf[i]& 0x0f), i, '.');
	putchar('\n');
}

/*
 * Return c if printable, '.' if not.
 */
int
clean(c) register int c;
{
	return (c >= ' ' && c <= '~' ) ? c : '.';
}

/*
 * Print c, preceded by s every 4 times.
 */
void
outc(c, i, s) register int i, c, s;
{
	if ((i&3) == 0 && i != 0 )
		putchar(s);
	putchar(c);
}

/*
 * Convert hex digit c to corresponding ASCII character.
 */
int
hex(c) register int c;
{
	return ( c <= 9 ) ? c + '0' : c + 'A' - 10;
}

/*
 * Mainline.
 */
main(argc, argv) int argc; char *argv[];
{
	register int i, c;

	while (EOF != (c = getargs(argc, argv, "adlrsxV?"))) {
		switch (c) {

		case 0:
			/* Process a COFF file. */
			readHeaders(optarg);
			for (i = 0; i < num_sections; i++)
				readSection(i);
			if (num_symbols) {
				readStrings();
				readSymbols();
			}
			/* Cleanup. */
			if (sec_name != NULL) {
				free(sec_name);
				sec_name = NULL;
			}
			if (str_tab != NULL) {
				free(str_tab);
				str_tab = NULL;
			}
			fclose(fp);
			break;

		case 'a':	aswitch++;	break;
		case 'd':	dswitch++;	break;
		case 'l':	lswitch++;	break;
		case 'r':	rswitch++;	break;
		case 's':	sswitch++;	break;
		case 'x':	xswitch++;	break;

		case 'V':
			fprintf(stderr, "cdmp: %s\n", VERSION);
			break;

		case '?':
		default:
			fprintf(stderr,
				"Usage: cdmp [ -adlrsx ] filename ...\n"
				"Options:\n"
				"\t-a\tsupress symbol aux entries\n"
				"\t-d\tsupress data dumps\n"
				"\t-l\tsupress line numbers\n"
				"\t-r\tsupress relocation entries\n"
				"\t-s\tsupress symbol entries\n"
				"\t-x\tdump aux entries in hex\n");
			exit(1);
			break;
		}
	}
	exit(0);
}

/* end of cdmp.c */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.