summaryrefslogtreecommitdiff
path: root/libcpu
diff options
context:
space:
mode:
Diffstat (limited to 'libcpu')
-rw-r--r--libcpu/aarch64/common/backtrace.c131
-rw-r--r--libcpu/aarch64/common/backtrace.h6
-rw-r--r--libcpu/aarch64/common/context_gcc.S30
-rw-r--r--libcpu/aarch64/common/trap.c13
4 files changed, 173 insertions, 7 deletions
diff --git a/libcpu/aarch64/common/backtrace.c b/libcpu/aarch64/common/backtrace.c
index d8985d0c09..14ea18a97f 100644
--- a/libcpu/aarch64/common/backtrace.c
+++ b/libcpu/aarch64/common/backtrace.c
@@ -6,10 +6,15 @@
* Change Logs:
* Date Author Notes
* 2022-06-02 Jesven the first version
+ * 2023-06-24 WangXiaoyao Support backtrace for non-active thread
*/
+#include "mm_aspace.h"
+#include "mmu.h"
+
#include <rtthread.h>
#include <backtrace.h>
+#include <stdlib.h>
#define BT_NESTING_MAX 100
@@ -19,7 +24,7 @@ static int unwind_frame(struct bt_frame *frame)
if ((fp & 0x7)
#ifdef RT_USING_LWP
- || fp < KERNEL_VADDR_START
+ || (rt_kmem_v2p((void *)fp) == ARCH_MAP_FAILED)
#endif
)
{
@@ -27,16 +32,18 @@ static int unwind_frame(struct bt_frame *frame)
}
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;
+ struct bt_frame frame = {fp, 1};
unsigned long lr = pc;
int nesting = 0;
- frame.fp = fp;
while (nesting < BT_NESTING_MAX)
{
rt_kprintf(" %p", (void *)lr);
@@ -51,18 +58,128 @@ static void walk_unwind(unsigned long pc, unsigned long fp)
void backtrace(unsigned long pc, unsigned long lr, unsigned long fp)
{
- rt_kprintf("please use: addr2line -e rtthread.elf -a -f %p", (void *)pc);
- walk_unwind(lr, 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 pc = (unsigned long)backtrace;
unsigned long ra = (unsigned long)__builtin_return_address(0U);
unsigned long fr = (unsigned long)__builtin_frame_address(0U);
- backtrace(pc, ra, fr);
+ 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)
+{
+ unsigned long lr;
+ unsigned long fp;
+
+ if (thread == rt_thread_self())
+ {
+ return -RT_EINVAL;
+ }
+ else
+ {
+ lr = ARCH_CONTEXT_FETCH(thread->sp, 3);
+ fp = ARCH_CONTEXT_FETCH(thread->sp, 7);
+ backtrace(0, lr, fp);
+ return 0;
+ }
+}
+
+#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)
+ {
+ 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;
+ }
+ else
+ return -1;
+}
+
+#endif /* RT_USING_SMART */
+
+static long custom_hex_to_long(const char* hex)
+{
+ long result = 0;
+ int i = 0;
+
+ // Skip the "0x" prefix
+ if (hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X'))
+ {
+ 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')
+ {
+ result = result * 16 + (digit - 'a' + 10);
+ }
+ else if (digit >= 'A' && digit <= 'F')
+ {
+ result = result * 16 + (digit - 'A' + 10);
+ }
+ else
+ {
+ // Invalid hex digit
+ return 0;
+ }
+ }
+
+ return result;
+}
+
+static void cmd_backtrace(int argc, char** argv)
+{
+ long pid;
+
+ if (argc < 2)
+ {
+ rt_kprintf("please use: backtrace pid\n");
+ return;
+ }
+
+ if (strncmp(argv[1], "0x", 2) == 0)
+ {
+ pid = custom_hex_to_long(argv[1]);
+ }
+ 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);
+ }
+}
+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
index 8c8006690c..e5e281978c 100644
--- a/libcpu/aarch64/common/backtrace.h
+++ b/libcpu/aarch64/common/backtrace.h
@@ -6,11 +6,14 @@
* 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;
@@ -20,4 +23,7 @@ struct bt_frame
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/context_gcc.S b/libcpu/aarch64/common/context_gcc.S
index d9dc2d1c93..e3487c9135 100644
--- a/libcpu/aarch64/common/context_gcc.S
+++ b/libcpu/aarch64/common/context_gcc.S
@@ -6,6 +6,7 @@
* Change Logs:
* Date Author Notes
* 2021-05-18 Jesven the first version
+ * 2023-06-24 WangXiaoyao Support backtrace for user thread
*/
#include "rtconfig.h"
@@ -375,13 +376,31 @@ rt_hw_context_switch_interrupt:
vector_fiq:
B .
+.macro SAVE_USER_CTX
+ MRS X1, SPSR_EL1
+ AND X1, X1, 0xf
+ CMP X1, XZR
+
+ BNE 1f
+ BL lwp_uthread_ctx_save
+ LDP X0, X1, [SP]
+1:
+.endm
+
.globl vector_irq
vector_irq:
SAVE_CONTEXT
STP X0, X1, [SP, #-0x10]! /* X0 is thread sp */
BL rt_interrupt_enter
+ LDP X0, X1, [SP]
+#ifdef RT_USING_LWP
+ SAVE_USER_CTX
+#endif
BL rt_hw_trap_irq
+#ifdef RT_USING_LWP
+ BL lwp_uthread_ctx_restore
+#endif
BL rt_interrupt_leave
LDP X0, X1, [SP], #0x10
@@ -515,7 +534,15 @@ vector_irq_exit:
START_POINT(vector_exception)
SAVE_CONTEXT
STP X0, X1, [SP, #-0x10]!
+#ifdef RT_USING_LWP
+ SAVE_USER_CTX
+#endif
+
BL rt_hw_trap_exception
+#ifdef RT_USING_LWP
+ BL lwp_uthread_ctx_restore
+#endif
+
LDP X0, X1, [SP], #0x10
MOV SP, X0
RESTORE_CONTEXT_WITHOUT_MMU_SWITCH
@@ -523,6 +550,9 @@ START_POINT_END(vector_exception)
START_POINT(vector_serror)
SAVE_CONTEXT
+#ifdef RT_USING_LWP
+ SAVE_USER_CTX
+#endif
STP X0, X1, [SP, #-0x10]!
BL rt_hw_trap_serror
b .
diff --git a/libcpu/aarch64/common/trap.c b/libcpu/aarch64/common/trap.c
index dd5468daf1..8e97a8b0aa 100644
--- a/libcpu/aarch64/common/trap.c
+++ b/libcpu/aarch64/common/trap.c
@@ -296,6 +296,19 @@ void rt_hw_trap_exception(struct rt_hw_exp_stack *regs)
#ifdef RT_USING_FINSH
list_thread();
#endif
+
+#ifdef RT_USING_LWP
+ {
+ rt_thread_t th;
+
+ th = rt_thread_self();
+ if (th && th->lwp)
+ {
+ rt_backtrace_user_thread(th);
+ }
+ }
+#endif
+
backtrace((unsigned long)regs->pc, (unsigned long)regs->x30, (unsigned long)regs->x29);
rt_hw_cpu_shutdown();
}