Skip to content

[kservice] Enhance support for backtrace service #9037

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

Merged
merged 1 commit into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/rthw.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

#include <rtdef.h>

#if defined (RT_USING_CACHE) || defined(RT_USING_SMP)
#if defined (RT_USING_CACHE) || defined(RT_USING_SMP) || defined(RT_HW_INCLUDE_CPUPORT)
#include <cpuport.h> /* include spinlock, cache ops, etc. */
#endif

Expand Down
6 changes: 5 additions & 1 deletion include/rtthread.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ void rt_mp_free_sethook(void (*hook)(struct rt_mempool *mp, void *block));
* heap memory interface
*/
void rt_system_heap_init(void *begin_addr, void *end_addr);
void rt_system_heap_init_generic(void *begin_addr, void *end_addr);

void *rt_malloc(rt_size_t size);
void rt_free(void *ptr);
Expand Down Expand Up @@ -729,7 +730,10 @@ void rt_kputs(const char *str);

rt_err_t rt_backtrace(void);
rt_err_t rt_backtrace_thread(rt_thread_t thread);
rt_err_t rt_backtrace_frame(struct rt_hw_backtrace_frame *frame);
rt_err_t rt_backtrace_frame(rt_thread_t thread, struct rt_hw_backtrace_frame *frame);
rt_err_t rt_backtrace_formatted_print(rt_ubase_t *buffer, long buflen);
rt_err_t rt_backtrace_to_buffer(rt_thread_t thread, struct rt_hw_backtrace_frame *frame,
long skip, rt_ubase_t *buffer, long buflen);

#if defined(RT_USING_DEVICE) && defined(RT_USING_CONSOLE)
rt_device_t rt_console_set_device(const char *name);
Expand Down
2 changes: 1 addition & 1 deletion libcpu/aarch64/common/trap.c
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ void rt_hw_trap_exception(struct rt_hw_exp_stack *regs)
#endif

struct rt_hw_backtrace_frame frame = {.fp = regs->x29, .pc = regs->pc};
rt_backtrace_frame(&frame);
rt_backtrace_frame(rt_thread_self(), &frame);
rt_hw_cpu_shutdown();
}

Expand Down
2 changes: 1 addition & 1 deletion libcpu/risc-v/virt64/trap.c
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ void handle_trap(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
.pc = sepc
};
rt_kprintf("fp = %p", frame.fp);
rt_backtrace_frame(&frame);
rt_backtrace_frame(rt_thread_self(), &frame);

RT_ASSERT(0);
}
Expand Down
14 changes: 7 additions & 7 deletions src/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,6 @@ config RT_TICK_PER_SECOND
help
System's tick frequency, Hz.

config RT_USING_OVERFLOW_CHECK
bool "Using stack overflow checking"
default y
help
Enable thread stack overflow checking. The stack overflow is checking when
each thread switch.

config RT_USING_HOOK
bool "Enable system hook"
default y
Expand Down Expand Up @@ -261,6 +254,13 @@ menuconfig RT_USING_DEBUG
depends on RT_USING_SMP
default y if RT_USING_SMART
default n

config RT_USING_OVERFLOW_CHECK
bool "Using stack overflow checking"
default y
help
Enable thread stack overflow checking. The stack overflow is checking when
each thread switch.
endif

menu "Inter-Thread communication"
Expand Down
179 changes: 158 additions & 21 deletions src/kservice.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,15 @@
* 2022-08-30 Yunjie make rt_vsnprintf adapt to ti c28x (16bit int)
* 2023-02-02 Bernard add Smart ID for logo version show
* 2023-10-16 Shell Add hook point for rt_malloc services
* 2023-10-21 Shell support the common backtrace API which is arch-independent
* 2023-12-10 xqyjlj perf rt_hw_interrupt_disable/enable, fix memheap lock
* 2024-03-10 Meco Man move std libc related functions to rtklibc
*/

#include <rtthread.h>

/* include rt_hw_backtrace macro defined in cpuport.h */
#define RT_HW_INCLUDE_CPUPORT
#include <rthw.h>

#define DBG_TAG "kernel.service"
Expand Down Expand Up @@ -86,6 +90,34 @@ rt_weak void rt_hw_cpu_shutdown(void)
return;
}

/**
* @note can be overridden by cpuport.h which is defined by a specific arch
*/
#ifndef RT_HW_BACKTRACE_FRAME_GET_SELF

#ifdef __GNUC__
#define RT_HW_BACKTRACE_FRAME_GET_SELF(frame) do { \
(frame)->fp = (rt_base_t)__builtin_frame_address(0U); \
(frame)->pc = ({__label__ pc; pc: (rt_base_t)&&pc;}); \
} while (0)

#else
#define RT_HW_BACKTRACE_FRAME_GET_SELF(frame) do { \
(frame)->fp = 0; \
(frame)->pc = 0; \
} while (0)

#endif /* __GNUC__ */

#endif /* RT_HW_BACKTRACE_FRAME_GET_SELF */

/**
* @brief Get the inner most frame of target thread
*
* @param thread the thread which frame belongs to
* @param frame the specified frame to be unwound
* @return rt_err_t 0 is succeed, otherwise a failure
*/
rt_weak rt_err_t rt_hw_backtrace_frame_get(rt_thread_t thread, struct rt_hw_backtrace_frame *frame)
{
RT_UNUSED(thread);
Expand All @@ -95,6 +127,13 @@ rt_weak rt_err_t rt_hw_backtrace_frame_get(rt_thread_t thread, struct rt_hw_back
return -RT_ENOSYS;
}

/**
* @brief Unwind the target frame
*
* @param thread the thread which frame belongs to
* @param frame the specified frame to be unwound
* @return rt_err_t 0 is succeed, otherwise a failure
*/
rt_weak rt_err_t rt_hw_backtrace_frame_unwind(rt_thread_t thread, struct rt_hw_backtrace_frame *frame)
{
RT_UNUSED(thread);
Expand Down Expand Up @@ -356,27 +395,34 @@ rt_weak int rt_kprintf(const char *fmt, ...)
RTM_EXPORT(rt_kprintf);
#endif /* RT_USING_CONSOLE */

#ifdef __GNUC__
/**
* @brief Print backtrace of current thread to system console device
*
* @return rt_err_t 0 is success, otherwise a failure
*/
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);
}
struct rt_hw_backtrace_frame frame;
rt_thread_t thread = rt_thread_self();

#else /* otherwise not implemented */
rt_weak rt_err_t rt_backtrace(void)
{
/* LOG_W cannot work under this environment */
rt_kprintf("%s is not implemented\n", __func__);
return -RT_ENOSYS;
RT_HW_BACKTRACE_FRAME_GET_SELF(&frame);
if (!frame.fp)
return -RT_EINVAL;

/* we don't want this frame to be printed which is nearly garbage info */
rt_hw_backtrace_frame_unwind(thread, &frame);

return rt_backtrace_frame(thread, &frame);
}
#endif

rt_err_t rt_backtrace_frame(struct rt_hw_backtrace_frame *frame)
/**
* @brief Print backtrace from frame to system console device
*
* @param thread the thread which frame belongs to
* @param frame where backtrace starts from
* @return rt_err_t 0 is success, otherwise a failure
*/
rt_weak rt_err_t rt_backtrace_frame(rt_thread_t thread, struct rt_hw_backtrace_frame *frame)
{
long nesting = 0;

Expand All @@ -385,7 +431,7 @@ rt_err_t rt_backtrace_frame(struct rt_hw_backtrace_frame *frame)
while (nesting < RT_BACKTRACE_LEVEL_MAX_NR)
{
rt_kprintf(" 0x%lx", (rt_ubase_t)frame->pc);
if (rt_hw_backtrace_frame_unwind(rt_thread_self(), frame))
if (rt_hw_backtrace_frame_unwind(thread, frame))
{
break;
}
Expand All @@ -395,6 +441,89 @@ rt_err_t rt_backtrace_frame(struct rt_hw_backtrace_frame *frame)
return RT_EOK;
}

/**
* @brief Print backtrace from buffer to system console
*
* @param buffer where traced frames saved
* @param buflen number of items in buffer
* @return rt_err_t 0 is success, otherwise a failure
*/
rt_weak rt_err_t rt_backtrace_formatted_print(rt_ubase_t *buffer, long buflen)
{
rt_kprintf("please use: addr2line -e rtthread.elf -a -f");

for (size_t i = 0; i < buflen && buffer[i] != 0; i++)
{
rt_kprintf(" 0x%lx", (rt_ubase_t)buffer[i]);
}

rt_kprintf("\n");
return RT_EOK;
}


/**
* @brief Print backtrace from frame to the given buffer
*
* @param frame where backtrace starts from. NULL if it's the current one
* @param skip the number of frames to discarded counted from calling function.
* Noted that the inner most frame is always discarded and not counted,
* which is obviously reasonable since that's this function itself.
* @param buffer where traced frames saved
* @param buflen max number of items can be saved in buffer. If there are no more
* than buflen items to be saved, there will be a NULL after the
* last saved item in the buffer.
* @return rt_err_t 0 is success, otherwise a failure
*/
rt_weak rt_err_t rt_backtrace_to_buffer(rt_thread_t thread,
struct rt_hw_backtrace_frame *frame,
long skip,
rt_ubase_t *buffer,
long buflen)
{
long nesting = 0;
struct rt_hw_backtrace_frame cur_frame;

if (!thread)
return -RT_EINVAL;

RT_ASSERT(rt_object_get_type(&thread->parent) == RT_Object_Class_Thread);

if (!frame)
{
frame = &cur_frame;
RT_HW_BACKTRACE_FRAME_GET_SELF(frame);
if (!frame->fp)
return -RT_EINVAL;
}

/* discard frames as required. The inner most is always threw. */
do {
rt_hw_backtrace_frame_unwind(thread, frame);
} while (skip-- > 0);

while (nesting < buflen)
{
*buffer++ = (rt_ubase_t)frame->pc;
if (rt_hw_backtrace_frame_unwind(thread, frame))
{
break;
}
nesting++;
}

if (nesting < buflen)
*buffer = RT_NULL;

return RT_EOK;
}

/**
* @brief Print backtrace of a thread to system console device
*
* @param thread which call stack is traced
* @return rt_err_t 0 is success, otherwise a failure
*/
rt_err_t rt_backtrace_thread(rt_thread_t thread)
{
rt_err_t rc;
Expand All @@ -404,7 +533,7 @@ rt_err_t rt_backtrace_thread(rt_thread_t thread)
rc = rt_hw_backtrace_frame_get(thread, &frame);
if (rc == RT_EOK)
{
rc = rt_backtrace_frame(&frame);
rc = rt_backtrace_frame(thread, &frame);
}
}
else
Expand Down Expand Up @@ -643,7 +772,14 @@ rt_inline void _slab_info(rt_size_t *total,
#define _MEM_INFO(...)
#endif

static void _rt_system_heap_init(void *begin_addr, void *end_addr)
/**
* @brief This function will do the generic system heap initialization.
*
* @param begin_addr the beginning address of system page.
*
* @param end_addr the end address of system page.
*/
void rt_system_heap_init_generic(void *begin_addr, void *end_addr)
{
rt_ubase_t begin_align = RT_ALIGN((rt_ubase_t)begin_addr, RT_ALIGN_SIZE);
rt_ubase_t end_align = RT_ALIGN_DOWN((rt_ubase_t)end_addr, RT_ALIGN_SIZE);
Expand All @@ -657,15 +793,16 @@ static void _rt_system_heap_init(void *begin_addr, void *end_addr)
}

/**
* @brief This function will init system heap.
* @brief This function will init system heap. User can override this API to
* complete other works, like heap sanitizer initialization.
*
* @param begin_addr the beginning address of system page.
*
* @param end_addr the end address of system page.
*/
rt_weak void rt_system_heap_init(void *begin_addr, void *end_addr)
{
_rt_system_heap_init(begin_addr, end_addr);
rt_system_heap_init_generic(begin_addr, end_addr);
}

/**
Expand Down
Loading