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

This is symtab.c in view mode; [Download] [Up]

/*	symtab.c -- Sorted symbol table management for disassembler

	Copyright (C) 1989 by Bill Spitzak.
	See Copyright notice in makefile

	All symbols are stored in the Mach-O format "symbol"
	structure, and the code calling this allocates those structures,
	this just manipulates pointers to them.  This is because most
	of the symbols are in the source file and thus already allocated
	when mapped.

	There are two types of symbols, those with addresses, and those
	without (no address is indicated by a section number of 0).  These
	non-address symbols are assummed to be "bound" to the address symbol
	before them in the table.  Since there can be any number of them
	after a symbol, and they themselves don't contain the address, this
	makes the sorting difficult.

	Since "absolute" symbols are used to mark the mapped locations of
	shared libraries and otherwise used for symbols, they are forced to
	have a section number by the file reader, so they are sorted.
*/

#include "dis.h"

/*	Symbols are sorted with a linked list of these pointer tables.
	Since symbols can be inserted into the middle of a list, a table
	may be split into two so there are blank entries for the new
	symbol to be added.
*/
#define TABLE_SIZE 251	/* note picked to get efficient malloc size */

struct symtab {
	struct symtab *prev;
	struct symtab *next;
	int size;
	int address;		/* address of first symbol in table */
	symbol *table[TABLE_SIZE];
	};

struct symtab initialsymtab;

/*	To make normal symbol operations fast, there is a "current symbol".
	This is always a real symbol, either the one returned by the last
	call, or if that returned zero, the symbol before the position it
	should be in the table (so nextsymbol will return an address after
	the symbol).
	If a non-found symbol is before the first one, it sets an offset of
	-1 into the first table.  This is the only time it is not the address
	of a real symbol.
*/
static struct symtab *symtab = &initialsymtab;	/* which table */
static int symoffset = -1;					/* offset into table */
int symaddress;	/* cached address, for NO_SECT symbols */

symbol *currentsymbol(void)
{
	if (symoffset<0) return(0);
	return(symtab->table[symoffset]);
	}

/*	The current symbol may be pushed/popped, so the location is not
	lost if you use the symbol table in a subroutine.
	Don't forget to fix these stacked references if the tables are
	modified!
*/
#define STACKSIZE 10
static struct symtab *symtabstack[STACKSIZE];
static int offsetstack[STACKSIZE];
static int addressstack[STACKSIZE];
static int stackptr;

void pushsymbol(void)
{	
	if (stackptr>=STACKSIZE) {
		printf("Symbol stack overflow.\n"); exit(1);
		}
	symtabstack[stackptr] = symtab;
	offsetstack[stackptr] = symoffset;
	addressstack[stackptr] = symaddress;
	stackptr++;
	}

void popsymbol(void)
{
	if (!stackptr) {
		printf("Symbol stack underflow.\n"); exit(1);
		}
	stackptr--;
	symtab = symtabstack[stackptr];
	symoffset = offsetstack[stackptr];
	symaddress = addressstack[stackptr];
	}

/*	All table lookups are based on this procedure, which returns a
	pointer to the last symbol, including NO_SECT (no address) ones
	before or equal to a certain address.  This is thus a pointer
	to the symbol before where a new symbol at a certain address
	should be added.
*/
static symbol *lastsymbol(unsigned address)
{
	struct symtab *t;
	int i; unsigned a;
	t = symtab; i = symoffset; a = symaddress;
	while (t->next && t->next->address <= address) {
		t = t->next;
		i = 0; a = t->address;
		}
	if (a > address) {
		i = 0;
		while ((a=t->address) > address) {
			if (!t->prev) {i = -1; break;}
			t = t->prev;
			}
		}
	/* gah! linear search: */
	while (++i < t->size) {
		if (t->table[i]->section) {
			unsigned b = t->table[i]->value;
			if (b > address) break;
			a = b;
			}
		}
	i--;
 RET:symtab = t; symoffset = i; symaddress = a;
	return(i>=0 ?t->table[i] : 0);
	}

/*	Find the first symbol at or after an address.  Returns 0 only if
	the address is after the last symbol.  This is used by disassembly
	printout, to find what symbols need to be printed at a certain
	point.
*/
symbol *firstsymbol(unsigned address)
{
	if (!address) {
		while (symtab->prev) symtab = symtab->prev;
		symaddress = 0;
		symoffset = -1;
		}
	else lastsymbol(address-1);
	return(nextsymbol());
	}

/*	Find the last label for an address.  This only returns N_SECT symbols
	which will print as labels.  It returns the last one if there are
	several (this is usually correct).  If there is none, returns 0 (and
	nextsymbol will return the same thing firstsymbol would).
*/
symbol *findlabel(unsigned address)
{
	symbol *n;
	n = lastsymbol(address);
	if (symaddress != address) return(0);
	if (n) while (!n->section || (n->type&0xe0)) {
		if (symoffset) symoffset--;
		else if (!symtab->prev) return(0);
		else {symtab = symtab->prev; symoffset = symtab->size-1;}
		n = symtab->table[symoffset];
		if (n->section) {
			symaddress = n->value;
			if (symaddress<address) return(0);
			}
		}
	return(n);
	}

/*	Advance to the next symbol and return it.  Return 0 if no more: */
symbol *nextsymbol(void)
{
	symbol *n;
	if (symoffset < symtab->size-1)
		n = symtab->table[++symoffset];
	else if (!symtab->next) return(0);
	else {
		symtab = symtab->next;
		symoffset = 0;
		n = symtab->table[0];
		}
	if (n->section) symaddress = n->value;
	return(n);
	}

/*	Add a new symbol.  If it is a NO_SECT symbol, it is inserted after
	the current one.  If it has an address, it is added after all other
	symbols at that address.
*/
void addsymbol(symbol *new)
{
	struct symtab *t;
	int i;
	if (new->section) {
		lastsymbol(new->value);
		symaddress = new->value;
		}
	if (!++symoffset) symtab->address = symaddress;
	if (symtab->size < TABLE_SIZE) {
		movmem(symtab->table+symoffset,symtab->table+symoffset+1,
			  (symtab->size-symoffset)*sizeof(symbol *));
		symtab->size++;
		for (i=0; i<stackptr; i++) {
			if (symtabstack[i]==symtab && offsetstack[i]>=symoffset)
				offsetstack[i]++;
			}
		}
	else {
		t = malloc(sizeof(struct symtab));
		t->prev = symtab;
		t->next = symtab->next;
		if (t->next) t->next->prev = t;
		symtab->next = t;
		if (symoffset >= TABLE_SIZE) {
			symtab = t;
			t->size = 1;
			t->address = symaddress;
			symoffset = 0;
			}
		else {
			t->size = TABLE_SIZE-symoffset;
			t->address = symtab->table[symoffset]->value;
			movmem(symtab->table+symoffset,t->table,
				  (t->size)*sizeof(symbol *));
			symtab->size = symoffset+1;
			for (i=0; i<stackptr; i++) {
				if (symtabstack[i]==symtab && offsetstack[i]>=symoffset) {
					symtabstack[i] = t;
					offsetstack[i] -= symoffset;
					}
				}
			}
		}
	symtab->table[symoffset] = new;
	}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.