aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_syscalls.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2010-02-17 12:27:37 -0500
committerThomas Gleixner <tglx@linutronix.de>2010-02-17 12:28:05 -0500
commitb7e56edba4b02f2079042c326a8cd72a44635817 (patch)
treeb5042002e9747cd8fb1278d61f86d8b92a74c018 /kernel/trace/trace_syscalls.c
parent13ca0fcaa33f6b1984c4111b6ec5df42689fea6f (diff)
parentb0483e78e5c4c9871fc5541875b3bc006846d46b (diff)
Merge branch 'linus' into x86/mm
x86/mm is on 32-rc4 and missing the spinlock namespace changes which are needed for further commits into this topic. Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/trace/trace_syscalls.c')
-rw-r--r--kernel/trace/trace_syscalls.c235
1 files changed, 142 insertions, 93 deletions
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 527e17eae575..75289f372dd2 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -14,6 +14,43 @@ static int sys_refcount_exit;
14static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); 14static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls);
15static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); 15static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls);
16 16
17extern unsigned long __start_syscalls_metadata[];
18extern unsigned long __stop_syscalls_metadata[];
19
20static struct syscall_metadata **syscalls_metadata;
21
22static struct syscall_metadata *find_syscall_meta(unsigned long syscall)
23{
24 struct syscall_metadata *start;
25 struct syscall_metadata *stop;
26 char str[KSYM_SYMBOL_LEN];
27
28
29 start = (struct syscall_metadata *)__start_syscalls_metadata;
30 stop = (struct syscall_metadata *)__stop_syscalls_metadata;
31 kallsyms_lookup(syscall, NULL, NULL, NULL, str);
32
33 for ( ; start < stop; start++) {
34 /*
35 * Only compare after the "sys" prefix. Archs that use
36 * syscall wrappers may have syscalls symbols aliases prefixed
37 * with "SyS" instead of "sys", leading to an unwanted
38 * mismatch.
39 */
40 if (start->name && !strcmp(start->name + 3, str + 3))
41 return start;
42 }
43 return NULL;
44}
45
46static struct syscall_metadata *syscall_nr_to_meta(int nr)
47{
48 if (!syscalls_metadata || nr >= NR_syscalls || nr < 0)
49 return NULL;
50
51 return syscalls_metadata[nr];
52}
53
17enum print_line_t 54enum print_line_t
18print_syscall_enter(struct trace_iterator *iter, int flags) 55print_syscall_enter(struct trace_iterator *iter, int flags)
19{ 56{
@@ -30,7 +67,7 @@ print_syscall_enter(struct trace_iterator *iter, int flags)
30 if (!entry) 67 if (!entry)
31 goto end; 68 goto end;
32 69
33 if (entry->enter_id != ent->type) { 70 if (entry->enter_event->id != ent->type) {
34 WARN_ON_ONCE(1); 71 WARN_ON_ONCE(1);
35 goto end; 72 goto end;
36 } 73 }
@@ -85,7 +122,7 @@ print_syscall_exit(struct trace_iterator *iter, int flags)
85 return TRACE_TYPE_HANDLED; 122 return TRACE_TYPE_HANDLED;
86 } 123 }
87 124
88 if (entry->exit_id != ent->type) { 125 if (entry->exit_event->id != ent->type) {
89 WARN_ON_ONCE(1); 126 WARN_ON_ONCE(1);
90 return TRACE_TYPE_UNHANDLED; 127 return TRACE_TYPE_UNHANDLED;
91 } 128 }
@@ -103,24 +140,19 @@ extern char *__bad_type_size(void);
103#define SYSCALL_FIELD(type, name) \ 140#define SYSCALL_FIELD(type, name) \
104 sizeof(type) != sizeof(trace.name) ? \ 141 sizeof(type) != sizeof(trace.name) ? \
105 __bad_type_size() : \ 142 __bad_type_size() : \
106 #type, #name, offsetof(typeof(trace), name), sizeof(trace.name) 143 #type, #name, offsetof(typeof(trace), name), \
144 sizeof(trace.name), is_signed_type(type)
107 145
108int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s) 146int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s)
109{ 147{
110 int i; 148 int i;
111 int nr;
112 int ret; 149 int ret;
113 struct syscall_metadata *entry; 150 struct syscall_metadata *entry = call->data;
114 struct syscall_trace_enter trace; 151 struct syscall_trace_enter trace;
115 int offset = offsetof(struct syscall_trace_enter, args); 152 int offset = offsetof(struct syscall_trace_enter, args);
116 153
117 nr = syscall_name_to_nr(call->data); 154 ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
118 entry = syscall_nr_to_meta(nr); 155 "\tsigned:%u;\n",
119
120 if (!entry)
121 return 0;
122
123 ret = trace_seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n",
124 SYSCALL_FIELD(int, nr)); 156 SYSCALL_FIELD(int, nr));
125 if (!ret) 157 if (!ret)
126 return 0; 158 return 0;
@@ -130,8 +162,10 @@ int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s)
130 entry->args[i]); 162 entry->args[i]);
131 if (!ret) 163 if (!ret)
132 return 0; 164 return 0;
133 ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;\n", offset, 165 ret = trace_seq_printf(s, "\toffset:%d;\tsize:%zu;"
134 sizeof(unsigned long)); 166 "\tsigned:%u;\n", offset,
167 sizeof(unsigned long),
168 is_signed_type(unsigned long));
135 if (!ret) 169 if (!ret)
136 return 0; 170 return 0;
137 offset += sizeof(unsigned long); 171 offset += sizeof(unsigned long);
@@ -163,8 +197,10 @@ int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s)
163 struct syscall_trace_exit trace; 197 struct syscall_trace_exit trace;
164 198
165 ret = trace_seq_printf(s, 199 ret = trace_seq_printf(s,
166 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n" 200 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
167 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n", 201 "\tsigned:%u;\n"
202 "\tfield:%s %s;\toffset:%zu;\tsize:%zu;"
203 "\tsigned:%u;\n",
168 SYSCALL_FIELD(int, nr), 204 SYSCALL_FIELD(int, nr),
169 SYSCALL_FIELD(long, ret)); 205 SYSCALL_FIELD(long, ret));
170 if (!ret) 206 if (!ret)
@@ -176,19 +212,12 @@ int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s)
176int syscall_enter_define_fields(struct ftrace_event_call *call) 212int syscall_enter_define_fields(struct ftrace_event_call *call)
177{ 213{
178 struct syscall_trace_enter trace; 214 struct syscall_trace_enter trace;
179 struct syscall_metadata *meta; 215 struct syscall_metadata *meta = call->data;
180 int ret; 216 int ret;
181 int nr;
182 int i; 217 int i;
183 int offset = offsetof(typeof(trace), args); 218 int offset = offsetof(typeof(trace), args);
184 219
185 nr = syscall_name_to_nr(call->data); 220 ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER);
186 meta = syscall_nr_to_meta(nr);
187
188 if (!meta)
189 return 0;
190
191 ret = trace_define_common_fields(call);
192 if (ret) 221 if (ret)
193 return ret; 222 return ret;
194 223
@@ -208,11 +237,11 @@ int syscall_exit_define_fields(struct ftrace_event_call *call)
208 struct syscall_trace_exit trace; 237 struct syscall_trace_exit trace;
209 int ret; 238 int ret;
210 239
211 ret = trace_define_common_fields(call); 240 ret = trace_define_field(call, SYSCALL_FIELD(int, nr), FILTER_OTHER);
212 if (ret) 241 if (ret)
213 return ret; 242 return ret;
214 243
215 ret = trace_define_field(call, SYSCALL_FIELD(long, ret), 0, 244 ret = trace_define_field(call, SYSCALL_FIELD(long, ret),
216 FILTER_OTHER); 245 FILTER_OTHER);
217 246
218 return ret; 247 return ret;
@@ -239,8 +268,8 @@ void ftrace_syscall_enter(struct pt_regs *regs, long id)
239 268
240 size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args; 269 size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args;
241 270
242 event = trace_current_buffer_lock_reserve(&buffer, sys_data->enter_id, 271 event = trace_current_buffer_lock_reserve(&buffer,
243 size, 0, 0); 272 sys_data->enter_event->id, size, 0, 0);
244 if (!event) 273 if (!event)
245 return; 274 return;
246 275
@@ -271,8 +300,8 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret)
271 if (!sys_data) 300 if (!sys_data)
272 return; 301 return;
273 302
274 event = trace_current_buffer_lock_reserve(&buffer, sys_data->exit_id, 303 event = trace_current_buffer_lock_reserve(&buffer,
275 sizeof(*entry), 0, 0); 304 sys_data->exit_event->id, sizeof(*entry), 0, 0);
276 if (!event) 305 if (!event)
277 return; 306 return;
278 307
@@ -285,23 +314,18 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret)
285 trace_current_buffer_unlock_commit(buffer, event, 0, 0); 314 trace_current_buffer_unlock_commit(buffer, event, 0, 0);
286} 315}
287 316
288int reg_event_syscall_enter(void *ptr) 317int reg_event_syscall_enter(struct ftrace_event_call *call)
289{ 318{
290 int ret = 0; 319 int ret = 0;
291 int num; 320 int num;
292 char *name;
293 321
294 name = (char *)ptr; 322 num = ((struct syscall_metadata *)call->data)->syscall_nr;
295 num = syscall_name_to_nr(name);
296 if (num < 0 || num >= NR_syscalls) 323 if (num < 0 || num >= NR_syscalls)
297 return -ENOSYS; 324 return -ENOSYS;
298 mutex_lock(&syscall_trace_lock); 325 mutex_lock(&syscall_trace_lock);
299 if (!sys_refcount_enter) 326 if (!sys_refcount_enter)
300 ret = register_trace_sys_enter(ftrace_syscall_enter); 327 ret = register_trace_sys_enter(ftrace_syscall_enter);
301 if (ret) { 328 if (!ret) {
302 pr_info("event trace: Could not activate"
303 "syscall entry trace point");
304 } else {
305 set_bit(num, enabled_enter_syscalls); 329 set_bit(num, enabled_enter_syscalls);
306 sys_refcount_enter++; 330 sys_refcount_enter++;
307 } 331 }
@@ -309,13 +333,11 @@ int reg_event_syscall_enter(void *ptr)
309 return ret; 333 return ret;
310} 334}
311 335
312void unreg_event_syscall_enter(void *ptr) 336void unreg_event_syscall_enter(struct ftrace_event_call *call)
313{ 337{
314 int num; 338 int num;
315 char *name;
316 339
317 name = (char *)ptr; 340 num = ((struct syscall_metadata *)call->data)->syscall_nr;
318 num = syscall_name_to_nr(name);
319 if (num < 0 || num >= NR_syscalls) 341 if (num < 0 || num >= NR_syscalls)
320 return; 342 return;
321 mutex_lock(&syscall_trace_lock); 343 mutex_lock(&syscall_trace_lock);
@@ -326,23 +348,18 @@ void unreg_event_syscall_enter(void *ptr)
326 mutex_unlock(&syscall_trace_lock); 348 mutex_unlock(&syscall_trace_lock);
327} 349}
328 350
329int reg_event_syscall_exit(void *ptr) 351int reg_event_syscall_exit(struct ftrace_event_call *call)
330{ 352{
331 int ret = 0; 353 int ret = 0;
332 int num; 354 int num;
333 char *name;
334 355
335 name = (char *)ptr; 356 num = ((struct syscall_metadata *)call->data)->syscall_nr;
336 num = syscall_name_to_nr(name);
337 if (num < 0 || num >= NR_syscalls) 357 if (num < 0 || num >= NR_syscalls)
338 return -ENOSYS; 358 return -ENOSYS;
339 mutex_lock(&syscall_trace_lock); 359 mutex_lock(&syscall_trace_lock);
340 if (!sys_refcount_exit) 360 if (!sys_refcount_exit)
341 ret = register_trace_sys_exit(ftrace_syscall_exit); 361 ret = register_trace_sys_exit(ftrace_syscall_exit);
342 if (ret) { 362 if (!ret) {
343 pr_info("event trace: Could not activate"
344 "syscall exit trace point");
345 } else {
346 set_bit(num, enabled_exit_syscalls); 363 set_bit(num, enabled_exit_syscalls);
347 sys_refcount_exit++; 364 sys_refcount_exit++;
348 } 365 }
@@ -350,13 +367,11 @@ int reg_event_syscall_exit(void *ptr)
350 return ret; 367 return ret;
351} 368}
352 369
353void unreg_event_syscall_exit(void *ptr) 370void unreg_event_syscall_exit(struct ftrace_event_call *call)
354{ 371{
355 int num; 372 int num;
356 char *name;
357 373
358 name = (char *)ptr; 374 num = ((struct syscall_metadata *)call->data)->syscall_nr;
359 num = syscall_name_to_nr(name);
360 if (num < 0 || num >= NR_syscalls) 375 if (num < 0 || num >= NR_syscalls)
361 return; 376 return;
362 mutex_lock(&syscall_trace_lock); 377 mutex_lock(&syscall_trace_lock);
@@ -367,13 +382,44 @@ void unreg_event_syscall_exit(void *ptr)
367 mutex_unlock(&syscall_trace_lock); 382 mutex_unlock(&syscall_trace_lock);
368} 383}
369 384
370struct trace_event event_syscall_enter = { 385int init_syscall_trace(struct ftrace_event_call *call)
371 .trace = print_syscall_enter, 386{
372}; 387 int id;
388
389 id = register_ftrace_event(call->event);
390 if (!id)
391 return -ENODEV;
392 call->id = id;
393 INIT_LIST_HEAD(&call->fields);
394 return 0;
395}
396
397int __init init_ftrace_syscalls(void)
398{
399 struct syscall_metadata *meta;
400 unsigned long addr;
401 int i;
402
403 syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) *
404 NR_syscalls, GFP_KERNEL);
405 if (!syscalls_metadata) {
406 WARN_ON(1);
407 return -ENOMEM;
408 }
409
410 for (i = 0; i < NR_syscalls; i++) {
411 addr = arch_syscall_addr(i);
412 meta = find_syscall_meta(addr);
413 if (!meta)
414 continue;
415
416 meta->syscall_nr = i;
417 syscalls_metadata[i] = meta;
418 }
373 419
374struct trace_event event_syscall_exit = { 420 return 0;
375 .trace = print_syscall_exit, 421}
376}; 422core_initcall(init_ftrace_syscalls);
377 423
378#ifdef CONFIG_EVENT_PROFILE 424#ifdef CONFIG_EVENT_PROFILE
379 425
@@ -387,8 +433,10 @@ static void prof_syscall_enter(struct pt_regs *regs, long id)
387 struct syscall_metadata *sys_data; 433 struct syscall_metadata *sys_data;
388 struct syscall_trace_enter *rec; 434 struct syscall_trace_enter *rec;
389 unsigned long flags; 435 unsigned long flags;
436 char *trace_buf;
390 char *raw_data; 437 char *raw_data;
391 int syscall_nr; 438 int syscall_nr;
439 int rctx;
392 int size; 440 int size;
393 int cpu; 441 int cpu;
394 442
@@ -412,41 +460,42 @@ static void prof_syscall_enter(struct pt_regs *regs, long id)
412 /* Protect the per cpu buffer, begin the rcu read side */ 460 /* Protect the per cpu buffer, begin the rcu read side */
413 local_irq_save(flags); 461 local_irq_save(flags);
414 462
463 rctx = perf_swevent_get_recursion_context();
464 if (rctx < 0)
465 goto end_recursion;
466
415 cpu = smp_processor_id(); 467 cpu = smp_processor_id();
416 468
417 if (in_nmi()) 469 trace_buf = rcu_dereference(perf_trace_buf);
418 raw_data = rcu_dereference(trace_profile_buf_nmi);
419 else
420 raw_data = rcu_dereference(trace_profile_buf);
421 470
422 if (!raw_data) 471 if (!trace_buf)
423 goto end; 472 goto end;
424 473
425 raw_data = per_cpu_ptr(raw_data, cpu); 474 raw_data = per_cpu_ptr(trace_buf, cpu);
426 475
427 /* zero the dead bytes from align to not leak stack to user */ 476 /* zero the dead bytes from align to not leak stack to user */
428 *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; 477 *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL;
429 478
430 rec = (struct syscall_trace_enter *) raw_data; 479 rec = (struct syscall_trace_enter *) raw_data;
431 tracing_generic_entry_update(&rec->ent, 0, 0); 480 tracing_generic_entry_update(&rec->ent, 0, 0);
432 rec->ent.type = sys_data->enter_id; 481 rec->ent.type = sys_data->enter_event->id;
433 rec->nr = syscall_nr; 482 rec->nr = syscall_nr;
434 syscall_get_arguments(current, regs, 0, sys_data->nb_args, 483 syscall_get_arguments(current, regs, 0, sys_data->nb_args,
435 (unsigned long *)&rec->args); 484 (unsigned long *)&rec->args);
436 perf_tp_event(sys_data->enter_id, 0, 1, rec, size); 485 perf_tp_event(sys_data->enter_event->id, 0, 1, rec, size);
437 486
438end: 487end:
488 perf_swevent_put_recursion_context(rctx);
489end_recursion:
439 local_irq_restore(flags); 490 local_irq_restore(flags);
440} 491}
441 492
442int reg_prof_syscall_enter(char *name) 493int prof_sysenter_enable(struct ftrace_event_call *call)
443{ 494{
444 int ret = 0; 495 int ret = 0;
445 int num; 496 int num;
446 497
447 num = syscall_name_to_nr(name); 498 num = ((struct syscall_metadata *)call->data)->syscall_nr;
448 if (num < 0 || num >= NR_syscalls)
449 return -ENOSYS;
450 499
451 mutex_lock(&syscall_trace_lock); 500 mutex_lock(&syscall_trace_lock);
452 if (!sys_prof_refcount_enter) 501 if (!sys_prof_refcount_enter)
@@ -462,13 +511,11 @@ int reg_prof_syscall_enter(char *name)
462 return ret; 511 return ret;
463} 512}
464 513
465void unreg_prof_syscall_enter(char *name) 514void prof_sysenter_disable(struct ftrace_event_call *call)
466{ 515{
467 int num; 516 int num;
468 517
469 num = syscall_name_to_nr(name); 518 num = ((struct syscall_metadata *)call->data)->syscall_nr;
470 if (num < 0 || num >= NR_syscalls)
471 return;
472 519
473 mutex_lock(&syscall_trace_lock); 520 mutex_lock(&syscall_trace_lock);
474 sys_prof_refcount_enter--; 521 sys_prof_refcount_enter--;
@@ -484,7 +531,9 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret)
484 struct syscall_trace_exit *rec; 531 struct syscall_trace_exit *rec;
485 unsigned long flags; 532 unsigned long flags;
486 int syscall_nr; 533 int syscall_nr;
534 char *trace_buf;
487 char *raw_data; 535 char *raw_data;
536 int rctx;
488 int size; 537 int size;
489 int cpu; 538 int cpu;
490 539
@@ -510,17 +559,19 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret)
510 559
511 /* Protect the per cpu buffer, begin the rcu read side */ 560 /* Protect the per cpu buffer, begin the rcu read side */
512 local_irq_save(flags); 561 local_irq_save(flags);
562
563 rctx = perf_swevent_get_recursion_context();
564 if (rctx < 0)
565 goto end_recursion;
566
513 cpu = smp_processor_id(); 567 cpu = smp_processor_id();
514 568
515 if (in_nmi()) 569 trace_buf = rcu_dereference(perf_trace_buf);
516 raw_data = rcu_dereference(trace_profile_buf_nmi);
517 else
518 raw_data = rcu_dereference(trace_profile_buf);
519 570
520 if (!raw_data) 571 if (!trace_buf)
521 goto end; 572 goto end;
522 573
523 raw_data = per_cpu_ptr(raw_data, cpu); 574 raw_data = per_cpu_ptr(trace_buf, cpu);
524 575
525 /* zero the dead bytes from align to not leak stack to user */ 576 /* zero the dead bytes from align to not leak stack to user */
526 *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL; 577 *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL;
@@ -528,24 +579,24 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret)
528 rec = (struct syscall_trace_exit *)raw_data; 579 rec = (struct syscall_trace_exit *)raw_data;
529 580
530 tracing_generic_entry_update(&rec->ent, 0, 0); 581 tracing_generic_entry_update(&rec->ent, 0, 0);
531 rec->ent.type = sys_data->exit_id; 582 rec->ent.type = sys_data->exit_event->id;
532 rec->nr = syscall_nr; 583 rec->nr = syscall_nr;
533 rec->ret = syscall_get_return_value(current, regs); 584 rec->ret = syscall_get_return_value(current, regs);
534 585
535 perf_tp_event(sys_data->exit_id, 0, 1, rec, size); 586 perf_tp_event(sys_data->exit_event->id, 0, 1, rec, size);
536 587
537end: 588end:
589 perf_swevent_put_recursion_context(rctx);
590end_recursion:
538 local_irq_restore(flags); 591 local_irq_restore(flags);
539} 592}
540 593
541int reg_prof_syscall_exit(char *name) 594int prof_sysexit_enable(struct ftrace_event_call *call)
542{ 595{
543 int ret = 0; 596 int ret = 0;
544 int num; 597 int num;
545 598
546 num = syscall_name_to_nr(name); 599 num = ((struct syscall_metadata *)call->data)->syscall_nr;
547 if (num < 0 || num >= NR_syscalls)
548 return -ENOSYS;
549 600
550 mutex_lock(&syscall_trace_lock); 601 mutex_lock(&syscall_trace_lock);
551 if (!sys_prof_refcount_exit) 602 if (!sys_prof_refcount_exit)
@@ -561,13 +612,11 @@ int reg_prof_syscall_exit(char *name)
561 return ret; 612 return ret;
562} 613}
563 614
564void unreg_prof_syscall_exit(char *name) 615void prof_sysexit_disable(struct ftrace_event_call *call)
565{ 616{
566 int num; 617 int num;
567 618
568 num = syscall_name_to_nr(name); 619 num = ((struct syscall_metadata *)call->data)->syscall_nr;
569 if (num < 0 || num >= NR_syscalls)
570 return;
571 620
572 mutex_lock(&syscall_trace_lock); 621 mutex_lock(&syscall_trace_lock);
573 sys_prof_refcount_exit--; 622 sys_prof_refcount_exit--;