aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/ftrace.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-11-16 01:57:13 -0500
committerIngo Molnar <mingo@elte.hu>2008-11-16 01:57:13 -0500
commit985809608f758a8d3ddda4ce5a53ed0e57fb9e1b (patch)
tree063fe72ed9bb3410c3293c83a7882cecc46e7410 /kernel/trace/ftrace.c
parentc91add5fa68ea9b1f2923b3788c5dae0e60e1f6b (diff)
parent1c80025a49855b12fa09bb6db71820e3367b1369 (diff)
Merge branch 'tracing/ftrace' into tracing/function-return-tracer
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r--kernel/trace/ftrace.c224
1 files changed, 109 insertions, 115 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 54cb9a7d15e5..b42ec1de546b 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -334,7 +334,7 @@ ftrace_record_ip(unsigned long ip)
334{ 334{
335 struct dyn_ftrace *rec; 335 struct dyn_ftrace *rec;
336 336
337 if (!ftrace_enabled || ftrace_disabled) 337 if (ftrace_disabled)
338 return NULL; 338 return NULL;
339 339
340 rec = ftrace_alloc_dyn_node(ip); 340 rec = ftrace_alloc_dyn_node(ip);
@@ -348,107 +348,129 @@ ftrace_record_ip(unsigned long ip)
348 return rec; 348 return rec;
349} 349}
350 350
351static void print_ip_ins(const char *fmt, unsigned char *p)
352{
353 int i;
354
355 printk(KERN_CONT "%s", fmt);
356
357 for (i = 0; i < MCOUNT_INSN_SIZE; i++)
358 printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]);
359}
360
361static void ftrace_bug(int failed, unsigned long ip)
362{
363 switch (failed) {
364 case -EFAULT:
365 FTRACE_WARN_ON_ONCE(1);
366 pr_info("ftrace faulted on modifying ");
367 print_ip_sym(ip);
368 break;
369 case -EINVAL:
370 FTRACE_WARN_ON_ONCE(1);
371 pr_info("ftrace failed to modify ");
372 print_ip_sym(ip);
373 print_ip_ins(" actual: ", (unsigned char *)ip);
374 printk(KERN_CONT "\n");
375 break;
376 case -EPERM:
377 FTRACE_WARN_ON_ONCE(1);
378 pr_info("ftrace faulted on writing ");
379 print_ip_sym(ip);
380 break;
381 default:
382 FTRACE_WARN_ON_ONCE(1);
383 pr_info("ftrace faulted on unknown error ");
384 print_ip_sym(ip);
385 }
386}
387
351#define FTRACE_ADDR ((long)(ftrace_caller)) 388#define FTRACE_ADDR ((long)(ftrace_caller))
352 389
353static int 390static int
354__ftrace_replace_code(struct dyn_ftrace *rec, 391__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
355 unsigned char *old, unsigned char *new, int enable)
356{ 392{
357 unsigned long ip, fl; 393 unsigned long ip, fl;
358 394
359 ip = rec->ip; 395 ip = rec->ip;
360 396
361 if (ftrace_filtered && enable) { 397 /*
398 * If this record is not to be traced and
399 * it is not enabled then do nothing.
400 *
401 * If this record is not to be traced and
402 * it is enabled then disabled it.
403 *
404 */
405 if (rec->flags & FTRACE_FL_NOTRACE) {
406 if (rec->flags & FTRACE_FL_ENABLED)
407 rec->flags &= ~FTRACE_FL_ENABLED;
408 else
409 return 0;
410
411 } else if (ftrace_filtered && enable) {
362 /* 412 /*
363 * If filtering is on: 413 * Filtering is on:
364 *
365 * If this record is set to be filtered and
366 * is enabled then do nothing.
367 *
368 * If this record is set to be filtered and
369 * it is not enabled, enable it.
370 *
371 * If this record is not set to be filtered
372 * and it is not enabled do nothing.
373 *
374 * If this record is set not to trace then
375 * do nothing.
376 *
377 * If this record is set not to trace and
378 * it is enabled then disable it.
379 *
380 * If this record is not set to be filtered and
381 * it is enabled, disable it.
382 */ 414 */
383 415
384 fl = rec->flags & (FTRACE_FL_FILTER | FTRACE_FL_NOTRACE | 416 fl = rec->flags & (FTRACE_FL_FILTER | FTRACE_FL_ENABLED);
385 FTRACE_FL_ENABLED);
386 417
387 if ((fl == (FTRACE_FL_FILTER | FTRACE_FL_ENABLED)) || 418 /* Record is filtered and enabled, do nothing */
388 (fl == (FTRACE_FL_FILTER | FTRACE_FL_NOTRACE)) || 419 if (fl == (FTRACE_FL_FILTER | FTRACE_FL_ENABLED))
389 !fl || (fl == FTRACE_FL_NOTRACE))
390 return 0; 420 return 0;
391 421
392 /* 422 /* Record is not filtered and is not enabled do nothing */
393 * If it is enabled disable it, 423 if (!fl)
394 * otherwise enable it! 424 return 0;
395 */ 425
396 if (fl & FTRACE_FL_ENABLED) { 426 /* Record is not filtered but enabled, disable it */
397 /* swap new and old */ 427 if (fl == FTRACE_FL_ENABLED)
398 new = old;
399 old = ftrace_call_replace(ip, FTRACE_ADDR);
400 rec->flags &= ~FTRACE_FL_ENABLED; 428 rec->flags &= ~FTRACE_FL_ENABLED;
401 } else { 429 else
402 new = ftrace_call_replace(ip, FTRACE_ADDR); 430 /* Otherwise record is filtered but not enabled, enable it */
403 rec->flags |= FTRACE_FL_ENABLED; 431 rec->flags |= FTRACE_FL_ENABLED;
404 }
405 } else { 432 } else {
433 /* Disable or not filtered */
406 434
407 if (enable) { 435 if (enable) {
408 /* 436 /* if record is enabled, do nothing */
409 * If this record is set not to trace and is
410 * not enabled, do nothing.
411 */
412 fl = rec->flags & (FTRACE_FL_NOTRACE | FTRACE_FL_ENABLED);
413 if (fl == FTRACE_FL_NOTRACE)
414 return 0;
415
416 new = ftrace_call_replace(ip, FTRACE_ADDR);
417 } else
418 old = ftrace_call_replace(ip, FTRACE_ADDR);
419
420 if (enable) {
421 if (rec->flags & FTRACE_FL_ENABLED) 437 if (rec->flags & FTRACE_FL_ENABLED)
422 return 0; 438 return 0;
439
423 rec->flags |= FTRACE_FL_ENABLED; 440 rec->flags |= FTRACE_FL_ENABLED;
441
424 } else { 442 } else {
443
444 /* if record is not enabled do nothing */
425 if (!(rec->flags & FTRACE_FL_ENABLED)) 445 if (!(rec->flags & FTRACE_FL_ENABLED))
426 return 0; 446 return 0;
447
427 rec->flags &= ~FTRACE_FL_ENABLED; 448 rec->flags &= ~FTRACE_FL_ENABLED;
428 } 449 }
429 } 450 }
430 451
431 return ftrace_modify_code(ip, old, new); 452 if (rec->flags & FTRACE_FL_ENABLED)
453 return ftrace_make_call(rec, FTRACE_ADDR);
454 else
455 return ftrace_make_nop(NULL, rec, FTRACE_ADDR);
432} 456}
433 457
434static void ftrace_replace_code(int enable) 458static void ftrace_replace_code(int enable)
435{ 459{
436 int i, failed; 460 int i, failed;
437 unsigned char *new = NULL, *old = NULL;
438 struct dyn_ftrace *rec; 461 struct dyn_ftrace *rec;
439 struct ftrace_page *pg; 462 struct ftrace_page *pg;
440 463
441 if (enable)
442 old = ftrace_nop_replace();
443 else
444 new = ftrace_nop_replace();
445
446 for (pg = ftrace_pages_start; pg; pg = pg->next) { 464 for (pg = ftrace_pages_start; pg; pg = pg->next) {
447 for (i = 0; i < pg->index; i++) { 465 for (i = 0; i < pg->index; i++) {
448 rec = &pg->records[i]; 466 rec = &pg->records[i];
449 467
450 /* don't modify code that has already faulted */ 468 /*
451 if (rec->flags & FTRACE_FL_FAILED) 469 * Skip over free records and records that have
470 * failed.
471 */
472 if (rec->flags & FTRACE_FL_FREE ||
473 rec->flags & FTRACE_FL_FAILED)
452 continue; 474 continue;
453 475
454 /* ignore updates to this record's mcount site */ 476 /* ignore updates to this record's mcount site */
@@ -459,68 +481,30 @@ static void ftrace_replace_code(int enable)
459 unfreeze_record(rec); 481 unfreeze_record(rec);
460 } 482 }
461 483
462 failed = __ftrace_replace_code(rec, old, new, enable); 484 failed = __ftrace_replace_code(rec, enable);
463 if (failed && (rec->flags & FTRACE_FL_CONVERTED)) { 485 if (failed && (rec->flags & FTRACE_FL_CONVERTED)) {
464 rec->flags |= FTRACE_FL_FAILED; 486 rec->flags |= FTRACE_FL_FAILED;
465 if ((system_state == SYSTEM_BOOTING) || 487 if ((system_state == SYSTEM_BOOTING) ||
466 !core_kernel_text(rec->ip)) { 488 !core_kernel_text(rec->ip)) {
467 ftrace_free_rec(rec); 489 ftrace_free_rec(rec);
468 } 490 } else
491 ftrace_bug(failed, rec->ip);
469 } 492 }
470 } 493 }
471 } 494 }
472} 495}
473 496
474static void print_ip_ins(const char *fmt, unsigned char *p)
475{
476 int i;
477
478 printk(KERN_CONT "%s", fmt);
479
480 for (i = 0; i < MCOUNT_INSN_SIZE; i++)
481 printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]);
482}
483
484static int 497static int
485ftrace_code_disable(struct dyn_ftrace *rec) 498ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec)
486{ 499{
487 unsigned long ip; 500 unsigned long ip;
488 unsigned char *nop, *call;
489 int ret; 501 int ret;
490 502
491 ip = rec->ip; 503 ip = rec->ip;
492 504
493 nop = ftrace_nop_replace(); 505 ret = ftrace_make_nop(mod, rec, mcount_addr);
494 call = ftrace_call_replace(ip, mcount_addr);
495
496 ret = ftrace_modify_code(ip, call, nop);
497 if (ret) { 506 if (ret) {
498 switch (ret) { 507 ftrace_bug(ret, ip);
499 case -EFAULT:
500 FTRACE_WARN_ON_ONCE(1);
501 pr_info("ftrace faulted on modifying ");
502 print_ip_sym(ip);
503 break;
504 case -EINVAL:
505 FTRACE_WARN_ON_ONCE(1);
506 pr_info("ftrace failed to modify ");
507 print_ip_sym(ip);
508 print_ip_ins(" expected: ", call);
509 print_ip_ins(" actual: ", (unsigned char *)ip);
510 print_ip_ins(" replace: ", nop);
511 printk(KERN_CONT "\n");
512 break;
513 case -EPERM:
514 FTRACE_WARN_ON_ONCE(1);
515 pr_info("ftrace faulted on writing ");
516 print_ip_sym(ip);
517 break;
518 default:
519 FTRACE_WARN_ON_ONCE(1);
520 pr_info("ftrace faulted on unknown error ");
521 print_ip_sym(ip);
522 }
523
524 rec->flags |= FTRACE_FL_FAILED; 508 rec->flags |= FTRACE_FL_FAILED;
525 return 0; 509 return 0;
526 } 510 }
@@ -560,8 +544,7 @@ static void ftrace_startup(void)
560 544
561 mutex_lock(&ftrace_start_lock); 545 mutex_lock(&ftrace_start_lock);
562 ftrace_start_up++; 546 ftrace_start_up++;
563 if (ftrace_start_up == 1) 547 command |= FTRACE_ENABLE_CALLS;
564 command |= FTRACE_ENABLE_CALLS;
565 548
566 if (saved_ftrace_func != ftrace_trace_function) { 549 if (saved_ftrace_func != ftrace_trace_function) {
567 saved_ftrace_func = ftrace_trace_function; 550 saved_ftrace_func = ftrace_trace_function;
@@ -639,7 +622,7 @@ static cycle_t ftrace_update_time;
639static unsigned long ftrace_update_cnt; 622static unsigned long ftrace_update_cnt;
640unsigned long ftrace_update_tot_cnt; 623unsigned long ftrace_update_tot_cnt;
641 624
642static int ftrace_update_code(void) 625static int ftrace_update_code(struct module *mod)
643{ 626{
644 struct dyn_ftrace *p, *t; 627 struct dyn_ftrace *p, *t;
645 cycle_t start, stop; 628 cycle_t start, stop;
@@ -656,7 +639,7 @@ static int ftrace_update_code(void)
656 list_del_init(&p->list); 639 list_del_init(&p->list);
657 640
658 /* convert record (i.e, patch mcount-call with NOP) */ 641 /* convert record (i.e, patch mcount-call with NOP) */
659 if (ftrace_code_disable(p)) { 642 if (ftrace_code_disable(mod, p)) {
660 p->flags |= FTRACE_FL_CONVERTED; 643 p->flags |= FTRACE_FL_CONVERTED;
661 ftrace_update_cnt++; 644 ftrace_update_cnt++;
662 } else 645 } else
@@ -1211,7 +1194,7 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable)
1211 1194
1212 mutex_lock(&ftrace_sysctl_lock); 1195 mutex_lock(&ftrace_sysctl_lock);
1213 mutex_lock(&ftrace_start_lock); 1196 mutex_lock(&ftrace_start_lock);
1214 if (iter->filtered && ftrace_start_up && ftrace_enabled) 1197 if (ftrace_start_up && ftrace_enabled)
1215 ftrace_run_update_code(FTRACE_ENABLE_CALLS); 1198 ftrace_run_update_code(FTRACE_ENABLE_CALLS);
1216 mutex_unlock(&ftrace_start_lock); 1199 mutex_unlock(&ftrace_start_lock);
1217 mutex_unlock(&ftrace_sysctl_lock); 1200 mutex_unlock(&ftrace_sysctl_lock);
@@ -1298,7 +1281,8 @@ static __init int ftrace_init_debugfs(void)
1298 1281
1299fs_initcall(ftrace_init_debugfs); 1282fs_initcall(ftrace_init_debugfs);
1300 1283
1301static int ftrace_convert_nops(unsigned long *start, 1284static int ftrace_convert_nops(struct module *mod,
1285 unsigned long *start,
1302 unsigned long *end) 1286 unsigned long *end)
1303{ 1287{
1304 unsigned long *p; 1288 unsigned long *p;
@@ -1309,23 +1293,32 @@ static int ftrace_convert_nops(unsigned long *start,
1309 p = start; 1293 p = start;
1310 while (p < end) { 1294 while (p < end) {
1311 addr = ftrace_call_adjust(*p++); 1295 addr = ftrace_call_adjust(*p++);
1296 /*
1297 * Some architecture linkers will pad between
1298 * the different mcount_loc sections of different
1299 * object files to satisfy alignments.
1300 * Skip any NULL pointers.
1301 */
1302 if (!addr)
1303 continue;
1312 ftrace_record_ip(addr); 1304 ftrace_record_ip(addr);
1313 } 1305 }
1314 1306
1315 /* disable interrupts to prevent kstop machine */ 1307 /* disable interrupts to prevent kstop machine */
1316 local_irq_save(flags); 1308 local_irq_save(flags);
1317 ftrace_update_code(); 1309 ftrace_update_code(mod);
1318 local_irq_restore(flags); 1310 local_irq_restore(flags);
1319 mutex_unlock(&ftrace_start_lock); 1311 mutex_unlock(&ftrace_start_lock);
1320 1312
1321 return 0; 1313 return 0;
1322} 1314}
1323 1315
1324void ftrace_init_module(unsigned long *start, unsigned long *end) 1316void ftrace_init_module(struct module *mod,
1317 unsigned long *start, unsigned long *end)
1325{ 1318{
1326 if (ftrace_disabled || start == end) 1319 if (ftrace_disabled || start == end)
1327 return; 1320 return;
1328 ftrace_convert_nops(start, end); 1321 ftrace_convert_nops(mod, start, end);
1329} 1322}
1330 1323
1331extern unsigned long __start_mcount_loc[]; 1324extern unsigned long __start_mcount_loc[];
@@ -1355,7 +1348,8 @@ void __init ftrace_init(void)
1355 1348
1356 last_ftrace_enabled = ftrace_enabled = 1; 1349 last_ftrace_enabled = ftrace_enabled = 1;
1357 1350
1358 ret = ftrace_convert_nops(__start_mcount_loc, 1351 ret = ftrace_convert_nops(NULL,
1352 __start_mcount_loc,
1359 __stop_mcount_loc); 1353 __stop_mcount_loc);
1360 1354
1361 return; 1355 return;