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.