-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Feature/ksym backtrace #11768
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Feature/ksym backtrace #11768
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -444,6 +444,23 @@ rt_weak rt_err_t rt_backtrace(void) | |
| return rt_backtrace_frame(thread, &frame); | ||
| } | ||
|
|
||
| #ifdef RT_USING_KSYMS | ||
| static void _rt_backtrace_print_pc(rt_ubase_t pc) | ||
| { | ||
| struct rt_ksym_info info; | ||
|
|
||
| rt_kprintf(" 0x%lx", (unsigned long)pc); | ||
| if (rt_ksym_lookup(pc, &info) == RT_EOK) | ||
| { | ||
| rt_kprintf(" <%s+0x%lx", info.name, | ||
| (unsigned long)info.offset); | ||
| if (info.size != 0) | ||
| rt_kprintf("/0x%lx", (unsigned long)info.size); | ||
| rt_kprintf(">"); | ||
| } | ||
| } | ||
| #endif /* RT_USING_KSYMS */ | ||
|
|
||
| /** | ||
| * @brief Print backtrace from frame to system console device | ||
| * | ||
|
|
@@ -455,11 +472,17 @@ rt_weak rt_err_t rt_backtrace_frame(rt_thread_t thread, struct rt_hw_backtrace_f | |
| { | ||
| long nesting = 0; | ||
|
|
||
| #ifndef RT_USING_KSYMS | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这个是条件宏越加越零碎了,后续再加的人多了,那就会变成100个 |
||
| rt_kprintf("please use: addr2line -e rtthread.elf -a -f\n"); | ||
| #endif | ||
|
|
||
| while (nesting < RT_BACKTRACE_LEVEL_MAX_NR) | ||
| { | ||
| #ifdef RT_USING_KSYMS | ||
| _rt_backtrace_print_pc((rt_ubase_t)frame->pc); | ||
| #else | ||
| rt_kprintf(" 0x%lx", (rt_ubase_t)frame->pc); | ||
| #endif | ||
| if (rt_hw_backtrace_frame_unwind(thread, frame)) | ||
| { | ||
| break; | ||
|
|
@@ -479,11 +502,17 @@ rt_weak rt_err_t rt_backtrace_frame(rt_thread_t thread, struct rt_hw_backtrace_f | |
| */ | ||
| rt_weak rt_err_t rt_backtrace_formatted_print(rt_ubase_t *buffer, long buflen) | ||
| { | ||
| #ifndef RT_USING_KSYMS | ||
| rt_kprintf("please use: addr2line -e rtthread.elf -a -f\n"); | ||
| #endif | ||
|
|
||
| for (rt_size_t i = 0; i < buflen && buffer[i] != 0; i++) | ||
| { | ||
| #ifdef RT_USING_KSYMS | ||
| _rt_backtrace_print_pc((rt_ubase_t)buffer[i]); | ||
| #else | ||
| rt_kprintf(" 0x%lx", (rt_ubase_t)buffer[i]); | ||
| #endif | ||
| } | ||
|
|
||
| rt_kprintf("\n"); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| /* | ||
| * Copyright (c) 2006-2026, RT-Thread Development Team | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| #include <rtthread.h> | ||
|
|
||
| #ifdef RT_USING_KSYMS | ||
|
|
||
| /* These objects are replaced by the generated table when using GCC builds. */ | ||
| rt_weak volatile const rt_uintptr_t rt_ksym_first_addr = 0; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这会更改内核文件,而这个功能目前只是 ARM 端少数几个才存在,并不适合于放入到内核中。
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @BernardXiong 熊大,感谢 review。这里补充一下这个功能的设计意图。 KSYMS 本身并不是针对 Cortex-A 实现的,我原本是希望把它作为一个架构无关的地址到函数符号解析能力。当前只是 Cortex-A 的 backtrace 路径完成得比较完整,其他架构还没有全部接入。 目前 ARM32、AArch64 和 RISC-V64 的 GCC/ELF 符号表生成和最终 ELF 地址验证都已经测试过,RISC-V64 上 如果这里主要 concern 是目前实际使用 KSYMS 的 backtrace consumer 太少,我可以继续调整这个 PR:
这样 如果即使有多个架构 consumer,这类 symbol resolver 仍然不适合放在 请问您这里主要考虑的是目前 consumer 数量还比较少,还是认为 KSYMS 这类诊断功能本身就不应该放在 kernel |
||
| rt_weak volatile const rt_uint32_t rt_ksym_count = 0; | ||
| rt_weak volatile const rt_uint32_t rt_ksym_entries[1][3] = {{0, 0, 0}}; | ||
| rt_weak const char rt_ksym_names[1] = ""; | ||
|
|
||
| static rt_uintptr_t _rt_ksym_normalize_addr(rt_uintptr_t addr) | ||
| { | ||
| #if defined(ARCH_ARM) && !defined(ARCH_CPU_64BIT) | ||
| return addr & ~((rt_uintptr_t)1); | ||
| #else | ||
| return addr; | ||
| #endif | ||
| } | ||
|
|
||
| static rt_uintptr_t _rt_ksym_entry_addr(rt_uint32_t index) | ||
| { | ||
| return rt_ksym_first_addr + rt_ksym_entries[index][0]; | ||
| } | ||
|
|
||
| rt_err_t rt_ksym_lookup(rt_uintptr_t addr, struct rt_ksym_info *info) | ||
| { | ||
| rt_uint32_t low; | ||
| rt_uint32_t high; | ||
| rt_uintptr_t start; | ||
| rt_uint32_t size; | ||
|
|
||
| if (!info) | ||
| return -RT_EINVAL; | ||
| if (rt_ksym_count == 0) | ||
| return -RT_ENOSYS; | ||
|
|
||
| addr = _rt_ksym_normalize_addr(addr); | ||
|
|
||
| if (addr < rt_ksym_first_addr || | ||
| addr - rt_ksym_first_addr > 0xffffffffu) | ||
| return -RT_ENOENT; | ||
|
|
||
| low = 0; | ||
| high = rt_ksym_count; | ||
| while (high - low > 1) | ||
| { | ||
| rt_uint32_t middle = low + (high - low) / 2; | ||
|
|
||
| if (_rt_ksym_entry_addr(middle) <= addr) | ||
| low = middle; | ||
| else | ||
| high = middle; | ||
| } | ||
|
|
||
| if (_rt_ksym_entry_addr(low) > addr) | ||
| return -RT_ENOENT; | ||
|
|
||
| /* Keep aliases together even if a hand-built table contains them. */ | ||
| while (low > 0 && | ||
| _rt_ksym_entry_addr(low - 1) == _rt_ksym_entry_addr(low)) | ||
| { | ||
| low--; | ||
| } | ||
|
|
||
| start = _rt_ksym_entry_addr(low); | ||
| size = rt_ksym_entries[low][2]; | ||
|
|
||
| if (size == 0 && addr != start) | ||
| return -RT_ENOENT; | ||
| if (size != 0 && addr - start >= size) | ||
| return -RT_ENOENT; | ||
|
|
||
| info->name = &rt_ksym_names[rt_ksym_entries[low][1]]; | ||
| info->start = start; | ||
| info->offset = addr - start; | ||
| info->size = size; | ||
|
|
||
| return RT_EOK; | ||
| } | ||
|
|
||
| #endif /* RT_USING_KSYMS */ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| /* | ||
| * Copyright (c) 2006-2026, RT-Thread Development Team | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| #include <rtthread.h> | ||
| #include "utest.h" | ||
| #include "utest_assert.h" | ||
|
|
||
| static void __attribute__((noinline)) ksym_test_level1(void); | ||
| static void __attribute__((noinline)) ksym_test_level2(void); | ||
| static void __attribute__((noinline)) ksym_test_level3(void); | ||
|
|
||
| static void __attribute__((noinline)) ksym_test_level1(void) | ||
| { | ||
| ksym_test_level2(); | ||
| } | ||
|
|
||
| static void __attribute__((noinline)) ksym_test_level2(void) | ||
| { | ||
| ksym_test_level3(); | ||
| } | ||
|
|
||
| static void __attribute__((noinline)) ksym_test_level3(void) | ||
| { | ||
| rt_backtrace(); | ||
| } | ||
|
|
||
| static void test_ksym_lookup(void) | ||
| { | ||
| struct rt_ksym_info info; | ||
| rt_uintptr_t address; | ||
|
|
||
| address = (rt_uintptr_t)(void *)ksym_test_level1; | ||
| uassert_int_equal(rt_ksym_lookup(address, &info), RT_EOK); | ||
| uassert_str_equal(info.name, "ksym_test_level1"); | ||
| uassert_int_equal(info.start, | ||
| #if defined(ARCH_ARM) && !defined(ARCH_CPU_64BIT) | ||
| address & ~((rt_uintptr_t)1) | ||
| #else | ||
| address | ||
| #endif | ||
| ); | ||
| uassert_int_equal(info.offset, 0); | ||
|
|
||
| #if defined(ARCH_ARM) && !defined(ARCH_CPU_64BIT) | ||
| uassert_int_equal(rt_ksym_lookup(address | 1, &info), RT_EOK); | ||
| uassert_int_equal(info.offset, 0); | ||
| #endif | ||
|
|
||
| uassert_int_equal(rt_ksym_lookup((rt_uintptr_t)-1, &info), -RT_ENOENT); | ||
| uassert_int_equal(rt_ksym_lookup(address, RT_NULL), -RT_EINVAL); | ||
| } | ||
|
|
||
| static void test_ksym_static_chain(void) | ||
| { | ||
| struct rt_ksym_info info; | ||
|
|
||
| #if defined(ARCH_ARM_CORTEX_A) || defined(ARCH_ARMV8) | ||
| ksym_test_level1(); | ||
| #endif | ||
| uassert_int_equal(rt_ksym_lookup((rt_uintptr_t)(void *)ksym_test_level2, | ||
| &info), RT_EOK); | ||
| uassert_str_equal(info.name, "ksym_test_level2"); | ||
| } | ||
|
|
||
| static rt_err_t utest_tc_init(void) | ||
| { | ||
| return RT_EOK; | ||
| } | ||
|
|
||
| static rt_err_t utest_tc_cleanup(void) | ||
| { | ||
| return RT_EOK; | ||
| } | ||
|
|
||
| static void testcase(void) | ||
| { | ||
| UTEST_UNIT_RUN(test_ksym_lookup); | ||
| UTEST_UNIT_RUN(test_ksym_static_chain); | ||
| } | ||
|
|
||
| UTEST_TC_EXPORT(testcase, "core.ksym", utest_tc_init, utest_tc_cleanup, 10); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
应该说核心的是这个函数,为了这个函数需要把一个.c文件都loop到内核中?