diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/include/asm/stacktrace.h | 15 |
1 files changed, 14 insertions, 1 deletions
diff --git a/arch/s390/include/asm/stacktrace.h b/arch/s390/include/asm/stacktrace.h index 0ae4bbf7779c..bb854e33e460 100644 --- a/arch/s390/include/asm/stacktrace.h +++ b/arch/s390/include/asm/stacktrace.h @@ -62,6 +62,17 @@ struct stack_frame { }; #endif +/* + * Unlike current_stack_pointer() which simply returns current value of %r15 + * current_frame_address() returns function stack frame address, which matches + * %r15 upon function invocation. It may differ from %r15 later if function + * allocates stack for local variables or new stack frame to call other + * functions. + */ +#define current_frame_address() \ + ((unsigned long)__builtin_frame_address(0) - \ + offsetof(struct stack_frame, back_chain)) + #define CALL_ARGS_0() \ register unsigned long r2 asm("2") #define CALL_ARGS_1(arg1) \ @@ -95,18 +106,20 @@ struct stack_frame { #define CALL_ON_STACK(fn, stack, nr, args...) \ ({ \ + unsigned long frame = current_frame_address(); \ CALL_ARGS_##nr(args); \ unsigned long prev; \ \ asm volatile( \ " la %[_prev],0(15)\n" \ " la 15,0(%[_stack])\n" \ - " stg %[_prev],%[_bc](15)\n" \ + " stg %[_frame],%[_bc](15)\n" \ " brasl 14,%[_fn]\n" \ " la 15,0(%[_prev])\n" \ : [_prev] "=&a" (prev), CALL_FMT_##nr \ [_stack] "a" (stack), \ [_bc] "i" (offsetof(struct stack_frame, back_chain)), \ + [_frame] "d" (frame), \ [_fn] "X" (fn) : CALL_CLOBBER_##nr); \ r2; \ }) |