diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-02-28 13:17:55 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-02-28 13:17:55 -0500 |
commit | e0d272429a34ff143bfa04ee8e29dd4eed2964c7 (patch) | |
tree | 5a719135b245811b5d61ed084d7b8c1bc2e87031 /kernel/trace/trace_kprobe.c | |
parent | d25e8dbdab203ed8b4fd0a174bb5259e35ecd87c (diff) | |
parent | 480917427b0b6ff39de55ffc81391055472e6c26 (diff) |
Merge branch 'tracing-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'tracing-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (28 commits)
ftrace: Add function names to dangling } in function graph tracer
tracing: Simplify memory recycle of trace_define_field
tracing: Remove unnecessary variable in print_graph_return
tracing: Fix typo of info text in trace_kprobe.c
tracing: Fix typo in prof_sysexit_enable()
tracing: Remove CONFIG_TRACE_POWER from kernel config
tracing: Fix ftrace_event_call alignment for use with gcc 4.5
ftrace: Remove memory barriers from NMI code when not needed
tracing/kprobes: Add short documentation for HAVE_REGS_AND_STACK_ACCESS_API
s390: Add pt_regs register and stack access API
tracing/kprobes: Make Kconfig dependencies generic
tracing: Unify arch_syscall_addr() implementations
tracing: Add notrace to TRACE_EVENT implementation functions
ftrace: Allow to remove a single function from function graph filter
tracing: Add correct/incorrect to sort keys for branch annotation output
tracing: Simplify test for function_graph tracing start point
tracing: Drop the tr check from the graph tracing path
tracing: Add stack dump to trace_printk if stacktrace option is set
tracing: Use appropriate perl constructs in recordmcount.pl
tracing: optimize recordmcount.pl for offsets-handling
...
Diffstat (limited to 'kernel/trace/trace_kprobe.c')
-rw-r--r-- | kernel/trace/trace_kprobe.c | 108 |
1 files changed, 46 insertions, 62 deletions
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 50b1b8239806..465b36bef4ca 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -651,12 +651,12 @@ static int create_trace_probe(int argc, char **argv) | |||
651 | event = strchr(group, '/') + 1; | 651 | event = strchr(group, '/') + 1; |
652 | event[-1] = '\0'; | 652 | event[-1] = '\0'; |
653 | if (strlen(group) == 0) { | 653 | if (strlen(group) == 0) { |
654 | pr_info("Group name is not specifiled\n"); | 654 | pr_info("Group name is not specified\n"); |
655 | return -EINVAL; | 655 | return -EINVAL; |
656 | } | 656 | } |
657 | } | 657 | } |
658 | if (strlen(event) == 0) { | 658 | if (strlen(event) == 0) { |
659 | pr_info("Event name is not specifiled\n"); | 659 | pr_info("Event name is not specified\n"); |
660 | return -EINVAL; | 660 | return -EINVAL; |
661 | } | 661 | } |
662 | } | 662 | } |
@@ -1174,80 +1174,60 @@ static int kretprobe_event_define_fields(struct ftrace_event_call *event_call) | |||
1174 | return 0; | 1174 | return 0; |
1175 | } | 1175 | } |
1176 | 1176 | ||
1177 | static int __probe_event_show_format(struct trace_seq *s, | 1177 | static int __set_print_fmt(struct trace_probe *tp, char *buf, int len) |
1178 | struct trace_probe *tp, const char *fmt, | ||
1179 | const char *arg) | ||
1180 | { | 1178 | { |
1181 | int i; | 1179 | int i; |
1180 | int pos = 0; | ||
1182 | 1181 | ||
1183 | /* Show format */ | 1182 | const char *fmt, *arg; |
1184 | if (!trace_seq_printf(s, "\nprint fmt: \"%s", fmt)) | ||
1185 | return 0; | ||
1186 | 1183 | ||
1187 | for (i = 0; i < tp->nr_args; i++) | 1184 | if (!probe_is_return(tp)) { |
1188 | if (!trace_seq_printf(s, " %s=%%lx", tp->args[i].name)) | 1185 | fmt = "(%lx)"; |
1189 | return 0; | 1186 | arg = "REC->" FIELD_STRING_IP; |
1187 | } else { | ||
1188 | fmt = "(%lx <- %lx)"; | ||
1189 | arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP; | ||
1190 | } | ||
1190 | 1191 | ||
1191 | if (!trace_seq_printf(s, "\", %s", arg)) | 1192 | /* When len=0, we just calculate the needed length */ |
1192 | return 0; | 1193 | #define LEN_OR_ZERO (len ? len - pos : 0) |
1193 | 1194 | ||
1194 | for (i = 0; i < tp->nr_args; i++) | 1195 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); |
1195 | if (!trace_seq_printf(s, ", REC->%s", tp->args[i].name)) | ||
1196 | return 0; | ||
1197 | 1196 | ||
1198 | return trace_seq_puts(s, "\n"); | 1197 | for (i = 0; i < tp->nr_args; i++) { |
1199 | } | 1198 | pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%%lx", |
1199 | tp->args[i].name); | ||
1200 | } | ||
1200 | 1201 | ||
1201 | #undef SHOW_FIELD | 1202 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); |
1202 | #define SHOW_FIELD(type, item, name) \ | ||
1203 | do { \ | ||
1204 | ret = trace_seq_printf(s, "\tfield:" #type " %s;\t" \ | ||
1205 | "offset:%u;\tsize:%u;\tsigned:%d;\n", name,\ | ||
1206 | (unsigned int)offsetof(typeof(field), item),\ | ||
1207 | (unsigned int)sizeof(type), \ | ||
1208 | is_signed_type(type)); \ | ||
1209 | if (!ret) \ | ||
1210 | return 0; \ | ||
1211 | } while (0) | ||
1212 | 1203 | ||
1213 | static int kprobe_event_show_format(struct ftrace_event_call *call, | 1204 | for (i = 0; i < tp->nr_args; i++) { |
1214 | struct trace_seq *s) | 1205 | pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s", |
1215 | { | 1206 | tp->args[i].name); |
1216 | struct kprobe_trace_entry field __attribute__((unused)); | 1207 | } |
1217 | int ret, i; | ||
1218 | struct trace_probe *tp = (struct trace_probe *)call->data; | ||
1219 | |||
1220 | SHOW_FIELD(unsigned long, ip, FIELD_STRING_IP); | ||
1221 | SHOW_FIELD(int, nargs, FIELD_STRING_NARGS); | ||
1222 | 1208 | ||
1223 | /* Show fields */ | 1209 | #undef LEN_OR_ZERO |
1224 | for (i = 0; i < tp->nr_args; i++) | ||
1225 | SHOW_FIELD(unsigned long, args[i], tp->args[i].name); | ||
1226 | trace_seq_puts(s, "\n"); | ||
1227 | 1210 | ||
1228 | return __probe_event_show_format(s, tp, "(%lx)", | 1211 | /* return the length of print_fmt */ |
1229 | "REC->" FIELD_STRING_IP); | 1212 | return pos; |
1230 | } | 1213 | } |
1231 | 1214 | ||
1232 | static int kretprobe_event_show_format(struct ftrace_event_call *call, | 1215 | static int set_print_fmt(struct trace_probe *tp) |
1233 | struct trace_seq *s) | ||
1234 | { | 1216 | { |
1235 | struct kretprobe_trace_entry field __attribute__((unused)); | 1217 | int len; |
1236 | int ret, i; | 1218 | char *print_fmt; |
1237 | struct trace_probe *tp = (struct trace_probe *)call->data; | ||
1238 | 1219 | ||
1239 | SHOW_FIELD(unsigned long, func, FIELD_STRING_FUNC); | 1220 | /* First: called with 0 length to calculate the needed length */ |
1240 | SHOW_FIELD(unsigned long, ret_ip, FIELD_STRING_RETIP); | 1221 | len = __set_print_fmt(tp, NULL, 0); |
1241 | SHOW_FIELD(int, nargs, FIELD_STRING_NARGS); | 1222 | print_fmt = kmalloc(len + 1, GFP_KERNEL); |
1223 | if (!print_fmt) | ||
1224 | return -ENOMEM; | ||
1242 | 1225 | ||
1243 | /* Show fields */ | 1226 | /* Second: actually write the @print_fmt */ |
1244 | for (i = 0; i < tp->nr_args; i++) | 1227 | __set_print_fmt(tp, print_fmt, len + 1); |
1245 | SHOW_FIELD(unsigned long, args[i], tp->args[i].name); | 1228 | tp->call.print_fmt = print_fmt; |
1246 | trace_seq_puts(s, "\n"); | ||
1247 | 1229 | ||
1248 | return __probe_event_show_format(s, tp, "(%lx <- %lx)", | 1230 | return 0; |
1249 | "REC->" FIELD_STRING_FUNC | ||
1250 | ", REC->" FIELD_STRING_RETIP); | ||
1251 | } | 1231 | } |
1252 | 1232 | ||
1253 | #ifdef CONFIG_EVENT_PROFILE | 1233 | #ifdef CONFIG_EVENT_PROFILE |
@@ -1448,18 +1428,20 @@ static int register_probe_event(struct trace_probe *tp) | |||
1448 | if (probe_is_return(tp)) { | 1428 | if (probe_is_return(tp)) { |
1449 | tp->event.trace = print_kretprobe_event; | 1429 | tp->event.trace = print_kretprobe_event; |
1450 | call->raw_init = probe_event_raw_init; | 1430 | call->raw_init = probe_event_raw_init; |
1451 | call->show_format = kretprobe_event_show_format; | ||
1452 | call->define_fields = kretprobe_event_define_fields; | 1431 | call->define_fields = kretprobe_event_define_fields; |
1453 | } else { | 1432 | } else { |
1454 | tp->event.trace = print_kprobe_event; | 1433 | tp->event.trace = print_kprobe_event; |
1455 | call->raw_init = probe_event_raw_init; | 1434 | call->raw_init = probe_event_raw_init; |
1456 | call->show_format = kprobe_event_show_format; | ||
1457 | call->define_fields = kprobe_event_define_fields; | 1435 | call->define_fields = kprobe_event_define_fields; |
1458 | } | 1436 | } |
1437 | if (set_print_fmt(tp) < 0) | ||
1438 | return -ENOMEM; | ||
1459 | call->event = &tp->event; | 1439 | call->event = &tp->event; |
1460 | call->id = register_ftrace_event(&tp->event); | 1440 | call->id = register_ftrace_event(&tp->event); |
1461 | if (!call->id) | 1441 | if (!call->id) { |
1442 | kfree(call->print_fmt); | ||
1462 | return -ENODEV; | 1443 | return -ENODEV; |
1444 | } | ||
1463 | call->enabled = 0; | 1445 | call->enabled = 0; |
1464 | call->regfunc = probe_event_enable; | 1446 | call->regfunc = probe_event_enable; |
1465 | call->unregfunc = probe_event_disable; | 1447 | call->unregfunc = probe_event_disable; |
@@ -1472,6 +1454,7 @@ static int register_probe_event(struct trace_probe *tp) | |||
1472 | ret = trace_add_event_call(call); | 1454 | ret = trace_add_event_call(call); |
1473 | if (ret) { | 1455 | if (ret) { |
1474 | pr_info("Failed to register kprobe event: %s\n", call->name); | 1456 | pr_info("Failed to register kprobe event: %s\n", call->name); |
1457 | kfree(call->print_fmt); | ||
1475 | unregister_ftrace_event(&tp->event); | 1458 | unregister_ftrace_event(&tp->event); |
1476 | } | 1459 | } |
1477 | return ret; | 1460 | return ret; |
@@ -1481,6 +1464,7 @@ static void unregister_probe_event(struct trace_probe *tp) | |||
1481 | { | 1464 | { |
1482 | /* tp->event is unregistered in trace_remove_event_call() */ | 1465 | /* tp->event is unregistered in trace_remove_event_call() */ |
1483 | trace_remove_event_call(&tp->call); | 1466 | trace_remove_event_call(&tp->call); |
1467 | kfree(tp->call.print_fmt); | ||
1484 | } | 1468 | } |
1485 | 1469 | ||
1486 | /* Make a debugfs interface for controling probe points */ | 1470 | /* Make a debugfs interface for controling probe points */ |