UPSTREAM: arm64: pass a task parameter to unwind_frame()
authorAKASHI Takahiro <takahiro.akashi@linaro.org>
Tue, 15 Dec 2015 08:33:40 +0000 (17:33 +0900)
committerJeff Vander Stoep <jeffv@google.com>
Sun, 18 Sep 2016 21:12:02 +0000 (14:12 -0700)
Function graph tracer modifies a return address (LR) in a stack frame
to hook a function's return. This will result in many useless entries
(return_to_handler) showing up in a call stack list.
We will fix this problem in a later patch ("arm64: ftrace: fix a stack
tracer's output under function graph tracer"). But since real return
addresses are saved in ret_stack[] array in struct task_struct,
unwind functions need to be notified of, in addition to a stack pointer
address, which task is being traced in order to find out real return
addresses.

This patch extends unwind functions' interfaces by adding an extra
argument of a pointer to task_struct.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Bug: 30369029
Patchset: rework-pagetable

(cherry picked from commit fe13f95b720075327a761fe6ddb45b0c90cab504)
Signed-off-by: Jeff Vander Stoep <jeffv@google.com>
Change-Id: I92a9a07468c182d5abbacaa73a90984ab11ad535

arch/arm64/include/asm/stacktrace.h
arch/arm64/kernel/perf_callchain.c
arch/arm64/kernel/process.c
arch/arm64/kernel/return_address.c
arch/arm64/kernel/stacktrace.c
arch/arm64/kernel/time.c
arch/arm64/kernel/traps.c

index 7318f6d54aa949ca906a990cce357a4cdd1358db..6fb61c5090b49bb07ca0e7e841f7a32f1b7bdb79 100644 (file)
 #ifndef __ASM_STACKTRACE_H
 #define __ASM_STACKTRACE_H
 
+struct task_struct;
+
 struct stackframe {
        unsigned long fp;
        unsigned long sp;
        unsigned long pc;
 };
 
-extern int unwind_frame(struct stackframe *frame);
-extern void walk_stackframe(struct stackframe *frame,
+extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame);
+extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
                            int (*fn)(struct stackframe *, void *), void *data);
 
 #endif /* __ASM_STACKTRACE_H */
index 3aa74830cc69af0053efb77c72e9c26ae3bd6c02..797220da912b77c2bb4a795324d190ec77c83d62 100644 (file)
@@ -165,7 +165,7 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry,
        frame.sp = regs->sp;
        frame.pc = regs->pc;
 
-       walk_stackframe(&frame, callchain_trace, entry);
+       walk_stackframe(current, &frame, callchain_trace, entry);
 }
 
 unsigned long perf_instruction_pointer(struct pt_regs *regs)
index 62068ded1e906fbadb505e29a61cc67b064148d9..51be6356fb03191cf33bb76138da194fb19f65e6 100644 (file)
@@ -414,7 +414,7 @@ unsigned long get_wchan(struct task_struct *p)
        do {
                if (frame.sp < stack_page ||
                    frame.sp >= stack_page + THREAD_SIZE ||
-                   unwind_frame(&frame))
+                   unwind_frame(p, &frame))
                        return 0;
                if (!in_sched_functions(frame.pc))
                        return frame.pc;
index 6c4fd2810ecb35b3e648db18923d21f19a50f422..07b37ac05be44f4608fcb539c29bfe0c4763f309 100644 (file)
@@ -44,7 +44,7 @@ void *return_address(unsigned int level)
        frame.sp = current_stack_pointer;
        frame.pc = (unsigned long)return_address; /* dummy */
 
-       walk_stackframe(&frame, save_return_addr, &data);
+       walk_stackframe(current, &frame, save_return_addr, &data);
 
        if (!data.level)
                return data.addr;
index b9fd3a8abfc1dffbdcc2c95512e1f31cad77da85..f7ee597ec8838b4a561e2876fb1d329c609f0b92 100644 (file)
@@ -36,7 +36,7 @@
  *     ldp     x29, x30, [sp]
  *     add     sp, sp, #0x10
  */
-int notrace unwind_frame(struct stackframe *frame)
+int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
 {
        unsigned long high, low;
        unsigned long fp = frame->fp;
@@ -99,7 +99,7 @@ int notrace unwind_frame(struct stackframe *frame)
        return 0;
 }
 
-void notrace walk_stackframe(struct stackframe *frame,
+void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
                     int (*fn)(struct stackframe *, void *), void *data)
 {
        while (1) {
@@ -107,7 +107,7 @@ void notrace walk_stackframe(struct stackframe *frame,
 
                if (fn(frame, data))
                        break;
-               ret = unwind_frame(frame);
+               ret = unwind_frame(tsk, frame);
                if (ret < 0)
                        break;
        }
@@ -159,7 +159,7 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
                frame.pc = (unsigned long)save_stack_trace_tsk;
        }
 
-       walk_stackframe(&frame, save_trace, &data);
+       walk_stackframe(tsk, &frame, save_trace, &data);
        if (trace->nr_entries < trace->max_entries)
                trace->entries[trace->nr_entries++] = ULONG_MAX;
 }
index 13339b6ffc1a07839103fca328f1eccd6d185c12..6e5c521f123ac5a833b862763408acfd815be9d2 100644 (file)
@@ -53,7 +53,7 @@ unsigned long profile_pc(struct pt_regs *regs)
        frame.sp = regs->sp;
        frame.pc = regs->pc;
        do {
-               int ret = unwind_frame(&frame);
+               int ret = unwind_frame(NULL, &frame);
                if (ret < 0)
                        return 0;
        } while (in_lock_functions(frame.pc));
index 8a0084541f84a33be6f95ddb9a16fac6b8a708c1..937008523fa5d516381d272b44805b65f2f83048 100644 (file)
@@ -177,7 +177,7 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
                int ret;
 
                dump_backtrace_entry(where);
-               ret = unwind_frame(&frame);
+               ret = unwind_frame(tsk, &frame);
                if (ret < 0)
                        break;
                stack = frame.sp;