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.