diff options
-rw-r--r-- | Documentation/trace/uprobetracer.txt | 1 | ||||
-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 |
5 files changed, 63 insertions, 1 deletions
diff --git a/Documentation/trace/uprobetracer.txt b/Documentation/trace/uprobetracer.txt index 6e5cff263e2b..f1cf9a34ad9d 100644 --- a/Documentation/trace/uprobetracer.txt +++ b/Documentation/trace/uprobetracer.txt | |||
@@ -32,6 +32,7 @@ Synopsis of uprobe_tracer | |||
32 | FETCHARGS : Arguments. Each probe can have up to 128 args. | 32 | FETCHARGS : Arguments. Each probe can have up to 128 args. |
33 | %REG : Fetch register REG | 33 | %REG : Fetch register REG |
34 | @ADDR : Fetch memory at ADDR (ADDR should be in userspace) | 34 | @ADDR : Fetch memory at ADDR (ADDR should be in userspace) |
35 | @+OFFSET : Fetch memory at OFFSET (OFFSET from same file as PATH) | ||
35 | $stackN : Fetch Nth entry of stack (N >= 0) | 36 | $stackN : Fetch Nth entry of stack (N >= 0) |
36 | $stack : Fetch stack address. | 37 | $stack : Fetch stack address. |
37 | $retval : Fetch return value.(*) | 38 | $retval : Fetch return value.(*) |
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 | ||