summaryrefslogtreecommitdiff
path: root/libcpu
diff options
context:
space:
mode:
Diffstat (limited to 'libcpu')
-rw-r--r--libcpu/aarch64/common/backtrace.c203
-rw-r--r--libcpu/aarch64/common/backtrace.h29
-rw-r--r--libcpu/aarch64/common/trap.c20
-rw-r--r--libcpu/arm/cortex-a/backtrace.c3
-rw-r--r--libcpu/arm/cortex-a/backtrace.h1
-rw-r--r--libcpu/risc-v/virt64/backtrace.c184
-rw-r--r--libcpu/risc-v/virt64/cpuport.h2
-rw-r--r--libcpu/risc-v/virt64/trap.c21
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(&regs, 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;