Skip to content

Commit e5b7f3f

Browse files
authored
[kservice] Enhance support for backtrace service (#9037)
[feat] Enhance support for backtrace service rt_backtrace_formatted_print() and rt_backtrace_to_buffer() to help debug routines. Also, following modification are included: - make rt_backtrace_frame patchable with weak attr - replace lwp backtrace with sync output Signed-off-by: Shell <[email protected]>
1 parent 1869c54 commit e5b7f3f

File tree

6 files changed

+173
-32
lines changed

6 files changed

+173
-32
lines changed

include/rthw.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
#include <rtdef.h>
2424

25-
#if defined (RT_USING_CACHE) || defined(RT_USING_SMP)
25+
#if defined (RT_USING_CACHE) || defined(RT_USING_SMP) || defined(RT_HW_INCLUDE_CPUPORT)
2626
#include <cpuport.h> /* include spinlock, cache ops, etc. */
2727
#endif
2828

include/rtthread.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ void rt_mp_free_sethook(void (*hook)(struct rt_mempool *mp, void *block));
296296
* heap memory interface
297297
*/
298298
void rt_system_heap_init(void *begin_addr, void *end_addr);
299+
void rt_system_heap_init_generic(void *begin_addr, void *end_addr);
299300

300301
void *rt_malloc(rt_size_t size);
301302
void rt_free(void *ptr);
@@ -729,7 +730,10 @@ void rt_kputs(const char *str);
729730

730731
rt_err_t rt_backtrace(void);
731732
rt_err_t rt_backtrace_thread(rt_thread_t thread);
732-
rt_err_t rt_backtrace_frame(struct rt_hw_backtrace_frame *frame);
733+
rt_err_t rt_backtrace_frame(rt_thread_t thread, struct rt_hw_backtrace_frame *frame);
734+
rt_err_t rt_backtrace_formatted_print(rt_ubase_t *buffer, long buflen);
735+
rt_err_t rt_backtrace_to_buffer(rt_thread_t thread, struct rt_hw_backtrace_frame *frame,
736+
long skip, rt_ubase_t *buffer, long buflen);
733737

734738
#if defined(RT_USING_DEVICE) && defined(RT_USING_CONSOLE)
735739
rt_device_t rt_console_set_device(const char *name);

libcpu/aarch64/common/trap.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ void rt_hw_trap_exception(struct rt_hw_exp_stack *regs)
370370
#endif
371371

372372
struct rt_hw_backtrace_frame frame = {.fp = regs->x29, .pc = regs->pc};
373-
rt_backtrace_frame(&frame);
373+
rt_backtrace_frame(rt_thread_self(), &frame);
374374
rt_hw_cpu_shutdown();
375375
}
376376

libcpu/risc-v/virt64/trap.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ void handle_trap(rt_size_t scause, rt_size_t stval, rt_size_t sepc, struct rt_hw
366366
.pc = sepc
367367
};
368368
rt_kprintf("fp = %p", frame.fp);
369-
rt_backtrace_frame(&frame);
369+
rt_backtrace_frame(rt_thread_self(), &frame);
370370

371371
RT_ASSERT(0);
372372
}

src/Kconfig

+7-7
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,6 @@ config RT_TICK_PER_SECOND
114114
help
115115
System's tick frequency, Hz.
116116

117-
config RT_USING_OVERFLOW_CHECK
118-
bool "Using stack overflow checking"
119-
default y
120-
help
121-
Enable thread stack overflow checking. The stack overflow is checking when
122-
each thread switch.
123-
124117
config RT_USING_HOOK
125118
bool "Enable system hook"
126119
default y
@@ -261,6 +254,13 @@ menuconfig RT_USING_DEBUG
261254
depends on RT_USING_SMP
262255
default y if RT_USING_SMART
263256
default n
257+
258+
config RT_USING_OVERFLOW_CHECK
259+
bool "Using stack overflow checking"
260+
default y
261+
help
262+
Enable thread stack overflow checking. The stack overflow is checking when
263+
each thread switch.
264264
endif
265265

266266
menu "Inter-Thread communication"

src/kservice.c

+158-21
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@
2525
* 2022-08-30 Yunjie make rt_vsnprintf adapt to ti c28x (16bit int)
2626
* 2023-02-02 Bernard add Smart ID for logo version show
2727
* 2023-10-16 Shell Add hook point for rt_malloc services
28+
* 2023-10-21 Shell support the common backtrace API which is arch-independent
2829
* 2023-12-10 xqyjlj perf rt_hw_interrupt_disable/enable, fix memheap lock
2930
* 2024-03-10 Meco Man move std libc related functions to rtklibc
3031
*/
3132

3233
#include <rtthread.h>
34+
35+
/* include rt_hw_backtrace macro defined in cpuport.h */
36+
#define RT_HW_INCLUDE_CPUPORT
3337
#include <rthw.h>
3438

3539
#define DBG_TAG "kernel.service"
@@ -86,6 +90,34 @@ rt_weak void rt_hw_cpu_shutdown(void)
8690
return;
8791
}
8892

93+
/**
94+
* @note can be overridden by cpuport.h which is defined by a specific arch
95+
*/
96+
#ifndef RT_HW_BACKTRACE_FRAME_GET_SELF
97+
98+
#ifdef __GNUC__
99+
#define RT_HW_BACKTRACE_FRAME_GET_SELF(frame) do { \
100+
(frame)->fp = (rt_base_t)__builtin_frame_address(0U); \
101+
(frame)->pc = ({__label__ pc; pc: (rt_base_t)&&pc;}); \
102+
} while (0)
103+
104+
#else
105+
#define RT_HW_BACKTRACE_FRAME_GET_SELF(frame) do { \
106+
(frame)->fp = 0; \
107+
(frame)->pc = 0; \
108+
} while (0)
109+
110+
#endif /* __GNUC__ */
111+
112+
#endif /* RT_HW_BACKTRACE_FRAME_GET_SELF */
113+
114+
/**
115+
* @brief Get the inner most frame of target thread
116+
*
117+
* @param thread the thread which frame belongs to
118+
* @param frame the specified frame to be unwound
119+
* @return rt_err_t 0 is succeed, otherwise a failure
120+
*/
89121
rt_weak rt_err_t rt_hw_backtrace_frame_get(rt_thread_t thread, struct rt_hw_backtrace_frame *frame)
90122
{
91123
RT_UNUSED(thread);
@@ -95,6 +127,13 @@ rt_weak rt_err_t rt_hw_backtrace_frame_get(rt_thread_t thread, struct rt_hw_back
95127
return -RT_ENOSYS;
96128
}
97129

130+
/**
131+
* @brief Unwind the target frame
132+
*
133+
* @param thread the thread which frame belongs to
134+
* @param frame the specified frame to be unwound
135+
* @return rt_err_t 0 is succeed, otherwise a failure
136+
*/
98137
rt_weak rt_err_t rt_hw_backtrace_frame_unwind(rt_thread_t thread, struct rt_hw_backtrace_frame *frame)
99138
{
100139
RT_UNUSED(thread);
@@ -356,27 +395,34 @@ rt_weak int rt_kprintf(const char *fmt, ...)
356395
RTM_EXPORT(rt_kprintf);
357396
#endif /* RT_USING_CONSOLE */
358397

359-
#ifdef __GNUC__
398+
/**
399+
* @brief Print backtrace of current thread to system console device
400+
*
401+
* @return rt_err_t 0 is success, otherwise a failure
402+
*/
360403
rt_weak rt_err_t rt_backtrace(void)
361404
{
362-
struct rt_hw_backtrace_frame frame = {
363-
.fp = (rt_base_t)__builtin_frame_address(0U),
364-
.pc = ({__label__ pc; pc: (rt_base_t)&&pc;})
365-
};
366-
rt_hw_backtrace_frame_unwind(rt_thread_self(), &frame);
367-
return rt_backtrace_frame(&frame);
368-
}
405+
struct rt_hw_backtrace_frame frame;
406+
rt_thread_t thread = rt_thread_self();
369407

370-
#else /* otherwise not implemented */
371-
rt_weak rt_err_t rt_backtrace(void)
372-
{
373-
/* LOG_W cannot work under this environment */
374-
rt_kprintf("%s is not implemented\n", __func__);
375-
return -RT_ENOSYS;
408+
RT_HW_BACKTRACE_FRAME_GET_SELF(&frame);
409+
if (!frame.fp)
410+
return -RT_EINVAL;
411+
412+
/* we don't want this frame to be printed which is nearly garbage info */
413+
rt_hw_backtrace_frame_unwind(thread, &frame);
414+
415+
return rt_backtrace_frame(thread, &frame);
376416
}
377-
#endif
378417

379-
rt_err_t rt_backtrace_frame(struct rt_hw_backtrace_frame *frame)
418+
/**
419+
* @brief Print backtrace from frame to system console device
420+
*
421+
* @param thread the thread which frame belongs to
422+
* @param frame where backtrace starts from
423+
* @return rt_err_t 0 is success, otherwise a failure
424+
*/
425+
rt_weak rt_err_t rt_backtrace_frame(rt_thread_t thread, struct rt_hw_backtrace_frame *frame)
380426
{
381427
long nesting = 0;
382428

@@ -385,7 +431,7 @@ rt_err_t rt_backtrace_frame(struct rt_hw_backtrace_frame *frame)
385431
while (nesting < RT_BACKTRACE_LEVEL_MAX_NR)
386432
{
387433
rt_kprintf(" 0x%lx", (rt_ubase_t)frame->pc);
388-
if (rt_hw_backtrace_frame_unwind(rt_thread_self(), frame))
434+
if (rt_hw_backtrace_frame_unwind(thread, frame))
389435
{
390436
break;
391437
}
@@ -395,6 +441,89 @@ rt_err_t rt_backtrace_frame(struct rt_hw_backtrace_frame *frame)
395441
return RT_EOK;
396442
}
397443

444+
/**
445+
* @brief Print backtrace from buffer to system console
446+
*
447+
* @param buffer where traced frames saved
448+
* @param buflen number of items in buffer
449+
* @return rt_err_t 0 is success, otherwise a failure
450+
*/
451+
rt_weak rt_err_t rt_backtrace_formatted_print(rt_ubase_t *buffer, long buflen)
452+
{
453+
rt_kprintf("please use: addr2line -e rtthread.elf -a -f");
454+
455+
for (size_t i = 0; i < buflen && buffer[i] != 0; i++)
456+
{
457+
rt_kprintf(" 0x%lx", (rt_ubase_t)buffer[i]);
458+
}
459+
460+
rt_kprintf("\n");
461+
return RT_EOK;
462+
}
463+
464+
465+
/**
466+
* @brief Print backtrace from frame to the given buffer
467+
*
468+
* @param frame where backtrace starts from. NULL if it's the current one
469+
* @param skip the number of frames to discarded counted from calling function.
470+
* Noted that the inner most frame is always discarded and not counted,
471+
* which is obviously reasonable since that's this function itself.
472+
* @param buffer where traced frames saved
473+
* @param buflen max number of items can be saved in buffer. If there are no more
474+
* than buflen items to be saved, there will be a NULL after the
475+
* last saved item in the buffer.
476+
* @return rt_err_t 0 is success, otherwise a failure
477+
*/
478+
rt_weak rt_err_t rt_backtrace_to_buffer(rt_thread_t thread,
479+
struct rt_hw_backtrace_frame *frame,
480+
long skip,
481+
rt_ubase_t *buffer,
482+
long buflen)
483+
{
484+
long nesting = 0;
485+
struct rt_hw_backtrace_frame cur_frame;
486+
487+
if (!thread)
488+
return -RT_EINVAL;
489+
490+
RT_ASSERT(rt_object_get_type(&thread->parent) == RT_Object_Class_Thread);
491+
492+
if (!frame)
493+
{
494+
frame = &cur_frame;
495+
RT_HW_BACKTRACE_FRAME_GET_SELF(frame);
496+
if (!frame->fp)
497+
return -RT_EINVAL;
498+
}
499+
500+
/* discard frames as required. The inner most is always threw. */
501+
do {
502+
rt_hw_backtrace_frame_unwind(thread, frame);
503+
} while (skip-- > 0);
504+
505+
while (nesting < buflen)
506+
{
507+
*buffer++ = (rt_ubase_t)frame->pc;
508+
if (rt_hw_backtrace_frame_unwind(thread, frame))
509+
{
510+
break;
511+
}
512+
nesting++;
513+
}
514+
515+
if (nesting < buflen)
516+
*buffer = RT_NULL;
517+
518+
return RT_EOK;
519+
}
520+
521+
/**
522+
* @brief Print backtrace of a thread to system console device
523+
*
524+
* @param thread which call stack is traced
525+
* @return rt_err_t 0 is success, otherwise a failure
526+
*/
398527
rt_err_t rt_backtrace_thread(rt_thread_t thread)
399528
{
400529
rt_err_t rc;
@@ -404,7 +533,7 @@ rt_err_t rt_backtrace_thread(rt_thread_t thread)
404533
rc = rt_hw_backtrace_frame_get(thread, &frame);
405534
if (rc == RT_EOK)
406535
{
407-
rc = rt_backtrace_frame(&frame);
536+
rc = rt_backtrace_frame(thread, &frame);
408537
}
409538
}
410539
else
@@ -643,7 +772,14 @@ rt_inline void _slab_info(rt_size_t *total,
643772
#define _MEM_INFO(...)
644773
#endif
645774

646-
static void _rt_system_heap_init(void *begin_addr, void *end_addr)
775+
/**
776+
* @brief This function will do the generic system heap initialization.
777+
*
778+
* @param begin_addr the beginning address of system page.
779+
*
780+
* @param end_addr the end address of system page.
781+
*/
782+
void rt_system_heap_init_generic(void *begin_addr, void *end_addr)
647783
{
648784
rt_ubase_t begin_align = RT_ALIGN((rt_ubase_t)begin_addr, RT_ALIGN_SIZE);
649785
rt_ubase_t end_align = RT_ALIGN_DOWN((rt_ubase_t)end_addr, RT_ALIGN_SIZE);
@@ -657,15 +793,16 @@ static void _rt_system_heap_init(void *begin_addr, void *end_addr)
657793
}
658794

659795
/**
660-
* @brief This function will init system heap.
796+
* @brief This function will init system heap. User can override this API to
797+
* complete other works, like heap sanitizer initialization.
661798
*
662799
* @param begin_addr the beginning address of system page.
663800
*
664801
* @param end_addr the end address of system page.
665802
*/
666803
rt_weak void rt_system_heap_init(void *begin_addr, void *end_addr)
667804
{
668-
_rt_system_heap_init(begin_addr, end_addr);
805+
rt_system_heap_init_generic(begin_addr, end_addr);
669806
}
670807

671808
/**

0 commit comments

Comments
 (0)