- 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:
John Baldwin 2006-06-20 20:37:17 +00:00
parent aaf3170501
commit 932151064a
3 changed files with 95 additions and 47 deletions

View File

@ -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;

View File

@ -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

View File

@ -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.
*/