diff options
Diffstat (limited to 'kernel/trace/trace_uprobe.c')
-rw-r--r-- | kernel/trace/trace_uprobe.c | 487 |
1 files changed, 352 insertions, 135 deletions
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index b6dcc42ef7f5..79e52d93860b 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c | |||
@@ -51,22 +51,17 @@ struct trace_uprobe_filter { | |||
51 | */ | 51 | */ |
52 | struct trace_uprobe { | 52 | struct trace_uprobe { |
53 | struct list_head list; | 53 | struct list_head list; |
54 | struct ftrace_event_class class; | ||
55 | struct ftrace_event_call call; | ||
56 | struct trace_uprobe_filter filter; | 54 | struct trace_uprobe_filter filter; |
57 | struct uprobe_consumer consumer; | 55 | struct uprobe_consumer consumer; |
58 | struct inode *inode; | 56 | struct inode *inode; |
59 | char *filename; | 57 | char *filename; |
60 | unsigned long offset; | 58 | unsigned long offset; |
61 | unsigned long nhit; | 59 | unsigned long nhit; |
62 | unsigned int flags; /* For TP_FLAG_* */ | 60 | struct trace_probe tp; |
63 | ssize_t size; /* trace entry size */ | ||
64 | unsigned int nr_args; | ||
65 | struct probe_arg args[]; | ||
66 | }; | 61 | }; |
67 | 62 | ||
68 | #define SIZEOF_TRACE_UPROBE(n) \ | 63 | #define SIZEOF_TRACE_UPROBE(n) \ |
69 | (offsetof(struct trace_uprobe, args) + \ | 64 | (offsetof(struct trace_uprobe, tp.args) + \ |
70 | (sizeof(struct probe_arg) * (n))) | 65 | (sizeof(struct probe_arg) * (n))) |
71 | 66 | ||
72 | static int register_uprobe_event(struct trace_uprobe *tu); | 67 | static int register_uprobe_event(struct trace_uprobe *tu); |
@@ -75,10 +70,151 @@ static int unregister_uprobe_event(struct trace_uprobe *tu); | |||
75 | static DEFINE_MUTEX(uprobe_lock); | 70 | static DEFINE_MUTEX(uprobe_lock); |
76 | static LIST_HEAD(uprobe_list); | 71 | static LIST_HEAD(uprobe_list); |
77 | 72 | ||
73 | struct uprobe_dispatch_data { | ||
74 | struct trace_uprobe *tu; | ||
75 | unsigned long bp_addr; | ||
76 | }; | ||
77 | |||
78 | 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); |
79 | static int uretprobe_dispatcher(struct uprobe_consumer *con, | 79 | static int uretprobe_dispatcher(struct uprobe_consumer *con, |
80 | unsigned long func, struct pt_regs *regs); | 80 | unsigned long func, struct pt_regs *regs); |
81 | 81 | ||
82 | #ifdef CONFIG_STACK_GROWSUP | ||
83 | static unsigned long adjust_stack_addr(unsigned long addr, unsigned int n) | ||
84 | { | ||
85 | return addr - (n * sizeof(long)); | ||
86 | } | ||
87 | #else | ||
88 | static unsigned long adjust_stack_addr(unsigned long addr, unsigned int n) | ||
89 | { | ||
90 | return addr + (n * sizeof(long)); | ||
91 | } | ||
92 | #endif | ||
93 | |||
94 | static unsigned long get_user_stack_nth(struct pt_regs *regs, unsigned int n) | ||
95 | { | ||
96 | unsigned long ret; | ||
97 | unsigned long addr = user_stack_pointer(regs); | ||
98 | |||
99 | addr = adjust_stack_addr(addr, n); | ||
100 | |||
101 | if (copy_from_user(&ret, (void __force __user *) addr, sizeof(ret))) | ||
102 | return 0; | ||
103 | |||
104 | return ret; | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * Uprobes-specific fetch functions | ||
109 | */ | ||
110 | #define DEFINE_FETCH_stack(type) \ | ||
111 | static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\ | ||
112 | void *offset, void *dest) \ | ||
113 | { \ | ||
114 | *(type *)dest = (type)get_user_stack_nth(regs, \ | ||
115 | ((unsigned long)offset)); \ | ||
116 | } | ||
117 | DEFINE_BASIC_FETCH_FUNCS(stack) | ||
118 | /* No string on the stack entry */ | ||
119 | #define fetch_stack_string NULL | ||
120 | #define fetch_stack_string_size NULL | ||
121 | |||
122 | #define DEFINE_FETCH_memory(type) \ | ||
123 | static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\ | ||
124 | void *addr, void *dest) \ | ||
125 | { \ | ||
126 | type retval; \ | ||
127 | void __user *vaddr = (void __force __user *) addr; \ | ||
128 | \ | ||
129 | if (copy_from_user(&retval, vaddr, sizeof(type))) \ | ||
130 | *(type *)dest = 0; \ | ||
131 | else \ | ||
132 | *(type *) dest = retval; \ | ||
133 | } | ||
134 | DEFINE_BASIC_FETCH_FUNCS(memory) | ||
135 | /* | ||
136 | * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max | ||
137 | * length and relative data location. | ||
138 | */ | ||
139 | static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, | ||
140 | void *addr, void *dest) | ||
141 | { | ||
142 | long ret; | ||
143 | u32 rloc = *(u32 *)dest; | ||
144 | int maxlen = get_rloc_len(rloc); | ||
145 | u8 *dst = get_rloc_data(dest); | ||
146 | void __user *src = (void __force __user *) addr; | ||
147 | |||
148 | if (!maxlen) | ||
149 | return; | ||
150 | |||
151 | ret = strncpy_from_user(dst, src, maxlen); | ||
152 | |||
153 | if (ret < 0) { /* Failed to fetch string */ | ||
154 | ((u8 *)get_rloc_data(dest))[0] = '\0'; | ||
155 | *(u32 *)dest = make_data_rloc(0, get_rloc_offs(rloc)); | ||
156 | } else { | ||
157 | *(u32 *)dest = make_data_rloc(ret, get_rloc_offs(rloc)); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, | ||
162 | void *addr, void *dest) | ||
163 | { | ||
164 | int len; | ||
165 | void __user *vaddr = (void __force __user *) addr; | ||
166 | |||
167 | len = strnlen_user(vaddr, MAX_STRING_SIZE); | ||
168 | |||
169 | if (len == 0 || len > MAX_STRING_SIZE) /* Failed to check length */ | ||
170 | *(u32 *)dest = 0; | ||
171 | else | ||
172 | *(u32 *)dest = len; | ||
173 | } | ||
174 | |||
175 | static unsigned long translate_user_vaddr(void *file_offset) | ||
176 | { | ||
177 | unsigned long base_addr; | ||
178 | struct uprobe_dispatch_data *udd; | ||
179 | |||
180 | udd = (void *) current->utask->vaddr; | ||
181 | |||
182 | base_addr = udd->bp_addr - udd->tu->offset; | ||
183 | return base_addr + (unsigned long)file_offset; | ||
184 | } | ||
185 | |||
186 | #define DEFINE_FETCH_file_offset(type) \ | ||
187 | static __kprobes void FETCH_FUNC_NAME(file_offset, type)(struct pt_regs *regs,\ | ||
188 | void *offset, void *dest) \ | ||
189 | { \ | ||
190 | void *vaddr = (void *)translate_user_vaddr(offset); \ | ||
191 | \ | ||
192 | FETCH_FUNC_NAME(memory, type)(regs, vaddr, dest); \ | ||
193 | } | ||
194 | DEFINE_BASIC_FETCH_FUNCS(file_offset) | ||
195 | DEFINE_FETCH_file_offset(string) | ||
196 | DEFINE_FETCH_file_offset(string_size) | ||
197 | |||
198 | /* Fetch type information table */ | ||
199 | const struct fetch_type uprobes_fetch_type_table[] = { | ||
200 | /* Special types */ | ||
201 | [FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string, | ||
202 | sizeof(u32), 1, "__data_loc char[]"), | ||
203 | [FETCH_TYPE_STRSIZE] = __ASSIGN_FETCH_TYPE("string_size", u32, | ||
204 | string_size, sizeof(u32), 0, "u32"), | ||
205 | /* Basic types */ | ||
206 | ASSIGN_FETCH_TYPE(u8, u8, 0), | ||
207 | ASSIGN_FETCH_TYPE(u16, u16, 0), | ||
208 | ASSIGN_FETCH_TYPE(u32, u32, 0), | ||
209 | ASSIGN_FETCH_TYPE(u64, u64, 0), | ||
210 | ASSIGN_FETCH_TYPE(s8, u8, 1), | ||
211 | ASSIGN_FETCH_TYPE(s16, u16, 1), | ||
212 | ASSIGN_FETCH_TYPE(s32, u32, 1), | ||
213 | ASSIGN_FETCH_TYPE(s64, u64, 1), | ||
214 | |||
215 | ASSIGN_FETCH_TYPE_END | ||
216 | }; | ||
217 | |||
82 | static inline void init_trace_uprobe_filter(struct trace_uprobe_filter *filter) | 218 | static inline void init_trace_uprobe_filter(struct trace_uprobe_filter *filter) |
83 | { | 219 | { |
84 | rwlock_init(&filter->rwlock); | 220 | rwlock_init(&filter->rwlock); |
@@ -114,13 +250,13 @@ alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret) | |||
114 | if (!tu) | 250 | if (!tu) |
115 | return ERR_PTR(-ENOMEM); | 251 | return ERR_PTR(-ENOMEM); |
116 | 252 | ||
117 | tu->call.class = &tu->class; | 253 | tu->tp.call.class = &tu->tp.class; |
118 | tu->call.name = kstrdup(event, GFP_KERNEL); | 254 | tu->tp.call.name = kstrdup(event, GFP_KERNEL); |
119 | if (!tu->call.name) | 255 | if (!tu->tp.call.name) |
120 | goto error; | 256 | goto error; |
121 | 257 | ||
122 | tu->class.system = kstrdup(group, GFP_KERNEL); | 258 | tu->tp.class.system = kstrdup(group, GFP_KERNEL); |
123 | if (!tu->class.system) | 259 | if (!tu->tp.class.system) |
124 | goto error; | 260 | goto error; |
125 | 261 | ||
126 | INIT_LIST_HEAD(&tu->list); | 262 | INIT_LIST_HEAD(&tu->list); |
@@ -128,11 +264,11 @@ alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret) | |||
128 | if (is_ret) | 264 | if (is_ret) |
129 | tu->consumer.ret_handler = uretprobe_dispatcher; | 265 | tu->consumer.ret_handler = uretprobe_dispatcher; |
130 | init_trace_uprobe_filter(&tu->filter); | 266 | init_trace_uprobe_filter(&tu->filter); |
131 | tu->call.flags |= TRACE_EVENT_FL_USE_CALL_FILTER; | 267 | tu->tp.call.flags |= TRACE_EVENT_FL_USE_CALL_FILTER; |
132 | return tu; | 268 | return tu; |
133 | 269 | ||
134 | error: | 270 | error: |
135 | kfree(tu->call.name); | 271 | kfree(tu->tp.call.name); |
136 | kfree(tu); | 272 | kfree(tu); |
137 | 273 | ||
138 | return ERR_PTR(-ENOMEM); | 274 | return ERR_PTR(-ENOMEM); |
@@ -142,12 +278,12 @@ static void free_trace_uprobe(struct trace_uprobe *tu) | |||
142 | { | 278 | { |
143 | int i; | 279 | int i; |
144 | 280 | ||
145 | for (i = 0; i < tu->nr_args; i++) | 281 | for (i = 0; i < tu->tp.nr_args; i++) |
146 | traceprobe_free_probe_arg(&tu->args[i]); | 282 | traceprobe_free_probe_arg(&tu->tp.args[i]); |
147 | 283 | ||
148 | iput(tu->inode); | 284 | iput(tu->inode); |
149 | kfree(tu->call.class->system); | 285 | kfree(tu->tp.call.class->system); |
150 | kfree(tu->call.name); | 286 | kfree(tu->tp.call.name); |
151 | kfree(tu->filename); | 287 | kfree(tu->filename); |
152 | kfree(tu); | 288 | kfree(tu); |
153 | } | 289 | } |
@@ -157,8 +293,8 @@ static struct trace_uprobe *find_probe_event(const char *event, const char *grou | |||
157 | struct trace_uprobe *tu; | 293 | struct trace_uprobe *tu; |
158 | 294 | ||
159 | list_for_each_entry(tu, &uprobe_list, list) | 295 | list_for_each_entry(tu, &uprobe_list, list) |
160 | if (strcmp(tu->call.name, event) == 0 && | 296 | if (strcmp(tu->tp.call.name, event) == 0 && |
161 | strcmp(tu->call.class->system, group) == 0) | 297 | strcmp(tu->tp.call.class->system, group) == 0) |
162 | return tu; | 298 | return tu; |
163 | 299 | ||
164 | return NULL; | 300 | return NULL; |
@@ -181,16 +317,16 @@ static int unregister_trace_uprobe(struct trace_uprobe *tu) | |||
181 | /* Register a trace_uprobe and probe_event */ | 317 | /* Register a trace_uprobe and probe_event */ |
182 | static int register_trace_uprobe(struct trace_uprobe *tu) | 318 | static int register_trace_uprobe(struct trace_uprobe *tu) |
183 | { | 319 | { |
184 | struct trace_uprobe *old_tp; | 320 | struct trace_uprobe *old_tu; |
185 | int ret; | 321 | int ret; |
186 | 322 | ||
187 | mutex_lock(&uprobe_lock); | 323 | mutex_lock(&uprobe_lock); |
188 | 324 | ||
189 | /* register as an event */ | 325 | /* register as an event */ |
190 | old_tp = find_probe_event(tu->call.name, tu->call.class->system); | 326 | old_tu = find_probe_event(tu->tp.call.name, tu->tp.call.class->system); |
191 | if (old_tp) { | 327 | if (old_tu) { |
192 | /* delete old event */ | 328 | /* delete old event */ |
193 | ret = unregister_trace_uprobe(old_tp); | 329 | ret = unregister_trace_uprobe(old_tu); |
194 | if (ret) | 330 | if (ret) |
195 | goto end; | 331 | goto end; |
196 | } | 332 | } |
@@ -211,7 +347,7 @@ end: | |||
211 | 347 | ||
212 | /* | 348 | /* |
213 | * Argument syntax: | 349 | * Argument syntax: |
214 | * - Add uprobe: p|r[:[GRP/]EVENT] PATH:SYMBOL [FETCHARGS] | 350 | * - Add uprobe: p|r[:[GRP/]EVENT] PATH:OFFSET [FETCHARGS] |
215 | * | 351 | * |
216 | * - Remove uprobe: -:[GRP/]EVENT | 352 | * - Remove uprobe: -:[GRP/]EVENT |
217 | */ | 353 | */ |
@@ -360,34 +496,36 @@ static int create_trace_uprobe(int argc, char **argv) | |||
360 | /* parse arguments */ | 496 | /* parse arguments */ |
361 | ret = 0; | 497 | ret = 0; |
362 | for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { | 498 | for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { |
499 | struct probe_arg *parg = &tu->tp.args[i]; | ||
500 | |||
363 | /* Increment count for freeing args in error case */ | 501 | /* Increment count for freeing args in error case */ |
364 | tu->nr_args++; | 502 | tu->tp.nr_args++; |
365 | 503 | ||
366 | /* Parse argument name */ | 504 | /* Parse argument name */ |
367 | arg = strchr(argv[i], '='); | 505 | arg = strchr(argv[i], '='); |
368 | if (arg) { | 506 | if (arg) { |
369 | *arg++ = '\0'; | 507 | *arg++ = '\0'; |
370 | tu->args[i].name = kstrdup(argv[i], GFP_KERNEL); | 508 | parg->name = kstrdup(argv[i], GFP_KERNEL); |
371 | } else { | 509 | } else { |
372 | arg = argv[i]; | 510 | arg = argv[i]; |
373 | /* If argument name is omitted, set "argN" */ | 511 | /* If argument name is omitted, set "argN" */ |
374 | snprintf(buf, MAX_EVENT_NAME_LEN, "arg%d", i + 1); | 512 | snprintf(buf, MAX_EVENT_NAME_LEN, "arg%d", i + 1); |
375 | tu->args[i].name = kstrdup(buf, GFP_KERNEL); | 513 | parg->name = kstrdup(buf, GFP_KERNEL); |
376 | } | 514 | } |
377 | 515 | ||
378 | if (!tu->args[i].name) { | 516 | if (!parg->name) { |
379 | pr_info("Failed to allocate argument[%d] name.\n", i); | 517 | pr_info("Failed to allocate argument[%d] name.\n", i); |
380 | ret = -ENOMEM; | 518 | ret = -ENOMEM; |
381 | goto error; | 519 | goto error; |
382 | } | 520 | } |
383 | 521 | ||
384 | if (!is_good_name(tu->args[i].name)) { | 522 | if (!is_good_name(parg->name)) { |
385 | pr_info("Invalid argument[%d] name: %s\n", i, tu->args[i].name); | 523 | pr_info("Invalid argument[%d] name: %s\n", i, parg->name); |
386 | ret = -EINVAL; | 524 | ret = -EINVAL; |
387 | goto error; | 525 | goto error; |
388 | } | 526 | } |
389 | 527 | ||
390 | if (traceprobe_conflict_field_name(tu->args[i].name, tu->args, i)) { | 528 | if (traceprobe_conflict_field_name(parg->name, tu->tp.args, i)) { |
391 | pr_info("Argument[%d] name '%s' conflicts with " | 529 | pr_info("Argument[%d] name '%s' conflicts with " |
392 | "another field.\n", i, argv[i]); | 530 | "another field.\n", i, argv[i]); |
393 | ret = -EINVAL; | 531 | ret = -EINVAL; |
@@ -395,7 +533,8 @@ static int create_trace_uprobe(int argc, char **argv) | |||
395 | } | 533 | } |
396 | 534 | ||
397 | /* Parse fetch argument */ | 535 | /* Parse fetch argument */ |
398 | ret = traceprobe_parse_probe_arg(arg, &tu->size, &tu->args[i], false, false); | 536 | ret = traceprobe_parse_probe_arg(arg, &tu->tp.size, parg, |
537 | is_return, false); | ||
399 | if (ret) { | 538 | if (ret) { |
400 | pr_info("Parse error at argument[%d]. (%d)\n", i, ret); | 539 | pr_info("Parse error at argument[%d]. (%d)\n", i, ret); |
401 | goto error; | 540 | goto error; |
@@ -459,11 +598,11 @@ static int probes_seq_show(struct seq_file *m, void *v) | |||
459 | char c = is_ret_probe(tu) ? 'r' : 'p'; | 598 | char c = is_ret_probe(tu) ? 'r' : 'p'; |
460 | int i; | 599 | int i; |
461 | 600 | ||
462 | seq_printf(m, "%c:%s/%s", c, tu->call.class->system, tu->call.name); | 601 | seq_printf(m, "%c:%s/%s", c, tu->tp.call.class->system, tu->tp.call.name); |
463 | seq_printf(m, " %s:0x%p", tu->filename, (void *)tu->offset); | 602 | seq_printf(m, " %s:0x%p", tu->filename, (void *)tu->offset); |
464 | 603 | ||
465 | for (i = 0; i < tu->nr_args; i++) | 604 | for (i = 0; i < tu->tp.nr_args; i++) |
466 | seq_printf(m, " %s=%s", tu->args[i].name, tu->args[i].comm); | 605 | seq_printf(m, " %s=%s", tu->tp.args[i].name, tu->tp.args[i].comm); |
467 | 606 | ||
468 | seq_printf(m, "\n"); | 607 | seq_printf(m, "\n"); |
469 | return 0; | 608 | return 0; |
@@ -509,7 +648,7 @@ static int probes_profile_seq_show(struct seq_file *m, void *v) | |||
509 | { | 648 | { |
510 | struct trace_uprobe *tu = v; | 649 | struct trace_uprobe *tu = v; |
511 | 650 | ||
512 | seq_printf(m, " %s %-44s %15lu\n", tu->filename, tu->call.name, tu->nhit); | 651 | seq_printf(m, " %s %-44s %15lu\n", tu->filename, tu->tp.call.name, tu->nhit); |
513 | return 0; | 652 | return 0; |
514 | } | 653 | } |
515 | 654 | ||
@@ -533,21 +672,117 @@ static const struct file_operations uprobe_profile_ops = { | |||
533 | .release = seq_release, | 672 | .release = seq_release, |
534 | }; | 673 | }; |
535 | 674 | ||
675 | struct uprobe_cpu_buffer { | ||
676 | struct mutex mutex; | ||
677 | void *buf; | ||
678 | }; | ||
679 | static struct uprobe_cpu_buffer __percpu *uprobe_cpu_buffer; | ||
680 | static int uprobe_buffer_refcnt; | ||
681 | |||
682 | static int uprobe_buffer_init(void) | ||
683 | { | ||
684 | int cpu, err_cpu; | ||
685 | |||
686 | uprobe_cpu_buffer = alloc_percpu(struct uprobe_cpu_buffer); | ||
687 | if (uprobe_cpu_buffer == NULL) | ||
688 | return -ENOMEM; | ||
689 | |||
690 | for_each_possible_cpu(cpu) { | ||
691 | struct page *p = alloc_pages_node(cpu_to_node(cpu), | ||
692 | GFP_KERNEL, 0); | ||
693 | if (p == NULL) { | ||
694 | err_cpu = cpu; | ||
695 | goto err; | ||
696 | } | ||
697 | per_cpu_ptr(uprobe_cpu_buffer, cpu)->buf = page_address(p); | ||
698 | mutex_init(&per_cpu_ptr(uprobe_cpu_buffer, cpu)->mutex); | ||
699 | } | ||
700 | |||
701 | return 0; | ||
702 | |||
703 | err: | ||
704 | for_each_possible_cpu(cpu) { | ||
705 | if (cpu == err_cpu) | ||
706 | break; | ||
707 | free_page((unsigned long)per_cpu_ptr(uprobe_cpu_buffer, cpu)->buf); | ||
708 | } | ||
709 | |||
710 | free_percpu(uprobe_cpu_buffer); | ||
711 | return -ENOMEM; | ||
712 | } | ||
713 | |||
714 | static int uprobe_buffer_enable(void) | ||
715 | { | ||
716 | int ret = 0; | ||
717 | |||
718 | BUG_ON(!mutex_is_locked(&event_mutex)); | ||
719 | |||
720 | if (uprobe_buffer_refcnt++ == 0) { | ||
721 | ret = uprobe_buffer_init(); | ||
722 | if (ret < 0) | ||
723 | uprobe_buffer_refcnt--; | ||
724 | } | ||
725 | |||
726 | return ret; | ||
727 | } | ||
728 | |||
729 | static void uprobe_buffer_disable(void) | ||
730 | { | ||
731 | BUG_ON(!mutex_is_locked(&event_mutex)); | ||
732 | |||
733 | if (--uprobe_buffer_refcnt == 0) { | ||
734 | free_percpu(uprobe_cpu_buffer); | ||
735 | uprobe_cpu_buffer = NULL; | ||
736 | } | ||
737 | } | ||
738 | |||
739 | static struct uprobe_cpu_buffer *uprobe_buffer_get(void) | ||
740 | { | ||
741 | struct uprobe_cpu_buffer *ucb; | ||
742 | int cpu; | ||
743 | |||
744 | cpu = raw_smp_processor_id(); | ||
745 | ucb = per_cpu_ptr(uprobe_cpu_buffer, cpu); | ||
746 | |||
747 | /* | ||
748 | * Use per-cpu buffers for fastest access, but we might migrate | ||
749 | * so the mutex makes sure we have sole access to it. | ||
750 | */ | ||
751 | mutex_lock(&ucb->mutex); | ||
752 | |||
753 | return ucb; | ||
754 | } | ||
755 | |||
756 | static void uprobe_buffer_put(struct uprobe_cpu_buffer *ucb) | ||
757 | { | ||
758 | mutex_unlock(&ucb->mutex); | ||
759 | } | ||
760 | |||
536 | static void uprobe_trace_print(struct trace_uprobe *tu, | 761 | static void uprobe_trace_print(struct trace_uprobe *tu, |
537 | unsigned long func, struct pt_regs *regs) | 762 | unsigned long func, struct pt_regs *regs) |
538 | { | 763 | { |
539 | struct uprobe_trace_entry_head *entry; | 764 | struct uprobe_trace_entry_head *entry; |
540 | struct ring_buffer_event *event; | 765 | struct ring_buffer_event *event; |
541 | struct ring_buffer *buffer; | 766 | struct ring_buffer *buffer; |
767 | struct uprobe_cpu_buffer *ucb; | ||
542 | void *data; | 768 | void *data; |
543 | int size, i; | 769 | int size, dsize, esize; |
544 | struct ftrace_event_call *call = &tu->call; | 770 | struct ftrace_event_call *call = &tu->tp.call; |
771 | |||
772 | dsize = __get_data_size(&tu->tp, regs); | ||
773 | esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); | ||
545 | 774 | ||
546 | size = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); | 775 | if (WARN_ON_ONCE(!uprobe_cpu_buffer || tu->tp.size + dsize > PAGE_SIZE)) |
776 | return; | ||
777 | |||
778 | ucb = uprobe_buffer_get(); | ||
779 | store_trace_args(esize, &tu->tp, regs, ucb->buf, dsize); | ||
780 | |||
781 | size = esize + tu->tp.size + dsize; | ||
547 | event = trace_current_buffer_lock_reserve(&buffer, call->event.type, | 782 | event = trace_current_buffer_lock_reserve(&buffer, call->event.type, |
548 | size + tu->size, 0, 0); | 783 | size, 0, 0); |
549 | if (!event) | 784 | if (!event) |
550 | return; | 785 | goto out; |
551 | 786 | ||
552 | entry = ring_buffer_event_data(event); | 787 | entry = ring_buffer_event_data(event); |
553 | if (is_ret_probe(tu)) { | 788 | if (is_ret_probe(tu)) { |
@@ -559,11 +794,13 @@ static void uprobe_trace_print(struct trace_uprobe *tu, | |||
559 | data = DATAOF_TRACE_ENTRY(entry, false); | 794 | data = DATAOF_TRACE_ENTRY(entry, false); |
560 | } | 795 | } |
561 | 796 | ||
562 | for (i = 0; i < tu->nr_args; i++) | 797 | memcpy(data, ucb->buf, tu->tp.size + dsize); |
563 | call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset); | ||
564 | 798 | ||
565 | if (!call_filter_check_discard(call, entry, buffer, event)) | 799 | if (!call_filter_check_discard(call, entry, buffer, event)) |
566 | trace_buffer_unlock_commit(buffer, event, 0, 0); | 800 | trace_buffer_unlock_commit(buffer, event, 0, 0); |
801 | |||
802 | out: | ||
803 | uprobe_buffer_put(ucb); | ||
567 | } | 804 | } |
568 | 805 | ||
569 | /* uprobe handler */ | 806 | /* uprobe handler */ |
@@ -591,23 +828,24 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *e | |||
591 | int i; | 828 | int i; |
592 | 829 | ||
593 | entry = (struct uprobe_trace_entry_head *)iter->ent; | 830 | entry = (struct uprobe_trace_entry_head *)iter->ent; |
594 | tu = container_of(event, struct trace_uprobe, call.event); | 831 | tu = container_of(event, struct trace_uprobe, tp.call.event); |
595 | 832 | ||
596 | if (is_ret_probe(tu)) { | 833 | if (is_ret_probe(tu)) { |
597 | if (!trace_seq_printf(s, "%s: (0x%lx <- 0x%lx)", tu->call.name, | 834 | if (!trace_seq_printf(s, "%s: (0x%lx <- 0x%lx)", tu->tp.call.name, |
598 | entry->vaddr[1], entry->vaddr[0])) | 835 | entry->vaddr[1], entry->vaddr[0])) |
599 | goto partial; | 836 | goto partial; |
600 | data = DATAOF_TRACE_ENTRY(entry, true); | 837 | data = DATAOF_TRACE_ENTRY(entry, true); |
601 | } else { | 838 | } else { |
602 | if (!trace_seq_printf(s, "%s: (0x%lx)", tu->call.name, | 839 | if (!trace_seq_printf(s, "%s: (0x%lx)", tu->tp.call.name, |
603 | entry->vaddr[0])) | 840 | entry->vaddr[0])) |
604 | goto partial; | 841 | goto partial; |
605 | data = DATAOF_TRACE_ENTRY(entry, false); | 842 | data = DATAOF_TRACE_ENTRY(entry, false); |
606 | } | 843 | } |
607 | 844 | ||
608 | for (i = 0; i < tu->nr_args; i++) { | 845 | for (i = 0; i < tu->tp.nr_args; i++) { |
609 | if (!tu->args[i].type->print(s, tu->args[i].name, | 846 | struct probe_arg *parg = &tu->tp.args[i]; |
610 | data + tu->args[i].offset, entry)) | 847 | |
848 | if (!parg->type->print(s, parg->name, data + parg->offset, entry)) | ||
611 | goto partial; | 849 | goto partial; |
612 | } | 850 | } |
613 | 851 | ||
@@ -618,11 +856,6 @@ partial: | |||
618 | return TRACE_TYPE_PARTIAL_LINE; | 856 | return TRACE_TYPE_PARTIAL_LINE; |
619 | } | 857 | } |
620 | 858 | ||
621 | static inline bool is_trace_uprobe_enabled(struct trace_uprobe *tu) | ||
622 | { | ||
623 | return tu->flags & (TP_FLAG_TRACE | TP_FLAG_PROFILE); | ||
624 | } | ||
625 | |||
626 | typedef bool (*filter_func_t)(struct uprobe_consumer *self, | 859 | typedef bool (*filter_func_t)(struct uprobe_consumer *self, |
627 | enum uprobe_filter_ctx ctx, | 860 | enum uprobe_filter_ctx ctx, |
628 | struct mm_struct *mm); | 861 | struct mm_struct *mm); |
@@ -632,29 +865,35 @@ probe_event_enable(struct trace_uprobe *tu, int flag, filter_func_t filter) | |||
632 | { | 865 | { |
633 | int ret = 0; | 866 | int ret = 0; |
634 | 867 | ||
635 | if (is_trace_uprobe_enabled(tu)) | 868 | if (trace_probe_is_enabled(&tu->tp)) |
636 | return -EINTR; | 869 | return -EINTR; |
637 | 870 | ||
871 | ret = uprobe_buffer_enable(); | ||
872 | if (ret < 0) | ||
873 | return ret; | ||
874 | |||
638 | WARN_ON(!uprobe_filter_is_empty(&tu->filter)); | 875 | WARN_ON(!uprobe_filter_is_empty(&tu->filter)); |
639 | 876 | ||
640 | tu->flags |= flag; | 877 | tu->tp.flags |= flag; |
641 | tu->consumer.filter = filter; | 878 | tu->consumer.filter = filter; |
642 | ret = uprobe_register(tu->inode, tu->offset, &tu->consumer); | 879 | ret = uprobe_register(tu->inode, tu->offset, &tu->consumer); |
643 | if (ret) | 880 | if (ret) |
644 | tu->flags &= ~flag; | 881 | tu->tp.flags &= ~flag; |
645 | 882 | ||
646 | return ret; | 883 | return ret; |
647 | } | 884 | } |
648 | 885 | ||
649 | static void probe_event_disable(struct trace_uprobe *tu, int flag) | 886 | static void probe_event_disable(struct trace_uprobe *tu, int flag) |
650 | { | 887 | { |
651 | if (!is_trace_uprobe_enabled(tu)) | 888 | if (!trace_probe_is_enabled(&tu->tp)) |
652 | return; | 889 | return; |
653 | 890 | ||
654 | WARN_ON(!uprobe_filter_is_empty(&tu->filter)); | 891 | WARN_ON(!uprobe_filter_is_empty(&tu->filter)); |
655 | 892 | ||
656 | uprobe_unregister(tu->inode, tu->offset, &tu->consumer); | 893 | uprobe_unregister(tu->inode, tu->offset, &tu->consumer); |
657 | tu->flags &= ~flag; | 894 | tu->tp.flags &= ~flag; |
895 | |||
896 | uprobe_buffer_disable(); | ||
658 | } | 897 | } |
659 | 898 | ||
660 | static int uprobe_event_define_fields(struct ftrace_event_call *event_call) | 899 | static int uprobe_event_define_fields(struct ftrace_event_call *event_call) |
@@ -672,12 +911,12 @@ static int uprobe_event_define_fields(struct ftrace_event_call *event_call) | |||
672 | size = SIZEOF_TRACE_ENTRY(false); | 911 | size = SIZEOF_TRACE_ENTRY(false); |
673 | } | 912 | } |
674 | /* Set argument names as fields */ | 913 | /* Set argument names as fields */ |
675 | for (i = 0; i < tu->nr_args; i++) { | 914 | for (i = 0; i < tu->tp.nr_args; i++) { |
676 | ret = trace_define_field(event_call, tu->args[i].type->fmttype, | 915 | struct probe_arg *parg = &tu->tp.args[i]; |
677 | tu->args[i].name, | 916 | |
678 | size + tu->args[i].offset, | 917 | ret = trace_define_field(event_call, parg->type->fmttype, |
679 | tu->args[i].type->size, | 918 | parg->name, size + parg->offset, |
680 | tu->args[i].type->is_signed, | 919 | parg->type->size, parg->type->is_signed, |
681 | FILTER_OTHER); | 920 | FILTER_OTHER); |
682 | 921 | ||
683 | if (ret) | 922 | if (ret) |
@@ -686,59 +925,6 @@ static int uprobe_event_define_fields(struct ftrace_event_call *event_call) | |||
686 | return 0; | 925 | return 0; |
687 | } | 926 | } |
688 | 927 | ||
689 | #define LEN_OR_ZERO (len ? len - pos : 0) | ||
690 | static int __set_print_fmt(struct trace_uprobe *tu, char *buf, int len) | ||
691 | { | ||
692 | const char *fmt, *arg; | ||
693 | int i; | ||
694 | int pos = 0; | ||
695 | |||
696 | if (is_ret_probe(tu)) { | ||
697 | fmt = "(%lx <- %lx)"; | ||
698 | arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP; | ||
699 | } else { | ||
700 | fmt = "(%lx)"; | ||
701 | arg = "REC->" FIELD_STRING_IP; | ||
702 | } | ||
703 | |||
704 | /* When len=0, we just calculate the needed length */ | ||
705 | |||
706 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); | ||
707 | |||
708 | for (i = 0; i < tu->nr_args; i++) { | ||
709 | pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%s", | ||
710 | tu->args[i].name, tu->args[i].type->fmt); | ||
711 | } | ||
712 | |||
713 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); | ||
714 | |||
715 | for (i = 0; i < tu->nr_args; i++) { | ||
716 | pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s", | ||
717 | tu->args[i].name); | ||
718 | } | ||
719 | |||
720 | return pos; /* return the length of print_fmt */ | ||
721 | } | ||
722 | #undef LEN_OR_ZERO | ||
723 | |||
724 | static int set_print_fmt(struct trace_uprobe *tu) | ||
725 | { | ||
726 | char *print_fmt; | ||
727 | int len; | ||
728 | |||
729 | /* First: called with 0 length to calculate the needed length */ | ||
730 | len = __set_print_fmt(tu, NULL, 0); | ||
731 | print_fmt = kmalloc(len + 1, GFP_KERNEL); | ||
732 | if (!print_fmt) | ||
733 | return -ENOMEM; | ||
734 | |||
735 | /* Second: actually write the @print_fmt */ | ||
736 | __set_print_fmt(tu, print_fmt, len + 1); | ||
737 | tu->call.print_fmt = print_fmt; | ||
738 | |||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | #ifdef CONFIG_PERF_EVENTS | 928 | #ifdef CONFIG_PERF_EVENTS |
743 | static bool | 929 | static bool |
744 | __uprobe_perf_filter(struct trace_uprobe_filter *filter, struct mm_struct *mm) | 930 | __uprobe_perf_filter(struct trace_uprobe_filter *filter, struct mm_struct *mm) |
@@ -831,14 +1017,27 @@ static bool uprobe_perf_filter(struct uprobe_consumer *uc, | |||
831 | static void uprobe_perf_print(struct trace_uprobe *tu, | 1017 | static void uprobe_perf_print(struct trace_uprobe *tu, |
832 | unsigned long func, struct pt_regs *regs) | 1018 | unsigned long func, struct pt_regs *regs) |
833 | { | 1019 | { |
834 | struct ftrace_event_call *call = &tu->call; | 1020 | struct ftrace_event_call *call = &tu->tp.call; |
835 | struct uprobe_trace_entry_head *entry; | 1021 | struct uprobe_trace_entry_head *entry; |
836 | struct hlist_head *head; | 1022 | struct hlist_head *head; |
1023 | struct uprobe_cpu_buffer *ucb; | ||
837 | void *data; | 1024 | void *data; |
838 | int size, rctx, i; | 1025 | int size, dsize, esize; |
1026 | int rctx; | ||
839 | 1027 | ||
840 | size = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); | 1028 | dsize = __get_data_size(&tu->tp, regs); |
841 | size = ALIGN(size + tu->size + sizeof(u32), sizeof(u64)) - sizeof(u32); | 1029 | esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); |
1030 | |||
1031 | if (WARN_ON_ONCE(!uprobe_cpu_buffer)) | ||
1032 | return; | ||
1033 | |||
1034 | size = esize + tu->tp.size + dsize; | ||
1035 | size = ALIGN(size + sizeof(u32), sizeof(u64)) - sizeof(u32); | ||
1036 | if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough")) | ||
1037 | return; | ||
1038 | |||
1039 | ucb = uprobe_buffer_get(); | ||
1040 | store_trace_args(esize, &tu->tp, regs, ucb->buf, dsize); | ||
842 | 1041 | ||
843 | preempt_disable(); | 1042 | preempt_disable(); |
844 | head = this_cpu_ptr(call->perf_events); | 1043 | head = this_cpu_ptr(call->perf_events); |
@@ -858,12 +1057,18 @@ static void uprobe_perf_print(struct trace_uprobe *tu, | |||
858 | data = DATAOF_TRACE_ENTRY(entry, false); | 1057 | data = DATAOF_TRACE_ENTRY(entry, false); |
859 | } | 1058 | } |
860 | 1059 | ||
861 | for (i = 0; i < tu->nr_args; i++) | 1060 | memcpy(data, ucb->buf, tu->tp.size + dsize); |
862 | call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset); | 1061 | |
1062 | if (size - esize > tu->tp.size + dsize) { | ||
1063 | int len = tu->tp.size + dsize; | ||
1064 | |||
1065 | memset(data + len, 0, size - esize - len); | ||
1066 | } | ||
863 | 1067 | ||
864 | perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL); | 1068 | perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL); |
865 | out: | 1069 | out: |
866 | preempt_enable(); | 1070 | preempt_enable(); |
1071 | uprobe_buffer_put(ucb); | ||
867 | } | 1072 | } |
868 | 1073 | ||
869 | /* uprobe profile handler */ | 1074 | /* uprobe profile handler */ |
@@ -921,16 +1126,22 @@ int trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type, | |||
921 | static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs) | 1126 | static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs) |
922 | { | 1127 | { |
923 | struct trace_uprobe *tu; | 1128 | struct trace_uprobe *tu; |
1129 | struct uprobe_dispatch_data udd; | ||
924 | int ret = 0; | 1130 | int ret = 0; |
925 | 1131 | ||
926 | tu = container_of(con, struct trace_uprobe, consumer); | 1132 | tu = container_of(con, struct trace_uprobe, consumer); |
927 | tu->nhit++; | 1133 | tu->nhit++; |
928 | 1134 | ||
929 | if (tu->flags & TP_FLAG_TRACE) | 1135 | udd.tu = tu; |
1136 | udd.bp_addr = instruction_pointer(regs); | ||
1137 | |||
1138 | current->utask->vaddr = (unsigned long) &udd; | ||
1139 | |||
1140 | if (tu->tp.flags & TP_FLAG_TRACE) | ||
930 | ret |= uprobe_trace_func(tu, regs); | 1141 | ret |= uprobe_trace_func(tu, regs); |
931 | 1142 | ||
932 | #ifdef CONFIG_PERF_EVENTS | 1143 | #ifdef CONFIG_PERF_EVENTS |
933 | if (tu->flags & TP_FLAG_PROFILE) | 1144 | if (tu->tp.flags & TP_FLAG_PROFILE) |
934 | ret |= uprobe_perf_func(tu, regs); | 1145 | ret |= uprobe_perf_func(tu, regs); |
935 | #endif | 1146 | #endif |
936 | return ret; | 1147 | return ret; |
@@ -940,14 +1151,20 @@ static int uretprobe_dispatcher(struct uprobe_consumer *con, | |||
940 | unsigned long func, struct pt_regs *regs) | 1151 | unsigned long func, struct pt_regs *regs) |
941 | { | 1152 | { |
942 | struct trace_uprobe *tu; | 1153 | struct trace_uprobe *tu; |
1154 | struct uprobe_dispatch_data udd; | ||
943 | 1155 | ||
944 | tu = container_of(con, struct trace_uprobe, consumer); | 1156 | tu = container_of(con, struct trace_uprobe, consumer); |
945 | 1157 | ||
946 | if (tu->flags & TP_FLAG_TRACE) | 1158 | udd.tu = tu; |
1159 | udd.bp_addr = func; | ||
1160 | |||
1161 | current->utask->vaddr = (unsigned long) &udd; | ||
1162 | |||
1163 | if (tu->tp.flags & TP_FLAG_TRACE) | ||
947 | uretprobe_trace_func(tu, func, regs); | 1164 | uretprobe_trace_func(tu, func, regs); |
948 | 1165 | ||
949 | #ifdef CONFIG_PERF_EVENTS | 1166 | #ifdef CONFIG_PERF_EVENTS |
950 | if (tu->flags & TP_FLAG_PROFILE) | 1167 | if (tu->tp.flags & TP_FLAG_PROFILE) |
951 | uretprobe_perf_func(tu, func, regs); | 1168 | uretprobe_perf_func(tu, func, regs); |
952 | #endif | 1169 | #endif |
953 | return 0; | 1170 | return 0; |
@@ -959,7 +1176,7 @@ static struct trace_event_functions uprobe_funcs = { | |||
959 | 1176 | ||
960 | static int register_uprobe_event(struct trace_uprobe *tu) | 1177 | static int register_uprobe_event(struct trace_uprobe *tu) |
961 | { | 1178 | { |
962 | struct ftrace_event_call *call = &tu->call; | 1179 | struct ftrace_event_call *call = &tu->tp.call; |
963 | int ret; | 1180 | int ret; |
964 | 1181 | ||
965 | /* Initialize ftrace_event_call */ | 1182 | /* Initialize ftrace_event_call */ |
@@ -967,7 +1184,7 @@ static int register_uprobe_event(struct trace_uprobe *tu) | |||
967 | call->event.funcs = &uprobe_funcs; | 1184 | call->event.funcs = &uprobe_funcs; |
968 | call->class->define_fields = uprobe_event_define_fields; | 1185 | call->class->define_fields = uprobe_event_define_fields; |
969 | 1186 | ||
970 | if (set_print_fmt(tu) < 0) | 1187 | if (set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) |
971 | return -ENOMEM; | 1188 | return -ENOMEM; |
972 | 1189 | ||
973 | ret = register_ftrace_event(&call->event); | 1190 | ret = register_ftrace_event(&call->event); |
@@ -994,11 +1211,11 @@ static int unregister_uprobe_event(struct trace_uprobe *tu) | |||
994 | int ret; | 1211 | int ret; |
995 | 1212 | ||
996 | /* tu->event is unregistered in trace_remove_event_call() */ | 1213 | /* tu->event is unregistered in trace_remove_event_call() */ |
997 | ret = trace_remove_event_call(&tu->call); | 1214 | ret = trace_remove_event_call(&tu->tp.call); |
998 | if (ret) | 1215 | if (ret) |
999 | return ret; | 1216 | return ret; |
1000 | kfree(tu->call.print_fmt); | 1217 | kfree(tu->tp.call.print_fmt); |
1001 | tu->call.print_fmt = NULL; | 1218 | tu->tp.call.print_fmt = NULL; |
1002 | return 0; | 1219 | return 0; |
1003 | } | 1220 | } |
1004 | 1221 | ||