summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/compat/ndis/subr_ndis.c50
-rw-r--r--sys/kern/kern_linker.c80
-rw-r--r--sys/sys/linker.h12
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);
OpenPOWER on IntegriCloud