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 2116239630SSteven 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 3016239630SSteven Rostedt int ftrace_arch_code_modify_prepare(void) 3116239630SSteven Rostedt { 3216239630SSteven Rostedt set_kernel_text_rw(); 3316239630SSteven Rostedt return 0; 3416239630SSteven Rostedt } 3516239630SSteven Rostedt 3616239630SSteven Rostedt int ftrace_arch_code_modify_post_process(void) 3716239630SSteven Rostedt { 3816239630SSteven Rostedt set_kernel_text_ro(); 3916239630SSteven Rostedt return 0; 4016239630SSteven Rostedt } 4116239630SSteven 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 984e6ea144SSteven Rostedt static atomic_t nmi_running = 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); 12790c7ac49SSteven Rostedt 12890c7ac49SSteven Rostedt /* if we fail, then kill any new writers */ 12990c7ac49SSteven Rostedt if (mod_code_status) 13090c7ac49SSteven Rostedt mod_code_write = 0; 13117666f02SSteven Rostedt } 13217666f02SSteven Rostedt 133a81bd80aSSteven Rostedt void ftrace_nmi_enter(void) 13417666f02SSteven Rostedt { 1354e6ea144SSteven Rostedt atomic_inc(&nmi_running); 1364e6ea144SSteven Rostedt /* Must have nmi_running seen before reading write flag */ 13717666f02SSteven Rostedt smp_mb(); 138b807c3d0SSteven Rostedt if (mod_code_write) { 13917666f02SSteven Rostedt ftrace_mod_code(); 140b807c3d0SSteven Rostedt atomic_inc(&nmi_update_count); 141b807c3d0SSteven Rostedt } 14217666f02SSteven Rostedt } 14317666f02SSteven Rostedt 144a81bd80aSSteven Rostedt void ftrace_nmi_exit(void) 14517666f02SSteven Rostedt { 1464e6ea144SSteven Rostedt /* Finish all executions before clearing nmi_running */ 14717666f02SSteven Rostedt smp_wmb(); 1484e6ea144SSteven Rostedt atomic_dec(&nmi_running); 14917666f02SSteven Rostedt } 15017666f02SSteven Rostedt 15117666f02SSteven Rostedt static void wait_for_nmi(void) 15217666f02SSteven Rostedt { 1534e6ea144SSteven Rostedt if (!atomic_read(&nmi_running)) 15489025282SCyrill Gorcunov return; 155b807c3d0SSteven Rostedt 15689025282SCyrill Gorcunov do { 15717666f02SSteven Rostedt cpu_relax(); 1584e6ea144SSteven Rostedt } while (atomic_read(&nmi_running)); 15917666f02SSteven Rostedt 160b807c3d0SSteven Rostedt nmi_wait_count++; 161b807c3d0SSteven Rostedt } 162b807c3d0SSteven Rostedt 16317666f02SSteven Rostedt static int 16417666f02SSteven Rostedt do_ftrace_mod_code(unsigned long ip, void *new_code) 16517666f02SSteven Rostedt { 16617666f02SSteven Rostedt mod_code_ip = (void *)ip; 16717666f02SSteven Rostedt mod_code_newcode = new_code; 16817666f02SSteven Rostedt 16917666f02SSteven Rostedt /* The buffers need to be visible before we let NMIs write them */ 17017666f02SSteven Rostedt smp_wmb(); 17117666f02SSteven Rostedt 17217666f02SSteven Rostedt mod_code_write = 1; 17317666f02SSteven Rostedt 17417666f02SSteven Rostedt /* Make sure write bit is visible before we wait on NMIs */ 17517666f02SSteven Rostedt smp_mb(); 17617666f02SSteven Rostedt 17717666f02SSteven Rostedt wait_for_nmi(); 17817666f02SSteven Rostedt 17917666f02SSteven Rostedt /* Make sure all running NMIs have finished before we write the code */ 18017666f02SSteven Rostedt smp_mb(); 18117666f02SSteven Rostedt 18217666f02SSteven Rostedt ftrace_mod_code(); 18317666f02SSteven Rostedt 18417666f02SSteven Rostedt /* Make sure the write happens before clearing the bit */ 18517666f02SSteven Rostedt smp_wmb(); 18617666f02SSteven Rostedt 18717666f02SSteven Rostedt mod_code_write = 0; 18817666f02SSteven Rostedt 18917666f02SSteven Rostedt /* make sure NMIs see the cleared bit */ 19017666f02SSteven Rostedt smp_mb(); 19117666f02SSteven Rostedt 19217666f02SSteven Rostedt wait_for_nmi(); 19317666f02SSteven Rostedt 19417666f02SSteven Rostedt return mod_code_status; 19517666f02SSteven Rostedt } 19617666f02SSteven Rostedt 19717666f02SSteven Rostedt 198caf4b323SFrederic Weisbecker 199caf4b323SFrederic Weisbecker 200caf4b323SFrederic Weisbecker static unsigned char ftrace_nop[MCOUNT_INSN_SIZE]; 201caf4b323SFrederic Weisbecker 20231e88909SSteven Rostedt static unsigned char *ftrace_nop_replace(void) 203caf4b323SFrederic Weisbecker { 204caf4b323SFrederic Weisbecker return ftrace_nop; 205caf4b323SFrederic Weisbecker } 206caf4b323SFrederic Weisbecker 20731e88909SSteven Rostedt static int 2083d083395SSteven Rostedt ftrace_modify_code(unsigned long ip, unsigned char *old_code, 2093d083395SSteven Rostedt unsigned char *new_code) 2103d083395SSteven Rostedt { 2116f93fc07SSteven Rostedt unsigned char replaced[MCOUNT_INSN_SIZE]; 2123d083395SSteven Rostedt 2133d083395SSteven Rostedt /* 2143d083395SSteven Rostedt * Note: Due to modules and __init, code can 2153d083395SSteven Rostedt * disappear and change, we need to protect against faulting 21676aefee5SSteven Rostedt * as well as code changing. We do this by using the 217ab9a0918SSteven Rostedt * probe_kernel_* functions. 2183d083395SSteven Rostedt * 2193d083395SSteven Rostedt * No real locking needed, this code is run through 2206f93fc07SSteven Rostedt * kstop_machine, or before SMP starts. 2213d083395SSteven Rostedt */ 22276aefee5SSteven Rostedt 22376aefee5SSteven Rostedt /* read the text we want to modify */ 224ab9a0918SSteven Rostedt if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) 225593eb8a2SSteven Rostedt return -EFAULT; 2266f93fc07SSteven Rostedt 22776aefee5SSteven Rostedt /* Make sure it is what we expect it to be */ 2286f93fc07SSteven Rostedt if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0) 229593eb8a2SSteven Rostedt return -EINVAL; 2306f93fc07SSteven Rostedt 23176aefee5SSteven Rostedt /* replace the text with the new text */ 23217666f02SSteven Rostedt if (do_ftrace_mod_code(ip, new_code)) 233593eb8a2SSteven Rostedt return -EPERM; 2346f93fc07SSteven Rostedt 2353d083395SSteven Rostedt sync_core(); 2363d083395SSteven Rostedt 2376f93fc07SSteven Rostedt return 0; 2383d083395SSteven Rostedt } 2393d083395SSteven Rostedt 24031e88909SSteven Rostedt int ftrace_make_nop(struct module *mod, 24131e88909SSteven Rostedt struct dyn_ftrace *rec, unsigned long addr) 24231e88909SSteven Rostedt { 24331e88909SSteven Rostedt unsigned char *new, *old; 24431e88909SSteven Rostedt unsigned long ip = rec->ip; 24531e88909SSteven Rostedt 24631e88909SSteven Rostedt old = ftrace_call_replace(ip, addr); 24731e88909SSteven Rostedt new = ftrace_nop_replace(); 24831e88909SSteven Rostedt 24931e88909SSteven Rostedt return ftrace_modify_code(rec->ip, old, new); 25031e88909SSteven Rostedt } 25131e88909SSteven Rostedt 25231e88909SSteven Rostedt int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) 25331e88909SSteven Rostedt { 25431e88909SSteven Rostedt unsigned char *new, *old; 25531e88909SSteven Rostedt unsigned long ip = rec->ip; 25631e88909SSteven Rostedt 25731e88909SSteven Rostedt old = ftrace_nop_replace(); 25831e88909SSteven Rostedt new = ftrace_call_replace(ip, addr); 25931e88909SSteven Rostedt 26031e88909SSteven Rostedt return ftrace_modify_code(rec->ip, old, new); 26131e88909SSteven Rostedt } 26231e88909SSteven Rostedt 26315adc048SSteven Rostedt int ftrace_update_ftrace_func(ftrace_func_t func) 264d61f82d0SSteven Rostedt { 265d61f82d0SSteven Rostedt unsigned long ip = (unsigned long)(&ftrace_call); 266395a59d0SAbhishek Sagar unsigned char old[MCOUNT_INSN_SIZE], *new; 267d61f82d0SSteven Rostedt int ret; 268d61f82d0SSteven Rostedt 269395a59d0SAbhishek Sagar memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE); 270d61f82d0SSteven Rostedt new = ftrace_call_replace(ip, (unsigned long)func); 271d61f82d0SSteven Rostedt ret = ftrace_modify_code(ip, old, new); 272d61f82d0SSteven Rostedt 273d61f82d0SSteven Rostedt return ret; 274d61f82d0SSteven Rostedt } 275d61f82d0SSteven Rostedt 276d61f82d0SSteven Rostedt int __init ftrace_dyn_arch_init(void *data) 2773d083395SSteven Rostedt { 278732f3ca7SSteven Rostedt extern const unsigned char ftrace_test_p6nop[]; 279732f3ca7SSteven Rostedt extern const unsigned char ftrace_test_nop5[]; 280732f3ca7SSteven Rostedt extern const unsigned char ftrace_test_jmp[]; 281732f3ca7SSteven Rostedt int faulted = 0; 2823d083395SSteven Rostedt 283732f3ca7SSteven Rostedt /* 284732f3ca7SSteven Rostedt * There is no good nop for all x86 archs. 285732f3ca7SSteven Rostedt * We will default to using the P6_NOP5, but first we 286732f3ca7SSteven Rostedt * will test to make sure that the nop will actually 287732f3ca7SSteven Rostedt * work on this CPU. If it faults, we will then 288732f3ca7SSteven Rostedt * go to a lesser efficient 5 byte nop. If that fails 289732f3ca7SSteven Rostedt * we then just use a jmp as our nop. This isn't the most 290732f3ca7SSteven Rostedt * efficient nop, but we can not use a multi part nop 291732f3ca7SSteven Rostedt * since we would then risk being preempted in the middle 292732f3ca7SSteven Rostedt * of that nop, and if we enabled tracing then, it might 293732f3ca7SSteven Rostedt * cause a system crash. 294732f3ca7SSteven Rostedt * 295732f3ca7SSteven Rostedt * TODO: check the cpuid to determine the best nop. 296732f3ca7SSteven Rostedt */ 297732f3ca7SSteven Rostedt asm volatile ( 298732f3ca7SSteven Rostedt "ftrace_test_jmp:" 299732f3ca7SSteven Rostedt "jmp ftrace_test_p6nop\n" 3008b27386aSAnders Kaseorg "nop\n" 3018b27386aSAnders Kaseorg "nop\n" 3028b27386aSAnders Kaseorg "nop\n" /* 2 byte jmp + 3 bytes */ 303732f3ca7SSteven Rostedt "ftrace_test_p6nop:" 304732f3ca7SSteven Rostedt P6_NOP5 305732f3ca7SSteven Rostedt "jmp 1f\n" 306732f3ca7SSteven Rostedt "ftrace_test_nop5:" 307732f3ca7SSteven Rostedt ".byte 0x66,0x66,0x66,0x66,0x90\n" 308732f3ca7SSteven Rostedt "1:" 309732f3ca7SSteven Rostedt ".section .fixup, \"ax\"\n" 310732f3ca7SSteven Rostedt "2: movl $1, %0\n" 311732f3ca7SSteven Rostedt " jmp ftrace_test_nop5\n" 312732f3ca7SSteven Rostedt "3: movl $2, %0\n" 313732f3ca7SSteven Rostedt " jmp 1b\n" 314732f3ca7SSteven Rostedt ".previous\n" 315732f3ca7SSteven Rostedt _ASM_EXTABLE(ftrace_test_p6nop, 2b) 316732f3ca7SSteven Rostedt _ASM_EXTABLE(ftrace_test_nop5, 3b) 317732f3ca7SSteven Rostedt : "=r"(faulted) : "0" (faulted)); 318d61f82d0SSteven Rostedt 319732f3ca7SSteven Rostedt switch (faulted) { 320732f3ca7SSteven Rostedt case 0: 321732f3ca7SSteven Rostedt pr_info("ftrace: converting mcount calls to 0f 1f 44 00 00\n"); 3228115f3f0SSteven Rostedt memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE); 323732f3ca7SSteven Rostedt break; 324732f3ca7SSteven Rostedt case 1: 325732f3ca7SSteven Rostedt pr_info("ftrace: converting mcount calls to 66 66 66 66 90\n"); 3268115f3f0SSteven Rostedt memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE); 327732f3ca7SSteven Rostedt break; 328732f3ca7SSteven Rostedt case 2: 3298b27386aSAnders Kaseorg pr_info("ftrace: converting mcount calls to jmp . + 5\n"); 3308115f3f0SSteven Rostedt memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE); 331732f3ca7SSteven Rostedt break; 332732f3ca7SSteven Rostedt } 333d61f82d0SSteven Rostedt 334732f3ca7SSteven Rostedt /* The return code is retured via data */ 335732f3ca7SSteven Rostedt *(unsigned long *)data = 0; 336dfa60abaSSteven Rostedt 3373d083395SSteven Rostedt return 0; 3383d083395SSteven Rostedt } 339caf4b323SFrederic Weisbecker #endif 340e7d3737eSFrederic Weisbecker 341fb52607aSFrederic Weisbecker #ifdef CONFIG_FUNCTION_GRAPH_TRACER 342e7d3737eSFrederic Weisbecker 3435a45cfe1SSteven Rostedt #ifdef CONFIG_DYNAMIC_FTRACE 3445a45cfe1SSteven Rostedt extern void ftrace_graph_call(void); 3455a45cfe1SSteven Rostedt 3465a45cfe1SSteven Rostedt static int ftrace_mod_jmp(unsigned long ip, 3475a45cfe1SSteven Rostedt int old_offset, int new_offset) 3485a45cfe1SSteven Rostedt { 3495a45cfe1SSteven Rostedt unsigned char code[MCOUNT_INSN_SIZE]; 3505a45cfe1SSteven Rostedt 3515a45cfe1SSteven Rostedt if (probe_kernel_read(code, (void *)ip, MCOUNT_INSN_SIZE)) 3525a45cfe1SSteven Rostedt return -EFAULT; 3535a45cfe1SSteven Rostedt 3545a45cfe1SSteven Rostedt if (code[0] != 0xe9 || old_offset != *(int *)(&code[1])) 3555a45cfe1SSteven Rostedt return -EINVAL; 3565a45cfe1SSteven Rostedt 3575a45cfe1SSteven Rostedt *(int *)(&code[1]) = new_offset; 3585a45cfe1SSteven Rostedt 3595a45cfe1SSteven Rostedt if (do_ftrace_mod_code(ip, &code)) 3605a45cfe1SSteven Rostedt return -EPERM; 3615a45cfe1SSteven Rostedt 3625a45cfe1SSteven Rostedt return 0; 3635a45cfe1SSteven Rostedt } 3645a45cfe1SSteven Rostedt 3655a45cfe1SSteven Rostedt int ftrace_enable_ftrace_graph_caller(void) 3665a45cfe1SSteven Rostedt { 3675a45cfe1SSteven Rostedt unsigned long ip = (unsigned long)(&ftrace_graph_call); 3685a45cfe1SSteven Rostedt int old_offset, new_offset; 3695a45cfe1SSteven Rostedt 3705a45cfe1SSteven Rostedt old_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE); 3715a45cfe1SSteven Rostedt new_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE); 3725a45cfe1SSteven Rostedt 3735a45cfe1SSteven Rostedt return ftrace_mod_jmp(ip, old_offset, new_offset); 3745a45cfe1SSteven Rostedt } 3755a45cfe1SSteven Rostedt 3765a45cfe1SSteven Rostedt int ftrace_disable_ftrace_graph_caller(void) 3775a45cfe1SSteven Rostedt { 3785a45cfe1SSteven Rostedt unsigned long ip = (unsigned long)(&ftrace_graph_call); 3795a45cfe1SSteven Rostedt int old_offset, new_offset; 3805a45cfe1SSteven Rostedt 3815a45cfe1SSteven Rostedt old_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE); 3825a45cfe1SSteven Rostedt new_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE); 3835a45cfe1SSteven Rostedt 3845a45cfe1SSteven Rostedt return ftrace_mod_jmp(ip, old_offset, new_offset); 3855a45cfe1SSteven Rostedt } 3865a45cfe1SSteven Rostedt 387e7d3737eSFrederic Weisbecker #endif /* !CONFIG_DYNAMIC_FTRACE */ 388e7d3737eSFrederic Weisbecker 389e7d3737eSFrederic Weisbecker /* 390e7d3737eSFrederic Weisbecker * Hook the return address and push it in the stack of return addrs 391e7d3737eSFrederic Weisbecker * in current thread info. 392e7d3737eSFrederic Weisbecker */ 393e7d3737eSFrederic Weisbecker void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) 394e7d3737eSFrederic Weisbecker { 395e7d3737eSFrederic Weisbecker unsigned long old; 396e7d3737eSFrederic Weisbecker unsigned long long calltime; 397e7d3737eSFrederic Weisbecker int faulted; 398287b6e68SFrederic Weisbecker struct ftrace_graph_ent trace; 399e7d3737eSFrederic Weisbecker unsigned long return_hooker = (unsigned long) 400e7d3737eSFrederic Weisbecker &return_to_handler; 401e7d3737eSFrederic Weisbecker 402e7d3737eSFrederic Weisbecker /* Nmi's are currently unsupported */ 4039a5fd902SSteven Rostedt if (unlikely(in_nmi())) 404380c4b14SFrederic Weisbecker return; 405380c4b14SFrederic Weisbecker 406380c4b14SFrederic Weisbecker if (unlikely(atomic_read(¤t->tracing_graph_pause))) 407e7d3737eSFrederic Weisbecker return; 408e7d3737eSFrederic Weisbecker 409e7d3737eSFrederic Weisbecker /* 410e7d3737eSFrederic Weisbecker * Protect against fault, even if it shouldn't 411e7d3737eSFrederic Weisbecker * happen. This tool is too much intrusive to 412e7d3737eSFrederic Weisbecker * ignore such a protection. 413e7d3737eSFrederic Weisbecker */ 414e7d3737eSFrederic Weisbecker asm volatile( 41596665788SSteven Rostedt "1: " _ASM_MOV " (%[parent]), %[old]\n" 41696665788SSteven Rostedt "2: " _ASM_MOV " %[return_hooker], (%[parent])\n" 417e7d3737eSFrederic Weisbecker " movl $0, %[faulted]\n" 418e3944bfaSSteven Rostedt "3:\n" 419e7d3737eSFrederic Weisbecker 420e7d3737eSFrederic Weisbecker ".section .fixup, \"ax\"\n" 421e3944bfaSSteven Rostedt "4: movl $1, %[faulted]\n" 422e3944bfaSSteven Rostedt " jmp 3b\n" 423e7d3737eSFrederic Weisbecker ".previous\n" 424e7d3737eSFrederic Weisbecker 425e3944bfaSSteven Rostedt _ASM_EXTABLE(1b, 4b) 426e3944bfaSSteven Rostedt _ASM_EXTABLE(2b, 4b) 427e7d3737eSFrederic Weisbecker 42896665788SSteven Rostedt : [old] "=r" (old), [faulted] "=r" (faulted) 42996665788SSteven Rostedt : [parent] "r" (parent), [return_hooker] "r" (return_hooker) 430e7d3737eSFrederic Weisbecker : "memory" 431e7d3737eSFrederic Weisbecker ); 432e7d3737eSFrederic Weisbecker 43314a866c5SSteven Rostedt if (unlikely(faulted)) { 43414a866c5SSteven Rostedt ftrace_graph_stop(); 43514a866c5SSteven Rostedt WARN_ON(1); 436e7d3737eSFrederic Weisbecker return; 437e7d3737eSFrederic Weisbecker } 438e7d3737eSFrederic Weisbecker 4390012693aSFrederic Weisbecker calltime = trace_clock_local(); 440e7d3737eSFrederic Weisbecker 441712406a6SSteven Rostedt if (ftrace_push_return_trace(old, calltime, 442287b6e68SFrederic Weisbecker self_addr, &trace.depth) == -EBUSY) { 443e7d3737eSFrederic Weisbecker *parent = old; 444287b6e68SFrederic Weisbecker return; 445287b6e68SFrederic Weisbecker } 446287b6e68SFrederic Weisbecker 447287b6e68SFrederic Weisbecker trace.func = self_addr; 448287b6e68SFrederic Weisbecker 449e49dc19cSSteven Rostedt /* Only trace if the calling function expects to */ 450e49dc19cSSteven Rostedt if (!ftrace_graph_entry(&trace)) { 451e49dc19cSSteven Rostedt current->curr_ret_stack--; 452e49dc19cSSteven Rostedt *parent = old; 453e49dc19cSSteven Rostedt } 454e7d3737eSFrederic Weisbecker } 455fb52607aSFrederic Weisbecker #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 456*f58ba100SFrederic Weisbecker 457*f58ba100SFrederic Weisbecker #ifdef CONFIG_FTRACE_SYSCALLS 458*f58ba100SFrederic Weisbecker 459*f58ba100SFrederic Weisbecker extern unsigned long __start_syscalls_metadata[]; 460*f58ba100SFrederic Weisbecker extern unsigned long __stop_syscalls_metadata[]; 461*f58ba100SFrederic Weisbecker extern unsigned long *sys_call_table; 462*f58ba100SFrederic Weisbecker 463*f58ba100SFrederic Weisbecker static struct syscall_metadata **syscalls_metadata; 464*f58ba100SFrederic Weisbecker 465*f58ba100SFrederic Weisbecker static struct syscall_metadata *find_syscall_meta(unsigned long *syscall) 466*f58ba100SFrederic Weisbecker { 467*f58ba100SFrederic Weisbecker struct syscall_metadata *start; 468*f58ba100SFrederic Weisbecker struct syscall_metadata *stop; 469*f58ba100SFrederic Weisbecker char str[KSYM_SYMBOL_LEN]; 470*f58ba100SFrederic Weisbecker 471*f58ba100SFrederic Weisbecker 472*f58ba100SFrederic Weisbecker start = (struct syscall_metadata *)__start_syscalls_metadata; 473*f58ba100SFrederic Weisbecker stop = (struct syscall_metadata *)__stop_syscalls_metadata; 474*f58ba100SFrederic Weisbecker kallsyms_lookup((unsigned long) syscall, NULL, NULL, NULL, str); 475*f58ba100SFrederic Weisbecker 476*f58ba100SFrederic Weisbecker for ( ; start < stop; start++) { 477*f58ba100SFrederic Weisbecker if (start->name && !strcmp(start->name, str)) 478*f58ba100SFrederic Weisbecker return start; 479*f58ba100SFrederic Weisbecker } 480*f58ba100SFrederic Weisbecker return NULL; 481*f58ba100SFrederic Weisbecker } 482*f58ba100SFrederic Weisbecker 483*f58ba100SFrederic Weisbecker struct syscall_metadata *syscall_nr_to_meta(int nr) 484*f58ba100SFrederic Weisbecker { 485*f58ba100SFrederic Weisbecker if (!syscalls_metadata || nr >= FTRACE_SYSCALL_MAX || nr < 0) 486*f58ba100SFrederic Weisbecker return NULL; 487*f58ba100SFrederic Weisbecker 488*f58ba100SFrederic Weisbecker return syscalls_metadata[nr]; 489*f58ba100SFrederic Weisbecker } 490*f58ba100SFrederic Weisbecker 491*f58ba100SFrederic Weisbecker void arch_init_ftrace_syscalls(void) 492*f58ba100SFrederic Weisbecker { 493*f58ba100SFrederic Weisbecker int i; 494*f58ba100SFrederic Weisbecker struct syscall_metadata *meta; 495*f58ba100SFrederic Weisbecker unsigned long **psys_syscall_table = &sys_call_table; 496*f58ba100SFrederic Weisbecker static atomic_t refs; 497*f58ba100SFrederic Weisbecker 498*f58ba100SFrederic Weisbecker if (atomic_inc_return(&refs) != 1) 499*f58ba100SFrederic Weisbecker goto end; 500*f58ba100SFrederic Weisbecker 501*f58ba100SFrederic Weisbecker syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * 502*f58ba100SFrederic Weisbecker FTRACE_SYSCALL_MAX, GFP_KERNEL); 503*f58ba100SFrederic Weisbecker if (!syscalls_metadata) { 504*f58ba100SFrederic Weisbecker WARN_ON(1); 505*f58ba100SFrederic Weisbecker return; 506*f58ba100SFrederic Weisbecker } 507*f58ba100SFrederic Weisbecker 508*f58ba100SFrederic Weisbecker for (i = 0; i < FTRACE_SYSCALL_MAX; i++) { 509*f58ba100SFrederic Weisbecker meta = find_syscall_meta(psys_syscall_table[i]); 510*f58ba100SFrederic Weisbecker syscalls_metadata[i] = meta; 511*f58ba100SFrederic Weisbecker } 512*f58ba100SFrederic Weisbecker return; 513*f58ba100SFrederic Weisbecker 514*f58ba100SFrederic Weisbecker /* Paranoid: avoid overflow */ 515*f58ba100SFrederic Weisbecker end: 516*f58ba100SFrederic Weisbecker atomic_dec(&refs); 517*f58ba100SFrederic Weisbecker } 518*f58ba100SFrederic Weisbecker #endif 519