diff options
| author | Namhyung Kim <namhyung.kim@lge.com> | 2013-11-24 23:42:47 -0500 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2014-01-02 20:57:05 -0500 |
| commit | b7e0bf341f6cfa92ae0a0e3d0c3496729595e1e9 (patch) | |
| tree | 0831ae7ab363f3789c5cb14bbf4973bfe17287bc /kernel/trace | |
| parent | 72fd293aa9ae8f4f48d6042be43fe81551c639f2 (diff) | |
tracing/uprobes: Add @+file_offset fetch method
Enable to fetch data from a file offset. Currently it only supports
fetching from same binary uprobe set. It'll translate the file offset
to a proper virtual address in the process.
The syntax is "@+OFFSET" as it does similar to normal memory fetching
(@ADDR) which does no address translation.
Suggested-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Acked-by: Oleg Nesterov <oleg@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: zhangwei(Jovi) <jovi.zhangwei@huawei.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/trace_kprobe.c | 8 | ||||
| -rw-r--r-- | kernel/trace/trace_probe.c | 13 | ||||
| -rw-r--r-- | kernel/trace/trace_probe.h | 2 | ||||
| -rw-r--r-- | kernel/trace/trace_uprobe.c | 40 |
4 files changed, 62 insertions, 1 deletions
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index f94a56915e69..ce0ed8afb77e 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
| @@ -239,6 +239,14 @@ DEFINE_BASIC_FETCH_FUNCS(symbol) | |||
| 239 | DEFINE_FETCH_symbol(string) | 239 | DEFINE_FETCH_symbol(string) |
| 240 | DEFINE_FETCH_symbol(string_size) | 240 | DEFINE_FETCH_symbol(string_size) |
| 241 | 241 | ||
| 242 | /* kprobes don't support file_offset fetch methods */ | ||
| 243 | #define fetch_file_offset_u8 NULL | ||
| 244 | #define fetch_file_offset_u16 NULL | ||
| 245 | #define fetch_file_offset_u32 NULL | ||
| 246 | #define fetch_file_offset_u64 NULL | ||
| 247 | #define fetch_file_offset_string NULL | ||
| 248 | #define fetch_file_offset_string_size NULL | ||
| 249 | |||
| 242 | /* Fetch type information table */ | 250 | /* Fetch type information table */ |
| 243 | const struct fetch_type kprobes_fetch_type_table[] = { | 251 | const struct fetch_type kprobes_fetch_type_table[] = { |
| 244 | /* Special types */ | 252 | /* Special types */ |
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index a130d612e705..8364a421b4df 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c | |||
| @@ -374,7 +374,7 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, | |||
| 374 | } | 374 | } |
| 375 | break; | 375 | break; |
| 376 | 376 | ||
| 377 | case '@': /* memory or symbol */ | 377 | case '@': /* memory, file-offset or symbol */ |
| 378 | if (isdigit(arg[1])) { | 378 | if (isdigit(arg[1])) { |
| 379 | ret = kstrtoul(arg + 1, 0, ¶m); | 379 | ret = kstrtoul(arg + 1, 0, ¶m); |
| 380 | if (ret) | 380 | if (ret) |
| @@ -382,6 +382,17 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, | |||
| 382 | 382 | ||
| 383 | f->fn = t->fetch[FETCH_MTD_memory]; | 383 | f->fn = t->fetch[FETCH_MTD_memory]; |
| 384 | f->data = (void *)param; | 384 | f->data = (void *)param; |
| 385 | } else if (arg[1] == '+') { | ||
| 386 | /* kprobes don't support file offsets */ | ||
| 387 | if (is_kprobe) | ||
| 388 | return -EINVAL; | ||
| 389 | |||
| 390 | ret = kstrtol(arg + 2, 0, &offset); | ||
| 391 | if (ret) | ||
| 392 | break; | ||
| 393 | |||
| 394 | f->fn = t->fetch[FETCH_MTD_file_offset]; | ||
| 395 | f->data = (void *)offset; | ||
| 385 | } else { | 396 | } else { |
| 386 | /* uprobes don't support symbols */ | 397 | /* uprobes don't support symbols */ |
| 387 | if (!is_kprobe) | 398 | if (!is_kprobe) |
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 2d5b8f5f5310..e29d743fef5d 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h | |||
| @@ -106,6 +106,7 @@ enum { | |||
| 106 | FETCH_MTD_symbol, | 106 | FETCH_MTD_symbol, |
| 107 | FETCH_MTD_deref, | 107 | FETCH_MTD_deref, |
| 108 | FETCH_MTD_bitfield, | 108 | FETCH_MTD_bitfield, |
| 109 | FETCH_MTD_file_offset, | ||
| 109 | FETCH_MTD_END, | 110 | FETCH_MTD_END, |
| 110 | }; | 111 | }; |
| 111 | 112 | ||
| @@ -217,6 +218,7 @@ ASSIGN_FETCH_FUNC(memory, ftype), \ | |||
| 217 | ASSIGN_FETCH_FUNC(symbol, ftype), \ | 218 | ASSIGN_FETCH_FUNC(symbol, ftype), \ |
| 218 | ASSIGN_FETCH_FUNC(deref, ftype), \ | 219 | ASSIGN_FETCH_FUNC(deref, ftype), \ |
| 219 | ASSIGN_FETCH_FUNC(bitfield, ftype), \ | 220 | ASSIGN_FETCH_FUNC(bitfield, ftype), \ |
| 221 | ASSIGN_FETCH_FUNC(file_offset, ftype), \ | ||
| 220 | } \ | 222 | } \ |
| 221 | } | 223 | } |
| 222 | 224 | ||
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 794e8bc171f3..1fdea6d3f851 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c | |||
| @@ -70,6 +70,11 @@ static int unregister_uprobe_event(struct trace_uprobe *tu); | |||
| 70 | static DEFINE_MUTEX(uprobe_lock); | 70 | static DEFINE_MUTEX(uprobe_lock); |
| 71 | static LIST_HEAD(uprobe_list); | 71 | static LIST_HEAD(uprobe_list); |
| 72 | 72 | ||
| 73 | struct uprobe_dispatch_data { | ||
| 74 | struct trace_uprobe *tu; | ||
| 75 | unsigned long bp_addr; | ||
| 76 | }; | ||
| 77 | |||
| 73 | static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs); | 78 | static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs); |
| 74 | static int uretprobe_dispatcher(struct uprobe_consumer *con, | 79 | static int uretprobe_dispatcher(struct uprobe_consumer *con, |
| 75 | unsigned long func, struct pt_regs *regs); | 80 | unsigned long func, struct pt_regs *regs); |
| @@ -175,6 +180,29 @@ static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, | |||
| 175 | #define fetch_symbol_string NULL | 180 | #define fetch_symbol_string NULL |
| 176 | #define fetch_symbol_string_size NULL | 181 | #define fetch_symbol_string_size NULL |
| 177 | 182 | ||
| 183 | static unsigned long translate_user_vaddr(void *file_offset) | ||
| 184 | { | ||
| 185 | unsigned long base_addr; | ||
| 186 | struct uprobe_dispatch_data *udd; | ||
| 187 | |||
| 188 | udd = (void *) current->utask->vaddr; | ||
| 189 | |||
| 190 | base_addr = udd->bp_addr - udd->tu->offset; | ||
| 191 | return base_addr + (unsigned long)file_offset; | ||
| 192 | } | ||
| 193 | |||
| 194 | #define DEFINE_FETCH_file_offset(type) \ | ||
| 195 | static __kprobes void FETCH_FUNC_NAME(file_offset, type)(struct pt_regs *regs,\ | ||
| 196 | void *offset, void *dest) \ | ||
| 197 | { \ | ||
| 198 | void *vaddr = (void *)translate_user_vaddr(offset); \ | ||
| 199 | \ | ||
| 200 | FETCH_FUNC_NAME(memory, type)(regs, vaddr, dest); \ | ||
| 201 | } | ||
| 202 | DEFINE_BASIC_FETCH_FUNCS(file_offset) | ||
| 203 | DEFINE_FETCH_file_offset(string) | ||
| 204 | DEFINE_FETCH_file_offset(string_size) | ||
| 205 | |||
| 178 | /* Fetch type information table */ | 206 | /* Fetch type information table */ |
| 179 | const struct fetch_type uprobes_fetch_type_table[] = { | 207 | const struct fetch_type uprobes_fetch_type_table[] = { |
| 180 | /* Special types */ | 208 | /* Special types */ |
| @@ -1106,11 +1134,17 @@ int trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type, | |||
| 1106 | static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs) | 1134 | static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs) |
| 1107 | { | 1135 | { |
| 1108 | struct trace_uprobe *tu; | 1136 | struct trace_uprobe *tu; |
| 1137 | struct uprobe_dispatch_data udd; | ||
| 1109 | int ret = 0; | 1138 | int ret = 0; |
| 1110 | 1139 | ||
| 1111 | tu = container_of(con, struct trace_uprobe, consumer); | 1140 | tu = container_of(con, struct trace_uprobe, consumer); |
| 1112 | tu->nhit++; | 1141 | tu->nhit++; |
| 1113 | 1142 | ||
| 1143 | udd.tu = tu; | ||
| 1144 | udd.bp_addr = instruction_pointer(regs); | ||
| 1145 | |||
| 1146 | current->utask->vaddr = (unsigned long) &udd; | ||
| 1147 | |||
| 1114 | if (tu->tp.flags & TP_FLAG_TRACE) | 1148 | if (tu->tp.flags & TP_FLAG_TRACE) |
| 1115 | ret |= uprobe_trace_func(tu, regs); | 1149 | ret |= uprobe_trace_func(tu, regs); |
| 1116 | 1150 | ||
| @@ -1125,9 +1159,15 @@ static int uretprobe_dispatcher(struct uprobe_consumer *con, | |||
| 1125 | unsigned long func, struct pt_regs *regs) | 1159 | unsigned long func, struct pt_regs *regs) |
| 1126 | { | 1160 | { |
| 1127 | struct trace_uprobe *tu; | 1161 | struct trace_uprobe *tu; |
| 1162 | struct uprobe_dispatch_data udd; | ||
| 1128 | 1163 | ||
| 1129 | tu = container_of(con, struct trace_uprobe, consumer); | 1164 | tu = container_of(con, struct trace_uprobe, consumer); |
| 1130 | 1165 | ||
| 1166 | udd.tu = tu; | ||
| 1167 | udd.bp_addr = func; | ||
| 1168 | |||
| 1169 | current->utask->vaddr = (unsigned long) &udd; | ||
| 1170 | |||
| 1131 | if (tu->tp.flags & TP_FLAG_TRACE) | 1171 | if (tu->tp.flags & TP_FLAG_TRACE) |
| 1132 | uretprobe_trace_func(tu, func, regs); | 1172 | uretprobe_trace_func(tu, func, regs); |
| 1133 | 1173 | ||
