diff options
| author | Shell <[email protected]> | 2023-10-21 20:14:45 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-10-21 20:14:45 +0800 |
| commit | 70a8d1d4656bc678ddada5e56263c9cb4423a623 (patch) | |
| tree | b81b97a4f4cf33df2b1a02742e80de218da51333 /libcpu | |
| parent | 90c7089d47755a3edaf9008282225c5019fa188c (diff) | |
[kservice] improve backtrace service in kernel (#8144)
Signed-off-by: Shell <[email protected]>
Diffstat (limited to 'libcpu')
| -rw-r--r-- | libcpu/aarch64/common/backtrace.c | 203 | ||||
| -rw-r--r-- | libcpu/aarch64/common/backtrace.h | 29 | ||||
| -rw-r--r-- | libcpu/aarch64/common/trap.c | 20 | ||||
| -rw-r--r-- | libcpu/arm/cortex-a/backtrace.c | 3 | ||||
| -rw-r--r-- | libcpu/arm/cortex-a/backtrace.h | 1 | ||||
| -rw-r--r-- | libcpu/risc-v/virt64/backtrace.c | 184 | ||||
| -rw-r--r-- | libcpu/risc-v/virt64/cpuport.h | 2 | ||||
| -rw-r--r-- | libcpu/risc-v/virt64/trap.c | 21 |
8 files changed, 189 insertions, 274 deletions
diff --git a/libcpu/aarch64/common/backtrace.c b/libcpu/aarch64/common/backtrace.c index 14ea18a97f..12cc3aedbf 100644 --- a/libcpu/aarch64/common/backtrace.c +++ b/libcpu/aarch64/common/backtrace.c @@ -7,179 +7,122 @@ * Date Author Notes * 2022-06-02 Jesven the first version * 2023-06-24 WangXiaoyao Support backtrace for non-active thread + * 2023-10-16 Shell Support a new backtrace framework */ -#include "mm_aspace.h" -#include "mmu.h" #include <rtthread.h> -#include <backtrace.h> +#include <rthw.h> + +#include <stdio.h> #include <stdlib.h> +#include <string.h> -#define BT_NESTING_MAX 100 +#include "mm_aspace.h" +#include "mmu.h" + +#define INST_WORD_BYTES 4 +#define WORD sizeof(rt_base_t) +#define ARCH_CONTEXT_FETCH(pctx, id) (*(((unsigned long *)pctx) + (id))) -static int unwind_frame(struct bt_frame *frame) +rt_inline rt_err_t _bt_kaddr(rt_ubase_t *fp, struct rt_hw_backtrace_frame *frame) { - unsigned long fp = frame->fp; + rt_err_t rc; + frame->fp = *fp; + frame->pc = *(fp + 1) - INST_WORD_BYTES; - if ((fp & 0x7) -#ifdef RT_USING_LWP - || (rt_kmem_v2p((void *)fp) == ARCH_MAP_FAILED) -#endif - ) + if ((rt_ubase_t)fp == frame->fp) { - return 1; + rc = -RT_ERROR; } - frame->fp = *(unsigned long *)fp; - frame->pc = *(unsigned long *)(fp + 8); - - if ((rt_kmem_v2p((void *)frame->pc) == ARCH_MAP_FAILED)) - return 1; - return 0; -} - -static void walk_unwind(unsigned long pc, unsigned long fp) -{ - struct bt_frame frame = {fp, 1}; - unsigned long lr = pc; - int nesting = 0; - - while (nesting < BT_NESTING_MAX) + else { - rt_kprintf(" %p", (void *)lr); - if (unwind_frame(&frame)) - { - break; - } - lr = frame.pc; - nesting++; + rc = RT_EOK; } + return rc; } -void backtrace(unsigned long pc, unsigned long lr, unsigned long fp) -{ - rt_kprintf("please use: addr2line -e rtthread.elf -a -f"); - if (pc) - rt_kprintf(" %p", (void *)pc); - - if (lr && fp) - walk_unwind(lr, fp); - rt_kprintf("\n"); -} - -int rt_backtrace(void) -{ - unsigned long ra = (unsigned long)__builtin_return_address(0U); - unsigned long fr = (unsigned long)__builtin_frame_address(0U); - - backtrace(0, ra, fr); - return 0; -} -MSH_CMD_EXPORT_ALIAS(rt_backtrace, bt_test, backtrace test); - -#define ARCH_CONTEXT_FETCH(pctx, id) (*(((unsigned long *)pctx) + (id))) - -int rt_backtrace_thread(rt_thread_t thread) +#ifdef RT_USING_SMART +#include <lwp_user_mm.h> +rt_inline rt_err_t _bt_uaddr(rt_lwp_t lwp, rt_ubase_t *fp, struct rt_hw_backtrace_frame *frame) { - unsigned long lr; - unsigned long fp; - - if (thread == rt_thread_self()) + rt_err_t rc; + if (lwp_data_get(lwp, &frame->fp, fp, WORD) != WORD) { - return -RT_EINVAL; + rc = -RT_EFAULT; } - else + else if (lwp_data_get(lwp, &frame->pc, fp + 1, WORD) != WORD) { - lr = ARCH_CONTEXT_FETCH(thread->sp, 3); - fp = ARCH_CONTEXT_FETCH(thread->sp, 7); - backtrace(0, lr, fp); - return 0; + rc = -RT_EFAULT; } -} - -#ifdef RT_USING_SMART - -int rt_backtrace_user_thread(rt_thread_t thread) -{ - unsigned long pc; - unsigned long lr; - unsigned long fp; - unsigned long ctx = (unsigned long)thread->user_ctx.ctx; - - if (ctx > (unsigned long)thread->stack_addr - && ctx < (unsigned long)thread->stack_addr + thread->stack_size) + else if ((rt_base_t)fp == frame->fp) { - pc = ARCH_CONTEXT_FETCH(thread->user_ctx.ctx, 0); - lr = ARCH_CONTEXT_FETCH(thread->user_ctx.ctx, 3); - fp = ARCH_CONTEXT_FETCH(thread->user_ctx.ctx, 7); - backtrace(pc, lr, fp); - return 0; + rc = -RT_ERROR; } else - return -1; + { + frame->pc -= INST_WORD_BYTES; + rc = RT_EOK; + } + return rc; } - #endif /* RT_USING_SMART */ -static long custom_hex_to_long(const char* hex) +rt_err_t rt_hw_backtrace_frame_unwind(rt_thread_t thread, struct rt_hw_backtrace_frame *frame) { - long result = 0; - int i = 0; + rt_err_t rc = -RT_ERROR; + rt_ubase_t *fp = (rt_ubase_t *)frame->fp; - // Skip the "0x" prefix - if (hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X')) + if (fp && !((long)fp & 0x7)) { - i = 2; - } - - // Convert each hex digit to its decimal value - for (; hex[i] != '\0'; i++) - { - char digit = hex[i]; - if (digit >= '0' && digit <= '9') - { - result = result * 16 + (digit - '0'); - } - else if (digit >= 'a' && digit <= 'f') +#ifdef RT_USING_SMART + if (thread->lwp) { - result = result * 16 + (digit - 'a' + 10); + rt_lwp_t lwp = thread->lwp; + void *this_lwp = lwp_self(); + if (this_lwp == lwp && rt_kmem_v2p(fp) != ARCH_MAP_FAILED) + { + rc = _bt_kaddr(fp, frame); + } + else if (lwp_user_accessible_ext(lwp, fp, sizeof(rt_base_t))) + { + rc = _bt_uaddr(lwp, fp, frame); + } + else + { + rc = -RT_EFAULT; + } } - else if (digit >= 'A' && digit <= 'F') + else +#endif + if (rt_kmem_v2p(fp) != ARCH_MAP_FAILED) { - result = result * 16 + (digit - 'A' + 10); + rc = _bt_kaddr(fp, frame); } else { - // Invalid hex digit - return 0; + rc = -RT_EFAULT; } } - - return result; -} - -static void cmd_backtrace(int argc, char** argv) -{ - long pid; - - if (argc < 2) + else { - rt_kprintf("please use: backtrace pid\n"); - return; + rc = -RT_EFAULT; } + return rc; +} - if (strncmp(argv[1], "0x", 2) == 0) +rt_err_t rt_hw_backtrace_frame_get(rt_thread_t thread, struct rt_hw_backtrace_frame *frame) +{ + rt_err_t rc; + if (!thread || !frame) { - pid = custom_hex_to_long(argv[1]); + rc = -RT_EINVAL; } else { - pid = atol(argv[1]); - } - if (pid) - { - rt_kprintf("backtrace %s(0x%lx), from %s\n", ((rt_thread_t)pid)->parent.name, pid, argv[1]); - rt_backtrace_thread((rt_thread_t)pid); + frame->pc = ARCH_CONTEXT_FETCH(thread->sp, 3); + frame->fp = ARCH_CONTEXT_FETCH(thread->sp, 7); + rc = RT_EOK; } + return rc; } -MSH_CMD_EXPORT_ALIAS(cmd_backtrace, backtrace, print backtrace of a thread); diff --git a/libcpu/aarch64/common/backtrace.h b/libcpu/aarch64/common/backtrace.h deleted file mode 100644 index e5e281978c..0000000000 --- a/libcpu/aarch64/common/backtrace.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2006-2022, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2022-06-02 Jesven the first version - * 2023-06-24 WangXiaoyao Support backtrace for non-active thread - */ - -#ifndef __BACKTRACE_H__ -#define __BACKTRACE_H__ - -#include <rtthread.h> - -struct bt_frame -{ - unsigned long fp; - unsigned long pc; -}; - -void backtrace(unsigned long pc, unsigned long lr, unsigned long fp); -int rt_backtrace(void); - -int rt_backtrace_user_thread(rt_thread_t thread); -int rt_backtrace_thread(rt_thread_t thread); - -#endif /*__BACKTRACE_H__*/ diff --git a/libcpu/aarch64/common/trap.c b/libcpu/aarch64/common/trap.c index 487e940600..e3e4bb43eb 100644 --- a/libcpu/aarch64/common/trap.c +++ b/libcpu/aarch64/common/trap.c @@ -16,16 +16,10 @@ #include "interrupt.h" #include "mm_aspace.h" -#include <backtrace.h> - #define DBG_TAG "libcpu.trap" #define DBG_LVL DBG_LOG #include <rtdbg.h> -void rt_unwind(struct rt_hw_exp_stack *regs, int pc_adj) -{ -} - #ifdef RT_USING_FINSH extern long list_thread(void); #endif @@ -54,7 +48,7 @@ static void _check_fault(struct rt_hw_exp_stack *regs, uint32_t pc_adj, char *in th = rt_thread_self(); if (th && th->lwp) { - rt_backtrace_user_thread(th); + arch_backtrace_uthread(th); } } #endif @@ -74,12 +68,17 @@ static void _check_fault(struct rt_hw_exp_stack *regs, uint32_t pc_adj, char *in th = rt_thread_self(); if (th && th->lwp) { - rt_backtrace_user_thread(th); + arch_backtrace_uthread(th); } } #endif + /* kernel stack backtrace */ - backtrace((unsigned long)regs->pc, (unsigned long)regs->x30, (unsigned long)regs->x29); + struct rt_hw_backtrace_frame frame = { + .fp = regs->x29, + .pc = regs->pc + }; + rt_backtrace_frame(&frame); } } @@ -373,6 +372,9 @@ void rt_hw_trap_exception(struct rt_hw_exp_stack *regs) #ifdef RT_USING_LWP _check_fault(regs, 0, "user fault"); #endif + + struct rt_hw_backtrace_frame frame = {.fp = regs->x29, .pc = regs->pc}; + rt_backtrace_frame(&frame); rt_hw_cpu_shutdown(); } diff --git a/libcpu/arm/cortex-a/backtrace.c b/libcpu/arm/cortex-a/backtrace.c index 9837c734cc..f9f4457f42 100644 --- a/libcpu/arm/cortex-a/backtrace.c +++ b/libcpu/arm/cortex-a/backtrace.c @@ -530,7 +530,7 @@ void rt_unwind(struct rt_hw_exp_stack *regs, unsigned int pc_adj) unwind_backtrace(&e_regs, __exidx_start, __exidx_end); } -void rt_backtrace(void) +rt_err_t rt_backtrace(void) { struct rt_hw_exp_stack regs; @@ -539,4 +539,5 @@ void rt_backtrace(void) asm volatile ("mov %0, lr":"=r"(regs.lr)); asm volatile ("mov %0, pc":"=r"(regs.pc)); rt_unwind(®s, 8); + return RT_EOK; } diff --git a/libcpu/arm/cortex-a/backtrace.h b/libcpu/arm/cortex-a/backtrace.h index c82ef66fc0..7847018ce2 100644 --- a/libcpu/arm/cortex-a/backtrace.h +++ b/libcpu/arm/cortex-a/backtrace.h @@ -76,7 +76,6 @@ int unwind_frame(struct stackframe *frame, const struct unwind_idx **origin_idx, void unwind_backtrace(struct pt_regs *regs, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[]); void rt_unwind(struct rt_hw_exp_stack *regs, unsigned int pc_adj); -void rt_backtrace(void); #endif /* !__ASSEMBLY__ */ diff --git a/libcpu/risc-v/virt64/backtrace.c b/libcpu/risc-v/virt64/backtrace.c index 0bcfa0b9d9..47c8956936 100644 --- a/libcpu/risc-v/virt64/backtrace.c +++ b/libcpu/risc-v/virt64/backtrace.c @@ -1,137 +1,125 @@ /* - * Copyright (c) 2006-2018, RT-Thread Development Team + * Copyright (c) 2006-2023, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes + * 2023-10-18 Shell Add backtrace support */ -#include <rtthread.h> -#ifdef RT_USING_SMART -#include <lwp_arch.h> - -#define TRANCE_LEVEL 20 +#define DBG_TAG "hw.backtrace" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> -extern rt_ubase_t __text_start[]; -extern rt_ubase_t __text_end[]; +#include <rtthread.h> +#include <mm_aspace.h> +#include "riscv_mmu.h" -static char *_get_elf_name(size_t sepc); +#define WORD sizeof(rt_base_t) +#define ARCH_CONTEXT_FETCH(pctx, id) (*(((unsigned long *)pctx) + (id))) -void rt_hw_backtrace(rt_uint32_t *ffp, rt_ubase_t sepc) +rt_inline rt_err_t _bt_kaddr(rt_ubase_t *fp, struct rt_hw_backtrace_frame *frame) { - rt_ubase_t *ra; - rt_ubase_t *fp; - rt_ubase_t vas, vae; - int i, j; + rt_err_t rc; + frame->fp = *(fp - 2); + frame->pc = *(fp - 1); - rt_kprintf("riscv64-unknown-linux-musl-addr2line -e %s -a -f", _get_elf_name(sepc)); + if ((rt_ubase_t)fp == frame->fp) + { + rc = -RT_ERROR; + } + else + { + rc = RT_EOK; + } + return rc; +} - fp = (rt_ubase_t *)ffp; +#ifdef RT_USING_SMART +#include <lwp_arch.h> +#include <lwp_user_mm.h> - if (!fp) +rt_inline rt_err_t _bt_uaddr(rt_lwp_t lwp, rt_ubase_t *fp, struct rt_hw_backtrace_frame *frame) +{ + rt_err_t rc; + if (lwp_data_get(lwp, &frame->fp, fp - 2, WORD) != WORD) { - asm volatile("mv %0, s0" - : "=r"(fp)); + rc = -RT_EFAULT; } - - if (sepc) + else if (lwp_data_get(lwp, &frame->pc, fp - 1, WORD) != WORD) { - rt_kprintf(" %p", sepc - 0x4); + rc = -RT_EFAULT; } - - if (fp > (rt_ubase_t *)USER_VADDR_START && fp < (rt_ubase_t *)USER_VADDR_TOP) + else if ((rt_ubase_t)fp == frame->fp) { - vas = USER_VADDR_START; - vae = USER_VADDR_TOP; + rc = -RT_ERROR; } else { - vas = (rt_ubase_t)&__text_start; - vae = (rt_ubase_t)&__text_end; + frame->pc -= 0; + rc = RT_EOK; } + return rc; +} +#endif /* RT_USING_SMART */ - for (i = j = 0; i < TRANCE_LEVEL; i++) +rt_err_t rt_hw_backtrace_frame_unwind(rt_thread_t thread, struct rt_hw_backtrace_frame *frame) +{ + rt_err_t rc = -RT_ERROR; + rt_ubase_t *fp = (rt_ubase_t *)frame->fp; + + if (fp && !((long)fp & 0x7)) { - if (RT_ALIGN((rt_ubase_t)fp, sizeof(void *)) != (rt_ubase_t)fp) +#ifdef RT_USING_SMART + if (thread->lwp) { - break; + void *lwp = thread->lwp; + void *this_lwp = lwp_self(); + if (this_lwp == lwp && rt_hw_mmu_v2p(lwp, fp) != ARCH_MAP_FAILED) + { + rc = _bt_kaddr(fp, frame); + } + else if (lwp_user_accessible_ext(lwp, (void *)fp, WORD)) + { + rc = _bt_uaddr(lwp, fp, frame); + } + else + { + rc = -RT_EFAULT; + } + } + else +#endif + if ((rt_kmem_v2p(fp) != ARCH_MAP_FAILED)) + { + rc = _bt_kaddr(fp, frame); + } + else + { + rc = -RT_EINVAL; } - - ra = fp - 1; - if (!rt_kmem_v2p(ra) || *ra < vas || *ra > vae) - break; - - rt_kprintf(" %p", *ra - 0x04); - - fp = fp - 2; - if (!rt_kmem_v2p(fp)) - break; - fp = (rt_ubase_t *)(*fp); - if (!fp) - break; } - - rt_kputs("\r\n"); -} - -static void _assert_backtrace_cb(const char *ex, const char *func, rt_size_t line) -{ - rt_hw_interrupt_disable(); - rt_kprintf("(%s) assertion failed at function:%s, line number:%d \n", ex, func, line); - - rt_hw_backtrace(0, 0); - rt_hw_cpu_shutdown(); -} - -static int rt_hw_backtrace_init(void) -{ - rt_assert_set_hook(_assert_backtrace_cb); - - return 0; + else + { + rc = -RT_EFAULT; + } + return rc; } -INIT_BOARD_EXPORT(rt_hw_backtrace_init); -static void backtrace_test(int args, char *argv[]) +rt_err_t rt_hw_backtrace_frame_get(rt_thread_t thread, struct rt_hw_backtrace_frame *frame) { - int *p = (void *)-1; - init_fn_t ft = 0; + rt_err_t rc; - if (args < 2) + if (!thread || !frame) { - rt_kprintf("backtrace_test usage:backtrace_test a(assert)/m(invalid memory)/i(illegal instruction)\r\n"); - return; - } - - if (!rt_strcmp(argv[1], "a")) - { - rt_kprintf("Assert test:\r\n", argv[1]); - RT_ASSERT(0); - } - else if (!rt_strcmp(argv[1], "m")) - { - rt_kprintf("Access invalid memory:\r\n", argv[1]); - *p = 0; - } - else if (!rt_strcmp(argv[1], "i")) - { - rt_kprintf("Illegal instruction:\r\n", argv[1]); - ft(); + rc = -RT_EINVAL; } else { - rt_kprintf("Unknown cmd :%s.\r\n", argv[1]); + frame->pc = ARCH_CONTEXT_FETCH(thread->sp, 13); + frame->fp = ARCH_CONTEXT_FETCH(thread->sp, 12); + rc = RT_EOK; } + return rc; } -MSH_CMD_EXPORT(backtrace_test, backtrace test case); - -extern struct rt_thread *rt_current_thread; - -#define IN_USERSPACE (sepc > USER_VADDR_START && sepc < USER_VADDR_TOP) - -static char *_get_elf_name(size_t sepc) -{ - return IN_USERSPACE ? rt_current_thread->parent.name : "rtthread.elf"; -} - -#endif /* RT_USING_SMART */ diff --git a/libcpu/risc-v/virt64/cpuport.h b/libcpu/risc-v/virt64/cpuport.h index 37b86910cc..35a47d987c 100644 --- a/libcpu/risc-v/virt64/cpuport.h +++ b/libcpu/risc-v/virt64/cpuport.h @@ -60,7 +60,7 @@ typedef union { #endif #ifndef __ASSEMBLY__ -#include <rtthread.h> +#include <rtdef.h> rt_inline void rt_hw_dsb() { asm volatile("fence":::"memory"); diff --git a/libcpu/risc-v/virt64/trap.c b/libcpu/risc-v/virt64/trap.c index 5a7d2bc4c5..6af0c0097d 100644 --- a/libcpu/risc-v/virt64/trap.c +++ b/libcpu/risc-v/virt64/trap.c @@ -149,6 +149,7 @@ static const char *get_exception_msg(int id) } #ifdef RT_USING_SMART +#include "lwp.h" void handle_user(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw_stack_frame *sp) { rt_size_t id = __MASKVALUE(scause, __MASK(63UL)); @@ -221,9 +222,15 @@ void handle_user(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw LOG_E("scause:0x%p,stval:0x%p,sepc:0x%p\n", scause, stval, sepc); dump_regs(sp); - rt_hw_backtrace((uint32_t *)sp->s0_fp, sepc); + rt_thread_t cur_thr = rt_thread_self(); + struct rt_hw_backtrace_frame frame = { + .fp = sp->s0_fp, + .pc = sepc + }; + rt_kprintf("fp = %p\n", frame.fp); + lwp_backtrace_frame(cur_thr, &frame); - LOG_E("User Fault, killing thread: %s", rt_thread_self()->parent.name); + LOG_E("User Fault, killing thread: %s", cur_thr->parent.name); EXIT_TRAP; sys_exit_group(-1); @@ -354,10 +361,14 @@ void handle_trap(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw extern struct rt_thread *rt_current_thread; rt_kprintf("--------------Backtrace--------------\n"); - rt_hw_backtrace((uint32_t *)sp->s0_fp, sepc); + struct rt_hw_backtrace_frame frame = { + .fp = sp->s0_fp, + .pc = sepc + }; + rt_kprintf("fp = %p", frame.fp); + rt_backtrace_frame(&frame); - while (1) - ; + RT_ASSERT(0); } _exit: EXIT_TRAP; |
