linux/arch/powerpc/kernel/ftrace.c
<<
>>
Prefs
   1/*
   2 * Code for replacing ftrace calls with jumps.
   3 *
   4 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
   5 *
   6 * Thanks goes out to P.A. Semi, Inc for supplying me with a PPC64 box.
   7 *
   8 * Added function graph tracer code, taken from x86 that was written
   9 * by Frederic Weisbecker, and ported to PPC by Steven Rostedt.
  10 *
  11 */
  12
  13#define pr_fmt(fmt) "ftrace-powerpc: " fmt
  14
  15#include <linux/spinlock.h>
  16#include <linux/hardirq.h>
  17#include <linux/uaccess.h>
  18#include <linux/module.h>
  19#include <linux/ftrace.h>
  20#include <linux/percpu.h>
  21#include <linux/init.h>
  22#include <linux/list.h>
  23
  24#include <asm/cacheflush.h>
  25#include <asm/code-patching.h>
  26#include <asm/ftrace.h>
  27#include <asm/syscall.h>
  28
  29
  30#ifdef CONFIG_DYNAMIC_FTRACE
  31static unsigned int
  32ftrace_call_replace(unsigned long ip, unsigned long addr, int link)
  33{
  34        unsigned int op;
  35
  36        addr = ppc_function_entry((void *)addr);
  37
  38        /* if (link) set op to 'bl' else 'b' */
  39        op = create_branch((unsigned int *)ip, addr, link ? 1 : 0);
  40
  41        return op;
  42}
  43
  44static int
  45ftrace_modify_code(unsigned long ip, unsigned int old, unsigned int new)
  46{
  47        unsigned int replaced;
  48
  49        /*
  50         * Note: Due to modules and __init, code can
  51         *  disappear and change, we need to protect against faulting
  52         *  as well as code changing. We do this by using the
  53         *  probe_kernel_* functions.
  54         *
  55         * No real locking needed, this code is run through
  56         * kstop_machine, or before SMP starts.
  57         */
  58
  59        /* read the text we want to modify */
  60        if (probe_kernel_read(&replaced, (void *)ip, MCOUNT_INSN_SIZE))
  61                return -EFAULT;
  62
  63        /* Make sure it is what we expect it to be */
  64        if (replaced != old) {
  65                pr_err("%p: replaced (%#x) != old (%#x)",
  66                (void *)ip, replaced, old);
  67                return -EINVAL;
  68        }
  69
  70        /* replace the text with the new text */
  71        if (patch_instruction((unsigned int *)ip, new))
  72                return -EPERM;
  73
  74        return 0;
  75}
  76
  77/*
  78 * Helper functions that are the same for both PPC64 and PPC32.
  79 */
  80static int test_24bit_addr(unsigned long ip, unsigned long addr)
  81{
  82        addr = ppc_function_entry((void *)addr);
  83
  84        /* use the create_branch to verify that this offset can be branched */
  85        return create_branch((unsigned int *)ip, addr, 0);
  86}
  87
  88#ifdef CONFIG_MODULES
  89
  90static int is_bl_op(unsigned int op)
  91{
  92        return (op & 0xfc000003) == 0x48000001;
  93}
  94
  95static unsigned long find_bl_target(unsigned long ip, unsigned int op)
  96{
  97        static int offset;
  98
  99        offset = (op & 0x03fffffc);
 100        /* make it signed */
 101        if (offset & 0x02000000)
 102                offset |= 0xfe000000;
 103
 104        return ip + (long)offset;
 105}
 106
 107#ifdef CONFIG_PPC64
 108static int
 109__ftrace_make_nop(struct module *mod,
 110                  struct dyn_ftrace *rec, unsigned long addr)
 111{
 112        unsigned long entry, ptr, tramp;
 113        unsigned long ip = rec->ip;
 114        unsigned int op, pop;
 115
 116        /* read where this goes */
 117        if (probe_kernel_read(&op, (void *)ip, sizeof(int))) {
 118                pr_err("Fetching opcode failed.\n");
 119                return -EFAULT;
 120        }
 121
 122        /* Make sure that that this is still a 24bit jump */
 123        if (!is_bl_op(op)) {
 124                pr_err("Not expected bl: opcode is %x\n", op);
 125                return -EINVAL;
 126        }
 127
 128        /* lets find where the pointer goes */
 129        tramp = find_bl_target(ip, op);
 130
 131        pr_devel("ip:%lx jumps to %lx", ip, tramp);
 132
 133        if (module_trampoline_target(mod, tramp, &ptr)) {
 134                pr_err("Failed to get trampoline target\n");
 135                return -EFAULT;
 136        }
 137
 138        pr_devel("trampoline target %lx", ptr);
 139
 140        entry = ppc_global_function_entry((void *)addr);
 141        /* This should match what was called */
 142        if (ptr != entry) {
 143                pr_err("addr %lx does not match expected %lx\n", ptr, entry);
 144                return -EINVAL;
 145        }
 146
 147        /*
 148         * Our original call site looks like:
 149         *
 150         * bl <tramp>
 151         * ld r2,XX(r1)
 152         *
 153         * Milton Miller pointed out that we can not simply nop the branch.
 154         * If a task was preempted when calling a trace function, the nops
 155         * will remove the way to restore the TOC in r2 and the r2 TOC will
 156         * get corrupted.
 157         *
 158         * Use a b +8 to jump over the load.
 159         */
 160
 161        pop = PPC_INST_BRANCH | 8;      /* b +8 */
 162
 163        /*
 164         * Check what is in the next instruction. We can see ld r2,40(r1), but
 165         * on first pass after boot we will see mflr r0.
 166         */
 167        if (probe_kernel_read(&op, (void *)(ip+4), MCOUNT_INSN_SIZE)) {
 168                pr_err("Fetching op failed.\n");
 169                return -EFAULT;
 170        }
 171
 172        if (op != PPC_INST_LD_TOC) {
 173                unsigned int inst;
 174
 175                if (probe_kernel_read(&inst, (void *)(ip - 4), 4)) {
 176                        pr_err("Fetching instruction at %lx failed.\n", ip - 4);
 177                        return -EFAULT;
 178                }
 179
 180                /* We expect either a mlfr r0, or a std r0, LRSAVE(r1) */
 181                if (inst != PPC_INST_MFLR && inst != PPC_INST_STD_LR) {
 182                        pr_err("Unexpected instructions around bl _mcount\n"
 183                               "when enabling dynamic ftrace!\t"
 184                               "(%08x,bl,%08x)\n", inst, op);
 185                        return -EINVAL;
 186                }
 187
 188                /* When using -mkernel_profile there is no load to jump over */
 189                pop = PPC_INST_NOP;
 190        }
 191
 192        if (patch_instruction((unsigned int *)ip, pop)) {
 193                pr_err("Patching NOP failed.\n");
 194                return -EPERM;
 195        }
 196
 197        return 0;
 198}
 199
 200#else /* !PPC64 */
 201static int
 202__ftrace_make_nop(struct module *mod,
 203                  struct dyn_ftrace *rec, unsigned long addr)
 204{
 205        unsigned int op;
 206        unsigned int jmp[4];
 207        unsigned long ip = rec->ip;
 208        unsigned long tramp;
 209
 210        if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE))
 211                return -EFAULT;
 212
 213        /* Make sure that that this is still a 24bit jump */
 214        if (!is_bl_op(op)) {
 215                pr_err("Not expected bl: opcode is %x\n", op);
 216                return -EINVAL;
 217        }
 218
 219        /* lets find where the pointer goes */
 220        tramp = find_bl_target(ip, op);
 221
 222        /*
 223         * On PPC32 the trampoline looks like:
 224         *  0x3d, 0x80, 0x00, 0x00  lis r12,sym@ha
 225         *  0x39, 0x8c, 0x00, 0x00  addi r12,r12,sym@l
 226         *  0x7d, 0x89, 0x03, 0xa6  mtctr r12
 227         *  0x4e, 0x80, 0x04, 0x20  bctr
 228         */
 229
 230        pr_devel("ip:%lx jumps to %lx", ip, tramp);
 231
 232        /* Find where the trampoline jumps to */
 233        if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) {
 234                pr_err("Failed to read %lx\n", tramp);
 235                return -EFAULT;
 236        }
 237
 238        pr_devel(" %08x %08x ", jmp[0], jmp[1]);
 239
 240        /* verify that this is what we expect it to be */
 241        if (((jmp[0] & 0xffff0000) != 0x3d800000) ||
 242            ((jmp[1] & 0xffff0000) != 0x398c0000) ||
 243            (jmp[2] != 0x7d8903a6) ||
 244            (jmp[3] != 0x4e800420)) {
 245                pr_err("Not a trampoline\n");
 246                return -EINVAL;
 247        }
 248
 249        tramp = (jmp[1] & 0xffff) |
 250                ((jmp[0] & 0xffff) << 16);
 251        if (tramp & 0x8000)
 252                tramp -= 0x10000;
 253
 254        pr_devel(" %lx ", tramp);
 255
 256        if (tramp != addr) {
 257                pr_err("Trampoline location %08lx does not match addr\n",
 258                       tramp);
 259                return -EINVAL;
 260        }
 261
 262        op = PPC_INST_NOP;
 263
 264        if (patch_instruction((unsigned int *)ip, op))
 265                return -EPERM;
 266
 267        return 0;
 268}
 269#endif /* PPC64 */
 270#endif /* CONFIG_MODULES */
 271
 272int ftrace_make_nop(struct module *mod,
 273                    struct dyn_ftrace *rec, unsigned long addr)
 274{
 275        unsigned long ip = rec->ip;
 276        unsigned int old, new;
 277
 278        /*
 279         * If the calling address is more that 24 bits away,
 280         * then we had to use a trampoline to make the call.
 281         * Otherwise just update the call site.
 282         */
 283        if (test_24bit_addr(ip, addr)) {
 284                /* within range */
 285                old = ftrace_call_replace(ip, addr, 1);
 286                new = PPC_INST_NOP;
 287                return ftrace_modify_code(ip, old, new);
 288        }
 289
 290#ifdef CONFIG_MODULES
 291        /*
 292         * Out of range jumps are called from modules.
 293         * We should either already have a pointer to the module
 294         * or it has been passed in.
 295         */
 296        if (!rec->arch.mod) {
 297                if (!mod) {
 298                        pr_err("No module loaded addr=%lx\n", addr);
 299                        return -EFAULT;
 300                }
 301                rec->arch.mod = mod;
 302        } else if (mod) {
 303                if (mod != rec->arch.mod) {
 304                        pr_err("Record mod %p not equal to passed in mod %p\n",
 305                               rec->arch.mod, mod);
 306                        return -EINVAL;
 307                }
 308                /* nothing to do if mod == rec->arch.mod */
 309        } else
 310                mod = rec->arch.mod;
 311
 312        return __ftrace_make_nop(mod, rec, addr);
 313#else
 314        /* We should not get here without modules */
 315        return -EINVAL;
 316#endif /* CONFIG_MODULES */
 317}
 318
 319#ifdef CONFIG_MODULES
 320#ifdef CONFIG_PPC64
 321/*
 322 * Examine the existing instructions for __ftrace_make_call.
 323 * They should effectively be a NOP, and follow formal constraints,
 324 * depending on the ABI. Return false if they don't.
 325 */
 326#ifndef CC_USING_MPROFILE_KERNEL
 327static int
 328expected_nop_sequence(void *ip, unsigned int op0, unsigned int op1)
 329{
 330        /*
 331         * We expect to see:
 332         *
 333         * b +8
 334         * ld r2,XX(r1)
 335         *
 336         * The load offset is different depending on the ABI. For simplicity
 337         * just mask it out when doing the compare.
 338         */
 339        if ((op0 != 0x48000008) || ((op1 & 0xffff0000) != 0xe8410000))
 340                return 0;
 341        return 1;
 342}
 343#else
 344static int
 345expected_nop_sequence(void *ip, unsigned int op0, unsigned int op1)
 346{
 347        /* look for patched "NOP" on ppc64 with -mprofile-kernel */
 348        if (op0 != PPC_INST_NOP)
 349                return 0;
 350        return 1;
 351}
 352#endif
 353
 354static int
 355__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 356{
 357        unsigned int op[2];
 358        void *ip = (void *)rec->ip;
 359        struct module_ext *mod_ext;
 360
 361        /* read where this goes */
 362        if (probe_kernel_read(op, ip, sizeof(op)))
 363                return -EFAULT;
 364
 365        if (!expected_nop_sequence(ip, op[0], op[1])) {
 366                pr_err("Unexpected call sequence at %p: %x %x\n",
 367                ip, op[0], op[1]);
 368                return -EINVAL;
 369        }
 370
 371        mutex_lock(&module_ext_mutex);
 372        mod_ext = find_module_ext(rec->arch.mod);
 373        mutex_unlock(&module_ext_mutex);
 374
 375        /* If we never set up a trampoline to ftrace_caller, then bail */
 376        if (!mod_ext->tramp) {
 377                pr_err("No ftrace trampoline\n");
 378                return -EINVAL;
 379        }
 380
 381        /* Ensure branch is within 24 bits */
 382        if (!create_branch(ip, mod_ext->tramp, BRANCH_SET_LINK)) {
 383                pr_err("Branch out of range\n");
 384                return -EINVAL;
 385        }
 386
 387        if (patch_branch(ip, mod_ext->tramp, BRANCH_SET_LINK)) {
 388                pr_err("REL24 out of range!\n");
 389                return -EINVAL;
 390        }
 391
 392        return 0;
 393}
 394
 395#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
 396int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
 397                        unsigned long addr)
 398{
 399        return ftrace_make_call(rec, addr);
 400}
 401#endif
 402
 403#else  /* !CONFIG_PPC64: */
 404static int
 405__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 406{
 407        unsigned int op;
 408        unsigned long ip = rec->ip;
 409
 410        /* read where this goes */
 411        if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE))
 412                return -EFAULT;
 413
 414        /* It should be pointing to a nop */
 415        if (op != PPC_INST_NOP) {
 416                pr_err("Expected NOP but have %x\n", op);
 417                return -EINVAL;
 418        }
 419
 420        /* If we never set up a trampoline to ftrace_caller, then bail */
 421        if (!rec->arch.mod->arch.tramp) {
 422                pr_err("No ftrace trampoline\n");
 423                return -EINVAL;
 424        }
 425
 426        /* create the branch to the trampoline */
 427        op = create_branch((unsigned int *)ip,
 428                           rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
 429        if (!op) {
 430                pr_err("REL24 out of range!\n");
 431                return -EINVAL;
 432        }
 433
 434        pr_devel("write to %lx\n", rec->ip);
 435
 436        if (patch_instruction((unsigned int *)ip, op))
 437                return -EPERM;
 438
 439        return 0;
 440}
 441#endif /* CONFIG_PPC64 */
 442#endif /* CONFIG_MODULES */
 443
 444int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 445{
 446        unsigned long ip = rec->ip;
 447        unsigned int old, new;
 448
 449        /*
 450         * If the calling address is more that 24 bits away,
 451         * then we had to use a trampoline to make the call.
 452         * Otherwise just update the call site.
 453         */
 454        if (test_24bit_addr(ip, addr)) {
 455                /* within range */
 456                old = PPC_INST_NOP;
 457                new = ftrace_call_replace(ip, addr, 1);
 458                return ftrace_modify_code(ip, old, new);
 459        }
 460
 461#ifdef CONFIG_MODULES
 462        /*
 463         * Out of range jumps are called from modules.
 464         * Being that we are converting from nop, it had better
 465         * already have a module defined.
 466         */
 467        if (!rec->arch.mod) {
 468                pr_err("No module loaded\n");
 469                return -EINVAL;
 470        }
 471
 472        return __ftrace_make_call(rec, addr);
 473#else
 474        /* We should not get here without modules */
 475        return -EINVAL;
 476#endif /* CONFIG_MODULES */
 477}
 478
 479int ftrace_update_ftrace_func(ftrace_func_t func)
 480{
 481        unsigned long ip = (unsigned long)(&ftrace_call);
 482        unsigned int old, new;
 483        int ret;
 484
 485        old = *(unsigned int *)&ftrace_call;
 486        new = ftrace_call_replace(ip, (unsigned long)func, 1);
 487        ret = ftrace_modify_code(ip, old, new);
 488
 489        return ret;
 490}
 491
 492static int __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
 493{
 494        unsigned long ftrace_addr = (unsigned long)FTRACE_ADDR;
 495        int ret;
 496
 497        ret = ftrace_update_record(rec, enable);
 498
 499        switch (ret) {
 500        case FTRACE_UPDATE_IGNORE:
 501                return 0;
 502        case FTRACE_UPDATE_MAKE_CALL:
 503                return ftrace_make_call(rec, ftrace_addr);
 504        case FTRACE_UPDATE_MAKE_NOP:
 505                return ftrace_make_nop(NULL, rec, ftrace_addr);
 506        }
 507
 508        return 0;
 509}
 510
 511void ftrace_replace_code(int enable)
 512{
 513        struct ftrace_rec_iter *iter;
 514        struct dyn_ftrace *rec;
 515        int ret;
 516
 517        for (iter = ftrace_rec_iter_start(); iter;
 518             iter = ftrace_rec_iter_next(iter)) {
 519                rec = ftrace_rec_iter_record(iter);
 520                ret = __ftrace_replace_code(rec, enable);
 521                if (ret) {
 522                        ftrace_bug(ret, rec->ip);
 523                        return;
 524                }
 525        }
 526}
 527
 528/*
 529 * Use the default ftrace_modify_all_code, but without
 530 * stop_machine().
 531 */
 532void arch_ftrace_update_code(int command)
 533{
 534        ftrace_modify_all_code(command);
 535}
 536
 537int __init ftrace_dyn_arch_init(void *data)
 538{
 539        /* caller expects data to be zero */
 540        unsigned long *p = data;
 541
 542        *p = 0;
 543
 544        return 0;
 545}
 546#endif /* CONFIG_DYNAMIC_FTRACE */
 547
 548#ifdef CONFIG_FUNCTION_GRAPH_TRACER
 549
 550#ifdef CONFIG_DYNAMIC_FTRACE
 551extern void ftrace_graph_call(void);
 552extern void ftrace_graph_stub(void);
 553
 554int ftrace_enable_ftrace_graph_caller(void)
 555{
 556        unsigned long ip = (unsigned long)(&ftrace_graph_call);
 557        unsigned long addr = (unsigned long)(&ftrace_graph_caller);
 558        unsigned long stub = (unsigned long)(&ftrace_graph_stub);
 559        unsigned int old, new;
 560
 561        old = ftrace_call_replace(ip, stub, 0);
 562        new = ftrace_call_replace(ip, addr, 0);
 563
 564        return ftrace_modify_code(ip, old, new);
 565}
 566
 567int ftrace_disable_ftrace_graph_caller(void)
 568{
 569        unsigned long ip = (unsigned long)(&ftrace_graph_call);
 570        unsigned long addr = (unsigned long)(&ftrace_graph_caller);
 571        unsigned long stub = (unsigned long)(&ftrace_graph_stub);
 572        unsigned int old, new;
 573
 574        old = ftrace_call_replace(ip, addr, 0);
 575        new = ftrace_call_replace(ip, stub, 0);
 576
 577        return ftrace_modify_code(ip, old, new);
 578}
 579#endif /* CONFIG_DYNAMIC_FTRACE */
 580
 581#ifdef CONFIG_PPC64
 582extern void mod_return_to_handler(void);
 583#endif
 584
 585/*
 586 * Hook the return address and push it in the stack of return addrs
 587 * in current thread info. Return the address we want to divert to.
 588 */
 589unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip)
 590{
 591        struct ftrace_graph_ent trace;
 592        unsigned long return_hooker = (unsigned long)&return_to_handler;
 593
 594        if (unlikely(ftrace_graph_is_dead()))
 595                goto out;
 596
 597        if (unlikely(atomic_read(&current->tracing_graph_pause)))
 598                goto out;
 599
 600#ifdef CONFIG_PPC64
 601        /* non core kernel code needs to save and restore the TOC */
 602        if (REGION_ID(self_addr) != KERNEL_REGION_ID)
 603                return_hooker = (unsigned long)&mod_return_to_handler;
 604#endif
 605
 606        return_hooker = ppc_function_entry((void *)return_hooker);
 607
 608        trace.func = ip;
 609        trace.depth = current->curr_ret_stack + 1;
 610
 611        /* Only trace if the calling function expects to */
 612        if (!ftrace_graph_entry(&trace))
 613                goto out;
 614
 615        if (ftrace_push_return_trace(parent, ip, &trace.depth, 0,
 616                                     NULL) == -EBUSY)
 617                goto out;
 618
 619        parent = return_hooker;
 620out:
 621        return parent;
 622}
 623#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 624
 625#if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_PPC64)
 626unsigned long __init arch_syscall_addr(int nr)
 627{
 628        return sys_call_table[nr*2];
 629}
 630#endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_PPC64 */
 631
 632#if defined(CONFIG_PPC64) && (!defined(_CALL_ELF) || _CALL_ELF != 2)
 633char *arch_ftrace_match_adjust(char *str, const char *search)
 634{
 635        if (str[0] == '.' && search[0] != '.')
 636                return str + 1;
 637        else
 638                return str;
 639}
 640#endif /* defined(CONFIG_PPC64) && (!defined(_CALL_ELF) || _CALL_ELF != 2) */
 641