Browse Source

s390/dumpstack: implement and use return_address()

Implement return_address() and use it instead of __builtin_return_address(n).

__builtin_return_address(n) is not guaranteed to work for n > 0,
therefore implement a private return_address() function which walks
the stack frames and returns the proper return address.

This way we get also rid of a compile warning which gcc 6.1 emits and
look like all other architectures.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Heiko Carstens 9 years ago
parent
commit
5606330627
2 changed files with 27 additions and 1 deletions
  1. 3 1
      arch/s390/include/asm/ftrace.h
  2. 24 0
      arch/s390/kernel/dumpstack.c

+ 3 - 1
arch/s390/include/asm/ftrace.h

@@ -12,7 +12,9 @@
 
 
 #ifndef __ASSEMBLY__
 #ifndef __ASSEMBLY__
 
 
-#define ftrace_return_address(n) __builtin_return_address(n)
+unsigned long return_address(int depth);
+
+#define ftrace_return_address(n) return_address(n)
 
 
 void _mcount(void);
 void _mcount(void);
 void ftrace_caller(void);
 void ftrace_caller(void);

+ 24 - 0
arch/s390/kernel/dumpstack.c

@@ -89,6 +89,30 @@ void dump_trace(dump_trace_func_t func, void *data, struct task_struct *task,
 }
 }
 EXPORT_SYMBOL_GPL(dump_trace);
 EXPORT_SYMBOL_GPL(dump_trace);
 
 
+struct return_address_data {
+	unsigned long address;
+	int depth;
+};
+
+static int __return_address(void *data, unsigned long address)
+{
+	struct return_address_data *rd = data;
+
+	if (rd->depth--)
+		return 0;
+	rd->address = address;
+	return 1;
+}
+
+unsigned long return_address(int depth)
+{
+	struct return_address_data rd = { .depth = depth + 2 };
+
+	dump_trace(__return_address, &rd, NULL, current_stack_pointer());
+	return rd.address;
+}
+EXPORT_SYMBOL_GPL(return_address);
+
 static int show_address(void *data, unsigned long address)
 static int show_address(void *data, unsigned long address)
 {
 {
 	printk("([<%016lx>] %pSR)\n", address, (void *)address);
 	printk("([<%016lx>] %pSR)\n", address, (void *)address);