symtab.c 4.86 KB
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <a.out.h> /* includes #include <filehdr.h> #include <syms.h> */
#include <ldfcn.h>
#include <errno.h>
#include <getopt.h>
#include "idbg.h"

int symmax = SYMMAX;
size_t namesize = NAMESIZ;
struct dbstbl dbstab[SYMMAX] = {0};
char nametab[NAMESIZ]  = {0};

int symMax;			
int symcnt;			/* number of symbols */
SYMR *stbl;			/* start of symbol table */
char *namelist = NULL;		/* namelist file */
int nameoffst;			/* index to next available byte in nametab */
int dbnum;			/* total number of entries went into dbstab */
int Verbose = 0;		/* verbose flag */

extern int errno;

static void usage(void);
static void error(char *);
static void rdsymtab(void);
static void setdbstab(void);
static int compar(struct dbstbl  *, struct dbstbl   *);
static int wrdbstab(void);

main(argc,argv)
char **argv;
{
	int c;
	extern char *optarg;
	extern int optind;

	while ((c = getopt(argc, argv, "v")) != -1) {
		switch (c) {
		case 'v':
			Verbose++;
			break;
		case '?':
			usage();
			break;
		}
	}
	if (argc - optind != 1)
		usage();
	else
		namelist = argv[optind];

	/* read symtab into an array */
	rdsymtab();
	/* setup symtab for dbgmon */
	setdbstab();
	/* write dbstab into obj file */
	wrdbstab();
	exit(0);
}

static void
usage()
{
	fprintf(stderr,"Usage: setsym [-v] file name\n");
	exit(1);
}

static void
error(char *s)
{
	perror(s);
	exit(1);
}

static int
compar(struct dbstbl  *x, struct dbstbl  *y)
{
	if(x->addr > y->addr)
		return(1);
	else if(x->addr == y->addr)
		return(0);
	return(-1);
}

/* 
 *	read symbol table from object file into memory 
 */
static void
rdsymtab()
{
	LDFILE	*ldptr = NULL;
	int	i;

	if((ldptr = ldopen(namelist, ldptr)) == NULL)
		error("cannot open namelist file");
	/* external symbols start at index isymMax and are iextMax long */
	/* read local and external symbols */
	symMax = SYMHEADER(ldptr).isymMax;
	symcnt = SYMHEADER(ldptr).isymMax + SYMHEADER(ldptr).iextMax; 
	if((stbl = (SYMR *) malloc (symcnt * sizeof(SYMR)))
		== NULL)
		error("cannot allocate space for namelist");
	for(i = 0; i < symcnt; i++) {
		if(ldtbread(ldptr, i , &stbl[i]) 
			!= SUCCESS) 
			error("cannot read symbol from namelist");
	}
	if(ldclose(ldptr) != SUCCESS)
		error("cannot ldclose namelist file");
}

/* 
	build dbstab with data from stbl, eliminate uninteresting data
*/
static void
setdbstab()
{
	LDFILE	*ldptr = NULL;
	char *np;
	SYMR *sp;
	struct dbstbl *db;
	int stop = 0;
	int count = 0;
	int i;

	if((ldptr = ldopen(namelist, ldptr)) == NULL)
		error("cannot open namelist file");

	db = &dbstab[0];
	for(sp = stbl, i=0; i<symcnt; sp++, i++) {
		if(db >= &dbstab[SYMMAX]) {
			if (!stop)
				fprintf(stderr,"Symbol table overflow with ");
				fprintf(stderr,"%d entries left!\n",symcnt-i);
				stop =1;
		}
		if (i < symMax &&
		    sp->st != stStatic &&
		    sp->st != stStaticProc)
		    /* statics allowed, throw away other locals */
		    continue;
		else if (sp->sc == scUndefined || sp->sc == scSUndefined)
		    /* we don't want undefineds */
		    continue;

		if (sp->value == 0)
			continue;
		if (stop) {
			/* out of space, count how many missing entries */
			count++;
			continue;
		}

		/* get name, put into nametab[] */
		np = (char *)ldgetname(ldptr, sp);
		if (np == (char *) NULL) {
			continue;
		}
		/* setup dbstab */
		db->addr = sp->value;
		db->noffst = nameoffst;
		if ( (nameoffst + strlen(np)) >= namesize) {
			fprintf(stderr,"Nametab overflow with %d entries left!\n",symcnt-i);
			break;
		}
		while (*np != '\0')
			nametab[nameoffst++] = *np++;
		nametab[nameoffst++] = '\0';
		db++;
	}
	if (stop)
		fprintf(stderr,"Missing %d symbol entries\n",count);
	/* sort in ascending addr */
	dbnum = db - dbstab;
	qsort(dbstab, dbnum, sizeof (struct dbstbl), compar);
	
	if (Verbose) {
		printf("First symbol %s @ 0x%x Last %s @ 0x%x\n",
			&nametab[dbstab[0].noffst], dbstab[0].addr,
			&nametab[dbstab[dbnum-1].noffst], dbstab[dbnum-1].addr);
	}
	/* swizzle words in dbstab if target is opposite endian */
	if (LDSWAP(ldptr))
		for (db = dbstab; db < &dbstab[dbnum]; db++) {
			db->addr = swap_word(db->addr);
			db->noffst = swap_word(db->noffst);
		}

	if(ldclose(ldptr) != SUCCESS)
		error("cannot ldclose namelist file");
}
		

static int
wrdbstab()
{
	FILE *f;
	char *symFile;

	if ((symFile = (char *)malloc(sysconf(_SC_ARG_MAX))) == NULL) {
		fprintf(stderr, "malloc failed\n");
		return(-1);
	}

	sprintf(symFile, "%s", namelist);
	strcat(symFile, ".sym");
	if ((f = fopen(symFile, "w")) == NULL) {
		fprintf(stderr, "setsym: %s: open error\n", symFile);
		exit(1);
        }

	if (fwrite(&dbstab, sizeof(char), sizeof(dbstab), f) != sizeof(dbstab)){
		fprintf(stderr, "setsym: %s: write error\n", symFile);
		exit(1);
	}
	if (fwrite(&nametab, sizeof(char), namesize, f) != namesize) {
		fprintf(stderr, "setsym: %s: write error\n", symFile);
		exit(1);
	}

	fclose(f);
}