summaryrefslogtreecommitdiff
path: root/libcpu/risc-v/virt64/backtrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcpu/risc-v/virt64/backtrace.c')
-rw-r--r--libcpu/risc-v/virt64/backtrace.c184
1 files changed, 86 insertions, 98 deletions
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 */