diff options
Diffstat (limited to 'runtime/uprobes/uprobes_x86.c')
-rw-r--r-- | runtime/uprobes/uprobes_x86.c | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/runtime/uprobes/uprobes_x86.c b/runtime/uprobes/uprobes_x86.c index 404c9518..93331715 100644 --- a/runtime/uprobes/uprobes_x86.c +++ b/runtime/uprobes/uprobes_x86.c @@ -716,12 +716,23 @@ unsigned long arch_hijack_uret_addr(unsigned long trampoline_address, return orig_ret_addr; } +/* + * On x86_32, if a function returns a struct or union, the return + * value is copied into an area created by the caller. The address + * of this area is passed on the stack as a "hidden" first argument. + * When such a function returns, it uses a "ret $4" instruction to pop + * not only the return address but also the hidden arg. To accommodate + * such functions, we add 4 bytes of slop when predicting the return + * address. See PR #10078. + */ +#define STRUCT_RETURN_SLOP 4 + static unsigned long arch_predict_sp_at_ret(struct pt_regs *regs, struct task_struct *tsk) { if (test_tsk_thread_flag(tsk, TIF_IA32)) - return (unsigned long) (REGS_SP + 4); + return (unsigned long) (REGS_SP + 4 + STRUCT_RETURN_SLOP); else return (unsigned long) (REGS_SP + 8); } |