Subject: kern/21526: Bugs in ksyms
To: None <gnats-bugs@gnats.netbsd.org>
From: Quentin Garnier <cube@cubidou.net>
List: netbsd-bugs
Date: 05/11/2003 02:59:03
>Number: 21526
>Category: kern
>Synopsis: Bugs in ksyms
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun May 11 01:08:00 UTC 2003
>Closed-Date:
>Last-Modified:
>Originator: Quentin Garnier
>Release: NetBSD 1.6S
>Organization:
Quentin Garnier - cube@cubidou.net
"Feels like I'm fiddling while Rome is burning down.
Should I lay my fiddle down and take a rifle from the ground ?"
Leigh Nash/Sixpence None The Richer, Paralyzed, Divine Discontents, 2002.
>Environment:
NetBSD 1.6S from today (well, before Jason's bump).
>Description:
While working on a LKM, I found two bugs in ksyms:
o Resolution of symbols from the LKM failed, possibly with a
segfault. This only happens when code is compiled for
/dev/ksyms support. After loading a symbol table,
ksyms_addsymtab() calls ksyms_sizes_calc() to adapt st_name
fields in the symbol table so that /dev/ksyms can present a
single STRTAB section to userland. ksyms_sizes_calc() adds
the necessary offset to each st_name value to do so, which
breaks the real meaning of the st_name field.
o Symbols are not loaded into the kernel symbol table until
the entry function of the LKM returned successfully. This is
because it is up to the LKM to set its name in the lkm_table
struct. Then symbols are added, the name of the table being
the name of the module. This is quite annoying since it makes
very difficult to debug the entry function of the LKM.
>How-To-Repeat:
Load a LKM, enter DDB and try resolving its symbols, with 'print'
or 'sifting'.
>Fix:
The very first hunk (one-liner) fixes the first bug. Note that it
breaks the meaning of st->sd_strstart inside the kernel, but as
long as it is always used along with the st_name field of a
symbol, it is harmless.
The rest adds code to allow access to the symbols of the LKM
within DDB while the entry function of the LKM runs (well, panics).
It simply loads the table with a generic name, and then rename it
to its final name.
Index: kern/kern_ksyms.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_ksyms.c,v
retrieving revision 1.7
diff -u -r1.7 kern_ksyms.c
--- kern/kern_ksyms.c 2003/05/02 09:34:57 1.7
+++ kern/kern_ksyms.c 2003/05/11 00:37:47
@@ -369,10 +369,11 @@
for (i = 0; i < st->sd_symsize/sizeof(Elf_Sym); i++)
st->sd_symstart[i].st_name =
strsz + st->sd_symnmoff[i];
+ st->sd_strstart -= strsz;
}
symsz += st->sd_symsize;
strsz += st->sd_strsize;
- }
+ }
}
#endif
@@ -547,6 +548,31 @@
ksyms_sizes_calc();
#endif
return 0;
+}
+
+int
+ksyms_rensymtab(char *old, 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(oldst->sd_name, M_DEVBUF);
+ oldst->sd_name = newstr;
+
+ return (0);
}
#ifdef DDB
Index: kern/kern_lkm.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_lkm.c,v
retrieving revision 1.65
diff -u -r1.65 kern_lkm.c
--- kern/kern_lkm.c 2003/04/24 20:09:43 1.65
+++ kern/kern_lkm.c 2003/05/11 00:37:48
@@ -410,11 +410,25 @@
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, curp->ver);
+ (void)ksyms_rensymtab("/lkmtemp/", curp->private.lkm_any->lkm_name);
if (error) {
/*
* Module may refuse loading or may have a
@@ -436,18 +450,6 @@
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;
Index: sys/ksyms.h
===================================================================
RCS file: /cvsroot/src/sys/sys/ksyms.h,v
retrieving revision 1.4
diff -u -r1.4 ksyms.h
--- sys/ksyms.h 2003/05/01 20:46:20 1.4
+++ sys/ksyms.h 2003/05/11 00:37:48
@@ -63,6 +63,7 @@
int ksyms_getval(char *, char *, unsigned long *, int);
int ksyms_addsymtab(char *, void *, vsize_t, char *, vsize_t);
int ksyms_delsymtab(char *);
+int ksyms_rensymtab(char *, char*);
void ksyms_init(int, void *, void *);
#ifdef DDB
int ksyms_sift(char *mod, char *sym, int mode);
>Release-Note:
>Audit-Trail:
>Unformatted: