diff options
Diffstat (limited to 'kernel/trace/trace_syscalls.c')
| -rw-r--r-- | kernel/trace/trace_syscalls.c | 235 |
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; | |||
| 14 | static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); | 14 | static DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); |
| 15 | static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); | 15 | static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); |
| 16 | 16 | ||
| 17 | extern unsigned long __start_syscalls_metadata[]; | ||
| 18 | extern unsigned long __stop_syscalls_metadata[]; | ||
| 19 | |||
| 20 | static struct syscall_metadata **syscalls_metadata; | ||
| 21 | |||
| 22 | static 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 | |||
| 46 | static 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 | |||
| 17 | enum print_line_t | 54 | enum print_line_t |
| 18 | print_syscall_enter(struct trace_iterator *iter, int flags) | 55 | print_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 | ||
| 108 | int syscall_enter_format(struct ftrace_event_call *call, struct trace_seq *s) | 146 | int 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) | |||
| 176 | int syscall_enter_define_fields(struct ftrace_event_call *call) | 212 | int 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 | ||
| 288 | int reg_event_syscall_enter(void *ptr) | 317 | int 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 | ||
| 312 | void unreg_event_syscall_enter(void *ptr) | 336 | void 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 | ||
| 329 | int reg_event_syscall_exit(void *ptr) | 351 | int 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 | ||
| 353 | void unreg_event_syscall_exit(void *ptr) | 370 | void 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 | ||
| 370 | struct trace_event event_syscall_enter = { | 385 | int 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 | |||
| 397 | int __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 | ||
| 374 | struct trace_event event_syscall_exit = { | 420 | return 0; |
| 375 | .trace = print_syscall_exit, | 421 | } |
| 376 | }; | 422 | core_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 | ||
| 438 | end: | 487 | end: |
| 488 | perf_swevent_put_recursion_context(rctx); | ||
| 489 | end_recursion: | ||
| 439 | local_irq_restore(flags); | 490 | local_irq_restore(flags); |
| 440 | } | 491 | } |
| 441 | 492 | ||
| 442 | int reg_prof_syscall_enter(char *name) | 493 | int 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 | ||
| 465 | void unreg_prof_syscall_enter(char *name) | 514 | void 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 | ||
| 537 | end: | 588 | end: |
| 589 | perf_swevent_put_recursion_context(rctx); | ||
| 590 | end_recursion: | ||
| 538 | local_irq_restore(flags); | 591 | local_irq_restore(flags); |
| 539 | } | 592 | } |
| 540 | 593 | ||
| 541 | int reg_prof_syscall_exit(char *name) | 594 | int 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 | ||
| 564 | void unreg_prof_syscall_exit(char *name) | 615 | void 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--; |
