- Add a new linker_file_foreach() function that walks the list of linker
file objects calling a user-specified predicate function on each object. The iteration terminates either when the entire list has been iterated over or the predicate function returns a non-zero value. linker_file_foreach() returns the value returned by the last invocation of the predicate function. It also accepts a void * context pointer that is passed to the predicate function as well. Using an iterator function avoids exposing linker internals to the rest of the kernel making locking simpler. - Use linker_file_foreach() instead of walking the list of linker files manually to lookup ndis files in ndis(4). - Use linker_file_foreach() to implement linker_hwpmc_list_objects().
This commit is contained in:
parent
aaf3170501
commit
932151064a
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -94,6 +94,11 @@ struct linker_class {
|
||||
TAILQ_ENTRY(linker_class) link; /* list of all file classes */
|
||||
};
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
@ -110,6 +115,13 @@ int linker_add_class(linker_class_t _cls);
|
||||
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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user