diff options
-rw-r--r-- | sys/compat/ndis/subr_ndis.c | 50 | ||||
-rw-r--r-- | sys/kern/kern_linker.c | 80 | ||||
-rw-r--r-- | sys/sys/linker.h | 12 |
3 files changed, 95 insertions, 47 deletions
diff --git a/sys/compat/ndis/subr_ndis.c b/sys/compat/ndis/subr_ndis.c index ee8a0f9..40ff543 100644 --- a/sys/compat/ndis/subr_ndis.c +++ b/sys/compat/ndis/subr_ndis.c @@ -2886,6 +2886,32 @@ ndis_find_sym(lf, filename, suffix, sym) return(0); } +struct ndis_checkmodule { + char *afilename; + ndis_fh *fh; +}; + +/* + * See if a single module contains the symbols for a specified file. + */ +static int +NdisCheckModule(linker_file_t lf, void *context) +{ + struct ndis_checkmodule *nc; + caddr_t kldstart, kldend; + + nc = (struct ndis_checkmodule *)context; + if (ndis_find_sym(lf, nc->afilename, "_start", &kldstart)) + return (0); + if (ndis_find_sym(lf, nc->afilename, "_end", &kldend)) + return (0); + nc->fh->nf_vp = lf; + nc->fh->nf_map = NULL; + nc->fh->nf_type = NDIS_FH_TYPE_MODULE; + nc->fh->nf_maplen = (kldend - kldstart) & 0xFFFFFFFF; + return (1); +} + /* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */ static void NdisOpenFile(status, filehandle, filelength, filename, highestaddr) @@ -2904,8 +2930,7 @@ NdisOpenFile(status, filehandle, filelength, filename, highestaddr) struct vattr *vap = &vat; ndis_fh *fh; char *path; - linker_file_t head, lf; - caddr_t kldstart, kldend; + struct ndis_checkmodule nc; if (RtlUnicodeStringToAnsiString(&as, filename, TRUE)) { *status = NDIS_STATUS_RESOURCES; @@ -2943,23 +2968,10 @@ NdisOpenFile(status, filehandle, filelength, filename, highestaddr) * us since the kernel appears to us as just another module. */ - /* - * This is an evil trick for getting the head of the linked - * file list, which is not exported from kern_linker.o. It - * happens that linker file #1 is always the kernel, and is - * always the first element in the list. - */ - - head = linker_find_file_by_id(1); - for (lf = head; lf != NULL; lf = TAILQ_NEXT(lf, link)) { - if (ndis_find_sym(lf, afilename, "_start", &kldstart)) - continue; - if (ndis_find_sym(lf, afilename, "_end", &kldend)) - continue; - fh->nf_vp = lf; - fh->nf_map = NULL; - fh->nf_type = NDIS_FH_TYPE_MODULE; - *filelength = fh->nf_maplen = (kldend - kldstart) & 0xFFFFFFFF; + nc.afilename = afilename; + nc.fh = fh; + if (linker_file_foreach(NdisCheckModule, &nc)) { + *filelength = fh->nf_maplen; *filehandle = fh; *status = NDIS_STATUS_SUCCESS; return; diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index 67c45c8..9d13542 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -449,6 +449,22 @@ linker_find_file_by_id(int fileid) return (lf); } +int +linker_file_foreach(linker_predicate_t *predicate, void *context) +{ + linker_file_t lf; + int retval = 0; + + mtx_lock(&Giant); + TAILQ_FOREACH(lf, &linker_files, link) { + retval = predicate(lf, context); + if (retval != 0) + break; + } + mtx_unlock(&Giant); + return (retval); +} + linker_file_t linker_make_file(const char *pathname, linker_class_t lc) { @@ -1669,53 +1685,61 @@ linker_basename(const char *path) #ifdef HWPMC_HOOKS +struct hwpmc_context { + int nobjects; + int nmappings; + struct pmckern_map_in *kobase; +}; + +static int +linker_hwpmc_list_object(linker_file_t lf, void *arg) +{ + struct hwpmc_context *hc; + + hc = arg; + + /* If we run out of mappings, fail. */ + if (hc->nobjects >= hc->nmappings) + return (1); + + /* Save the info for this linker file. */ + hc->kobase[hc->nobjects].pm_file = lf->filename; + hc->kobase[hc->nobjects].pm_address = (uintptr_t)lf->address; + hc->nobjects++; + return (0); +} + /* * Inform hwpmc about the set of kernel modules currently loaded. */ void * linker_hwpmc_list_objects(void) { - int nobjects, nmappings; - linker_file_t lf; - struct pmckern_map_in *ko, *kobase; + struct hwpmc_context hc; - nmappings = 15; /* a reasonable default */ + hc.nmappings = 15; /* a reasonable default */ retry: /* allocate nmappings+1 entries */ - MALLOC(kobase, struct pmckern_map_in *, - (nmappings + 1) * sizeof(struct pmckern_map_in), M_LINKER, + MALLOC(hc.kobase, struct pmckern_map_in *, + (hc.nmappings + 1) * sizeof(struct pmckern_map_in), M_LINKER, M_WAITOK | M_ZERO); - nobjects = 0; - mtx_lock(&kld_mtx); - TAILQ_FOREACH(lf, &linker_files, link) - nobjects++; - - KASSERT(nobjects > 0, ("linker_hpwmc_list_objects: no kernel " - "objects?")); - - if (nobjects > nmappings) { - nmappings = nobjects; - FREE(kobase, M_LINKER); - mtx_unlock(&kld_mtx); + hc.nobjects = 0; + if (linker_file_foreach(linker_hwpmc_list_object, &hc) != 0) { + hc.nmappings = hc.nobjects; + FREE(hc.kobase, M_LINKER); goto retry; } - ko = kobase; - TAILQ_FOREACH(lf, &linker_files, link) { - ko->pm_file = lf->filename; - ko->pm_address = (uintptr_t) lf->address; - ko++; - } + KASSERT(hc.nobjects > 0, ("linker_hpwmc_list_objects: no kernel " + "objects?")); /* The last entry of the malloced area comprises of all zeros. */ - KASSERT(ko->pm_file == NULL, + KASSERT(hc.kobase[hc.nobjects].pm_file == NULL, ("linker_hwpmc_list_objects: last object not NULL")); - mtx_unlock(&kld_mtx); - - return ((void *) kobase); + return ((void *)hc.kobase); } #endif diff --git a/sys/sys/linker.h b/sys/sys/linker.h index bfd9804..bebe9c9 100644 --- a/sys/sys/linker.h +++ b/sys/sys/linker.h @@ -95,6 +95,11 @@ struct linker_class { }; /* + * Function type used when iterating over the list of linker files. + */ +typedef int linker_predicate_t(linker_file_t, void *); + +/* * The "file" for the kernel. */ extern linker_file_t linker_kernel_file; @@ -111,6 +116,13 @@ int linker_reference_module(const char* _modname, struct mod_depend *_verinfo, linker_file_t* _result); /* + * 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); |