We had a mess of functionality with repeated code in various spots, which made it difficult to add new features.
As part of this, we have backtrace_hwtf(), which can print out the appropriate BT based on whether the TF is the kernel's or the user's. This means that CTRL-B will work on user TFs, and it will spit out text (via printk) that can be processed with scripts/bt-akaros.sh. So now the answer to "how do I backtrace a deadlocked user SCP" is "CTRL-B", instead of a long discussion. =) Signed-off-by: Barret Rhoden <[email protected]> --- kern/arch/riscv/kdebug.c | 16 ++++++++-- kern/arch/x86/kdebug.c | 55 ++++++++-------------------------- kern/include/kdebug.h | 37 ++++++++++++++++++----- kern/src/kdebug.c | 77 +++++++++++++++++++++++++++++++++++++++--------- kern/src/profiler.c | 2 +- 5 files changed, 119 insertions(+), 68 deletions(-) diff --git a/kern/arch/riscv/kdebug.c b/kern/arch/riscv/kdebug.c index 934e1fb82e37..2be24b5427a2 100644 --- a/kern/arch/riscv/kdebug.c +++ b/kern/arch/riscv/kdebug.c @@ -7,6 +7,8 @@ #include <ros/memlayout.h> +/* Here's the old backtrace, remove it once gen_backtrace is done: */ +#if 0 void backtrace(void) { void **fp; @@ -20,10 +22,11 @@ void backtrace(void) fp = (void**)sp; } } +#endif -void backtrace_frame(uintptr_t pc, uintptr_t fp) +void gen_backtrace(void (*pfunc)(void *, const char *), void *opaque) { - printk("\n\tTODO: backtrace frame on riscv\n\n"); + printk("\n\tTODO: %s on riscv\n\n", __func__); } /* can either implement these, or use the x86 ones globally and limit the @@ -31,6 +34,13 @@ void backtrace_frame(uintptr_t pc, uintptr_t fp) size_t backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs, size_t nr_slots) { - printk("\n\tTODO: backtrace list on riscv\n\n"); + printk("\n\tTODO: %s on riscv\n\n", __func__); + return 0; +} + +size_t backtrace_user_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs, + size_t nr_slots) +{ + printk("\n\tTODO: %s on riscv\n\n", __func__); return 0; } diff --git a/kern/arch/x86/kdebug.c b/kern/arch/x86/kdebug.c index 3ee432c5e56d..5b7f3b999988 100644 --- a/kern/arch/x86/kdebug.c +++ b/kern/arch/x86/kdebug.c @@ -41,37 +41,6 @@ typedef struct UserStabData { const char *stabstr_end; } user_stab_data_t; -static void printk_func(void *opaque, const char *str) -{ - printk("%s", str); -} - -void gen_backtrace_frame(uintptr_t eip, uintptr_t ebp, - void (*pfunc)(void *, const char *), void *opaque) -{ -#define MAX_BT_DEPTH 20 - char *func_name; - char bt_line[128]; - uintptr_t pcs[MAX_BT_DEPTH]; - size_t nr_pcs = backtrace_list(eip, ebp, pcs, MAX_BT_DEPTH); - - for (size_t i = 0; i < nr_pcs; i++) { - func_name = get_fn_name(pcs[i]); - snprintf(bt_line, sizeof(bt_line), "#%02d [<%p>] in %s\n", i + 1, - pcs[i], func_name); - pfunc(opaque, bt_line); - kfree(func_name); - } -} - -void gen_backtrace(void (*pfunc)(void *, const char *), void *opaque) -{ - uintptr_t ebp, eip; - - GET_FRAME_START(ebp, eip); - gen_backtrace_frame(eip, ebp, pfunc, opaque); -} - /* We used to check for a null terminating byte for the entire strings section * (due to JOS, I think), but that's not what the spec says: only that all * strings are null terminated. There might be random stuff tacked on at the @@ -347,6 +316,17 @@ void *debug_get_fn_addr(char *fn_name) return retval; } +void gen_backtrace(void (*pfunc)(void *, const char *), void *opaque) +{ + uintptr_t ebp, eip; + uintptr_t pcs[MAX_BT_DEPTH]; + size_t nr_pcs; + + GET_FRAME_START(ebp, eip); + nr_pcs = backtrace_list(eip, ebp, pcs, MAX_BT_DEPTH); + print_backtrace_list(pcs, nr_pcs, pfunc, opaque); +} + size_t backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs, size_t nr_slots) { @@ -366,7 +346,7 @@ size_t backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs, return nr_pcs; } -size_t user_backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs, +size_t backtrace_user_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs, size_t nr_slots) { int error; @@ -387,17 +367,6 @@ size_t user_backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs, return nr_pcs; } -void backtrace_frame(uintptr_t eip, uintptr_t ebp) -{ - gen_backtrace_frame(eip, ebp, &printk_func, NULL); -} - -void backtrace(void) -{ - printk("Stack Backtrace on Core %d:\n", core_id()); - gen_backtrace(&printk_func, NULL); -} - /* Assumes 32-bit header */ void print_fpu_state(struct ancillary_state *fpu) { diff --git a/kern/include/kdebug.h b/kern/include/kdebug.h index 6b7afd7a2655..28a852bc6e7e 100644 --- a/kern/include/kdebug.h +++ b/kern/include/kdebug.h @@ -4,6 +4,7 @@ #include <ros/trapframe.h> #include <arch/kdebug.h> #include <profiler.h> +/* for includes */ struct proc; struct symtab_entry { char *name; @@ -12,18 +13,40 @@ struct symtab_entry { #define TRACEME() trace_printk(TRUE, "%s(%d)", __FILE__, __LINE__) +/* An alternative here is to have backtrace_list kmalloc an array. The downside + * is that we're calling into the allocator in potentially-delicate situations, + * such as the NMI handler. */ +#define MAX_BT_DEPTH 20 + +/*** Printk Backtraces, usually used for debugging or from the monitor */ +/* Backtraces the calling kernel context */ void backtrace(void); -void gen_backtrace_frame(uintptr_t eip, uintptr_t ebp, - void (*pfunc)(void *, const char *), void *opaque); -void gen_backtrace(void (*pfunc)(void *, const char *), void *opaque); +/* Backtraces a PC/FP, with no protections */ void backtrace_frame(uintptr_t pc, uintptr_t fp); +/* Backtraces a user PC/FP */ +void backtrace_user_frame(uintptr_t pc, uintptr_t fp); +/* Backtraces a hardware TF. Can handle user or kernel TFs */ +void backtrace_hwtf(struct hw_trapframe *hw_tf); +/* Backtraces a user context */ +void backtrace_user_ctx(struct proc *p, struct user_context *ctx); + +/*** Programmatic Backtraces */ +/* Backtraces a PC/FP, stores results in *pcs, with no protections */ size_t backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs, size_t nr_slots); -size_t user_backtrace_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs, +/* Backtraces a user PC/FP, stores results in *pcs */ +size_t backtrace_user_list(uintptr_t pc, uintptr_t fp, uintptr_t *pcs, size_t nr_slots); -void backtrace_kframe(struct hw_trapframe *hw_tf); -/* for includes */ struct proc; -void backtrace_user_ctx(struct proc *p, struct user_context *ctx); +/* Prints out a backtrace list, using pfunc(opaque, "line") for the printk. + * This does a symbol lookup on the kernel binary, so it is less useful for a + * user backtrace. */ +void print_backtrace_list(uintptr_t *pcs, size_t nr_pcs, + void (*pfunc)(void *, const char *), void *opaque); +/* Backtraces the calling kernel context, using pfunc for printing */ +void gen_backtrace(void (*pfunc)(void *, const char *), void *opaque); + +/* Temporary func */ +#define backtrace_kframe backtrace_hwtf /* Arch dependent, listed here for ease-of-use */ static inline uintptr_t get_caller_pc(void); diff --git a/kern/src/kdebug.c b/kern/src/kdebug.c index 32495d5c679b..8756a41aacbd 100644 --- a/kern/src/kdebug.c +++ b/kern/src/kdebug.c @@ -201,31 +201,80 @@ void debug_addr_pid(int pid, unsigned long addr) proc_decref(p); } -void backtrace_kframe(struct hw_trapframe *hw_tf) +void print_backtrace_list(uintptr_t *pcs, size_t nr_pcs, + void (*pfunc)(void *, const char *), void *opaque) +{ + char *func_name; + char bt_line[128]; + + for (size_t i = 0; i < nr_pcs; i++) { + func_name = get_fn_name(pcs[i]); + snprintf(bt_line, sizeof(bt_line), "#%02d [<%p>] in %s\n", i + 1, + pcs[i], func_name); + pfunc(opaque, bt_line); + kfree(func_name); + } +} + +static void printk_func(void *opaque, const char *str) +{ + printk("%s", str); +} + +void backtrace(void) +{ + printk("Stack Backtrace on Core %d:\n", core_id()); + gen_backtrace(&printk_func, NULL); +} + +void backtrace_frame(uintptr_t eip, uintptr_t ebp) +{ + uintptr_t pcs[MAX_BT_DEPTH]; + size_t nr_pcs = backtrace_list(eip, ebp, pcs, MAX_BT_DEPTH); + + printk("\nBacktrace of kernel context on Core %d:\n", core_id()); + print_backtrace_list(pcs, nr_pcs, &printk_func, NULL); +} + +/* TODO: change debug_addr_proc() to allow print redirection like + * print_backtrace_list(). */ +void backtrace_user_frame(uintptr_t eip, uintptr_t ebp) +{ + uintptr_t pcs[MAX_BT_DEPTH]; + size_t nr_pcs = backtrace_user_list(eip, ebp, pcs, MAX_BT_DEPTH); + + printk("\nBacktrace of user context on Core %d:\n", core_id()); + printk("\tOffsets only matter for shared libraries\n"); + /* This formatting is consumed by scripts/bt-akaros.sh. */ + for (int i = 0; i < nr_pcs; i++) { + printk("#%02d ", i + 1); + /* TODO: user backtraces all assume we're working on 'current' */ + debug_addr_proc(current, pcs[i]); + } +} + +void backtrace_hwtf(struct hw_trapframe *hw_tf) { struct per_cpu_info *pcpui = &per_cpu_info[core_id()]; + pcpui->__lock_checking_enabled--; - printk("\nBacktrace of kernel context on Core %d:\n", core_id()); - backtrace_frame(get_hwtf_pc(hw_tf), get_hwtf_fp(hw_tf)); + if (in_kernel(hw_tf)) + backtrace_frame(get_hwtf_pc(hw_tf), get_hwtf_fp(hw_tf)); + else + backtrace_user_frame(get_hwtf_pc(hw_tf), get_hwtf_fp(hw_tf)); pcpui->__lock_checking_enabled++; } void backtrace_user_ctx(struct proc *p, struct user_context *ctx) { - #define MAX_BT_DEPTH 20 - uintptr_t pcs[MAX_BT_DEPTH]; - size_t nr_pcs; + struct per_cpu_info *pcpui = &per_cpu_info[core_id()]; if (!ctx) { printk("Null user context!\n"); return; } - nr_pcs = backtrace_list(get_user_ctx_pc(ctx), get_user_ctx_fp(ctx), pcs, - MAX_BT_DEPTH); - printk("User context backtrace:\n"); - printk("\tOffsets only matter for shared libraries\n"); - for (int i = 0; i < nr_pcs; i++) { - printk("#%02d ", i + 1); - debug_addr_proc(p, pcs[i]); - } + assert(pcpui->cur_proc); + pcpui->__lock_checking_enabled--; + backtrace_user_frame(get_user_ctx_pc(ctx), get_user_ctx_fp(ctx)); + pcpui->__lock_checking_enabled++; } diff --git a/kern/src/profiler.c b/kern/src/profiler.c index 2cc8b85e277e..e09b311e5645 100644 --- a/kern/src/profiler.c +++ b/kern/src/profiler.c @@ -463,7 +463,7 @@ void profiler_add_user_backtrace(uintptr_t pc, uintptr_t fp) trace[0] = pc; if (likely(fp)) - n = user_backtrace_list(pc, fp, trace + 1, + n = backtrace_user_list(pc, fp, trace + 1, PROFILER_BT_DEPTH - 1) + 1; profiler_push_user_trace64(cpu_buf, p, trace, n); -- 2.6.0.rc2.230.g3dd15c0 -- You received this message because you are subscribed to the Google Groups "Akaros" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. For more options, visit https://groups.google.com/d/optout.
