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 assumed 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"
/* $Log: symtab.c,v $
* Revision 1.5 94/08/22 22:32:07 ediger
* ditch movmem macro
*
* Revision 1.4 94/05/30 23:06:38 ediger
* some "readability" corrections
*
* Revision 1.3 94/01/19 00:12:08 ediger
* bug fixes, reformatting
*
* Revision 1.2 94/01/16 17:17:50 ediger
* ditched phony nlist struct def
*
* Revision 1.1 94/01/16 16:48:35 ediger
* Initial revision
* */
static char rcsident[] = "$Id: symtab.c,v 1.5 94/08/22 22:32:07 ediger Exp Locker: ediger $";
/* 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 */
struct nlist *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 */
struct nlist *
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 struct nlist *
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]->n_sect)
{
unsigned b = t->table[i]->n_value;
if (b > address)
break;
a = b;
}
}
i--;
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.
*/
struct nlist *
firstsymbol(unsigned address)
{
if (address == 0)
{
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).
*/
struct nlist *
findlabel(unsigned address)
{
struct nlist *n;
n = lastsymbol(address);
if (symaddress != address)
return (0);
if (n != NULL)
{
while (n->n_sect == NO_SECT || (n->n_type & N_STAB))
{
if (symoffset)
symoffset--;
else if (!symtab->prev)
return (0);
else
{
symtab = symtab->prev;
symoffset = symtab->size - 1;
}
n = symtab->table[symoffset];
if (n->n_sect)
{
symaddress = n->n_value;
if (symaddress < address)
return (0);
}
}
}
return (n);
}
/* Advance to the next symbol and return it. Return 0 if no more: */
struct nlist *
nextsymbol(void)
{
struct nlist *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->n_sect)
symaddress = n->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(struct nlist *new)
{
struct symtab *t;
int i;
if (new->n_sect)
{
lastsymbol(new->n_value);
symaddress = new->n_value;
}
if (!++symoffset)
symtab->address = symaddress;
if (symtab->size < TABLE_SIZE)
{
memmove(
symtab->table + symoffset + 1,
symtab->table + symoffset,
(symtab->size - symoffset) * sizeof(struct nlist *)
);
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]->n_value;
memmove(
t->table,
symtab->table + symoffset,
(t->size) * sizeof(struct nlist *)
);
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.