#include <linux/list.h>
#include <asm/alternative.h>
+#include <asm/ftrace.h>
-#define CALL_BACK 5
/* Long is fine, even if it is only 4 bytes ;-) */
static long *ftrace_nop;
union ftrace_code_union {
- char code[5];
+ char code[MCOUNT_INSN_SIZE];
struct {
char e8;
int offset;
} __attribute__((packed));
};
-notrace int ftrace_ip_converted(unsigned long ip)
-{
- unsigned long save;
-
- ip -= CALL_BACK;
- save = *(long *)ip;
-
- return save == *ftrace_nop;
-}
static int notrace ftrace_calc_offset(long ip, long addr)
{
static union ftrace_code_union calc;
calc.e8 = 0xe8;
- calc.offset = ftrace_calc_offset(ip, addr);
+ calc.offset = ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr);
/*
* No locking needed, this must be called via kstop_machine
unsigned char newch = new_code[4];
int faulted = 0;
- /* move the IP back to the start of the call */
- ip -= CALL_BACK;
-
/*
* Note: Due to modules and __init, code can
* disappear and change, we need to protect against faulting
" movb %b4, 4(%2)\n"
"2:\n"
".section .fixup, \"ax\"\n"
- " movl $1, %0\n"
- "3: jmp 2b\n"
+ "3: movl $1, %0\n"
+ " jmp 2b\n"
".previous\n"
_ASM_EXTABLE(1b, 3b)
: "=r"(faulted), "=a"(replaced)
- : "r"(ip), "r"(new), "r"(newch),
+ : "r"(ip), "r"(new), "c"(newch),
"0"(faulted), "a"(old)
: "memory");
sync_core();
return faulted;
}
-int __init ftrace_dyn_arch_init(void)
+notrace int ftrace_update_ftrace_func(ftrace_func_t func)
{
- const unsigned char *const *noptable = find_nop_table();
+ unsigned long ip = (unsigned long)(&ftrace_call);
+ unsigned char old[MCOUNT_INSN_SIZE], *new;
+ int ret;
- ftrace_nop = (unsigned long *)noptable[CALL_BACK];
+ memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE);
+ new = ftrace_call_replace(ip, (unsigned long)func);
+ ret = ftrace_modify_code(ip, old, new);
+
+ return ret;
+}
+
+notrace int ftrace_mcount_set(unsigned long *data)
+{
+ unsigned long ip = (long)(&mcount_call);
+ unsigned long *addr = data;
+ unsigned char old[MCOUNT_INSN_SIZE], *new;
+
+ /*
+ * Replace the mcount stub with a pointer to the
+ * ip recorder function.
+ */
+ memcpy(old, &mcount_call, MCOUNT_INSN_SIZE);
+ new = ftrace_call_replace(ip, *addr);
+ *addr = ftrace_modify_code(ip, old, new);
return 0;
}
+int __init ftrace_dyn_arch_init(void *data)
+{
+ const unsigned char *const *noptable = find_nop_table();
+
+ /* This is running in kstop_machine */
+
+ ftrace_mcount_set(data);
+
+ ftrace_nop = (unsigned long *)noptable[MCOUNT_INSN_SIZE];
+
+ return 0;
+}