Remove useless entries from the symbol table at load.
Add patricia-tree-style lookup code for symbols (for fast lookups).
This commit is contained in:
parent
38b24046a0
commit
4f432cf54f
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: kern_ksyms.c,v 1.7 2003/05/02 09:34:57 ragge Exp $ */
|
||||
/* $NetBSD: kern_ksyms.c,v 1.8 2003/05/07 21:28:16 ragge Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2001, 2003 Anders Magnusson (ragge@ludd.luth.se).
|
||||
* All rights reserved.
|
||||
|
@ -36,7 +36,6 @@
|
|||
|
||||
/*
|
||||
* TODO:
|
||||
* Fix quick-search of symbols. (comes with linker)
|
||||
* Change the ugly way of adding new symbols (comes with linker)
|
||||
* Add kernel locking stuff.
|
||||
* (Ev) add support for poll.
|
||||
|
@ -129,9 +128,136 @@ static CIRCLEQ_HEAD(, symtab) symtab_queue =
|
|||
|
||||
static struct symtab kernel_symtab;
|
||||
|
||||
#define USE_PTREE
|
||||
#ifdef USE_PTREE
|
||||
/*
|
||||
* Patricia-tree-based lookup structure for the in-kernel global symbols.
|
||||
* Based on a design by Mikael Sundstrom, msm@sm.luth.se.
|
||||
*/
|
||||
struct ptree {
|
||||
int16_t bitno;
|
||||
int16_t lr[2];
|
||||
} *symb;
|
||||
static int16_t baseidx;
|
||||
static int treex = 1;
|
||||
|
||||
#define P_BIT(key, bit) ((key[bit >> 3] >> (bit & 7)) & 1)
|
||||
#define STRING(idx) kernel_symtab.sd_symstart[idx].st_name + \
|
||||
kernel_symtab.sd_strstart
|
||||
|
||||
/*
|
||||
* Walk down the tree until a terminal node is found.
|
||||
*/
|
||||
static int
|
||||
symbol_traverse(char *key)
|
||||
{
|
||||
int16_t nb, rbit = baseidx;
|
||||
|
||||
while (rbit > 0) {
|
||||
nb = symb[rbit].bitno;
|
||||
rbit = symb[rbit].lr[P_BIT(key, nb)];
|
||||
}
|
||||
return -rbit;
|
||||
}
|
||||
|
||||
static int
|
||||
ptree_add(char *key, int val)
|
||||
{
|
||||
int idx;
|
||||
int nix, cix, bit, rbit, sb, lastrbit, svbit, ix;
|
||||
char *m, *k;
|
||||
|
||||
if (baseidx == 0) {
|
||||
baseidx = -val;
|
||||
return 0; /* First element */
|
||||
}
|
||||
|
||||
/* Get string to match against */
|
||||
idx = symbol_traverse(key);
|
||||
|
||||
/* Find first mismatching bit */
|
||||
m = STRING(idx);
|
||||
k = key;
|
||||
if (strcmp(m, k) == 0)
|
||||
return 1;
|
||||
|
||||
for (cix = 0; *m && *k && *m == *k; m++, k++, cix += 8)
|
||||
;
|
||||
ix = ffs((int)*m ^ (int)*k) - 1;
|
||||
cix += ix;
|
||||
|
||||
/* Create new node */
|
||||
nix = treex++;
|
||||
bit = P_BIT(key, cix);
|
||||
symb[nix].bitno = cix;
|
||||
symb[nix].lr[bit] = -val;
|
||||
|
||||
/* Find where to insert node */
|
||||
rbit = baseidx;
|
||||
lastrbit = 0;
|
||||
for (;;) {
|
||||
if (rbit < 0)
|
||||
break;
|
||||
sb = symb[rbit].bitno;
|
||||
if (sb > cix)
|
||||
break;
|
||||
if (sb == cix)
|
||||
printf("symb[rbit].bitno == cix!!!\n");
|
||||
lastrbit = rbit;
|
||||
svbit = P_BIT(key, sb);
|
||||
rbit = symb[rbit].lr[svbit];
|
||||
}
|
||||
|
||||
/* Do the actual insertion */
|
||||
if (lastrbit == 0) {
|
||||
/* first element */
|
||||
symb[nix].lr[!bit] = baseidx;
|
||||
baseidx = nix;
|
||||
} else {
|
||||
symb[nix].lr[!bit] = rbit;
|
||||
symb[lastrbit].lr[svbit] = nix;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ptree_find(char *key)
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (baseidx == 0)
|
||||
return 0;
|
||||
idx = symbol_traverse(key);
|
||||
|
||||
if (strcmp(key, STRING(idx)) == 0)
|
||||
return idx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ptree_gen(char *off, struct symtab *tab)
|
||||
{
|
||||
Elf_Sym *sym;
|
||||
int i;
|
||||
|
||||
if (off != NULL)
|
||||
symb = (struct ptree *)ALIGN(off);
|
||||
else
|
||||
symb = malloc((tab->sd_symsize/sizeof(Elf_Sym)) *
|
||||
sizeof(struct ptree), M_DEVBUF, M_WAITOK);
|
||||
symb--; /* sym index won't be 0 */
|
||||
|
||||
sym = tab->sd_symstart;
|
||||
for (i = 1; i < tab->sd_symsize/sizeof(Elf_Sym); i++) {
|
||||
if (ELF_ST_BIND(sym[i].st_info) != STB_GLOBAL)
|
||||
continue;
|
||||
ptree_add(tab->sd_strstart+sym[i].st_name, i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Finds a certain symbol name in a certain symbol table.
|
||||
* XXX - symbol hashing must be rewritten (missing)
|
||||
*/
|
||||
static Elf_Sym *
|
||||
findsym(char *name, struct symtab *table)
|
||||
|
@ -140,6 +266,11 @@ findsym(char *name, struct symtab *table)
|
|||
int i, sz = table->sd_symsize/sizeof(Elf_Sym);
|
||||
char *np;
|
||||
|
||||
#ifdef USE_PTREE
|
||||
if (table == &kernel_symtab && (i = ptree_find(name)) != 0)
|
||||
return &start[i];
|
||||
#endif
|
||||
|
||||
for (i = 0; i < sz; i++) {
|
||||
np = table->sd_strstart + start[i].st_name;
|
||||
if (name[0] == np[0] && name[1] == np[1] &&
|
||||
|
@ -156,6 +287,12 @@ void ksymsattach(int);
|
|||
void
|
||||
ksymsattach(int arg)
|
||||
{
|
||||
|
||||
#ifdef USE_PTREE
|
||||
if (baseidx == 0)
|
||||
ptree_gen(0, &kernel_symtab);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -166,9 +303,11 @@ static void
|
|||
addsymtab(char *name, Elf_Ehdr *ehdr, struct symtab *tab)
|
||||
{
|
||||
caddr_t start = (caddr_t)ehdr;
|
||||
caddr_t send;
|
||||
Elf_Shdr *shdr;
|
||||
Elf_Sym *sym;
|
||||
int i, j;
|
||||
Elf_Sym *sym, *nsym;
|
||||
int i, j, n, g;
|
||||
char *str;
|
||||
|
||||
/* Find the symbol table and the corresponding string table. */
|
||||
shdr = (Elf_Shdr *)(start + ehdr->e_shoff);
|
||||
|
@ -187,21 +326,94 @@ addsymtab(char *name, Elf_Ehdr *ehdr, struct symtab *tab)
|
|||
break;
|
||||
}
|
||||
tab->sd_name = name;
|
||||
send = tab->sd_strstart + tab->sd_strsize;
|
||||
|
||||
/* Change all symbols to be absolute references */
|
||||
sym = (Elf_Sym *)tab->sd_symstart;
|
||||
for (i = 0; i < tab->sd_symsize/sizeof(Elf_Sym); i++) {
|
||||
sym[i].st_shndx = SHN_ABS;
|
||||
if (sym[i].st_name == 0)
|
||||
#ifdef KSYMS_DEBUG
|
||||
printf("start %p sym %p symsz %d str %p strsz %d send %p\n",
|
||||
start, tab->sd_symstart, tab->sd_symsize,
|
||||
tab->sd_strstart, tab->sd_strsize, send);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Pack symbol table by removing all file name references
|
||||
* and overwrite the elf header.
|
||||
*/
|
||||
sym = tab->sd_symstart;
|
||||
nsym = (Elf_Sym *)start;
|
||||
str = tab->sd_strstart;
|
||||
for (g = i = n = 0; i < tab->sd_symsize/sizeof(Elf_Sym); i++) {
|
||||
if (i == 0) {
|
||||
nsym[n++] = sym[i];
|
||||
continue;
|
||||
j = strlen(sym[i].st_name + tab->sd_strstart) + 1;
|
||||
}
|
||||
/*
|
||||
* Remove useless symbols.
|
||||
* Should actually remove all typeless symbols.
|
||||
*/
|
||||
if (sym[i].st_name == 0)
|
||||
continue; /* Skip nameless entries */
|
||||
if (ELF_ST_TYPE(sym[i].st_info) == STT_FILE)
|
||||
continue; /* Skip filenames */
|
||||
if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE &&
|
||||
sym[i].st_value == 0 &&
|
||||
strcmp(str + sym[i].st_name, "*ABS*") == 0)
|
||||
continue; /* XXX */
|
||||
if (ELF_ST_TYPE(sym[i].st_info) == STT_NOTYPE &&
|
||||
strcmp(str + sym[i].st_name, "gcc2_compiled.") == 0)
|
||||
continue; /* XXX */
|
||||
|
||||
#ifndef DDB
|
||||
/* Only need global symbols */
|
||||
if (ELF_ST_BIND(sym[i].st_info) != STB_GLOBAL)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* Save symbol. Set it as an absolute offset */
|
||||
nsym[n] = sym[i];
|
||||
nsym[n].st_shndx = SHN_ABS;
|
||||
if (ELF_ST_BIND(nsym[n].st_info) == STB_GLOBAL)
|
||||
g++;
|
||||
#if NKSYMS
|
||||
j = strlen(nsym[n].st_name + tab->sd_strstart) + 1;
|
||||
if (j > ksyms_maxlen)
|
||||
ksyms_maxlen = j;
|
||||
#endif
|
||||
n++;
|
||||
|
||||
}
|
||||
tab->sd_symstart = nsym;
|
||||
tab->sd_symsize = n * sizeof(Elf_Sym);
|
||||
|
||||
#ifdef notyet
|
||||
/*
|
||||
* Remove left-over strings.
|
||||
*/
|
||||
sym = tab->sd_symstart;
|
||||
str = (caddr_t)tab->sd_symstart + tab->sd_symsize;
|
||||
str[0] = 0;
|
||||
n = 1;
|
||||
for (i = 1; i < tab->sd_symsize/sizeof(Elf_Sym); i++) {
|
||||
strcpy(str+n, tab->sd_strstart + sym[i].st_name);
|
||||
sym[i].st_name = n;
|
||||
n += strlen(str+n) + 1;
|
||||
}
|
||||
tab->sd_strstart = str;
|
||||
tab->sd_strsize = n;
|
||||
|
||||
#ifdef KSYMS_DEBUG
|
||||
printf("str %p strsz %d send %p\n", str, n, send);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
CIRCLEQ_INSERT_HEAD(&symtab_queue, tab, sd_queue);
|
||||
|
||||
#ifdef notyet
|
||||
#ifdef USE_PTREE
|
||||
/* Try to use the freed space, if possible */
|
||||
if (send - str - n > g * sizeof(struct ptree))
|
||||
ptree_gen(str + n, tab);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -247,20 +459,24 @@ ksyms_init(int symsize, void *start, void *end)
|
|||
return; /* nothing to do */
|
||||
}
|
||||
|
||||
#if NKSYMS
|
||||
/* Loaded header will be scratched in addsymtab */
|
||||
ksyms_hdr_init(start);
|
||||
#endif
|
||||
|
||||
addsymtab("netbsd", ehdr, &kernel_symtab);
|
||||
|
||||
#if NKSYMS
|
||||
ksyms_sizes_calc();
|
||||
#endif
|
||||
|
||||
ksymsinited = 1;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("Loaded initial symtab at %p, strtab at %p, # entries %ld\n",
|
||||
kernel_symtab.sd_symstart, kernel_symtab.sd_strstart,
|
||||
(long)kernel_symtab.sd_symsize/sizeof(Elf_Sym));
|
||||
#endif
|
||||
|
||||
#if NKSYMS
|
||||
ksyms_hdr_init(start);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -284,7 +500,6 @@ ksyms_getval(char *mod, char *sym, unsigned long *val, int type)
|
|||
printf("ksyms_getval: mod %s sym %s valp %p\n", mod, sym, val);
|
||||
#endif
|
||||
|
||||
/* XXX search order XXX */
|
||||
CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
|
||||
if (mod && strcmp(st->sd_name, mod))
|
||||
continue;
|
||||
|
|
Loading…
Reference in New Issue