这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【换取手持数字示波器】GD32VF103(RISC-V)RT-thread函数栈

共1条 1/1 1 跳转至

【换取手持数字示波器】GD32VF103(RISC-V)RT-thread函数栈回溯工具使用

工程师
2025-01-04 11:29:57     打赏

简介:

在github 上发现个基于RT-thread 系统的RISC-V 架构的backtrace 工具(https://github.com/Yaochenger/RvBacktrace) 正好使用手里的GD32VF103  芯片上移植体验该功能。 

RvBacktrace 的移植适配相对容易只有三个.c文件和一个.h文件加入到工程编译即可,移植适配有两种方式。

image.png

方式1通过在链接脚本中添加代码段的符号,来查找栈帧中的地址信息来回溯。

image.png

方式2 通过编译选项,使用特定的S0 寄存器作为栈帧保存寄存器来进行栈回溯,本次移植适配我们使用方式2。

对应栈回溯算法如下

#include "../include/rvbacktrace.h"
#if defined(BACKTRACE_USE_FP)
static rt_uint32_t _rt_susrstack;
static rt_uint32_t _rt_eusrstack;
static rt_thread_t _backtrace_thread;
static rt_thread_t _backtrace_threadn;
static rt_object_t * thread_object_table = RT_NULL;
extern unsigned int rvstack_frame[STACK_FRAME_LEN]; // stack frame
extern unsigned int rvstack_frame_len; // stack frame len

static void walk_stackframe(int (*print_func)(const char *fmt, ...))
{
    rt_uint32_t num = 0;
    _backtrace_thread = rt_thread_self(); //    get current thread
    _rt_susrstack = (rt_uint32_t)(uintptr_t)_backtrace_thread->stack_addr; // stack start address
    _rt_eusrstack = (rt_uint32_t)(uintptr_t)(_backtrace_thread->stack_addr + _backtrace_thread->stack_size); // stack end address

    unsigned long sp, fp, ra, pc; // stack pointer, frame pointer, return address, program counter
    struct stackframe *frame;

    const register unsigned long current_sp __asm__("sp"); //   get current stack pointer
    sp = current_sp;
    fp = (unsigned long)__builtin_frame_address(0); //  get current frame pointer
    print_func("Current Thread Name:  %s \n", _backtrace_thread->parent.name);
    while (1)
    {
        frame = (struct stackframe *)(fp - BACKTRACE_LEN); //   get frame pointer

        if ((rt_uint32_t *)frame > (rt_uint32_t *)(uintptr_t)_rt_eusrstack)
        {
            rvstack_frame_len = num;
            return;
        }

        sp = fp;  // get stack pointer
        fp = frame->s_fp; // get frame pointer
        ra = frame->s_ra; // get return address
        pc = frame->s_ra - 4; // get program counter

        //  print stack interval, return address, program counter
        print_func("[%d]Stack interval :[0x%016lx - 0x%016lx]  ra 0x%016lx pc 0x%016lx\n", num, sp, fp, ra, pc);
        rvstack_frame[num] = pc; // save stack frame address
        num++;
    }
}

#if defined(BACKTRACE_ALL)
static void walk_stackframe_all(int (*print_func)(const char *fmt, ...))
{
    rt_uint32_t num = 0, i = 0;
    int thread_object_len = 0;
    unsigned long sp, fp, ra, pc; // stack pointer, frame pointer, return address, program counter
    struct stackframe *frame;

    thread_object_len = rt_object_get_length(RT_Object_Class_Thread);
    if (thread_object_len == RT_NULL)
    {
        return;
    }

    thread_object_table = (rt_object_t *) rt_malloc((sizeof(rt_object_t) * thread_object_len));
    RT_ASSERT(thread_object_table != RT_NULL);

    rt_object_get_pointers(RT_Object_Class_Thread, (rt_object_t *) thread_object_table, thread_object_len);

    for (i = 0; i < thread_object_len; i++)
    {
        _backtrace_threadn = (rt_thread_t) thread_object_table[i];

        if (_backtrace_threadn == (rt_thread_t) rt_thread_self())
        {
            continue;
        }

        _rt_susrstack = (rt_uint32_t) (uintptr_t) _backtrace_threadn->stack_addr; // stack start address
        _rt_eusrstack = (rt_uint32_t) (uintptr_t) (_backtrace_threadn->stack_addr + _backtrace_threadn->stack_size); // stack end address

        print_func("------------------------------Thread: %s backtrace------------------------------\r\n",
                _backtrace_threadn->parent.name);
        print_func("[%d]Thread Name:  %s \n", i, _backtrace_threadn->parent.name);
        sp = (unsigned long) _backtrace_threadn->sp;
        fp = ((rt_ubase_t *) (_backtrace_threadn->sp))[BACKTRACE_FP_POS]; // get current frame pointer
        while (1)
        {
            frame = (struct stackframe *) (fp - BACKTRACE_LEN); //   get frame pointer

            if ((rt_uint32_t *) frame > (rt_uint32_t *) (uintptr_t) _rt_eusrstack)
            {
                rvstack_frame_len = num;
                rvbacktrace_addr2line((rt_uint32_t *) &rvstack_frame[0], print_func);
                num = 0;
                break;
            }

            sp = fp;  // get stack pointer
            fp = frame->s_fp; // get frame pointer
            ra = frame->s_ra; // get return address
            pc = frame->s_ra - 4; // get program counter

            //  print stack interval, return address, program counter
            print_func("[%d]Stack interval :[0x%016lx - 0x%016lx]  ra 0x%016lx pc 0x%016lx\n", num, sp, fp, ra, pc);
            rvstack_frame[num] = pc; // save stack frame address
            num++;
        }
    }
    print_func("Thread Total Num: %d\n", thread_object_len);
}
#endif /* BACKTRACE_ALL */

//  backtrace function
void rvbacktrace_fno(int (*print_func)(const char *fmt, ...))
{
    print_func("\r\n---- RV_Backtrace Call Frame Start: ----\r\n");
    print_func("###Please consider the value of ra as accurate and the value of sp as only for reference###\n");
    print_func("------------------------------Thread: %s backtrace------------------------------\r\n", ((rt_thread_t)rt_thread_self())->parent.name);
    walk_stackframe(print_func);
    rvbacktrace_addr2line((rt_uint32_t *)&rvstack_frame[0], print_func); // addr2line function
#if defined (BACKTRACE_ALL_THREAD)
    print_func("\r\n");
    walk_stackframe_all(print_func);
#endif /* BACKTRACE_ALL_THREAD */
    print_func("---- RV_Backtrace Call Frame End:----\r\n");
    print_func("\r\n");
}

MSH_CMD_EXPORT_ALIAS(rvbacktrace_fno, rv_backtrace_all, backtrace all threads);
#endif /* BACKTRACE_USE_FP */

将源代码加入工程编译,便添加编译选项 -fno-omit-frame-pointer

image.png

编译完成后添加测试以下测试代码。

void backtrace(int argc, char* argv[])
{
    rvbacktrace();
}
MSH_CMD_EXPORT(backtrace, risc-v back trace)

运行输出如下

image.png

使用 addr2line -e rtthread.elf -a -f 8003e30 8003e6c 800264e 800354a 80035b6 8003a66 800108a 查看调用栈

输出结果如下跟实际的调用关系也是一致

image.png



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]