aboutsummaryrefslogtreecommitdiff
path: root/core/stack.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-11-18 15:32:17 +1100
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-11-18 15:32:17 +1100
commit0f79a1eaf69390d4a319229b735eed9f4dc7de8a (patch)
tree423893987ceeadcc823bb464e78aa0fdaa6f016a /core/stack.c
parent8f41f30053e2b1431703f3c7e19dc8bf7107b19a (diff)
downloadskiboot-0f79a1eaf69390d4a319229b735eed9f4dc7de8a.zip
skiboot-0f79a1eaf69390d4a319229b735eed9f4dc7de8a.tar.gz
skiboot-0f79a1eaf69390d4a319229b735eed9f4dc7de8a.tar.bz2
Fix backtraces
__builtin_frame_address really wants constants Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'core/stack.c')
-rw-r--r--core/stack.c33
1 files changed, 18 insertions, 15 deletions
diff --git a/core/stack.c b/core/stack.c
index 9858968..15c6e54 100644
--- a/core/stack.c
+++ b/core/stack.c
@@ -19,6 +19,7 @@
#include <processor.h>
#include <cpu.h>
#include <stack.h>
+#include <mem_region.h>
#define STACK_BUF_ENTRIES 20
static struct bt_entry bt_buf[STACK_BUF_ENTRIES];
@@ -29,20 +30,18 @@ extern uint32_t _stext, _etext;
void __nomcount __backtrace(struct bt_entry *entries, unsigned int *count)
{
unsigned int room = *count;
- unsigned int i = 1; /* Start at level 1 */
+ unsigned long *fp = __builtin_frame_address(1);
*count = 0;
while(room) {
- unsigned long pc,
- fp = (unsigned long)__builtin_frame_address(i);
- if (!fp)
+ if (!fp || (unsigned long)fp > top_of_ram)
break;
- pc = (unsigned long)__builtin_return_address(i);
- entries->sp = fp;
- entries->pc = pc;
+ entries->sp = (unsigned long)fp;
+ entries->pc = fp[2];
entries++;
*count = (*count) + 1;
room--;
+ fp = (unsigned long *)fp[0];
}
}
@@ -162,7 +161,7 @@ void __nomcount __mcount_stack_check(uint64_t sp, uint64_t lr)
void check_stacks(void)
{
- struct cpu_thread *c;
+ struct cpu_thread *c, *lowest = NULL;
/* We should never call that from mcount */
assert(!this_cpu()->in_mcount);
@@ -177,16 +176,20 @@ void check_stacks(void)
c->stack_bot_mark >= lowest_stack_mark)
continue;
lock(&stack_check_lock);
- if (c->stack_bot_mark >= lowest_stack_mark) {
- unlock(&stack_check_lock);
- continue;
+ if (c->stack_bot_mark < lowest_stack_mark) {
+ lowest = c;
+ lowest_stack_mark = c->stack_bot_mark;
}
+ unlock(&stack_check_lock);
+ }
+ if (lowest) {
+ lock(&stack_check_lock);
prlog(PR_NOTICE, "CPU %04x lowest stack mark %lld bytes left"
" pc=%08llx token=%lld\n",
- c->pir, c->stack_bot_mark, c->stack_bot_pc,
- c->stack_bot_tok);
- __print_backtrace(c->pir, c->stack_bot_bt,
- c->stack_bot_bt_count, NULL, NULL);
+ lowest->pir, lowest->stack_bot_mark, lowest->stack_bot_pc,
+ lowest->stack_bot_tok);
+ __print_backtrace(lowest->pir, lowest->stack_bot_bt,
+ lowest->stack_bot_bt_count, NULL, NULL);
unlock(&stack_check_lock);
}