1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-10-18 Shell Add backtrace support
9 */
10
11 #define DBG_TAG "hw.backtrace"
12 #define DBG_LVL DBG_INFO
13 #include <rtdbg.h>
14
15 #include <rtthread.h>
16 #include <mm_aspace.h>
17 #include "riscv_mmu.h"
18 #include "stack.h"
19
20 #define WORD sizeof(rt_base_t)
21 #define ARCH_CONTEXT_FETCH(pctx, id) (*(((unsigned long *)pctx) + (id)))
22
_bt_kaddr(rt_ubase_t * fp,struct rt_hw_backtrace_frame * frame)23 rt_inline rt_err_t _bt_kaddr(rt_ubase_t *fp, struct rt_hw_backtrace_frame *frame)
24 {
25 rt_err_t rc;
26 frame->fp = *(fp - 2);
27 frame->pc = *(fp - 1);
28
29 if ((rt_ubase_t)fp == frame->fp)
30 {
31 rc = -RT_ERROR;
32 }
33 else
34 {
35 rc = RT_EOK;
36 }
37 return rc;
38 }
39
40 #ifdef RT_USING_SMART
41 #include <lwp_arch.h>
42 #include <lwp_user_mm.h>
43
_bt_uaddr(rt_lwp_t lwp,rt_ubase_t * fp,struct rt_hw_backtrace_frame * frame)44 rt_inline rt_err_t _bt_uaddr(rt_lwp_t lwp, rt_ubase_t *fp, struct rt_hw_backtrace_frame *frame)
45 {
46 rt_err_t rc;
47 if (lwp_data_get(lwp, &frame->fp, fp - 2, WORD) != WORD)
48 {
49 rc = -RT_EFAULT;
50 }
51 else if (lwp_data_get(lwp, &frame->pc, fp - 1, WORD) != WORD)
52 {
53 rc = -RT_EFAULT;
54 }
55 else if ((rt_ubase_t)fp == frame->fp)
56 {
57 rc = -RT_ERROR;
58 }
59 else
60 {
61 frame->pc -= 0;
62 rc = RT_EOK;
63 }
64 return rc;
65 }
66 #endif /* RT_USING_SMART */
67
rt_hw_backtrace_frame_unwind(rt_thread_t thread,struct rt_hw_backtrace_frame * frame)68 rt_err_t rt_hw_backtrace_frame_unwind(rt_thread_t thread, struct rt_hw_backtrace_frame *frame)
69 {
70 rt_err_t rc = -RT_ERROR;
71 rt_uintptr_t *fp = (rt_uintptr_t *)frame->fp;
72
73 if (fp && !((long)fp & 0x7))
74 {
75 #ifdef RT_USING_SMART
76 if (thread->lwp)
77 {
78 void *lwp = thread->lwp;
79 void *this_lwp = lwp_self();
80 if (this_lwp == lwp && rt_hw_mmu_v2p(((rt_lwp_t)lwp)->aspace, fp) != ARCH_MAP_FAILED)
81 {
82 rc = _bt_kaddr(fp, frame);
83 }
84 else if (lwp_user_accessible_ext(lwp, (void *)fp, WORD))
85 {
86 rc = _bt_uaddr(lwp, fp, frame);
87 }
88 else
89 {
90 rc = -RT_EFAULT;
91 }
92 }
93 else
94 #endif
95 if ((rt_kmem_v2p(fp) != ARCH_MAP_FAILED))
96 {
97 rc = _bt_kaddr(fp, frame);
98 }
99 else
100 {
101 rc = -RT_EINVAL;
102 }
103 }
104 else
105 {
106 rc = -RT_EFAULT;
107 }
108 return rc;
109 }
110
rt_hw_backtrace_frame_get(rt_thread_t thread,struct rt_hw_backtrace_frame * frame)111 rt_err_t rt_hw_backtrace_frame_get(rt_thread_t thread, struct rt_hw_backtrace_frame *frame)
112 {
113 rt_err_t rc;
114
115 if (!thread || !frame)
116 {
117 rc = -RT_EINVAL;
118 }
119 else
120 {
121 rt_hw_switch_frame_t sframe = thread->sp;
122 frame->pc = sframe->regs[RT_HW_SWITCH_CONTEXT_RA];
123 frame->fp = sframe->regs[RT_HW_SWITCH_CONTEXT_S0];;
124 rc = RT_EOK;
125 }
126 return rc;
127 }
128