aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/module.c2
-rw-r--r--kernel/trace/ftrace.c62
2 files changed, 25 insertions, 39 deletions
diff --git a/kernel/module.c b/kernel/module.c
index 1f4cc00e0c20..69791274e899 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2201,7 +2201,7 @@ static noinline struct module *load_module(void __user *umod,
2201 /* sechdrs[0].sh_size is always zero */ 2201 /* sechdrs[0].sh_size is always zero */
2202 mseg = section_objs(hdr, sechdrs, secstrings, "__mcount_loc", 2202 mseg = section_objs(hdr, sechdrs, secstrings, "__mcount_loc",
2203 sizeof(*mseg), &num_mcount); 2203 sizeof(*mseg), &num_mcount);
2204 ftrace_init_module(mseg, mseg + num_mcount); 2204 ftrace_init_module(mod, mseg, mseg + num_mcount);
2205 2205
2206 err = module_finalize(hdr, sechdrs, mod); 2206 err = module_finalize(hdr, sechdrs, mod);
2207 if (err < 0) 2207 if (err < 0)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 3940c71ac2a2..e9a5fbfce08e 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -358,9 +358,7 @@ static void print_ip_ins(const char *fmt, unsigned char *p)
358 printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]); 358 printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]);
359} 359}
360 360
361static void ftrace_bug(int failed, unsigned long ip, 361static void ftrace_bug(int failed, unsigned long ip)
362 unsigned char *expected,
363 unsigned char *replace)
364{ 362{
365 switch (failed) { 363 switch (failed) {
366 case -EFAULT: 364 case -EFAULT:
@@ -372,9 +370,7 @@ static void ftrace_bug(int failed, unsigned long ip,
372 FTRACE_WARN_ON_ONCE(1); 370 FTRACE_WARN_ON_ONCE(1);
373 pr_info("ftrace failed to modify "); 371 pr_info("ftrace failed to modify ");
374 print_ip_sym(ip); 372 print_ip_sym(ip);
375 print_ip_ins(" expected: ", expected);
376 print_ip_ins(" actual: ", (unsigned char *)ip); 373 print_ip_ins(" actual: ", (unsigned char *)ip);
377 print_ip_ins(" replace: ", replace);
378 printk(KERN_CONT "\n"); 374 printk(KERN_CONT "\n");
379 break; 375 break;
380 case -EPERM: 376 case -EPERM:
@@ -392,8 +388,7 @@ static void ftrace_bug(int failed, unsigned long ip,
392#define FTRACE_ADDR ((long)(ftrace_caller)) 388#define FTRACE_ADDR ((long)(ftrace_caller))
393 389
394static int 390static int
395__ftrace_replace_code(struct dyn_ftrace *rec, 391__ftrace_replace_code(struct dyn_ftrace *rec, int enable)
396 unsigned char *old, unsigned char *new, int enable)
397{ 392{
398 unsigned long ip, fl; 393 unsigned long ip, fl;
399 394
@@ -435,12 +430,10 @@ __ftrace_replace_code(struct dyn_ftrace *rec,
435 * otherwise enable it! 430 * otherwise enable it!
436 */ 431 */
437 if (fl & FTRACE_FL_ENABLED) { 432 if (fl & FTRACE_FL_ENABLED) {
438 /* swap new and old */ 433 enable = 0;
439 new = old;
440 old = ftrace_call_replace(ip, FTRACE_ADDR);
441 rec->flags &= ~FTRACE_FL_ENABLED; 434 rec->flags &= ~FTRACE_FL_ENABLED;
442 } else { 435 } else {
443 new = ftrace_call_replace(ip, FTRACE_ADDR); 436 enable = 1;
444 rec->flags |= FTRACE_FL_ENABLED; 437 rec->flags |= FTRACE_FL_ENABLED;
445 } 438 }
446 } else { 439 } else {
@@ -453,10 +446,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec,
453 fl = rec->flags & (FTRACE_FL_NOTRACE | FTRACE_FL_ENABLED); 446 fl = rec->flags & (FTRACE_FL_NOTRACE | FTRACE_FL_ENABLED);
454 if (fl == FTRACE_FL_NOTRACE) 447 if (fl == FTRACE_FL_NOTRACE)
455 return 0; 448 return 0;
456 449 }
457 new = ftrace_call_replace(ip, FTRACE_ADDR);
458 } else
459 old = ftrace_call_replace(ip, FTRACE_ADDR);
460 450
461 if (enable) { 451 if (enable) {
462 if (rec->flags & FTRACE_FL_ENABLED) 452 if (rec->flags & FTRACE_FL_ENABLED)
@@ -469,21 +459,18 @@ __ftrace_replace_code(struct dyn_ftrace *rec,
469 } 459 }
470 } 460 }
471 461
472 return ftrace_modify_code(ip, old, new); 462 if (enable)
463 return ftrace_make_call(rec, FTRACE_ADDR);
464 else
465 return ftrace_make_nop(NULL, rec, FTRACE_ADDR);
473} 466}
474 467
475static void ftrace_replace_code(int enable) 468static void ftrace_replace_code(int enable)
476{ 469{
477 int i, failed; 470 int i, failed;
478 unsigned char *new = NULL, *old = NULL;
479 struct dyn_ftrace *rec; 471 struct dyn_ftrace *rec;
480 struct ftrace_page *pg; 472 struct ftrace_page *pg;
481 473
482 if (enable)
483 old = ftrace_nop_replace();
484 else
485 new = ftrace_nop_replace();
486
487 for (pg = ftrace_pages_start; pg; pg = pg->next) { 474 for (pg = ftrace_pages_start; pg; pg = pg->next) {
488 for (i = 0; i < pg->index; i++) { 475 for (i = 0; i < pg->index; i++) {
489 rec = &pg->records[i]; 476 rec = &pg->records[i];
@@ -504,34 +491,30 @@ static void ftrace_replace_code(int enable)
504 unfreeze_record(rec); 491 unfreeze_record(rec);
505 } 492 }
506 493
507 failed = __ftrace_replace_code(rec, old, new, enable); 494 failed = __ftrace_replace_code(rec, enable);
508 if (failed && (rec->flags & FTRACE_FL_CONVERTED)) { 495 if (failed && (rec->flags & FTRACE_FL_CONVERTED)) {
509 rec->flags |= FTRACE_FL_FAILED; 496 rec->flags |= FTRACE_FL_FAILED;
510 if ((system_state == SYSTEM_BOOTING) || 497 if ((system_state == SYSTEM_BOOTING) ||
511 !core_kernel_text(rec->ip)) { 498 !core_kernel_text(rec->ip)) {
512 ftrace_free_rec(rec); 499 ftrace_free_rec(rec);
513 } else 500 } else
514 ftrace_bug(failed, rec->ip, old, new); 501 ftrace_bug(failed, rec->ip);
515 } 502 }
516 } 503 }
517 } 504 }
518} 505}
519 506
520static int 507static int
521ftrace_code_disable(struct dyn_ftrace *rec) 508ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec)
522{ 509{
523 unsigned long ip; 510 unsigned long ip;
524 unsigned char *nop, *call;
525 int ret; 511 int ret;
526 512
527 ip = rec->ip; 513 ip = rec->ip;
528 514
529 nop = ftrace_nop_replace(); 515 ret = ftrace_make_nop(mod, rec, mcount_addr);
530 call = ftrace_call_replace(ip, mcount_addr);
531
532 ret = ftrace_modify_code(ip, call, nop);
533 if (ret) { 516 if (ret) {
534 ftrace_bug(ret, ip, call, nop); 517 ftrace_bug(ret, ip);
535 rec->flags |= FTRACE_FL_FAILED; 518 rec->flags |= FTRACE_FL_FAILED;
536 return 0; 519 return 0;
537 } 520 }
@@ -650,7 +633,7 @@ static cycle_t ftrace_update_time;
650static unsigned long ftrace_update_cnt; 633static unsigned long ftrace_update_cnt;
651unsigned long ftrace_update_tot_cnt; 634unsigned long ftrace_update_tot_cnt;
652 635
653static int ftrace_update_code(void) 636static int ftrace_update_code(struct module *mod)
654{ 637{
655 struct dyn_ftrace *p, *t; 638 struct dyn_ftrace *p, *t;
656 cycle_t start, stop; 639 cycle_t start, stop;
@@ -667,7 +650,7 @@ static int ftrace_update_code(void)
667 list_del_init(&p->list); 650 list_del_init(&p->list);
668 651
669 /* convert record (i.e, patch mcount-call with NOP) */ 652 /* convert record (i.e, patch mcount-call with NOP) */
670 if (ftrace_code_disable(p)) { 653 if (ftrace_code_disable(mod, p)) {
671 p->flags |= FTRACE_FL_CONVERTED; 654 p->flags |= FTRACE_FL_CONVERTED;
672 ftrace_update_cnt++; 655 ftrace_update_cnt++;
673 } else 656 } else
@@ -1309,7 +1292,8 @@ static __init int ftrace_init_debugfs(void)
1309 1292
1310fs_initcall(ftrace_init_debugfs); 1293fs_initcall(ftrace_init_debugfs);
1311 1294
1312static int ftrace_convert_nops(unsigned long *start, 1295static int ftrace_convert_nops(struct module *mod,
1296 unsigned long *start,
1313 unsigned long *end) 1297 unsigned long *end)
1314{ 1298{
1315 unsigned long *p; 1299 unsigned long *p;
@@ -1325,18 +1309,19 @@ static int ftrace_convert_nops(unsigned long *start,
1325 1309
1326 /* disable interrupts to prevent kstop machine */ 1310 /* disable interrupts to prevent kstop machine */
1327 local_irq_save(flags); 1311 local_irq_save(flags);
1328 ftrace_update_code(); 1312 ftrace_update_code(mod);
1329 local_irq_restore(flags); 1313 local_irq_restore(flags);
1330 mutex_unlock(&ftrace_start_lock); 1314 mutex_unlock(&ftrace_start_lock);
1331 1315
1332 return 0; 1316 return 0;
1333} 1317}
1334 1318
1335void ftrace_init_module(unsigned long *start, unsigned long *end) 1319void ftrace_init_module(struct module *mod,
1320 unsigned long *start, unsigned long *end)
1336{ 1321{
1337 if (ftrace_disabled || start == end) 1322 if (ftrace_disabled || start == end)
1338 return; 1323 return;
1339 ftrace_convert_nops(start, end); 1324 ftrace_convert_nops(mod, start, end);
1340} 1325}
1341 1326
1342extern unsigned long __start_mcount_loc[]; 1327extern unsigned long __start_mcount_loc[];
@@ -1366,7 +1351,8 @@ void __init ftrace_init(void)
1366 1351
1367 last_ftrace_enabled = ftrace_enabled = 1; 1352 last_ftrace_enabled = ftrace_enabled = 1;
1368 1353
1369 ret = ftrace_convert_nops(__start_mcount_loc, 1354 ret = ftrace_convert_nops(NULL,
1355 __start_mcount_loc,
1370 __stop_mcount_loc); 1356 __stop_mcount_loc);
1371 1357
1372 return; 1358 return;