aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/ftrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/ftrace.c')
-rw-r--r--arch/x86/kernel/ftrace.c56
1 files changed, 8 insertions, 48 deletions
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 52819e816f87..cbc4a91b131e 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -297,16 +297,7 @@ int ftrace_int3_handler(struct pt_regs *regs)
297 297
298static int ftrace_write(unsigned long ip, const char *val, int size) 298static int ftrace_write(unsigned long ip, const char *val, int size)
299{ 299{
300 /* 300 ip = text_ip_addr(ip);
301 * On x86_64, kernel text mappings are mapped read-only with
302 * CONFIG_DEBUG_RODATA. So we use the kernel identity mapping instead
303 * of the kernel text mapping to modify the kernel text.
304 *
305 * For 32bit kernels, these mappings are same and we can use
306 * kernel identity mapping to modify code.
307 */
308 if (within(ip, (unsigned long)_text, (unsigned long)_etext))
309 ip = (unsigned long)__va(__pa_symbol(ip));
310 301
311 if (probe_kernel_write((void *)ip, val, size)) 302 if (probe_kernel_write((void *)ip, val, size))
312 return -EPERM; 303 return -EPERM;
@@ -349,40 +340,14 @@ static int add_brk_on_nop(struct dyn_ftrace *rec)
349 return add_break(rec->ip, old); 340 return add_break(rec->ip, old);
350} 341}
351 342
352/*
353 * If the record has the FTRACE_FL_REGS set, that means that it
354 * wants to convert to a callback that saves all regs. If FTRACE_FL_REGS
355 * is not not set, then it wants to convert to the normal callback.
356 */
357static unsigned long get_ftrace_addr(struct dyn_ftrace *rec)
358{
359 if (rec->flags & FTRACE_FL_REGS)
360 return (unsigned long)FTRACE_REGS_ADDR;
361 else
362 return (unsigned long)FTRACE_ADDR;
363}
364
365/*
366 * The FTRACE_FL_REGS_EN is set when the record already points to
367 * a function that saves all the regs. Basically the '_EN' version
368 * represents the current state of the function.
369 */
370static unsigned long get_ftrace_old_addr(struct dyn_ftrace *rec)
371{
372 if (rec->flags & FTRACE_FL_REGS_EN)
373 return (unsigned long)FTRACE_REGS_ADDR;
374 else
375 return (unsigned long)FTRACE_ADDR;
376}
377
378static int add_breakpoints(struct dyn_ftrace *rec, int enable) 343static int add_breakpoints(struct dyn_ftrace *rec, int enable)
379{ 344{
380 unsigned long ftrace_addr; 345 unsigned long ftrace_addr;
381 int ret; 346 int ret;
382 347
383 ret = ftrace_test_record(rec, enable); 348 ftrace_addr = ftrace_get_addr_curr(rec);
384 349
385 ftrace_addr = get_ftrace_addr(rec); 350 ret = ftrace_test_record(rec, enable);
386 351
387 switch (ret) { 352 switch (ret) {
388 case FTRACE_UPDATE_IGNORE: 353 case FTRACE_UPDATE_IGNORE:
@@ -392,10 +357,7 @@ static int add_breakpoints(struct dyn_ftrace *rec, int enable)
392 /* converting nop to call */ 357 /* converting nop to call */
393 return add_brk_on_nop(rec); 358 return add_brk_on_nop(rec);
394 359
395 case FTRACE_UPDATE_MODIFY_CALL_REGS:
396 case FTRACE_UPDATE_MODIFY_CALL: 360 case FTRACE_UPDATE_MODIFY_CALL:
397 ftrace_addr = get_ftrace_old_addr(rec);
398 /* fall through */
399 case FTRACE_UPDATE_MAKE_NOP: 361 case FTRACE_UPDATE_MAKE_NOP:
400 /* converting a call to a nop */ 362 /* converting a call to a nop */
401 return add_brk_on_call(rec, ftrace_addr); 363 return add_brk_on_call(rec, ftrace_addr);
@@ -440,14 +402,14 @@ static int remove_breakpoint(struct dyn_ftrace *rec)
440 * If not, don't touch the breakpoint, we make just create 402 * If not, don't touch the breakpoint, we make just create
441 * a disaster. 403 * a disaster.
442 */ 404 */
443 ftrace_addr = get_ftrace_addr(rec); 405 ftrace_addr = ftrace_get_addr_new(rec);
444 nop = ftrace_call_replace(ip, ftrace_addr); 406 nop = ftrace_call_replace(ip, ftrace_addr);
445 407
446 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) == 0) 408 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) == 0)
447 goto update; 409 goto update;
448 410
449 /* Check both ftrace_addr and ftrace_old_addr */ 411 /* Check both ftrace_addr and ftrace_old_addr */
450 ftrace_addr = get_ftrace_old_addr(rec); 412 ftrace_addr = ftrace_get_addr_curr(rec);
451 nop = ftrace_call_replace(ip, ftrace_addr); 413 nop = ftrace_call_replace(ip, ftrace_addr);
452 414
453 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0) 415 if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0)
@@ -491,13 +453,12 @@ static int add_update(struct dyn_ftrace *rec, int enable)
491 453
492 ret = ftrace_test_record(rec, enable); 454 ret = ftrace_test_record(rec, enable);
493 455
494 ftrace_addr = get_ftrace_addr(rec); 456 ftrace_addr = ftrace_get_addr_new(rec);
495 457
496 switch (ret) { 458 switch (ret) {
497 case FTRACE_UPDATE_IGNORE: 459 case FTRACE_UPDATE_IGNORE:
498 return 0; 460 return 0;
499 461
500 case FTRACE_UPDATE_MODIFY_CALL_REGS:
501 case FTRACE_UPDATE_MODIFY_CALL: 462 case FTRACE_UPDATE_MODIFY_CALL:
502 case FTRACE_UPDATE_MAKE_CALL: 463 case FTRACE_UPDATE_MAKE_CALL:
503 /* converting nop to call */ 464 /* converting nop to call */
@@ -538,13 +499,12 @@ static int finish_update(struct dyn_ftrace *rec, int enable)
538 499
539 ret = ftrace_update_record(rec, enable); 500 ret = ftrace_update_record(rec, enable);
540 501
541 ftrace_addr = get_ftrace_addr(rec); 502 ftrace_addr = ftrace_get_addr_new(rec);
542 503
543 switch (ret) { 504 switch (ret) {
544 case FTRACE_UPDATE_IGNORE: 505 case FTRACE_UPDATE_IGNORE:
545 return 0; 506 return 0;
546 507
547 case FTRACE_UPDATE_MODIFY_CALL_REGS:
548 case FTRACE_UPDATE_MODIFY_CALL: 508 case FTRACE_UPDATE_MODIFY_CALL:
549 case FTRACE_UPDATE_MAKE_CALL: 509 case FTRACE_UPDATE_MAKE_CALL:
550 /* converting nop to call */ 510 /* converting nop to call */
@@ -621,8 +581,8 @@ void ftrace_replace_code(int enable)
621 return; 581 return;
622 582
623 remove_breakpoints: 583 remove_breakpoints:
584 pr_warn("Failed on %s (%d):\n", report, count);
624 ftrace_bug(ret, rec ? rec->ip : 0); 585 ftrace_bug(ret, rec ? rec->ip : 0);
625 printk(KERN_WARNING "Failed on %s (%d):\n", report, count);
626 for_ftrace_rec_iter(iter) { 586 for_ftrace_rec_iter(iter) {
627 rec = ftrace_rec_iter_record(iter); 587 rec = ftrace_rec_iter_record(iter);
628 /* 588 /*