13d083395SSteven Rostedt /* 23d083395SSteven Rostedt * Code for replacing ftrace calls with jumps. 33d083395SSteven Rostedt * 43d083395SSteven Rostedt * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com> 53d083395SSteven Rostedt * 63d083395SSteven Rostedt * Thanks goes to Ingo Molnar, for suggesting the idea. 73d083395SSteven Rostedt * Mathieu Desnoyers, for suggesting postponing the modifications. 83d083395SSteven Rostedt * Arjan van de Ven, for keeping me straight, and explaining to me 93d083395SSteven Rostedt * the dangers of modifying code on the run. 103d083395SSteven Rostedt */ 113d083395SSteven Rostedt 123d083395SSteven Rostedt #include <linux/spinlock.h> 133d083395SSteven Rostedt #include <linux/hardirq.h> 146f93fc07SSteven Rostedt #include <linux/uaccess.h> 153d083395SSteven Rostedt #include <linux/ftrace.h> 163d083395SSteven Rostedt #include <linux/percpu.h> 1719b3e967SIngo Molnar #include <linux/sched.h> 183d083395SSteven Rostedt #include <linux/init.h> 193d083395SSteven Rostedt #include <linux/list.h> 203d083395SSteven Rostedt 21*16239630SSteven Rostedt #include <asm/cacheflush.h> 22395a59d0SAbhishek Sagar #include <asm/ftrace.h> 23caf4b323SFrederic Weisbecker #include <linux/ftrace.h> 24732f3ca7SSteven Rostedt #include <asm/nops.h> 25caf4b323SFrederic Weisbecker #include <asm/nmi.h> 26dfa60abaSSteven Rostedt 273d083395SSteven Rostedt 28caf4b323SFrederic Weisbecker #ifdef CONFIG_DYNAMIC_FTRACE 293d083395SSteven Rostedt 30*16239630SSteven Rostedt int ftrace_arch_code_modify_prepare(void) 31*16239630SSteven Rostedt { 32*16239630SSteven Rostedt set_kernel_text_rw(); 33*16239630SSteven Rostedt return 0; 34*16239630SSteven Rostedt } 35*16239630SSteven Rostedt 36*16239630SSteven Rostedt int ftrace_arch_code_modify_post_process(void) 37*16239630SSteven Rostedt { 38*16239630SSteven Rostedt set_kernel_text_ro(); 39*16239630SSteven Rostedt return 0; 40*16239630SSteven Rostedt } 41*16239630SSteven Rostedt 423d083395SSteven Rostedt union ftrace_code_union { 43395a59d0SAbhishek Sagar char code[MCOUNT_INSN_SIZE]; 443d083395SSteven Rostedt struct { 453d083395SSteven Rostedt char e8; 463d083395SSteven Rostedt int offset; 473d083395SSteven Rostedt } __attribute__((packed)); 483d083395SSteven Rostedt }; 493d083395SSteven Rostedt 5015adc048SSteven Rostedt static int ftrace_calc_offset(long ip, long addr) 513c1720f0SSteven Rostedt { 523c1720f0SSteven Rostedt return (int)(addr - ip); 533d083395SSteven Rostedt } 543d083395SSteven Rostedt 5531e88909SSteven Rostedt static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) 563c1720f0SSteven Rostedt { 573c1720f0SSteven Rostedt static union ftrace_code_union calc; 583c1720f0SSteven Rostedt 593c1720f0SSteven Rostedt calc.e8 = 0xe8; 60395a59d0SAbhishek Sagar calc.offset = ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr); 613c1720f0SSteven Rostedt 623c1720f0SSteven Rostedt /* 633c1720f0SSteven Rostedt * No locking needed, this must be called via kstop_machine 643c1720f0SSteven Rostedt * which in essence is like running on a uniprocessor machine. 653c1720f0SSteven Rostedt */ 663c1720f0SSteven Rostedt return calc.code; 673c1720f0SSteven Rostedt } 683c1720f0SSteven Rostedt 6917666f02SSteven Rostedt /* 7017666f02SSteven Rostedt * Modifying code must take extra care. On an SMP machine, if 7117666f02SSteven Rostedt * the code being modified is also being executed on another CPU 7217666f02SSteven Rostedt * that CPU will have undefined results and possibly take a GPF. 7317666f02SSteven Rostedt * We use kstop_machine to stop other CPUS from exectuing code. 7417666f02SSteven Rostedt * But this does not stop NMIs from happening. We still need 7517666f02SSteven Rostedt * to protect against that. We separate out the modification of 7617666f02SSteven Rostedt * the code to take care of this. 7717666f02SSteven Rostedt * 7817666f02SSteven Rostedt * Two buffers are added: An IP buffer and a "code" buffer. 7917666f02SSteven Rostedt * 80a26a2a27SSteven Rostedt * 1) Put the instruction pointer into the IP buffer 8117666f02SSteven Rostedt * and the new code into the "code" buffer. 8217666f02SSteven Rostedt * 2) Set a flag that says we are modifying code 8317666f02SSteven Rostedt * 3) Wait for any running NMIs to finish. 8417666f02SSteven Rostedt * 4) Write the code 8517666f02SSteven Rostedt * 5) clear the flag. 8617666f02SSteven Rostedt * 6) Wait for any running NMIs to finish. 8717666f02SSteven Rostedt * 8817666f02SSteven Rostedt * If an NMI is executed, the first thing it does is to call 8917666f02SSteven Rostedt * "ftrace_nmi_enter". This will check if the flag is set to write 9017666f02SSteven Rostedt * and if it is, it will write what is in the IP and "code" buffers. 9117666f02SSteven Rostedt * 9217666f02SSteven Rostedt * The trick is, it does not matter if everyone is writing the same 9317666f02SSteven Rostedt * content to the code location. Also, if a CPU is executing code 9417666f02SSteven Rostedt * it is OK to write to that code location if the contents being written 9517666f02SSteven Rostedt * are the same as what exists. 9617666f02SSteven Rostedt */ 9717666f02SSteven Rostedt 98a26a2a27SSteven Rostedt static atomic_t in_nmi = ATOMIC_INIT(0); 99a26a2a27SSteven Rostedt static int mod_code_status; /* holds return value of text write */ 100a26a2a27SSteven Rostedt static int mod_code_write; /* set when NMI should do the write */ 101a26a2a27SSteven Rostedt static void *mod_code_ip; /* holds the IP to write to */ 102a26a2a27SSteven Rostedt static void *mod_code_newcode; /* holds the text to write to the IP */ 10317666f02SSteven Rostedt 104a26a2a27SSteven Rostedt static unsigned nmi_wait_count; 105a26a2a27SSteven Rostedt static atomic_t nmi_update_count = ATOMIC_INIT(0); 106b807c3d0SSteven Rostedt 107b807c3d0SSteven Rostedt int ftrace_arch_read_dyn_info(char *buf, int size) 108b807c3d0SSteven Rostedt { 109b807c3d0SSteven Rostedt int r; 110b807c3d0SSteven Rostedt 111b807c3d0SSteven Rostedt r = snprintf(buf, size, "%u %u", 112b807c3d0SSteven Rostedt nmi_wait_count, 113b807c3d0SSteven Rostedt atomic_read(&nmi_update_count)); 114b807c3d0SSteven Rostedt return r; 115b807c3d0SSteven Rostedt } 116b807c3d0SSteven Rostedt 11717666f02SSteven Rostedt static void ftrace_mod_code(void) 11817666f02SSteven Rostedt { 11917666f02SSteven Rostedt /* 12017666f02SSteven Rostedt * Yes, more than one CPU process can be writing to mod_code_status. 12117666f02SSteven Rostedt * (and the code itself) 12217666f02SSteven Rostedt * But if one were to fail, then they all should, and if one were 12317666f02SSteven Rostedt * to succeed, then they all should. 12417666f02SSteven Rostedt */ 12517666f02SSteven Rostedt mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode, 12617666f02SSteven Rostedt MCOUNT_INSN_SIZE); 12717666f02SSteven Rostedt } 12817666f02SSteven Rostedt 12917666f02SSteven Rostedt void ftrace_nmi_enter(void) 13017666f02SSteven Rostedt { 13117666f02SSteven Rostedt atomic_inc(&in_nmi); 13217666f02SSteven Rostedt /* Must have in_nmi seen before reading write flag */ 13317666f02SSteven Rostedt smp_mb(); 134b807c3d0SSteven Rostedt if (mod_code_write) { 13517666f02SSteven Rostedt ftrace_mod_code(); 136b807c3d0SSteven Rostedt atomic_inc(&nmi_update_count); 137b807c3d0SSteven Rostedt } 13817666f02SSteven Rostedt } 13917666f02SSteven Rostedt 14017666f02SSteven Rostedt void ftrace_nmi_exit(void) 14117666f02SSteven Rostedt { 14217666f02SSteven Rostedt /* Finish all executions before clearing in_nmi */ 14317666f02SSteven Rostedt smp_wmb(); 14417666f02SSteven Rostedt atomic_dec(&in_nmi); 14517666f02SSteven Rostedt } 14617666f02SSteven Rostedt 14717666f02SSteven Rostedt static void wait_for_nmi(void) 14817666f02SSteven Rostedt { 149b807c3d0SSteven Rostedt int waited = 0; 150b807c3d0SSteven Rostedt 151b807c3d0SSteven Rostedt while (atomic_read(&in_nmi)) { 152b807c3d0SSteven Rostedt waited = 1; 15317666f02SSteven Rostedt cpu_relax(); 15417666f02SSteven Rostedt } 15517666f02SSteven Rostedt 156b807c3d0SSteven Rostedt if (waited) 157b807c3d0SSteven Rostedt nmi_wait_count++; 158b807c3d0SSteven Rostedt } 159b807c3d0SSteven Rostedt 16017666f02SSteven Rostedt static int 16117666f02SSteven Rostedt do_ftrace_mod_code(unsigned long ip, void *new_code) 16217666f02SSteven Rostedt { 16317666f02SSteven Rostedt mod_code_ip = (void *)ip; 16417666f02SSteven Rostedt mod_code_newcode = new_code; 16517666f02SSteven Rostedt 16617666f02SSteven Rostedt /* The buffers need to be visible before we let NMIs write them */ 16717666f02SSteven Rostedt smp_wmb(); 16817666f02SSteven Rostedt 16917666f02SSteven Rostedt mod_code_write = 1; 17017666f02SSteven Rostedt 17117666f02SSteven Rostedt /* Make sure write bit is visible before we wait on NMIs */ 17217666f02SSteven Rostedt smp_mb(); 17317666f02SSteven Rostedt 17417666f02SSteven Rostedt wait_for_nmi(); 17517666f02SSteven Rostedt 17617666f02SSteven Rostedt /* Make sure all running NMIs have finished before we write the code */ 17717666f02SSteven Rostedt smp_mb(); 17817666f02SSteven Rostedt 17917666f02SSteven Rostedt ftrace_mod_code(); 18017666f02SSteven Rostedt 18117666f02SSteven Rostedt /* Make sure the write happens before clearing the bit */ 18217666f02SSteven Rostedt smp_wmb(); 18317666f02SSteven Rostedt 18417666f02SSteven Rostedt mod_code_write = 0; 18517666f02SSteven Rostedt 18617666f02SSteven Rostedt /* make sure NMIs see the cleared bit */ 18717666f02SSteven Rostedt smp_mb(); 18817666f02SSteven Rostedt 18917666f02SSteven Rostedt wait_for_nmi(); 19017666f02SSteven Rostedt 19117666f02SSteven Rostedt return mod_code_status; 19217666f02SSteven Rostedt } 19317666f02SSteven Rostedt 19417666f02SSteven Rostedt 195caf4b323SFrederic Weisbecker 196caf4b323SFrederic Weisbecker 197caf4b323SFrederic Weisbecker static unsigned char ftrace_nop[MCOUNT_INSN_SIZE]; 198caf4b323SFrederic Weisbecker 19931e88909SSteven Rostedt static unsigned char *ftrace_nop_replace(void) 200caf4b323SFrederic Weisbecker { 201caf4b323SFrederic Weisbecker return ftrace_nop; 202caf4b323SFrederic Weisbecker } 203caf4b323SFrederic Weisbecker 20431e88909SSteven Rostedt static int 2053d083395SSteven Rostedt ftrace_modify_code(unsigned long ip, unsigned char *old_code, 2063d083395SSteven Rostedt unsigned char *new_code) 2073d083395SSteven Rostedt { 2086f93fc07SSteven Rostedt unsigned char replaced[MCOUNT_INSN_SIZE]; 2093d083395SSteven Rostedt 2103d083395SSteven Rostedt /* 2113d083395SSteven Rostedt * Note: Due to modules and __init, code can 2123d083395SSteven Rostedt * disappear and change, we need to protect against faulting 21376aefee5SSteven Rostedt * as well as code changing. We do this by using the 214ab9a0918SSteven Rostedt * probe_kernel_* functions. 2153d083395SSteven Rostedt * 2163d083395SSteven Rostedt * No real locking needed, this code is run through 2176f93fc07SSteven Rostedt * kstop_machine, or before SMP starts. 2183d083395SSteven Rostedt */ 21976aefee5SSteven Rostedt 22076aefee5SSteven Rostedt /* read the text we want to modify */ 221ab9a0918SSteven Rostedt if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) 222593eb8a2SSteven Rostedt return -EFAULT; 2236f93fc07SSteven Rostedt 22476aefee5SSteven Rostedt /* Make sure it is what we expect it to be */ 2256f93fc07SSteven Rostedt if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0) 226593eb8a2SSteven Rostedt return -EINVAL; 2276f93fc07SSteven Rostedt 22876aefee5SSteven Rostedt /* replace the text with the new text */ 22917666f02SSteven Rostedt if (do_ftrace_mod_code(ip, new_code)) 230593eb8a2SSteven Rostedt return -EPERM; 2316f93fc07SSteven Rostedt 2323d083395SSteven Rostedt sync_core(); 2333d083395SSteven Rostedt 2346f93fc07SSteven Rostedt return 0; 2353d083395SSteven Rostedt } 2363d083395SSteven Rostedt 23731e88909SSteven Rostedt int ftrace_make_nop(struct module *mod, 23831e88909SSteven Rostedt struct dyn_ftrace *rec, unsigned long addr) 23931e88909SSteven Rostedt { 24031e88909SSteven Rostedt unsigned char *new, *old; 24131e88909SSteven Rostedt unsigned long ip = rec->ip; 24231e88909SSteven Rostedt 24331e88909SSteven Rostedt old = ftrace_call_replace(ip, addr); 24431e88909SSteven Rostedt new = ftrace_nop_replace(); 24531e88909SSteven Rostedt 24631e88909SSteven Rostedt return ftrace_modify_code(rec->ip, old, new); 24731e88909SSteven Rostedt } 24831e88909SSteven Rostedt 24931e88909SSteven Rostedt int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) 25031e88909SSteven Rostedt { 25131e88909SSteven Rostedt unsigned char *new, *old; 25231e88909SSteven Rostedt unsigned long ip = rec->ip; 25331e88909SSteven Rostedt 25431e88909SSteven Rostedt old = ftrace_nop_replace(); 25531e88909SSteven Rostedt new = ftrace_call_replace(ip, addr); 25631e88909SSteven Rostedt 25731e88909SSteven Rostedt return ftrace_modify_code(rec->ip, old, new); 25831e88909SSteven Rostedt } 25931e88909SSteven Rostedt 26015adc048SSteven Rostedt int ftrace_update_ftrace_func(ftrace_func_t func) 261d61f82d0SSteven Rostedt { 262d61f82d0SSteven Rostedt unsigned long ip = (unsigned long)(&ftrace_call); 263395a59d0SAbhishek Sagar unsigned char old[MCOUNT_INSN_SIZE], *new; 264d61f82d0SSteven Rostedt int ret; 265d61f82d0SSteven Rostedt 266395a59d0SAbhishek Sagar memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE); 267d61f82d0SSteven Rostedt new = ftrace_call_replace(ip, (unsigned long)func); 268d61f82d0SSteven Rostedt ret = ftrace_modify_code(ip, old, new); 269d61f82d0SSteven Rostedt 270d61f82d0SSteven Rostedt return ret; 271d61f82d0SSteven Rostedt } 272d61f82d0SSteven Rostedt 273d61f82d0SSteven Rostedt int __init ftrace_dyn_arch_init(void *data) 2743d083395SSteven Rostedt { 275732f3ca7SSteven Rostedt extern const unsigned char ftrace_test_p6nop[]; 276732f3ca7SSteven Rostedt extern const unsigned char ftrace_test_nop5[]; 277732f3ca7SSteven Rostedt extern const unsigned char ftrace_test_jmp[]; 278732f3ca7SSteven Rostedt int faulted = 0; 2793d083395SSteven Rostedt 280732f3ca7SSteven Rostedt /* 281732f3ca7SSteven Rostedt * There is no good nop for all x86 archs. 282732f3ca7SSteven Rostedt * We will default to using the P6_NOP5, but first we 283732f3ca7SSteven Rostedt * will test to make sure that the nop will actually 284732f3ca7SSteven Rostedt * work on this CPU. If it faults, we will then 285732f3ca7SSteven Rostedt * go to a lesser efficient 5 byte nop. If that fails 286732f3ca7SSteven Rostedt * we then just use a jmp as our nop. This isn't the most 287732f3ca7SSteven Rostedt * efficient nop, but we can not use a multi part nop 288732f3ca7SSteven Rostedt * since we would then risk being preempted in the middle 289732f3ca7SSteven Rostedt * of that nop, and if we enabled tracing then, it might 290732f3ca7SSteven Rostedt * cause a system crash. 291732f3ca7SSteven Rostedt * 292732f3ca7SSteven Rostedt * TODO: check the cpuid to determine the best nop. 293732f3ca7SSteven Rostedt */ 294732f3ca7SSteven Rostedt asm volatile ( 295732f3ca7SSteven Rostedt "ftrace_test_jmp:" 296732f3ca7SSteven Rostedt "jmp ftrace_test_p6nop\n" 2978b27386aSAnders Kaseorg "nop\n" 2988b27386aSAnders Kaseorg "nop\n" 2998b27386aSAnders Kaseorg "nop\n" /* 2 byte jmp + 3 bytes */ 300732f3ca7SSteven Rostedt "ftrace_test_p6nop:" 301732f3ca7SSteven Rostedt P6_NOP5 302732f3ca7SSteven Rostedt "jmp 1f\n" 303732f3ca7SSteven Rostedt "ftrace_test_nop5:" 304732f3ca7SSteven Rostedt ".byte 0x66,0x66,0x66,0x66,0x90\n" 305732f3ca7SSteven Rostedt "1:" 306732f3ca7SSteven Rostedt ".section .fixup, \"ax\"\n" 307732f3ca7SSteven Rostedt "2: movl $1, %0\n" 308732f3ca7SSteven Rostedt " jmp ftrace_test_nop5\n" 309732f3ca7SSteven Rostedt "3: movl $2, %0\n" 310732f3ca7SSteven Rostedt " jmp 1b\n" 311732f3ca7SSteven Rostedt ".previous\n" 312732f3ca7SSteven Rostedt _ASM_EXTABLE(ftrace_test_p6nop, 2b) 313732f3ca7SSteven Rostedt _ASM_EXTABLE(ftrace_test_nop5, 3b) 314732f3ca7SSteven Rostedt : "=r"(faulted) : "0" (faulted)); 315d61f82d0SSteven Rostedt 316732f3ca7SSteven Rostedt switch (faulted) { 317732f3ca7SSteven Rostedt case 0: 318732f3ca7SSteven Rostedt pr_info("ftrace: converting mcount calls to 0f 1f 44 00 00\n"); 3198115f3f0SSteven Rostedt memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE); 320732f3ca7SSteven Rostedt break; 321732f3ca7SSteven Rostedt case 1: 322732f3ca7SSteven Rostedt pr_info("ftrace: converting mcount calls to 66 66 66 66 90\n"); 3238115f3f0SSteven Rostedt memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE); 324732f3ca7SSteven Rostedt break; 325732f3ca7SSteven Rostedt case 2: 3268b27386aSAnders Kaseorg pr_info("ftrace: converting mcount calls to jmp . + 5\n"); 3278115f3f0SSteven Rostedt memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE); 328732f3ca7SSteven Rostedt break; 329732f3ca7SSteven Rostedt } 330d61f82d0SSteven Rostedt 331732f3ca7SSteven Rostedt /* The return code is retured via data */ 332732f3ca7SSteven Rostedt *(unsigned long *)data = 0; 333dfa60abaSSteven Rostedt 3343d083395SSteven Rostedt return 0; 3353d083395SSteven Rostedt } 336caf4b323SFrederic Weisbecker #endif 337e7d3737eSFrederic Weisbecker 338fb52607aSFrederic Weisbecker #ifdef CONFIG_FUNCTION_GRAPH_TRACER 339e7d3737eSFrederic Weisbecker 3405a45cfe1SSteven Rostedt #ifdef CONFIG_DYNAMIC_FTRACE 3415a45cfe1SSteven Rostedt extern void ftrace_graph_call(void); 3425a45cfe1SSteven Rostedt 3435a45cfe1SSteven Rostedt static int ftrace_mod_jmp(unsigned long ip, 3445a45cfe1SSteven Rostedt int old_offset, int new_offset) 3455a45cfe1SSteven Rostedt { 3465a45cfe1SSteven Rostedt unsigned char code[MCOUNT_INSN_SIZE]; 3475a45cfe1SSteven Rostedt 3485a45cfe1SSteven Rostedt if (probe_kernel_read(code, (void *)ip, MCOUNT_INSN_SIZE)) 3495a45cfe1SSteven Rostedt return -EFAULT; 3505a45cfe1SSteven Rostedt 3515a45cfe1SSteven Rostedt if (code[0] != 0xe9 || old_offset != *(int *)(&code[1])) 3525a45cfe1SSteven Rostedt return -EINVAL; 3535a45cfe1SSteven Rostedt 3545a45cfe1SSteven Rostedt *(int *)(&code[1]) = new_offset; 3555a45cfe1SSteven Rostedt 3565a45cfe1SSteven Rostedt if (do_ftrace_mod_code(ip, &code)) 3575a45cfe1SSteven Rostedt return -EPERM; 3585a45cfe1SSteven Rostedt 3595a45cfe1SSteven Rostedt return 0; 3605a45cfe1SSteven Rostedt } 3615a45cfe1SSteven Rostedt 3625a45cfe1SSteven Rostedt int ftrace_enable_ftrace_graph_caller(void) 3635a45cfe1SSteven Rostedt { 3645a45cfe1SSteven Rostedt unsigned long ip = (unsigned long)(&ftrace_graph_call); 3655a45cfe1SSteven Rostedt int old_offset, new_offset; 3665a45cfe1SSteven Rostedt 3675a45cfe1SSteven Rostedt old_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE); 3685a45cfe1SSteven Rostedt new_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE); 3695a45cfe1SSteven Rostedt 3705a45cfe1SSteven Rostedt return ftrace_mod_jmp(ip, old_offset, new_offset); 3715a45cfe1SSteven Rostedt } 3725a45cfe1SSteven Rostedt 3735a45cfe1SSteven Rostedt int ftrace_disable_ftrace_graph_caller(void) 3745a45cfe1SSteven Rostedt { 3755a45cfe1SSteven Rostedt unsigned long ip = (unsigned long)(&ftrace_graph_call); 3765a45cfe1SSteven Rostedt int old_offset, new_offset; 3775a45cfe1SSteven Rostedt 3785a45cfe1SSteven Rostedt old_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE); 3795a45cfe1SSteven Rostedt new_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE); 3805a45cfe1SSteven Rostedt 3815a45cfe1SSteven Rostedt return ftrace_mod_jmp(ip, old_offset, new_offset); 3825a45cfe1SSteven Rostedt } 3835a45cfe1SSteven Rostedt 3845a45cfe1SSteven Rostedt #else /* CONFIG_DYNAMIC_FTRACE */ 385e7d3737eSFrederic Weisbecker 386e7d3737eSFrederic Weisbecker /* 387e7d3737eSFrederic Weisbecker * These functions are picked from those used on 388e7d3737eSFrederic Weisbecker * this page for dynamic ftrace. They have been 389e7d3737eSFrederic Weisbecker * simplified to ignore all traces in NMI context. 390e7d3737eSFrederic Weisbecker */ 391e7d3737eSFrederic Weisbecker static atomic_t in_nmi; 392e7d3737eSFrederic Weisbecker 393e7d3737eSFrederic Weisbecker void ftrace_nmi_enter(void) 394e7d3737eSFrederic Weisbecker { 395e7d3737eSFrederic Weisbecker atomic_inc(&in_nmi); 396e7d3737eSFrederic Weisbecker } 397e7d3737eSFrederic Weisbecker 398e7d3737eSFrederic Weisbecker void ftrace_nmi_exit(void) 399e7d3737eSFrederic Weisbecker { 400e7d3737eSFrederic Weisbecker atomic_dec(&in_nmi); 401e7d3737eSFrederic Weisbecker } 4025a45cfe1SSteven Rostedt 403e7d3737eSFrederic Weisbecker #endif /* !CONFIG_DYNAMIC_FTRACE */ 404e7d3737eSFrederic Weisbecker 405e7d3737eSFrederic Weisbecker /* Add a function return address to the trace stack on thread info.*/ 406e7d3737eSFrederic Weisbecker static int push_return_trace(unsigned long ret, unsigned long long time, 407287b6e68SFrederic Weisbecker unsigned long func, int *depth) 408e7d3737eSFrederic Weisbecker { 409e7d3737eSFrederic Weisbecker int index; 410f201ae23SFrederic Weisbecker 411f201ae23SFrederic Weisbecker if (!current->ret_stack) 412f201ae23SFrederic Weisbecker return -EBUSY; 413e7d3737eSFrederic Weisbecker 414e7d3737eSFrederic Weisbecker /* The return trace stack is full */ 415f201ae23SFrederic Weisbecker if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) { 416f201ae23SFrederic Weisbecker atomic_inc(¤t->trace_overrun); 417e7d3737eSFrederic Weisbecker return -EBUSY; 4180231022cSFrederic Weisbecker } 419e7d3737eSFrederic Weisbecker 420f201ae23SFrederic Weisbecker index = ++current->curr_ret_stack; 421e7d3737eSFrederic Weisbecker barrier(); 422f201ae23SFrederic Weisbecker current->ret_stack[index].ret = ret; 423f201ae23SFrederic Weisbecker current->ret_stack[index].func = func; 424f201ae23SFrederic Weisbecker current->ret_stack[index].calltime = time; 425287b6e68SFrederic Weisbecker *depth = index; 426e7d3737eSFrederic Weisbecker 427e7d3737eSFrederic Weisbecker return 0; 428e7d3737eSFrederic Weisbecker } 429e7d3737eSFrederic Weisbecker 430e7d3737eSFrederic Weisbecker /* Retrieve a function return address to the trace stack on thread info.*/ 431287b6e68SFrederic Weisbecker static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret) 432e7d3737eSFrederic Weisbecker { 433e7d3737eSFrederic Weisbecker int index; 434e7d3737eSFrederic Weisbecker 435f201ae23SFrederic Weisbecker index = current->curr_ret_stack; 43662679efeSSteven Rostedt 43762679efeSSteven Rostedt if (unlikely(index < 0)) { 43862679efeSSteven Rostedt ftrace_graph_stop(); 43962679efeSSteven Rostedt WARN_ON(1); 44062679efeSSteven Rostedt /* Might as well panic, otherwise we have no where to go */ 44162679efeSSteven Rostedt *ret = (unsigned long)panic; 44262679efeSSteven Rostedt return; 44362679efeSSteven Rostedt } 44462679efeSSteven Rostedt 445f201ae23SFrederic Weisbecker *ret = current->ret_stack[index].ret; 446287b6e68SFrederic Weisbecker trace->func = current->ret_stack[index].func; 447287b6e68SFrederic Weisbecker trace->calltime = current->ret_stack[index].calltime; 448287b6e68SFrederic Weisbecker trace->overrun = atomic_read(¤t->trace_overrun); 449287b6e68SFrederic Weisbecker trace->depth = index; 450e49dc19cSSteven Rostedt barrier(); 451f201ae23SFrederic Weisbecker current->curr_ret_stack--; 45262679efeSSteven Rostedt 453e7d3737eSFrederic Weisbecker } 454e7d3737eSFrederic Weisbecker 455e7d3737eSFrederic Weisbecker /* 456e7d3737eSFrederic Weisbecker * Send the trace to the ring-buffer. 457e7d3737eSFrederic Weisbecker * @return the original return address. 458e7d3737eSFrederic Weisbecker */ 459e7d3737eSFrederic Weisbecker unsigned long ftrace_return_to_handler(void) 460e7d3737eSFrederic Weisbecker { 461fb52607aSFrederic Weisbecker struct ftrace_graph_ret trace; 462287b6e68SFrederic Weisbecker unsigned long ret; 463e7d3737eSFrederic Weisbecker 464287b6e68SFrederic Weisbecker pop_return_trace(&trace, &ret); 465287b6e68SFrederic Weisbecker trace.rettime = cpu_clock(raw_smp_processor_id()); 466287b6e68SFrederic Weisbecker ftrace_graph_return(&trace); 467287b6e68SFrederic Weisbecker 46862679efeSSteven Rostedt if (unlikely(!ret)) { 46962679efeSSteven Rostedt ftrace_graph_stop(); 47062679efeSSteven Rostedt WARN_ON(1); 47162679efeSSteven Rostedt /* Might as well panic. What else to do? */ 47262679efeSSteven Rostedt ret = (unsigned long)panic; 47362679efeSSteven Rostedt } 47462679efeSSteven Rostedt 475287b6e68SFrederic Weisbecker return ret; 476e7d3737eSFrederic Weisbecker } 477e7d3737eSFrederic Weisbecker 478e7d3737eSFrederic Weisbecker /* 479e7d3737eSFrederic Weisbecker * Hook the return address and push it in the stack of return addrs 480e7d3737eSFrederic Weisbecker * in current thread info. 481e7d3737eSFrederic Weisbecker */ 482e7d3737eSFrederic Weisbecker void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) 483e7d3737eSFrederic Weisbecker { 484e7d3737eSFrederic Weisbecker unsigned long old; 485e7d3737eSFrederic Weisbecker unsigned long long calltime; 486e7d3737eSFrederic Weisbecker int faulted; 487287b6e68SFrederic Weisbecker struct ftrace_graph_ent trace; 488e7d3737eSFrederic Weisbecker unsigned long return_hooker = (unsigned long) 489e7d3737eSFrederic Weisbecker &return_to_handler; 490e7d3737eSFrederic Weisbecker 491e7d3737eSFrederic Weisbecker /* Nmi's are currently unsupported */ 492380c4b14SFrederic Weisbecker if (unlikely(atomic_read(&in_nmi))) 493380c4b14SFrederic Weisbecker return; 494380c4b14SFrederic Weisbecker 495380c4b14SFrederic Weisbecker if (unlikely(atomic_read(¤t->tracing_graph_pause))) 496e7d3737eSFrederic Weisbecker return; 497e7d3737eSFrederic Weisbecker 498e7d3737eSFrederic Weisbecker /* 499e7d3737eSFrederic Weisbecker * Protect against fault, even if it shouldn't 500e7d3737eSFrederic Weisbecker * happen. This tool is too much intrusive to 501e7d3737eSFrederic Weisbecker * ignore such a protection. 502e7d3737eSFrederic Weisbecker */ 503e7d3737eSFrederic Weisbecker asm volatile( 504f47a454dSSteven Rostedt "1: " _ASM_MOV " (%[parent]), %[old]\n" 505f47a454dSSteven Rostedt "2: " _ASM_MOV " %[return_hooker], (%[parent])\n" 506e7d3737eSFrederic Weisbecker " movl $0, %[faulted]\n" 507e3944bfaSSteven Rostedt "3:\n" 508e7d3737eSFrederic Weisbecker 509e7d3737eSFrederic Weisbecker ".section .fixup, \"ax\"\n" 510e3944bfaSSteven Rostedt "4: movl $1, %[faulted]\n" 511e3944bfaSSteven Rostedt " jmp 3b\n" 512e7d3737eSFrederic Weisbecker ".previous\n" 513e7d3737eSFrederic Weisbecker 514e3944bfaSSteven Rostedt _ASM_EXTABLE(1b, 4b) 515e3944bfaSSteven Rostedt _ASM_EXTABLE(2b, 4b) 516e7d3737eSFrederic Weisbecker 517f47a454dSSteven Rostedt : [old] "=r" (old), [faulted] "=r" (faulted) 518f47a454dSSteven Rostedt : [parent] "r" (parent), [return_hooker] "r" (return_hooker) 519e7d3737eSFrederic Weisbecker : "memory" 520e7d3737eSFrederic Weisbecker ); 521e7d3737eSFrederic Weisbecker 52214a866c5SSteven Rostedt if (unlikely(faulted)) { 52314a866c5SSteven Rostedt ftrace_graph_stop(); 52414a866c5SSteven Rostedt WARN_ON(1); 525e7d3737eSFrederic Weisbecker return; 526e7d3737eSFrederic Weisbecker } 527e7d3737eSFrederic Weisbecker 52814a866c5SSteven Rostedt if (unlikely(!__kernel_text_address(old))) { 52914a866c5SSteven Rostedt ftrace_graph_stop(); 530e7d3737eSFrederic Weisbecker *parent = old; 53114a866c5SSteven Rostedt WARN_ON(1); 532e7d3737eSFrederic Weisbecker return; 533e7d3737eSFrederic Weisbecker } 534e7d3737eSFrederic Weisbecker 535e7d3737eSFrederic Weisbecker calltime = cpu_clock(raw_smp_processor_id()); 536e7d3737eSFrederic Weisbecker 537287b6e68SFrederic Weisbecker if (push_return_trace(old, calltime, 538287b6e68SFrederic Weisbecker self_addr, &trace.depth) == -EBUSY) { 539e7d3737eSFrederic Weisbecker *parent = old; 540287b6e68SFrederic Weisbecker return; 541287b6e68SFrederic Weisbecker } 542287b6e68SFrederic Weisbecker 543287b6e68SFrederic Weisbecker trace.func = self_addr; 544287b6e68SFrederic Weisbecker 545e49dc19cSSteven Rostedt /* Only trace if the calling function expects to */ 546e49dc19cSSteven Rostedt if (!ftrace_graph_entry(&trace)) { 547e49dc19cSSteven Rostedt current->curr_ret_stack--; 548e49dc19cSSteven Rostedt *parent = old; 549e49dc19cSSteven Rostedt } 550e7d3737eSFrederic Weisbecker } 551fb52607aSFrederic Weisbecker #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 552