Date: Mon, 9 Jun 2008 02:52:10 GMT From: John Birrell <jb@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 143149 for review Message-ID: <200806090252.m592qAv4048574@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=143149 Change 143149 by jb@freebsd3 on 2008/06/09 02:51:12 Add the linker method for the DTrace kernel modules. Affected files ... .. //depot/projects/dtrace6/src/sys/kern/kern_linker.c#4 edit .. //depot/projects/dtrace6/src/sys/kern/linker_if.m#2 edit .. //depot/projects/dtrace6/src/sys/sys/linker.h#5 edit Differences ... ==== //depot/projects/dtrace6/src/sys/kern/kern_linker.c#4 (text+ko) ==== @@ -68,7 +68,13 @@ linker_file_t linker_kernel_file; -static struct mtx kld_mtx; /* kernel linker mutex */ +static struct mtx kld_mtx; /* kernel linker lock */ + +/* + * Load counter used by clients to determine if a linker file has been + * re-loaded. This counter is incremented for each file load. + */ +static int loadcnt; static linker_class_list_t classes; static linker_file_list_t linker_files; @@ -475,6 +481,22 @@ return (lf); } +int +linker_file_foreach(linker_predicate_t *predicate, void *context) +{ + linker_file_t lf; + int retval = 0; + + mtx_lock(&kld_mtx); + TAILQ_FOREACH(lf, &linker_files, link) { + retval = predicate(lf, context); + if (retval != 0) + break; + } + mtx_unlock(&kld_mtx); + return (retval); +} + linker_file_t linker_make_file(const char *pathname, linker_class_t lc) { @@ -496,6 +518,9 @@ LINKER_GET_NEXT_FILE_ID(lf->id); lf->ndeps = 0; lf->deps = NULL; + lf->loadcnt = ++loadcnt; + lf->sdt_probes = NULL; + lf->sdt_nprobes = 0; STAILQ_INIT(&lf->common); TAILQ_INIT(&lf->modules); mtx_lock(&kld_mtx); @@ -601,6 +626,12 @@ } int +linker_ctf_get(linker_file_t file, linker_ctf_t *lc) +{ + return (LINKER_CTF_GET(file, lc)); +} + +int linker_file_add_dependency(linker_file_t file, linker_file_t dep) { linker_file_t *newdeps; @@ -629,8 +660,17 @@ linker_file_lookup_set(linker_file_t file, const char *name, void *firstp, void *lastp, int *countp) { + return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp)); +} - return (LINKER_LOOKUP_SET(file, name, firstp, lastp, countp)); +/* + * List all functions in a file. + */ +int +linker_file_function_listall(linker_file_t lf, + linker_function_nameval_callback_t callback_func, void *arg) +{ + return (LINKER_EACH_FUNCTION_NAMEVAL(lf, callback_func, arg)); } caddr_t @@ -850,7 +890,13 @@ lf = linker_find_file_by_id(fileid); if (lf) { KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); - if (lf->userrefs == 0) { + + /* Check if there are DTrace probes enabled on this file. */ + if (lf->nenabled > 0) { + printf("kldunload: attempt to unload file that has" + " DTrace probes enabled\n"); + error = EBUSY; + } else if (lf->userrefs == 0) { /* * XXX: maybe LINKER_UNLOAD_FORCE should override ? */ @@ -975,10 +1021,21 @@ int kldstat(struct thread *td, struct kldstat_args *uap) { + struct kld_file_stat stat; linker_file_t lf; - int error = 0; - int namelen, version, version_num; - struct kld_file_stat *stat; + int error, namelen, version, version_num; + + /* + * Check the version of the user's structure. + */ + if ((error = copyin(&uap->stat->version, &version, sizeof(version))) != 0) + return (error); + if (version == sizeof(struct kld_file_stat_1)) + version_num = 1; + else if (version == sizeof(struct kld_file_stat)) + version_num = 2; + else + return (EINVAL); #ifdef MAC error = mac_check_kld_stat(td->td_ucred); @@ -987,57 +1044,33 @@ #endif mtx_lock(&Giant); - lf = linker_find_file_by_id(uap->fileid); if (lf == NULL) { - error = ENOENT; - goto out; + mtx_unlock(&Giant); + return (ENOENT); } - stat = uap->stat; - /* - * Check the version of the user's structure. - */ - if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) - goto out; - if (version == sizeof(struct kld_file_stat_1)) - version_num = 1; - else if (version == sizeof(struct kld_file_stat)) - version_num = 2; - else { - error = EINVAL; - goto out; - } - /* Version 1 fields: */ namelen = strlen(lf->filename) + 1; if (namelen > MAXPATHLEN) namelen = MAXPATHLEN; - if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0) - goto out; - if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0) - goto out; - if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0) - goto out; - if ((error = copyout(&lf->address, &stat->address, - sizeof(caddr_t))) != 0) - goto out; - if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0) - goto out; + bcopy(lf->filename, &stat.name[0], namelen); + stat.refs = lf->refs; + stat.id = lf->id; + stat.address = lf->address; + stat.size = lf->size; if (version_num > 1) { /* Version 2 fields: */ namelen = strlen(lf->pathname) + 1; if (namelen > MAXPATHLEN) namelen = MAXPATHLEN; - if ((error = copyout(lf->pathname, &stat->pathname[0], - namelen)) != 0) - goto out; + bcopy(lf->pathname, &stat.pathname[0], namelen); } + mtx_unlock(&Giant); td->td_retval[0] = 0; -out: - mtx_unlock(&Giant); - return (error); + + return (copyout(&stat, uap->stat, sizeof(struct kld_file_stat))); } /* ==== //depot/projects/dtrace6/src/sys/kern/linker_if.m#2 (text+ko) ==== @@ -23,7 +23,7 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# $FreeBSD: src/sys/kern/linker_if.m,v 1.6 2005/01/06 23:35:39 imp Exp $ +# $FreeBSD: src/sys/kern/linker_if.m,v 1.8 2008/05/23 04:06:49 jb Exp $ # #include <sys/linker.h> @@ -64,6 +64,17 @@ }; # +# Call the callback with each specified function and it's value +# defined in the file. +# Stop and return the error if the callback returns an error. +# +METHOD int each_function_nameval { + linker_file_t file; + linker_function_nameval_callback_t callback; + void* opaque; +}; + +# # Search for a linker set in a file. Return a pointer to the first # entry (which is itself a pointer), and the number of entries. # "stop" points to the entry beyond the last valid entry. @@ -85,6 +96,15 @@ }; # +# Load CTF data if necessary and if there is a .SUNW_ctf section +# in the ELF file, returning info in the linker CTF structure. +# +METHOD int ctf_get { + linker_file_t file; + linker_ctf_t *lc; +}; + +# # Load a file, returning the new linker_file_t in *result. If # the class does not recognise the file type, zero should be # returned, without modifying *result. If the file is ==== //depot/projects/dtrace6/src/sys/sys/linker.h#5 (text+ko) ==== @@ -59,6 +59,8 @@ size_t size; } linker_symval_t; +typedef int (*linker_function_nameval_callback_t)(linker_file_t, int, linker_symval_t *, void *); + struct common_symbol { STAILQ_ENTRY(common_symbol) link; char* name; @@ -113,6 +115,11 @@ extern linker_file_t linker_kernel_file; /* + * Function type used when iterating over the list of linker files. + */ +typedef int linker_predicate_t(linker_file_t, void *); + +/* * Add a new file class to the linker. */ int linker_add_class(linker_class_t _cls); @@ -139,6 +146,13 @@ linker_file_t _file); /* + * Iterate over all of the currently loaded linker files calling the + * predicate function while the function returns 0. Returns the value + * returned by the last predicate function. + */ +int linker_file_foreach(linker_predicate_t *_predicate, void *_context); + +/* * Find a currently loaded file given its filename. */ linker_file_t linker_find_file_by_name(const char* _filename); @@ -171,6 +185,12 @@ int _deps); /* + * List all functions in a file. + */ +int linker_file_function_listall(linker_file_t, + linker_function_nameval_callback_t, void *); + +/* * Lookup a linker set in a file. Return pointers to the first entry, * last + 1, and count of entries. Use: for (p = start; p < stop; p++) {} * void *start is really: "struct yoursetmember ***start;" @@ -271,6 +291,20 @@ const Elf_Sym *elf_get_sym(linker_file_t _lf, Elf_Size _symidx); const char *elf_get_symname(linker_file_t _lf, Elf_Size _symidx); +typedef struct linker_ctf { + const uint8_t *ctftab; /* Decompressed CTF data. */ + int ctfcnt; /* Number of CTF data bytes. */ + const Elf_Sym *symtab; /* Ptr to the symbol table. */ + int nsym; /* Number of symbols. */ + const char *strtab; /* Ptr to the string table. */ + int strcnt; /* Number of string bytes. */ + uint32_t **ctfoffp; /* Ptr to array of obj/fnc offsets. */ + uint32_t **typoffp; /* Ptr to array of type offsets. */ + long *typlenp; /* Ptr to number of type data entries. */ +} linker_ctf_t; + +int linker_ctf_get(linker_file_t, linker_ctf_t *); + int elf_cpu_load_file(linker_file_t); int elf_cpu_unload_file(linker_file_t);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200806090252.m592qAv4048574>