365 lines
7.9 KiB
C
365 lines
7.9 KiB
C
/* $XFree86: xc/programs/Xserver/hw/xfree86/loader/hash.c,v 1.19 2001/07/25 15:05:07 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 <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(
|
|
#if NeedFunctionPrototypes
|
|
unsigned long
|
|
#endif
|
|
);
|
|
|
|
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(string)
|
|
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( entry )
|
|
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(handle, module, list)
|
|
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++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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(string)
|
|
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(string)
|
|
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(address)
|
|
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(address)
|
|
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", entry->address, entry->name,
|
|
address - (unsigned long) entry->address);
|
|
#else
|
|
ErrorF("0x%x %s+%x\n", 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", pItem->address, pItem->name);
|
|
#else
|
|
ErrorF("0x%lx %s\n", 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(symbol)
|
|
const char *symbol;
|
|
{
|
|
itemPtr entry;
|
|
entry = LoaderHashFind(symbol);
|
|
LoaderPrintItem(entry);
|
|
}
|
|
|
|
void
|
|
LoaderHashTraverse(card, fnp)
|
|
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;
|
|
}
|
|
}
|
|
|
|
}
|