diff options
-rw-r--r-- | asm/head.S | 6 | ||||
-rw-r--r-- | core/stack.c | 33 | ||||
-rw-r--r-- | include/stack.h | 25 |
3 files changed, 53 insertions, 11 deletions
@@ -359,7 +359,10 @@ boot_entry: /* Get ready for C code: get a stack */ 2: GET_STACK(%r1,%r31) - /* Clear up initial frame */ + /* Clear up initial frame. + * Zero back chain indicates stack entry from boot, + * non-zero indicates entry from OS (see backtrace code). + */ li %r3,0 std %r3,0(%r1) std %r3,8(%r1) @@ -965,6 +968,7 @@ opal_entry: stdu %r12,-STACK_FRAMESIZE(%r12) /* Save caller r1, establish new r1 */ + std %r1,0(%r12) std %r1,STACK_GPR1(%r12) mr %r1,%r12 diff --git a/core/stack.c b/core/stack.c index e04a4dd..10118e4 100644 --- a/core/stack.c +++ b/core/stack.c @@ -29,11 +29,14 @@ static struct bt_entry bt_buf[STACK_BUF_ENTRIES]; extern uint32_t _stext, _etext; /* Dumps backtrace to buffer */ -void __nomcount __backtrace(struct bt_entry *entries, unsigned int *count) +void __nomcount ___backtrace(struct bt_entry *entries, unsigned int *count, + unsigned long r1, + unsigned long *token, unsigned long *r1_caller) { unsigned int room = *count; - unsigned long *fp = __builtin_frame_address(0); + unsigned long *fp = (unsigned long *)r1; unsigned long top_adj = top_of_ram; + struct stack_frame *eframe = (struct stack_frame *)fp; /* Assume one stack for early backtraces */ if (top_of_ram == SKIBOOT_BASE + SKIBOOT_SIZE) @@ -44,17 +47,26 @@ void __nomcount __backtrace(struct bt_entry *entries, unsigned int *count) fp = (unsigned long *)fp[0]; if (!fp || (unsigned long)fp > top_adj) break; + eframe = (struct stack_frame *)fp; entries->sp = (unsigned long)fp; entries->pc = fp[2]; entries++; *count = (*count) + 1; room--; } + + *r1_caller = eframe->gpr[1]; + + if (fp) + *token = eframe->gpr[0]; + else + *token = -1UL; } -void __print_backtrace(unsigned int pir, - struct bt_entry *entries, unsigned int count, - char *out_buf, unsigned int *len, bool symbols) +void ___print_backtrace(unsigned int pir, struct bt_entry *entries, + unsigned int count, unsigned long token, + unsigned long r1_caller, char *out_buf, + unsigned int *len, bool symbols) { static char bt_text_buf[4096]; int i, l = 0, max; @@ -89,6 +101,10 @@ void __print_backtrace(unsigned int pir, l += snprintf(buf + l, max - l, "\n"); entries++; } + if (token <= OPAL_LAST) + l += snprintf(buf + l, max - l, " --- OPAL call token: 0x%lx caller R1: 0x%016lx ---\n", token, r1_caller); + else if (token == -1UL) + l += snprintf(buf + l, max - l, " --- OPAL boot ---\n"); if (!out_buf) write(stdout->fd, bt_text_buf, l); buf[l++] = 0; @@ -107,11 +123,14 @@ struct lock bt_lock = LOCK_UNLOCKED; void backtrace(void) { unsigned int ents = STACK_BUF_ENTRIES; + unsigned long token, r1_caller; lock(&bt_lock); - __backtrace(bt_buf, &ents); - __print_backtrace(mfspr(SPR_PIR), bt_buf, ents, NULL, NULL, true); + ___backtrace(bt_buf, &ents, (unsigned long)__builtin_frame_address(0), + &token, &r1_caller); + ___print_backtrace(mfspr(SPR_PIR), bt_buf, ents, token, r1_caller, + NULL, NULL, true); unlock(&bt_lock); } diff --git a/include/stack.h b/include/stack.h index df08ac1..4d3e504 100644 --- a/include/stack.h +++ b/include/stack.h @@ -49,6 +49,7 @@ #ifndef __ASSEMBLY__ #include <stdint.h> +#include <opal-api.h> /* This is the struct used to save GPRs etc.. on OPAL entry * and from some exceptions. It is not always entirely populated @@ -108,13 +109,31 @@ struct bt_entry { extern void *boot_stack_top; /* Create a backtrace */ -extern void __backtrace(struct bt_entry *entries, unsigned int *count); +void ___backtrace(struct bt_entry *entries, unsigned int *count, + unsigned long r1, + unsigned long *token, unsigned long *r1_caller); +static inline void __backtrace(struct bt_entry *entries, unsigned int *count) +{ + unsigned long token, r1_caller; + + ___backtrace(entries, count, + (unsigned long)__builtin_frame_address(0), + &token, &r1_caller); +} /* Convert a backtrace to ASCII */ -extern void __print_backtrace(unsigned int pir, struct bt_entry *entries, - unsigned int count, char *out_buf, +extern void ___print_backtrace(unsigned int pir, struct bt_entry *entries, + unsigned int count, unsigned long token, + unsigned long r1_caller, char *out_buf, unsigned int *len, bool symbols); +static inline void __print_backtrace(unsigned int pir, struct bt_entry *entries, + unsigned int count, char *out_buf, + unsigned int *len, bool symbols) +{ + ___print_backtrace(pir, entries, count, OPAL_LAST + 1, 0, out_buf, len, symbols); +} + /* For use by debug code, create and print backtrace, uses a static buffer */ extern void backtrace(void); |