|
@@ -33,12 +33,12 @@ static unsigned int ftrace_calc_offset(long ip, long addr)
|
|
return (int)(addr - ip);
|
|
return (int)(addr - ip);
|
|
}
|
|
}
|
|
|
|
|
|
-unsigned char *ftrace_nop_replace(void)
|
|
|
|
|
|
+static unsigned char *ftrace_nop_replace(void)
|
|
{
|
|
{
|
|
return (char *)&ftrace_nop;
|
|
return (char *)&ftrace_nop;
|
|
}
|
|
}
|
|
|
|
|
|
-unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
|
|
|
|
|
|
+static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
|
|
{
|
|
{
|
|
static unsigned int op;
|
|
static unsigned int op;
|
|
|
|
|
|
@@ -68,7 +68,7 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
|
|
# define _ASM_PTR " .long "
|
|
# define _ASM_PTR " .long "
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-int
|
|
|
|
|
|
+static int
|
|
ftrace_modify_code(unsigned long ip, unsigned char *old_code,
|
|
ftrace_modify_code(unsigned long ip, unsigned char *old_code,
|
|
unsigned char *new_code)
|
|
unsigned char *new_code)
|
|
{
|
|
{
|
|
@@ -113,6 +113,62 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
|
|
return faulted;
|
|
return faulted;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int test_24bit_addr(unsigned long ip, unsigned long addr)
|
|
|
|
+{
|
|
|
|
+ long diff;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Can we get to addr from ip in 24 bits?
|
|
|
|
+ * (26 really, since we mulitply by 4 for 4 byte alignment)
|
|
|
|
+ */
|
|
|
|
+ diff = addr - ip;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Return true if diff is less than 1 << 25
|
|
|
|
+ * and greater than -1 << 26.
|
|
|
|
+ */
|
|
|
|
+ return (diff < (1 << 25)) && (diff > (-1 << 26));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int ftrace_make_nop(struct module *mod,
|
|
|
|
+ struct dyn_ftrace *rec, unsigned long addr)
|
|
|
|
+{
|
|
|
|
+ unsigned char *old, *new;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * If the calling address is more that 24 bits away,
|
|
|
|
+ * then we had to use a trampoline to make the call.
|
|
|
|
+ * Otherwise just update the call site.
|
|
|
|
+ */
|
|
|
|
+ if (test_24bit_addr(rec->ip, addr)) {
|
|
|
|
+ /* within range */
|
|
|
|
+ old = ftrace_call_replace(rec->ip, addr);
|
|
|
|
+ new = ftrace_nop_replace();
|
|
|
|
+ return ftrace_modify_code(rec->ip, old, new);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
|
|
|
+{
|
|
|
|
+ unsigned char *old, *new;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * If the calling address is more that 24 bits away,
|
|
|
|
+ * then we had to use a trampoline to make the call.
|
|
|
|
+ * Otherwise just update the call site.
|
|
|
|
+ */
|
|
|
|
+ if (test_24bit_addr(rec->ip, addr)) {
|
|
|
|
+ /* within range */
|
|
|
|
+ old = ftrace_nop_replace();
|
|
|
|
+ new = ftrace_call_replace(rec->ip, addr);
|
|
|
|
+ return ftrace_modify_code(rec->ip, old, new);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
int ftrace_update_ftrace_func(ftrace_func_t func)
|
|
int ftrace_update_ftrace_func(ftrace_func_t func)
|
|
{
|
|
{
|
|
unsigned long ip = (unsigned long)(&ftrace_call);
|
|
unsigned long ip = (unsigned long)(&ftrace_call);
|
|
@@ -128,9 +184,10 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
|
|
|
|
|
|
int __init ftrace_dyn_arch_init(void *data)
|
|
int __init ftrace_dyn_arch_init(void *data)
|
|
{
|
|
{
|
|
- /* This is running in kstop_machine */
|
|
|
|
|
|
+ /* caller expects data to be zero */
|
|
|
|
+ unsigned long *p = data;
|
|
|
|
|
|
- ftrace_mcount_set(data);
|
|
|
|
|
|
+ *p = 0;
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|