diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-08-29 15:17:39 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-08-29 15:17:39 +0000 |
commit | 29f834d31814d57f1078f9dd8c6c35d25dd95fd4 (patch) | |
tree | 70caf975a80db81260089c09ce9551648670c3a2 | |
parent | ae1e1b8cbcad3467f164ef591e5441a8a7657a75 (diff) |
lkm ddb symbol table loading. done during the middle ages by jtkohl, merged
to modern day sources by rees@umich.edu
-rw-r--r-- | sbin/modload/modload.c | 116 | ||||
-rw-r--r-- | sys/kern/kern_lkm.c | 93 | ||||
-rw-r--r-- | sys/sys/lkm.h | 20 |
3 files changed, 214 insertions, 15 deletions
diff --git a/sbin/modload/modload.c b/sbin/modload/modload.c index 0337fbd1f40..5e7dee9be9e 100644 --- a/sbin/modload/modload.c +++ b/sbin/modload/modload.c @@ -1,4 +1,4 @@ -/* $OpenBSD: modload.c,v 1.7 1996/08/13 17:56:06 deraadt Exp $ */ +/* $OpenBSD: modload.c,v 1.8 1996/08/29 15:17:38 deraadt Exp $ */ /* $NetBSD: modload.c,v 1.13 1995/05/28 05:21:58 jtc Exp $ */ /* @@ -38,6 +38,7 @@ #include <sys/conf.h> #include <sys/mount.h> #include <sys/lkm.h> +#include <sys/stat.h> #include <sys/file.h> #include <sys/wait.h> #include <errno.h> @@ -64,6 +65,7 @@ int debug = 0; int verbose = 0; +int symtab = 1; int quiet = 0; int dounlink = 0; @@ -159,14 +161,18 @@ main(argc, argv) char *modobj; char modout[80], *p; struct exec info_buf; + struct stat stb; u_int modsize; /* XXX */ u_int modentry; /* XXX */ + struct nlist nl, *nlp; + int strtablen, numsyms; struct lmc_loadbuf ldbuf; - int sz, bytesleft; + int sz, bytesleft, old = 0; char buf[MODIOBUF]; + char *symbuf; - while ((c = getopt(argc, argv, "dvuqA:e:p:o:")) != EOF) { + while ((c = getopt(argc, argv, "dvsuqA:e:p:o:")) != EOF) { switch (c) { case 'd': debug = 1; @@ -192,6 +198,9 @@ main(argc, argv) case 'o': out = optarg; break; /* output file */ + case 's': + symtab = 0; + break; case '?': usage(); default: @@ -272,6 +281,12 @@ main(argc, argv) err(3, "read `%s'", out); /* + * stat for filesize to figure out string table size + */ + if (fstat(modfd, &stb) == -1) + err(3, "fstat `%s'", out); + + /* * Close the dummy module -- we have our sizing information. */ close(modfd); @@ -296,8 +311,25 @@ main(argc, argv) resrv.name = modout; /* objname w/o ".o" */ resrv.slot = -1; /* returned */ resrv.addr = 0; /* returned */ - if (ioctl(devfd, LMRESERV, &resrv) == -1) + strtablen = stb.st_size - N_STROFF(info_buf); + if (symtab) { + /* XXX TODO: grovel through symbol table looking + for just the symbol table stuff from the new module, + and skip the stuff from the kernel. */ + resrv.sym_size = info_buf.a_syms + strtablen; + resrv.sym_symsize = info_buf.a_syms; + } else + resrv.sym_size = resrv.sym_symsize = 0; + + if (ioctl(devfd, LMRESERV, &resrv) == -1) { + if (symtab) + warn("not loading symbols: kernel does not support symbol table loading"); + doold: + symtab = 0; + if (ioctl(devfd, LMRESERV_O, &resrv) == -1) err(9, "can't reserve memory"); + old = 1; + } fileopen |= PART_RESRV; /* @@ -345,6 +377,69 @@ main(argc, argv) err(11, "error transferring buffer"); } + if (symtab) { + /* + * Seek to the symbol table to start loading it... + */ + if (lseek(modfd, N_SYMOFF(info_buf), SEEK_SET) == -1) + err(12, "lseek"); + + /* + * Transfer the symbol table entries. First, read them all in, + * then adjust their string table pointers, then + * copy in bulk. Then copy the string table itself. + */ + + symbuf = malloc(info_buf.a_syms); + if (symbuf == 0) + err(13, "malloc"); + + if (read(modfd, symbuf, info_buf.a_syms) != info_buf.a_syms) + err(14, "read"); + numsyms = info_buf.a_syms / sizeof(struct nlist); + for (nlp = (struct nlist *)symbuf; + (char *)nlp < symbuf + info_buf.a_syms; + nlp++) { + register int strx; + strx = nlp->n_un.n_strx; + if (strx != 0) { + /* If a valid name, set the name ptr to point at the + * loaded address for the string in the string table. + */ + if (strx > strtablen) + nlp->n_un.n_name = 0; + else + nlp->n_un.n_name = + (char *)(strx + resrv.sym_addr + info_buf.a_syms); + } + } + /* + * we've fixed the symbol table entries, now load them + */ + for (bytesleft = info_buf.a_syms; + bytesleft > 0; + bytesleft -= sz) { + sz = min(bytesleft, MODIOBUF); + ldbuf.cnt = sz; + ldbuf.data = symbuf; + if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1) + err(11, "error transferring sym buffer"); + symbuf += sz; + } + free(symbuf - info_buf.a_syms); + /* and now read the string table and load it. */ + for (bytesleft = strtablen; + bytesleft > 0; + bytesleft -= sz) { + sz = min(bytesleft, MODIOBUF); + read(modfd, buf, sz); + ldbuf.cnt = sz; + ldbuf.data = buf; + if (ioctl(devfd, LMLOADSYMS, &ldbuf) == -1) + err(11, "error transferring stringtable buffer"); + } + } + /* * Save ourselves before disaster (potentitally) strikes... */ @@ -356,8 +451,19 @@ main(argc, argv) * is maintained on success, or blow everything back to ground * zero on failure. */ - if (ioctl(devfd, LMREADY, &modentry) == -1) + if (ioctl(devfd, LMREADY, &modentry) == -1) { + if (errno == EINVAL && !old) { + if (fileopen & MOD_OPEN) + close(modfd); + /* PART_RESRV is not true since the kernel cleans up + after a failed LMREADY */ + fileopen &= ~(MOD_OPEN|PART_RESRV); + /* try using oldstyle */ + warn("module failed to load using new version; trying old version"); + goto doold; + } else err(14, "error initializing module"); + } /* * Success! diff --git a/sys/kern/kern_lkm.c b/sys/kern/kern_lkm.c index dca32291ee0..7d5d3d105d3 100644 --- a/sys/kern/kern_lkm.c +++ b/sys/kern/kern_lkm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_lkm.c,v 1.6 1996/07/02 06:51:56 niklas Exp $ */ +/* $OpenBSD: kern_lkm.c,v 1.7 1996/08/29 15:17:37 deraadt Exp $ */ /* $NetBSD: kern_lkm.c,v 1.31 1996/03/31 21:40:27 christos Exp $ */ /* @@ -59,6 +59,11 @@ #include <sys/lkm.h> #include <sys/syscall.h> +#ifdef DDB +#include <machine/db_machdep.h> +#include <ddb/db_sym.h> +#endif + #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/vm_kern.h> @@ -69,6 +74,7 @@ #define LKMS_IDLE 0x00 #define LKMS_RESERVED 0x01 #define LKMS_LOADING 0x02 +#define LKMS_LOADING_SYMS 0x03 #define LKMS_LOADED 0x04 #define LKMS_UNLOADING 0x08 @@ -235,6 +241,11 @@ lkmunreserve() if (lkm_state == LKMS_IDLE) return; +#ifdef DDB + if (curp && curp->private.lkm_any && curp->private.lkm_any->lkm_name) + db_del_symbol_table(curp->private.lkm_any->lkm_name); +#endif + /* * Actually unreserve the memory */ @@ -286,7 +297,7 @@ lkmioctl(dev, cmd, data, flag, p) int flag; struct proc *p; { - int error = 0; + int error = 0, i; struct lmc_resrv *resrvp; struct lmc_loadbuf *loadbufp; struct lmc_unload *unloadp; @@ -294,6 +305,7 @@ lkmioctl(dev, cmd, data, flag, p) switch(cmd) { case LMRESERV: /* reserve pages for a module */ + case LMRESERV_O: /* reserve pages for a module */ if (securelevel > 0) return EPERM; @@ -306,6 +318,7 @@ lkmioctl(dev, cmd, data, flag, p) error = ENOMEM; /* no slots available */ break; } + curp->ver = (cmd == LMRESERV) ? LKM_VERSION : LKM_OLDVERSION; resrvp->slot = curp->id; /* return slot */ /* @@ -319,8 +332,22 @@ lkmioctl(dev, cmd, data, flag, p) resrvp->addr = curp->area; /* ret kernel addr */ + if (cmd == LMRESERV && resrvp->sym_size) { + curp->sym_size = resrvp->sym_size; + curp->sym_symsize = resrvp->sym_symsize; + curp->syms = (caddr_t)kmem_alloc(kmem_map, curp->sym_size); + curp->sym_offset = 0; + resrvp->sym_addr = curp->syms; /* ret symbol addr */ + } else { + curp->sym_size = 0; + curp->syms = 0; + curp->sym_offset = 0; + if (cmd == LMRESERV) + resrvp->sym_addr = 0; + } #ifdef DEBUG printf("LKM: LMRESERV (actual = 0x%08lx)\n", curp->area); + printf("LKM: LMRESERV (syms = 0x%08x)\n", curp->syms); printf("LKM: LMRESERV (adjusted = 0x%08lx)\n", trunc_page(curp->area)); #endif /* DEBUG */ @@ -356,7 +383,7 @@ lkmioctl(dev, cmd, data, flag, p) curp->offset, curp->size, loadbufp->cnt); #endif /* DEBUG */ } else { - lkm_state = LKMS_LOADED; + lkm_state = LKMS_LOADING_SYMS; #ifdef DEBUG printf("LKM: LMLOADBUF (loaded)\n"); #endif /* DEBUG */ @@ -364,6 +391,40 @@ lkmioctl(dev, cmd, data, flag, p) curp->offset += loadbufp->cnt; break; + case LMLOADSYMS: /* Copy in; stateful, follows LMRESERV*/ + if ((flag & FWRITE) == 0) /* only allow this if writing */ + return EPERM; + + loadbufp = (struct lmc_loadbuf *)data; + i = loadbufp->cnt; + if ((lkm_state != LKMS_LOADING && + lkm_state != LKMS_LOADING_SYMS) + || i < 0 + || i > MODIOBUF + || i > curp->sym_size - curp->sym_offset) { + error = ENOMEM; + break; + } + + /* copy in buffer full of data*/ + if (error = copyin(loadbufp->data, curp->syms + curp->sym_offset, i)) + break; + + if ((curp->sym_offset + i) < curp->sym_size) { + lkm_state = LKMS_LOADING_SYMS; +#ifdef DEBUG + printf( "LKM: LMLOADSYMS (loading @ %d of %d, i = %d)\n", + curp->sym_offset, curp->sym_size, i); +#endif /* DEBUG*/ + } else { + lkm_state = LKMS_LOADED; +#ifdef DEBUG + printf( "LKM: LMLOADSYMS (loaded)\n"); +#endif /* DEBUG*/ + } + curp->sym_offset += i; + break; + case LMUNRESRV: /* discard reserved pages for a module */ if (securelevel > 0) return EPERM; @@ -388,9 +449,11 @@ lkmioctl(dev, cmd, data, flag, p) case LKMS_LOADED: break; case LKMS_LOADING: - /* The remainder must be bss, so we clear it */ - bzero((caddr_t)curp->area + curp->offset, - curp->size - curp->offset); + case LKMS_LOADING_SYMS: + if (curp->size - curp->offset > 0) + /* The remainder must be bss, so we clear it */ + bzero((caddr_t)curp->area + curp->offset, + curp->size - curp->offset); break; default: @@ -403,8 +466,11 @@ lkmioctl(dev, cmd, data, flag, p) curp->entry = (int (*) __P((struct lkm_table *, int, int))) (*((long *) (data))); +#ifdef DEBUG + printf("LKM: call entrypoint %x\n", curp->entry); +#endif /* call entry(load)... (assigns "private" portion) */ - error = (*(curp->entry))(curp, LKM_E_LOAD, LKM_VERSION); + error = (*(curp->entry))(curp, LKM_E_LOAD, curp->ver); if (error) { /* * Module may refuse loading or may have a @@ -419,6 +485,15 @@ lkmioctl(dev, cmd, data, flag, p) #ifdef DEBUG printf("LKM: LMREADY, id=%d, dev=%d\n", curp->id, curp->private.lkm_any->lkm_offset); #endif /* DEBUG */ +#ifdef DDB + if (curp->syms && curp->sym_offset >= curp->sym_size) { + db_add_symbol_table(curp->syms, + curp->syms + curp->sym_symsize, + curp->private.lkm_any->lkm_name, + curp->syms, NULL); + printf("DDB symbols added: %d bytes\n", curp->sym_symsize); + } +#endif curp->refcnt++; lkm_state = LKMS_IDLE; break; @@ -436,7 +511,7 @@ lkmioctl(dev, cmd, data, flag, p) break; /* error set in lkmlookup */ /* call entry(unload) */ - if ((*(curp->entry))(curp, LKM_E_UNLOAD, LKM_VERSION)) { + if ((*(curp->entry))(curp, LKM_E_UNLOAD, curp->ver)) { error = EBUSY; break; } @@ -905,6 +980,8 @@ lkmdispatch(lkmtp, cmd) { int error = 0; /* default = success */ + printf("lkmdispatch: %x %d\n", lkmtp, cmd); + switch(lkmtp->private.lkm_any->lkm_type) { case LM_SYSCALL: error = _lkm_syscall(lkmtp, cmd); diff --git a/sys/sys/lkm.h b/sys/sys/lkm.h index ab03e250573..090fa254d56 100644 --- a/sys/sys/lkm.h +++ b/sys/sys/lkm.h @@ -1,4 +1,4 @@ -/* $OpenBSD: lkm.h,v 1.4 1996/06/21 17:03:25 mickey Exp $ */ +/* $OpenBSD: lkm.h,v 1.5 1996/08/29 15:17:34 deraadt Exp $ */ /* $NetBSD: lkm.h,v 1.12 1996/02/09 18:25:13 christos Exp $ */ /* @@ -57,6 +57,7 @@ typedef enum loadmod { } MODTYPE; +#define LKM_OLDVERSION 1 /* version of module loader */ #define LKM_VERSION 1 /* version of module loader */ #define MAXLKMNAME 32 @@ -192,6 +193,13 @@ struct lkm_table { int (*entry) __P((struct lkm_table *, int, int));/* entry function */ union lkm_generic private; /* module private data */ + + /* ddb support */ + char *syms; /* ? start of symbol table */ + u_long sym_size; /* ? size of symbol table */ + u_long sym_offset; /* ? offset */ + u_long sym_symsize; /* ? symsize */ + char *sym_addr; /* ? addr */ }; @@ -286,14 +294,16 @@ extern struct lkm_table *lkm_list __P((struct lkm_table *)); /* * IOCTL's recognized by /dev/lkm */ -#define LMRESERV _IOWR('K', 0, struct lmc_resrv) +#define LMRESERV_O _IOWR('K', 0, struct lmc_resrv) #define LMLOADBUF _IOW('K', 1, struct lmc_loadbuf) #define LMUNRESRV _IO('K', 2) #define LMREADY _IOW('K', 3, int) +#define LMRESERV _IOWR('K', 4, struct lmc_resrv) #define LMLOAD _IOW('K', 9, struct lmc_load) #define LMUNLOAD _IOWR('K', 10, struct lmc_unload) #define LMSTAT _IOWR('K', 11, struct lmc_stat) +#define LMLOADSYMS _IOW('K', 12, struct lmc_loadbuf) #define MODIOBUF 512 /* # of bytes at a time to loadbuf */ @@ -310,6 +320,12 @@ struct lmc_resrv { char *name; /* IN: name (must be provided */ int slot; /* OUT: allocated slot (module ID) */ u_long addr; /* OUT: Link-to address */ + /* ddb support */ + char *syms; /* ? start of symbol table */ + u_long sym_size; /* ? size of symbol table */ + u_long sym_offset; /* ? offset */ + u_long sym_symsize; /* ? symsize */ + char *sym_addr; /* ? addr */ }; |