/* $XFree86: xc/programs/Xserver/hw/xfree86/loader/hash.c,v 1.24 2003/11/17 22:20:40 dawes Exp $ */ /* * * Copyright 1995-1998 by Metro Link, Inc. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Metro Link, Inc. not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Metro Link, Inc. makes no * representations about the suitability of this software for any purpose. * It is provided "as is" without express or implied warranty. * * METRO LINK, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL METRO LINK, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "os.h" #include "Xos.h" #undef abs #include #include "sym.h" #include "loader.h" #include "hash.h" #if defined(Lynx) #define MAXINT 32000 #else #include #undef MAXINT #define MAXINT INT_MAX #endif /* Prototypes for static functions. */ static unsigned int hashFunc(const char *); static itemPtr LoaderHashFindNearest(unsigned long); static itemPtr LoaderhashTable[HASHSIZE]; #ifdef DEBUG static int hashhits[HASHSIZE]; void DumpHashHits(void) { int i; int depth = 0; int dev = 0; for (i = 0; i < HASHSIZE; i++) { ErrorF("hashhits[%d]=%d\n", i, hashhits[i]); depth += hashhits[i]; } depth /= HASHSIZE; ErrorF("Average hash depth=%d\n", depth); for (i = 0; i < HASHSIZE; i++) { if (hashhits[i] < depth) dev += depth - hashhits[i]; else dev += hashhits[i] - depth; } dev /= HASHSIZE; ErrorF("Average hash deviation=%d\n", dev); } #endif static unsigned int hashFunc(const char *string) { int i = 0; while (i < 10 && string[i]) i++; if (i < 5) { #ifdef DEBUG hashhits[i]++; #endif return i; } /* * Original has function #define HASH ((string[ i-4 ] * string[i-3] + string[i-2] ) & (HASHSIZE-1)) */ #define HASH ((string[i-5] * string[ i-4 ] + string[i-3] * string[i-2] ) & (HASHSIZE-1)) #ifdef DEBUG hashhits[HASH]++; #endif return HASH; } void LoaderHashAdd(itemPtr entry) { int bucket = hashFunc(entry->name); itemPtr oentry; if ((oentry = LoaderHashFind(entry->name)) != NULL) LoaderDuplicateSymbol(entry->name, oentry->handle); entry->next = LoaderhashTable[bucket]; LoaderhashTable[bucket] = entry; return; } void LoaderAddSymbols(int handle, int module, LOOKUP *list) { LOOKUP *l = list, *exports = NULL; itemPtr i, exportsItem = NULL; char *modname; if (!list) return; /* * First look for a symbol called ExportedSymbols. If it exists, * only export the symbols that are listed in that array. Otherwise * export all of the external symbols. */ modname = _LoaderHandleToCanonicalName(handle); if (modname) { char *exportname; exportname = xf86loadermalloc(strlen("ExportedSymbols") + strlen(modname) + 1); if (exportname) { sprintf(exportname, "%sExportedSymbols", modname); while (l->symName) { if (strcmp(l->symName, exportname) == 0) { exports = l; ErrorF("LoaderAddSymbols: %s: %s found\n", modname, exportname); break; } l++; } xf86loaderfree(exportname); } } /* * Allocate the exports list item first. */ if (exports) { exportsItem = xf86loadermalloc(sizeof(itemRec)); exportsItem->name = exports->symName; exportsItem->address = (char *)exports->offset; exportsItem->handle = handle; exportsItem->module = module; exportsItem->exports = NULL; LoaderHashAdd(exportsItem); } /* * Visit every symbol in the lookup table, tagging it with the * reference to the export list, if present. */ l = list; while (l->symName) { if (l != exports) { i = xf86loadermalloc(sizeof(itemRec)); i->name = l->symName; i->address = (char *)l->offset; i->handle = handle; i->module = module; i->exports = exportsItem; LoaderHashAdd(i); } l++; } } itemPtr LoaderHashDelete(const char *string) { int bucket = hashFunc(string); itemPtr entry; itemPtr *entry2; entry = LoaderhashTable[bucket]; entry2 = &(LoaderhashTable[bucket]); while (entry) { if (!strcmp(entry->name, string)) { *entry2 = entry->next; xf86loaderfree(entry->name); xf86loaderfree(entry); return 0; } entry2 = &(entry->next); entry = entry->next; } return 0; } itemPtr LoaderHashFind(const char *string) { int bucket = hashFunc(string); itemPtr entry; entry = LoaderhashTable[bucket]; while (entry) { if (!strcmp(entry->name, string)) { return entry; } entry = entry->next; } return 0; } static itemPtr LoaderHashFindNearest(unsigned long address) { int i; itemPtr entry, best_entry = 0; long best_difference = MAXINT; for (i = 0; i < HASHSIZE; i++) { entry = LoaderhashTable[i]; while (entry) { long difference = (long)address - (long)entry->address; if (difference >= 0) { if (best_entry) { if (difference < best_difference) { best_entry = entry; best_difference = difference; } } else { best_entry = entry; best_difference = difference; } } entry = entry->next; } } return best_entry; } void LoaderPrintSymbol(unsigned long address) { itemPtr entry; entry = LoaderHashFindNearest(address); if (entry) { const char *module, *section; #if defined(__alpha__) || defined(__ia64__) ErrorF("0x%016lx %s+%lx\n", (unsigned long)entry->address, entry->name, address - (unsigned long)entry->address); #else ErrorF("0x%lx %s+%lx\n", (unsigned long)entry->address, entry->name, address - (unsigned long)entry->address); #endif if (_LoaderAddressToSection(address, &module, §ion)) ErrorF("\tModule \"%s\"\n\tSection \"%s\"\n", module, section); } else { ErrorF("(null)\n"); } } void LoaderPrintItem(itemPtr pItem) { if (pItem) { const char *module, *section; #if defined(__alpha__) || defined(__ia64__) ErrorF("0x%016lx %s\n", (unsigned long)pItem->address, pItem->name); #else ErrorF("0x%lx %s\n", (unsigned long)pItem->address, pItem->name); #endif if (_LoaderAddressToSection((unsigned long)pItem->address, &module, §ion)) ErrorF("\tModule \"%s\"\n\tSection \"%s\"\n", module, section); } else ErrorF("(null)\n"); } void LoaderPrintAddress(const char *symbol) { itemPtr entry; entry = LoaderHashFind(symbol); LoaderPrintItem(entry); } void LoaderHashTraverse(void *card, int (*fnp)(void *, itemPtr)) { int i; itemPtr entry, last_entry = 0; for (i = 0; i < HASHSIZE; i++) { last_entry = 0; entry = LoaderhashTable[i]; while (entry) { if ((*fnp) (card, entry)) { if (last_entry) { last_entry->next = entry->next; xf86loaderfree(entry->name); xf86loaderfree(entry); entry = last_entry->next; } else { LoaderhashTable[i] = entry->next; xf86loaderfree(entry->name); xf86loaderfree(entry); entry = LoaderhashTable[i]; } } else { last_entry = entry; entry = entry->next; } } } } void LoaderDumpSymbols() { itemPtr entry; int j; for (j = 0; j < HASHSIZE; j++) { entry = LoaderhashTable[j]; while (entry) { LoaderPrintItem(entry); entry = entry->next; } } }