forked from luck/tmp_suning_uos_patched
module: add within_module_core() and within_module_init()
This series of patches allows kprobes to probe module's __init and __exit functions. This means, you can probe driver initialization and terminating. Currently, kprobes can't probe __init function because these functions are freed after module initialization. And it also can't probe module __exit functions because kprobe increments reference count of target module and user can't unload it. this means __exit functions never be called unless removing probes from the module. To solve both cases, this series of patches introduces GONE flag and sets it when the target code is freed(for this purpose, kprobes hooks MODULE_STATE_* events). This also removes refcount incrementing for allowing user to unload target module. Users can check which probes are GONE by debugfs interface. For taking timing of freeing module's .init text, these also include a patch which adds module's notifier of MODULE_STATE_LIVE event. This patch: Add within_module_core() and within_module_init() for checking whether an address is in the module .init.text section or .text section, and replace within() local inline functions in kernel/module.c with them. kprobes uses these functions to check where the kprobe is inserted. Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> Acked-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
12da3b888b
commit
a06f6211ef
@ -365,6 +365,18 @@ struct module *module_text_address(unsigned long addr);
|
||||
struct module *__module_text_address(unsigned long addr);
|
||||
int is_module_address(unsigned long addr);
|
||||
|
||||
static inline int within_module_core(unsigned long addr, struct module *mod)
|
||||
{
|
||||
return (unsigned long)mod->module_core <= addr &&
|
||||
addr < (unsigned long)mod->module_core + mod->core_size;
|
||||
}
|
||||
|
||||
static inline int within_module_init(unsigned long addr, struct module *mod)
|
||||
{
|
||||
return (unsigned long)mod->module_init <= addr &&
|
||||
addr < (unsigned long)mod->module_init + mod->init_size;
|
||||
}
|
||||
|
||||
/* Returns 0 and fills in value, defined and namebuf, or -ERANGE if
|
||||
symnum out of range. */
|
||||
int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
|
||||
|
@ -2390,7 +2390,7 @@ static const char *get_ksymbol(struct module *mod,
|
||||
unsigned long nextval;
|
||||
|
||||
/* At worse, next value is at end of module */
|
||||
if (within(addr, mod->module_init, mod->init_size))
|
||||
if (within_module_init(addr, mod))
|
||||
nextval = (unsigned long)mod->module_init+mod->init_text_size;
|
||||
else
|
||||
nextval = (unsigned long)mod->module_core+mod->core_text_size;
|
||||
@ -2438,8 +2438,8 @@ const char *module_address_lookup(unsigned long addr,
|
||||
|
||||
preempt_disable();
|
||||
list_for_each_entry_rcu(mod, &modules, list) {
|
||||
if (within(addr, mod->module_init, mod->init_size)
|
||||
|| within(addr, mod->module_core, mod->core_size)) {
|
||||
if (within_module_init(addr, mod) ||
|
||||
within_module_core(addr, mod)) {
|
||||
if (modname)
|
||||
*modname = mod->name;
|
||||
ret = get_ksymbol(mod, addr, size, offset);
|
||||
@ -2461,8 +2461,8 @@ int lookup_module_symbol_name(unsigned long addr, char *symname)
|
||||
|
||||
preempt_disable();
|
||||
list_for_each_entry_rcu(mod, &modules, list) {
|
||||
if (within(addr, mod->module_init, mod->init_size) ||
|
||||
within(addr, mod->module_core, mod->core_size)) {
|
||||
if (within_module_init(addr, mod) ||
|
||||
within_module_core(addr, mod)) {
|
||||
const char *sym;
|
||||
|
||||
sym = get_ksymbol(mod, addr, NULL, NULL);
|
||||
@ -2485,8 +2485,8 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
|
||||
|
||||
preempt_disable();
|
||||
list_for_each_entry_rcu(mod, &modules, list) {
|
||||
if (within(addr, mod->module_init, mod->init_size) ||
|
||||
within(addr, mod->module_core, mod->core_size)) {
|
||||
if (within_module_init(addr, mod) ||
|
||||
within_module_core(addr, mod)) {
|
||||
const char *sym;
|
||||
|
||||
sym = get_ksymbol(mod, addr, size, offset);
|
||||
@ -2705,7 +2705,7 @@ int is_module_address(unsigned long addr)
|
||||
preempt_disable();
|
||||
|
||||
list_for_each_entry_rcu(mod, &modules, list) {
|
||||
if (within(addr, mod->module_core, mod->core_size)) {
|
||||
if (within_module_core(addr, mod)) {
|
||||
preempt_enable();
|
||||
return 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user