|
|
@@ -752,18 +752,20 @@ union ftrace_op_code_union {
|
|
|
} __attribute__((packed));
|
|
|
};
|
|
|
|
|
|
+#define RET_SIZE 1
|
|
|
+
|
|
|
static unsigned long
|
|
|
create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
|
|
|
{
|
|
|
- unsigned const char *jmp;
|
|
|
unsigned long start_offset;
|
|
|
unsigned long end_offset;
|
|
|
unsigned long op_offset;
|
|
|
unsigned long offset;
|
|
|
unsigned long size;
|
|
|
- unsigned long ip;
|
|
|
+ unsigned long retq;
|
|
|
unsigned long *ptr;
|
|
|
void *trampoline;
|
|
|
+ void *ip;
|
|
|
/* 48 8b 15 <offset> is movq <offset>(%rip), %rdx */
|
|
|
unsigned const char op_ref[] = { 0x48, 0x8b, 0x15 };
|
|
|
union ftrace_op_code_union op_ptr;
|
|
|
@@ -783,27 +785,27 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
|
|
|
|
|
|
/*
|
|
|
* Allocate enough size to store the ftrace_caller code,
|
|
|
- * the jmp to ftrace_epilogue, as well as the address of
|
|
|
- * the ftrace_ops this trampoline is used for.
|
|
|
+ * the iret , as well as the address of the ftrace_ops this
|
|
|
+ * trampoline is used for.
|
|
|
*/
|
|
|
- trampoline = alloc_tramp(size + MCOUNT_INSN_SIZE + sizeof(void *));
|
|
|
+ trampoline = alloc_tramp(size + RET_SIZE + sizeof(void *));
|
|
|
if (!trampoline)
|
|
|
return 0;
|
|
|
|
|
|
- *tramp_size = size + MCOUNT_INSN_SIZE + sizeof(void *);
|
|
|
+ *tramp_size = size + RET_SIZE + sizeof(void *);
|
|
|
|
|
|
/* Copy ftrace_caller onto the trampoline memory */
|
|
|
ret = probe_kernel_read(trampoline, (void *)start_offset, size);
|
|
|
- if (WARN_ON(ret < 0)) {
|
|
|
- tramp_free(trampoline, *tramp_size);
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ if (WARN_ON(ret < 0))
|
|
|
+ goto fail;
|
|
|
|
|
|
- ip = (unsigned long)trampoline + size;
|
|
|
+ ip = trampoline + size;
|
|
|
|
|
|
- /* The trampoline ends with a jmp to ftrace_epilogue */
|
|
|
- jmp = ftrace_jmp_replace(ip, (unsigned long)ftrace_epilogue);
|
|
|
- memcpy(trampoline + size, jmp, MCOUNT_INSN_SIZE);
|
|
|
+ /* The trampoline ends with ret(q) */
|
|
|
+ retq = (unsigned long)ftrace_stub;
|
|
|
+ ret = probe_kernel_read(ip, (void *)retq, RET_SIZE);
|
|
|
+ if (WARN_ON(ret < 0))
|
|
|
+ goto fail;
|
|
|
|
|
|
/*
|
|
|
* The address of the ftrace_ops that is used for this trampoline
|
|
|
@@ -813,17 +815,15 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
|
|
|
* the global function_trace_op variable.
|
|
|
*/
|
|
|
|
|
|
- ptr = (unsigned long *)(trampoline + size + MCOUNT_INSN_SIZE);
|
|
|
+ ptr = (unsigned long *)(trampoline + size + RET_SIZE);
|
|
|
*ptr = (unsigned long)ops;
|
|
|
|
|
|
op_offset -= start_offset;
|
|
|
memcpy(&op_ptr, trampoline + op_offset, OP_REF_SIZE);
|
|
|
|
|
|
/* Are we pointing to the reference? */
|
|
|
- if (WARN_ON(memcmp(op_ptr.op, op_ref, 3) != 0)) {
|
|
|
- tramp_free(trampoline, *tramp_size);
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ if (WARN_ON(memcmp(op_ptr.op, op_ref, 3) != 0))
|
|
|
+ goto fail;
|
|
|
|
|
|
/* Load the contents of ptr into the callback parameter */
|
|
|
offset = (unsigned long)ptr;
|
|
|
@@ -838,6 +838,9 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
|
|
|
ops->flags |= FTRACE_OPS_FL_ALLOC_TRAMP;
|
|
|
|
|
|
return (unsigned long)trampoline;
|
|
|
+fail:
|
|
|
+ tramp_free(trampoline, *tramp_size);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static unsigned long calc_trampoline_call_offset(bool save_regs)
|