From e44401b785a1fffb6524e85f215bd99bfc778bf1 Mon Sep 17 00:00:00 2001 From: green Date: Tue, 30 Oct 2001 15:21:45 +0000 Subject: Add the sysctl "kern.function_list", which currently exports all function symbols in the kernel in a list of C strings, with an extra nul-termination at the end. This sysctl requires addition of a new linker operation. Now, linker_file_t's need to respond to "each_function_name" to export their function symbols. Note that the sysctl doesn't currently allow distinguishing multiple symbols with the same name from different modules, but could quite easily without a change to the linker operation. This will be a nicety to have when it can be used. Obtained from: NAI Labs CBOSS project Funded by: DARPA --- sys/kern/kern_linker.c | 31 +++++++++++++++++++++++++++++++ sys/kern/link_elf.c | 23 +++++++++++++++++++++++ sys/kern/link_elf_obj.c | 23 +++++++++++++++++++++++ sys/kern/linker_if.m | 10 ++++++++++ 4 files changed, 87 insertions(+) (limited to 'sys/kern') diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index 353d811..7c2b59d 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -1702,3 +1702,34 @@ linker_load_dependancies(linker_file_t lf) linker_addmodules(lf, start, stop, 0); return error; } + +static int +sysctl_kern_function_list_iterate(const char *name, void *opaque) +{ + struct sysctl_req *req; + + req = opaque; + return (SYSCTL_OUT(req, name, strlen(name) + 1)); +} + +/* + * Export a nul-separated, double-nul-terminated list of all function names + * in the kernel. + */ +static int +sysctl_kern_function_list(SYSCTL_HANDLER_ARGS) +{ + linker_file_t lf; + int error; + + TAILQ_FOREACH(lf, &linker_files, link) { + error = LINKER_EACH_FUNCTION_NAME(lf, + sysctl_kern_function_list_iterate, req); + if (error) + return (error); + } + return (SYSCTL_OUT(req, "", 1)); +} + +SYSCTL_PROC(_kern, OID_AUTO, function_list, CTLFLAG_RD, + NULL, 0, sysctl_kern_function_list, "", "kernel function list"); diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c index 888ce5e..5da9a83 100644 --- a/sys/kern/link_elf.c +++ b/sys/kern/link_elf.c @@ -113,6 +113,9 @@ static void link_elf_unload_file(linker_file_t); static void link_elf_unload_preload(linker_file_t); static int link_elf_lookup_set(linker_file_t, const char *, void ***, void ***, int *); +static int link_elf_each_function_name(linker_file_t, + int (*)(const char *, void *), + void *); static kobj_method_t link_elf_methods[] = { KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), @@ -123,6 +126,7 @@ static kobj_method_t link_elf_methods[] = { KOBJMETHOD(linker_link_preload, link_elf_link_preload), KOBJMETHOD(linker_link_preload_finish, link_elf_link_preload_finish), KOBJMETHOD(linker_lookup_set, link_elf_lookup_set), + KOBJMETHOD(linker_each_function_name, link_elf_each_function_name), { 0, 0 } }; @@ -1149,3 +1153,22 @@ out: free(setsym, M_LINKER); return error; } + +static int +link_elf_each_function_name(linker_file_t file, + int (*callback)(const char *, void *), void *opaque) { + elf_file_t ef = (elf_file_t)file; + const Elf_Sym* symp; + int i, error; + + /* Exhaustive search */ + for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { + if (symp->st_value != 0 && + ELF_ST_TYPE(symp->st_info) == STT_FUNC) { + error = callback(ef->ddbstrtab + symp->st_name, opaque); + if (error) + return (error); + } + } + return (0); +} diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c index 888ce5e..5da9a83 100644 --- a/sys/kern/link_elf_obj.c +++ b/sys/kern/link_elf_obj.c @@ -113,6 +113,9 @@ static void link_elf_unload_file(linker_file_t); static void link_elf_unload_preload(linker_file_t); static int link_elf_lookup_set(linker_file_t, const char *, void ***, void ***, int *); +static int link_elf_each_function_name(linker_file_t, + int (*)(const char *, void *), + void *); static kobj_method_t link_elf_methods[] = { KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), @@ -123,6 +126,7 @@ static kobj_method_t link_elf_methods[] = { KOBJMETHOD(linker_link_preload, link_elf_link_preload), KOBJMETHOD(linker_link_preload_finish, link_elf_link_preload_finish), KOBJMETHOD(linker_lookup_set, link_elf_lookup_set), + KOBJMETHOD(linker_each_function_name, link_elf_each_function_name), { 0, 0 } }; @@ -1149,3 +1153,22 @@ out: free(setsym, M_LINKER); return error; } + +static int +link_elf_each_function_name(linker_file_t file, + int (*callback)(const char *, void *), void *opaque) { + elf_file_t ef = (elf_file_t)file; + const Elf_Sym* symp; + int i, error; + + /* Exhaustive search */ + for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) { + if (symp->st_value != 0 && + ELF_ST_TYPE(symp->st_info) == STT_FUNC) { + error = callback(ef->ddbstrtab + symp->st_name, opaque); + if (error) + return (error); + } + } + return (0); +} diff --git a/sys/kern/linker_if.m b/sys/kern/linker_if.m index be84b9e..9dafb57 100644 --- a/sys/kern/linker_if.m +++ b/sys/kern/linker_if.m @@ -54,6 +54,16 @@ METHOD int search_symbol { }; # +# Call the callback with each specified function defined in the file. +# Stop and return the error if the callback returns an error. +# +METHOD int each_function_name { + linker_file_t file; + linker_function_name_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. -- cgit v1.1