]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
s390: correct CALL_ON_STACK back_chain saving
authorVasily Gorbik <gor@linux.ibm.com>
Fri, 22 Nov 2019 11:47:52 +0000 (12:47 +0100)
committerVasily Gorbik <gor@linux.ibm.com>
Sat, 30 Nov 2019 09:52:45 +0000 (10:52 +0100)
Currently CALL_ON_STACK saves r15 as back_chain in the first stack frame of
the stack we about to switch to. But if a function which uses CALL_ON_STACK
calls other function it allocates a stack frame for a callee. In this
case r15 is pointing to a callee stack frame and not a stack frame of
function itself. This results in dummy unwinding entry with random
sp and ip values.

Introduce and utilize current_frame_address macro to get an address of
actual function stack frame.

Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
arch/s390/include/asm/stacktrace.h

index 0ae4bbf7779c8bed1602d90898a2f30751eba50b..bb854e33e46098e017601814291cf05d8d731c86 100644 (file)
@@ -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;                                                             \
 })