xserver-multidpi/hw/xfree86/loader/hash.c

357 lines
7.9 KiB
C

/* $XdotOrg: xc/programs/Xserver/hw/xfree86/loader/hash.c,v 1.3 2005/04/20 12:25:34 daniels Exp $ */
/* $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.
*/
#ifdef HAVE_XORG_CONFIG_H
#include <xorg-config.h>
#endif
#include "os.h"
#include <X11/Xos.h>
#undef abs
#include <stdlib.h>
#include "sym.h"
#include "loader.h"
#include "hash.h"
#if defined(Lynx)
#define MAXINT 32000
#else
#include <limits.h>
#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 <name>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, &section))
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, &section))
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;
}
}
}