tracing: kprobe: Check kretprobe offset from symbol correctly From: Masami Hiramatsu Check the kretprobe event offset from the nearest symbol correctly instead of checking given offset value. This will allow users to specify the relative offset from _text or _stext so that they can put a kretprobe on one of same-name functions. Signed-off-by: Masami Hiramatsu --- include/linux/kprobes.h | 9 +++++++++ kernel/kprobes.c | 9 --------- kernel/trace/trace_kprobe.c | 18 +++++++++++++++++- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index 862f87a..6a92734 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h @@ -44,6 +44,15 @@ #ifdef CONFIG_KPROBES #include +/* + * Some oddball architectures like 64bit powerpc have function descriptors + * so this must be overridable. + */ +#ifndef kprobe_lookup_name +#define kprobe_lookup_name(name, addr) \ + addr = ((kprobe_opcode_t *)(kallsyms_lookup_name(name))) +#endif + /* kprobe_status settings */ #define KPROBE_HIT_ACTIVE 0x00000001 #define KPROBE_HIT_SS 0x00000002 diff --git a/kernel/kprobes.c b/kernel/kprobes.c index a77f9d7..9236f3f 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -58,15 +58,6 @@ #define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS) -/* - * Some oddball architectures like 64bit powerpc have function descriptors - * so this must be overridable. - */ -#ifndef kprobe_lookup_name -#define kprobe_lookup_name(name, addr) \ - addr = ((kprobe_opcode_t *)(kallsyms_lookup_name(name))) -#endif - static int kprobes_initialized; static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE]; static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE]; diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index c60f9dc..59f2b2f 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -587,6 +587,22 @@ static int trace_kprobe_module_callback(struct notifier_block *nb, return NOTIFY_DONE; } +static bool function_offset_within_entry(const char *sym, unsigned long offs) +{ + void *addr = NULL; + + kprobe_lookup_name(sym, addr); + if (!addr) + return false; + addr += offs; + + if (kallsyms_lookup_size_offset((unsigned long)addr, NULL, &offs) && + offs == 0) + return true; + + return false; +} + static struct notifier_block trace_kprobe_module_nb = { .notifier_call = trace_kprobe_module_callback, .priority = 1 /* Invoked after kprobe module callback */ @@ -695,7 +711,7 @@ static int create_trace_kprobe(int argc, char **argv) return ret; } if (offset && is_return && - !arch_function_offset_within_entry(offset)) { + !function_offset_within_entry(symbol, offset)) { pr_info("Given offset is not valid for return probe.\n"); return -EINVAL; }