From d3730f1c68018b66f2f27ee8b6226a6f36c084d5 Mon Sep 17 00:00:00 2001 From: cube Date: Mon, 17 Nov 2003 10:16:18 +0000 Subject: [PATCH] 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@. --- sys/ddb/db_sym.c | 14 +++++----- sys/kern/kern_ksyms.c | 59 +++++++++++++++++++++++++++++++++---------- sys/kern/kern_lkm.c | 30 ++++++++++++---------- sys/sys/ksyms.h | 7 +++-- 4 files changed, 73 insertions(+), 37 deletions(-) diff --git a/sys/ddb/db_sym.c b/sys/ddb/db_sym.c index 86d5751249fa..207c7e346543 100644 --- a/sys/ddb/db_sym.c +++ b/sys/ddb/db_sym.c @@ -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 -__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); diff --git a/sys/kern/kern_ksyms.c b/sys/kern/kern_ksyms.c index 7f6a04f123e0..cb23d8b63bf0 100644 --- a/sys/kern/kern_ksyms.c +++ b/sys/kern/kern_ksyms.c @@ -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 -__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 */ diff --git a/sys/kern/kern_lkm.c b/sys/kern/kern_lkm.c index 2143c3d27dbf..9189d184179a 100644 --- a/sys/kern/kern_lkm.c +++ b/sys/kern/kern_lkm.c @@ -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 -__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; diff --git a/sys/sys/ksyms.h b/sys/sys/ksyms.h index 41b7d3ce2b50..8e1738646b0b 100644 --- a/sys/sys/ksyms.h +++ b/sys/sys/ksyms.h @@ -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);