o Fix a bug in ksyms that changed the real meaning of st_name entries for

symbols, and made it impossible for the kernel to use that value, and
  correctly find symbols from LKMs.
o Allow LKM users to use DDB to debug the entry function of a LKM by
  loading the symbol table with the temporary name /lkmtemp/ before calling
  it, and then renaming it once we know the module name.

Approved by ragge@.
This commit is contained in:
cube 2003-11-17 10:16:18 +00:00
parent 0714799990
commit d3730f1c68
4 changed files with 73 additions and 37 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: db_sym.c,v 1.44 2003/10/25 08:54:01 christos Exp $ */
/* $NetBSD: db_sym.c,v 1.45 2003/11/17 10:16:18 cube Exp $ */
/*
* Mach Operating System
@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: db_sym.c,v 1.44 2003/10/25 08:54:01 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: db_sym.c,v 1.45 2003/11/17 10:16:18 cube Exp $");
#include "opt_ddbparam.h"
@ -109,12 +109,12 @@ db_value_of_name(char *name, db_expr_t *valuep)
}
#endif
db_symsplit(name, &mod, &sym);
if (ksyms_getval(mod, sym, &uval, KSYMS_EXTERN) == 0) {
if (ksyms_getval_from_kernel(mod, sym, &uval, KSYMS_EXTERN) == 0) {
val = (long) uval;
*valuep = (db_expr_t)val;
return TRUE;
}
if (ksyms_getval(mod, sym, &uval, KSYMS_ANY) == 0) {
if (ksyms_getval_from_kernel(mod, sym, &uval, KSYMS_ANY) == 0) {
val = (long) uval;
*valuep = (db_expr_t)val;
return TRUE;
@ -229,7 +229,7 @@ db_search_symbol(db_addr_t val, db_strategy_t strategy, db_expr_t *offp)
#endif
if (ksyms_getname(&mod, &sym, (vaddr_t)val, strategy) == 0) {
(void)ksyms_getval(mod, sym, &naddr, KSYMS_ANY);
(void)ksyms_getval_from_kernel(mod, sym, &naddr, KSYMS_ANY);
diff = val - (db_addr_t)naddr;
ret = (db_sym_t)naddr;
} else
@ -337,7 +337,7 @@ db_symstr(char *buf, size_t buflen, db_expr_t off, db_strategy_t strategy)
#endif
if (ksyms_getname(&mod, &name, (vaddr_t)off,
strategy|KSYMS_CLOSEST) == 0) {
(void)ksyms_getval(mod, name, &val, KSYMS_ANY);
(void)ksyms_getval_from_kernel(mod, name, &val, KSYMS_ANY);
if (((off - val) < db_maxoff) && val) {
sprintf(buf, "%s:%s", mod, name);
if (off - val) {
@ -407,7 +407,7 @@ db_printsym(db_expr_t off, db_strategy_t strategy,
#endif
if (ksyms_getname(&mod, &name, (vaddr_t)off,
strategy|KSYMS_CLOSEST) == 0) {
(void)ksyms_getval(mod, name, &uval, KSYMS_ANY);
(void)ksyms_getval_from_kernel(mod, name, &uval, KSYMS_ANY);
val = (long) uval;
if (((off - val) < db_maxoff) && val) {
(*pr)("%s:%s", mod, name);

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_ksyms.c,v 1.16 2003/11/06 18:22:01 ragge Exp $ */
/* $NetBSD: kern_ksyms.c,v 1.17 2003/11/17 10:16:18 cube Exp $ */
/*
* Copyright (c) 2001, 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
@ -46,7 +46,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.16 2003/11/06 18:22:01 ragge Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_ksyms.c,v 1.17 2003/11/17 10:16:18 cube Exp $");
#ifdef _KERNEL
#include "opt_ddb.h"
@ -121,6 +121,7 @@ struct symtab {
const char *sd_name; /* Name of this table */
Elf_Sym *sd_symstart; /* Address of symbol table */
caddr_t sd_strstart; /* Adderss of corresponding string table */
int sd_usroffset; /* Real address for userspace */
int sd_symsize; /* Size in bytes of symbol table */
int sd_strsize; /* Size of string table */
int *sd_symnmoff; /* Used when calculating the name offset */
@ -268,11 +269,12 @@ ptree_gen(char *off, struct symtab *tab)
* Finds a certain symbol name in a certain symbol table.
*/
static Elf_Sym *
findsym(char *name, struct symtab *table)
findsym(char *name, struct symtab *table, int userreq)
{
Elf_Sym *start = table->sd_symstart;
int i, sz = table->sd_symsize/sizeof(Elf_Sym);
char *np;
caddr_t realstart = table->sd_strstart - (userreq ? 0 : table->sd_usroffset);
#ifdef USE_PTREE
if (table == &kernel_symtab && (i = ptree_find(name)) != 0)
@ -280,7 +282,7 @@ findsym(char *name, struct symtab *table)
#endif
for (i = 0; i < sz; i++) {
np = table->sd_strstart + start[i].st_name;
np = realstart + start[i].st_name;
if (name[0] == np[0] && name[1] == np[1] &&
strcmp(name, np) == 0)
return &start[i];
@ -495,7 +497,7 @@ ksyms_init(int symsize, void *start, void *end)
* Returns 0 if success or ENOENT if no such entry.
*/
int
ksyms_getval(const char *mod, char *sym, unsigned long *val, int type)
ksyms_getval(const char *mod, char *sym, unsigned long *val, int type, int userreq)
{
struct symtab *st;
Elf_Sym *es;
@ -511,7 +513,7 @@ ksyms_getval(const char *mod, char *sym, unsigned long *val, int type)
CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
if (mod && strcmp(st->sd_name, mod))
continue;
if ((es = findsym(sym, st)) == NULL)
if ((es = findsym(sym, st, userreq)) == NULL)
continue;
/* Skip if bad binding */
@ -563,7 +565,7 @@ ksyms_getname(const char **mod, char **sym, vaddr_t v, int f)
laddr = les->st_value;
es = les;
lmod = st->sd_name;
stable = st->sd_strstart;
stable = st->sd_strstart - st->sd_usroffset;
}
}
}
@ -593,10 +595,11 @@ ksyms_sizes_calc(void)
for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++)
st->sd_symstart[i].st_name =
strsz + st->sd_symnmoff[i];
st->sd_usroffset = strsz;
}
symsz += st->sd_symsize;
strsz += st->sd_strsize;
}
}
}
#endif
@ -693,7 +696,7 @@ ksyms_addsymtab(const char *mod, void *symstart, vsize_t symsize,
continue;
/* Check if the symbol exists */
if (ksyms_getval(NULL, strstart + sym[i].st_name,
if (ksyms_getval_from_kernel(NULL, strstart + sym[i].st_name,
&rval, KSYMS_EXTERN) == 0) {
/* Check (and complain) about differing values */
if (sym[i].st_value != rval) {
@ -776,6 +779,31 @@ ksyms_delsymtab(const char *mod)
return 0;
}
int
ksyms_rensymtab(const char *old, const char *new)
{
struct symtab *st, *oldst = NULL;
char *newstr;
CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
if (strcmp(old, st->sd_name) == 0)
oldst = st;
if (strcmp(new, st->sd_name) == 0)
return (EEXIST);
}
if (oldst == NULL)
return (ENOENT);
newstr = malloc(strlen(new)+1, M_DEVBUF, M_WAITOK);
if (!newstr)
return (ENOMEM);
strcpy(newstr, new);
free((char *)oldst->sd_name, M_DEVBUF);
oldst->sd_name = newstr;
return (0);
}
#ifdef DDB
/*
@ -801,7 +829,8 @@ ksyms_sift(char *mod, char *sym, int mode)
Elf_Sym *les = st->sd_symstart + i;
char c;
if (strstr(sb + les->st_name, sym) == NULL)
if (strstr(sb + les->st_name - st->sd_usroffset, sym)
== NULL)
continue;
if (mode == 'F') {
@ -822,9 +851,11 @@ ksyms_sift(char *mod, char *sym, int mode)
c = ' ';
break;
}
db_printf("%s%c ", sb + les->st_name, c);
db_printf("%s%c ", sb + les->st_name -
st->sd_usroffset, c);
} else
db_printf("%s ", sb + les->st_name);
db_printf("%s ", sb + les->st_name -
st->sd_usroffset);
}
}
return ENOENT;
@ -1033,7 +1064,7 @@ ksymsioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
*/
if ((error = copyinstr(kg->kg_name, str, ksyms_maxlen, NULL)))
break;
if ((error = ksyms_getval(NULL, str, &val, KSYMS_EXTERN)))
if ((error = ksyms_getval_from_userland(NULL, str, &val, KSYMS_EXTERN)))
break;
error = copyout(&val, kg->kg_value, sizeof(long));
break;
@ -1046,7 +1077,7 @@ ksymsioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
if ((error = copyinstr(kg->kg_name, str, ksyms_maxlen, NULL)))
break;
CIRCLEQ_FOREACH(st, &symtab_queue, sd_queue) {
if ((sym = findsym(str, st)) == NULL)
if ((sym = findsym(str, st, 1)) == NULL) /* from userland */
continue;
/* Skip if bad binding */

View File

@ -1,4 +1,4 @@
/* $NetBSD: kern_lkm.c,v 1.69 2003/11/01 07:07:31 christos Exp $ */
/* $NetBSD: kern_lkm.c,v 1.70 2003/11/17 10:16:18 cube Exp $ */
/*
* Copyright (c) 1994 Christopher G. Demetriou
@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kern_lkm.c,v 1.69 2003/11/01 07:07:31 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: kern_lkm.c,v 1.70 2003/11/17 10:16:18 cube Exp $");
#include "opt_ddb.h"
#include "opt_malloclog.h"
@ -413,11 +413,25 @@ lkmioctl(dev, cmd, data, flag, p)
memset((caddr_t)curp->area + curp->offset, 0,
curp->size - curp->offset);
if (curp->syms && curp->sym_offset >= curp->sym_size) {
error = ksyms_addsymtab("/lkmtemp/",
(char *)curp->syms, curp->sym_symsize,
(char *)curp->syms + curp->sym_symsize,
curp->sym_size - curp->sym_symsize);
if (error)
break;
#ifdef DEBUG
if (lkmdebug & LKMDB_INFO)
printf( "DDB symbols added!\n" );
#endif
}
curp->entry = (int (*) __P((struct lkm_table *, int, int)))
(*((long *) (data)));
/* call entry(load)... (assigns "private" portion) */
error = (*(curp->entry))(curp, LKM_E_LOAD, LKM_VERSION);
(void)ksyms_rensymtab("/lkmtemp/", curp->private.lkm_any->lkm_name);
if (error) {
/*
* Module may refuse loading or may have a
@ -439,18 +453,6 @@ lkmioctl(dev, cmd, data, flag, p)
if (lkmdebug & LKMDB_INFO)
printf("LKM: LMREADY\n");
#endif /* DEBUG */
if (curp->syms && curp->sym_offset >= curp->sym_size) {
error = ksyms_addsymtab(curp->private.lkm_any->lkm_name,
(char *)curp->syms, curp->sym_symsize,
(char *)curp->syms + curp->sym_symsize,
curp->sym_size - curp->sym_symsize);
if (error)
break;
#ifdef DEBUG
if (lkmdebug & LKMDB_INFO)
printf( "DDB symbols added!\n" );
#endif
}
lkm_state = LKMS_IDLE;
break;

View File

@ -1,4 +1,4 @@
/* $NetBSD: ksyms.h,v 1.7 2003/07/08 06:32:15 itojun Exp $ */
/* $NetBSD: ksyms.h,v 1.8 2003/11/17 10:16:18 cube Exp $ */
/*
* Copyright (c) 2001, 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
@ -60,9 +60,12 @@ struct ksyms_gsymbol {
* Prototypes
*/
int ksyms_getname(const char **, char **, vaddr_t, int);
int ksyms_getval(const char *, char *, unsigned long *, int);
int ksyms_getval(const char *, char *, unsigned long *, int, int);
#define ksyms_getval_from_kernel(a,b,c,d) ksyms_getval(a,b,c,d,0)
#define ksyms_getval_from_userland(a,b,c,d) ksyms_getval(a,b,c,d,1)
int ksyms_addsymtab(const char *, void *, vsize_t, char *, vsize_t);
int ksyms_delsymtab(const char *);
int ksyms_rensymtab(const char *, const char*);
void ksyms_init(int, void *, void *);
#ifdef DDB
int ksyms_sift(char *, char *, int);