Skip to content

Commit 16c5584

Browse files
authored
Merge pull request cnlohr#830 from BogdanTheGeek/stackusage
Stack Usage Example
2 parents 3e5c58e + f00b1a9 commit 16c5584

4 files changed

Lines changed: 162 additions & 0 deletions

File tree

projects/stack_usage/Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
all : flash
2+
3+
TARGET:=stack_usage
4+
5+
TARGET_MCU?=CH32V003
6+
# TARGET_MCU:=CH570
7+
# TARGET_MCU_PACKAGE:=CH570D
8+
include ../../ch32fun/ch32fun.mk
9+
10+
CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
11+
12+
flash : cv_flash
13+
clean : cv_clean
14+

projects/stack_usage/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Stack Info Example
2+
3+
This example shows how to measure runtime stack usage using a canary value.
4+
The stack is filled with a canary value (0xDEADBEEF) and after a few operations,
5+
the stack is scanned to see how much of the canary value has been overwritten,
6+
indicating the maximum stack depth used.
7+
8+
The second part of the example shows a call trace (frame pointer backtrace) of a recursive
9+
function with random depth.
10+
11+
RA is the return address. You can use the following command to get the function name from the
12+
address (replace `<address>` with the actual address):
13+
14+
```sh
15+
riscv32-unknown-elf-addr2line -f -e *.elf <address>
16+
```
17+
> [!NOTE]
18+
> Your toolchain prefix may vary.

projects/stack_usage/funconfig.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#ifndef _FUNCONFIG_H
2+
#define _FUNCONFIG_H
3+
4+
// Place configuration items here, you can see a full list in ch32fun/ch32fun.h
5+
// To reconfigure to a different processor, update TARGET_MCU in the Makefile
6+
#if defined(CH570_CH572)
7+
#define FUNCONF_USE_HSI 0 // CH5xx does not have HSI
8+
#define FUNCONF_USE_HSE 1
9+
#define CLK_SOURCE_CH5XX CLK_SOURCE_PLL_60MHz // default so not really needed
10+
#define FUNCONF_SYSTEM_CORE_CLOCK 60 * 1000 * 1000 // keep in line with CLK_SOURCE_CH5XX
11+
12+
#define FUNCONF_DEBUG_HARDFAULT 1
13+
#define FUNCONF_USE_CLK_SEC 0
14+
#endif
15+
16+
#endif
17+

projects/stack_usage/stack_usage.c

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#include "ch32fun.h"
2+
#include <stdio.h>
3+
4+
#define RANDOM_STRENGTH 2
5+
#include "lib_rand.h"
6+
7+
#define CANARY 0xF0CACC1A
8+
9+
// stack start and end defined in the linker script
10+
extern uint32_t _eusrstack;
11+
extern uint32_t end;
12+
13+
static inline void *get_stack_pointer()
14+
{
15+
register void *sp asm( "sp" );
16+
return sp;
17+
}
18+
19+
20+
void print_stacktrace()
21+
{
22+
volatile uintptr_t *fp;
23+
asm volatile( "mv %0, s0" : "=r"( fp ) );
24+
25+
int depth = 0;
26+
27+
printf( "Stack Trace:\n" );
28+
while ( fp )
29+
{
30+
uintptr_t ra = *( fp - 1 );
31+
uintptr_t *nextfp = (void *)*( fp - 2 );
32+
33+
printf( " Frame %d: FP=0x%x, RA=0x%x\n", depth, (uintptr_t)nextfp, ra );
34+
35+
fp = (void *)nextfp;
36+
if ( fp == (uintptr_t *)&_eusrstack )
37+
{
38+
printf( "Done\n" );
39+
break;
40+
}
41+
42+
if ( ++depth > 20 )
43+
{
44+
printf( "Stack trace depth limit reached.\n" );
45+
break;
46+
}
47+
}
48+
}
49+
50+
void fill_canary( uint32_t canary )
51+
{
52+
uint32_t *p = get_stack_pointer();
53+
printf( "Filling canary from 0x%lx to 0x%lx\n", (uint32_t)p, (uint32_t)&end );
54+
55+
while ( --p > &end )
56+
{
57+
*p = canary;
58+
}
59+
}
60+
61+
void *get_stack_watermark( uint32_t canary )
62+
{
63+
const uint32_t *const top = get_stack_pointer();
64+
uint32_t *p = &end;
65+
while ( ++p < top )
66+
{
67+
if ( *p != canary )
68+
{
69+
break;
70+
}
71+
}
72+
return p;
73+
}
74+
75+
void test_function( int depth )
76+
{
77+
if ( ( rand() & 0xf ) != 0 )
78+
{
79+
test_function( depth + 1 );
80+
}
81+
else
82+
{
83+
printf( "Reached depth %d, printing stack trace:\n", depth );
84+
print_stacktrace();
85+
}
86+
}
87+
88+
int main()
89+
{
90+
SystemInit();
91+
funAnalogInit();
92+
seed( funAnalogRead( 1 ) );
93+
94+
void *const initial_sp = get_stack_pointer();
95+
96+
printf( "Initial SP: 0x%lx\n", (uint32_t)initial_sp );
97+
98+
printf( "Stack Start: 0x%lx\n", (uint32_t)&_eusrstack );
99+
printf( "Stack End: 0x%lx\n", (uint32_t)&end );
100+
101+
fill_canary( CANARY );
102+
103+
printf( "Hello, Stack Usage!\n" );
104+
105+
const void *const used_stack = get_stack_watermark( CANARY );
106+
const size_t used_bytes = (size_t)initial_sp - (size_t)used_stack;
107+
printf( "Used Stack: %u bytes\n", (unsigned int)used_bytes );
108+
109+
test_function( 0 );
110+
111+
while ( 1 )
112+
;
113+
}

0 commit comments

Comments
 (0)