From 70a8d1d4656bc678ddada5e56263c9cb4423a623 Mon Sep 17 00:00:00 2001 From: Shell Date: Sat, 21 Oct 2023 20:14:45 +0800 Subject: [kservice] improve backtrace service in kernel (#8144) Signed-off-by: Shell --- src/Kconfig | 4 ++ src/kservice.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/Kconfig b/src/Kconfig index bb93e76bb7..e76efca64d 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -421,4 +421,8 @@ config RT_USING_STDC_ATOMIC bool "Use atomic implemented in stdatomic.h" default n +config RT_BACKTRACE_LEVEL_MAX_NR + int "Max number of backtrace level" + default 32 + endmenu diff --git a/src/kservice.c b/src/kservice.c index 5b005a9551..b8ea8b2ecd 100644 --- a/src/kservice.c +++ b/src/kservice.c @@ -29,7 +29,7 @@ #include #include -#define DBG_TAG "kernel.device" +#define DBG_TAG "kernel.service" #ifdef RT_DEBUG_DEVICE #define DBG_LVL DBG_LOG #else @@ -91,6 +91,18 @@ rt_weak void rt_hw_cpu_shutdown(void) return; } +rt_weak rt_err_t rt_hw_backtrace_frame_get(rt_thread_t thread, struct rt_hw_backtrace_frame *frame) +{ + LOG_W("%s: not implemented"); + return -RT_ENOSYS; +} + +rt_weak rt_err_t rt_hw_backtrace_frame_unwind(rt_thread_t thread, struct rt_hw_backtrace_frame *frame) +{ + LOG_W("%s: not implemented"); + return -RT_ENOSYS; +} + rt_weak const char *rt_hw_cpu_arch(void) { return "unknown"; @@ -1537,6 +1549,108 @@ rt_weak int rt_kprintf(const char *fmt, ...) RTM_EXPORT(rt_kprintf); #endif /* RT_USING_CONSOLE */ +#ifdef __GNUC__ +rt_weak rt_err_t rt_backtrace(void) +{ + struct rt_hw_backtrace_frame frame = { + .fp = (rt_base_t)__builtin_frame_address(0U), + .pc = ({__label__ pc; pc: (rt_base_t)&&pc;}) + }; + rt_hw_backtrace_frame_unwind(rt_thread_self(), &frame); + return rt_backtrace_frame(&frame); +} + +#else /* otherwise not implemented */ +rt_weak rt_err_t rt_backtrace(void) +{ + LOG_W("%s: not implemented"); + return -RT_ENOSYS; +} +#endif + +rt_err_t rt_backtrace_frame(struct rt_hw_backtrace_frame *frame) +{ + long nesting = 0; + LOG_RAW("please use: addr2line -e rtthread.elf -a -f"); + + while (nesting < RT_BACKTRACE_LEVEL_MAX_NR) + { + LOG_RAW(" 0x%lx", (rt_ubase_t)frame->pc); + if (rt_hw_backtrace_frame_unwind(rt_thread_self(), frame)) + { + break; + } + nesting++; + } + LOG_RAW("\n"); + return RT_EOK; +} + +rt_err_t rt_backtrace_thread(rt_thread_t thread) +{ + rt_err_t rc; + struct rt_hw_backtrace_frame frame; + if (thread) + { + rc = rt_hw_backtrace_frame_get(thread, &frame); + if (rc == RT_EOK) + { + rc = rt_backtrace_frame(&frame); + } + } + else + { + rc = -RT_EINVAL; + } + return rc; +} + +#ifdef RT_USING_LIBC +#include /* for string service */ + +static void cmd_backtrace(int argc, char** argv) +{ + rt_ubase_t pid; + char *end_ptr; + + if (argc != 2) + { + if (argc == 1) + { + LOG_RAW("[INFO] No thread specified\n" + "[HELP] You can use commands like: backtrace %p\n" + "Printing backtrace of calling stack...\n", + rt_thread_self()); + rt_backtrace(); + return ; + } + else + { + LOG_RAW("please use: backtrace [thread_address]\n"); + return; + } + } + + pid = strtol(argv[1], &end_ptr, 0); + if (end_ptr == argv[1]) + { + LOG_RAW("Invalid input: %s\n", argv[1]); + return ; + } + + if (pid && rt_object_get_type((void *)pid) == RT_Object_Class_Thread) + { + rt_thread_t target = (rt_thread_t)pid; + LOG_RAW("backtrace %s(0x%lx), from %s\n", target->parent.name, pid, argv[1]); + rt_backtrace_thread(target); + } + else + LOG_RAW("Invalid pid: %ld\n", pid); +} +MSH_CMD_EXPORT_ALIAS(cmd_backtrace, backtrace, print backtrace of a thread); + +#endif /* RT_USING_LIBC */ + #if defined(RT_USING_HEAP) && !defined(RT_USING_USERHEAP) #ifdef RT_USING_HOOK static void (*rt_malloc_hook)(void *ptr, rt_size_t size); @@ -2061,6 +2175,7 @@ void rt_assert_handler(const char *ex_string, const char *func, rt_size_t line) #endif /*RT_USING_MODULE*/ { rt_kprintf("(%s) assertion failed at function:%s, line number:%d \n", ex_string, func, line); + rt_backtrace(); while (dummy == 0); } } -- cgit v1.3.1