Embedded 微芯片PIC32和dsPIC33E的运行时堆栈监控

Embedded 微芯片PIC32和dsPIC33E的运行时堆栈监控,embedded,stack-overflow,microchip,pic32,Embedded,Stack Overflow,Microchip,Pic32,我需要对嵌入式硬件进行运行时堆栈分析,以确保分配了足够的堆栈空间。我理解基本理论。启动时,使用已知模式(如all 0xFF或0xAA)初始化堆栈,然后允许程序运行。堆栈在运行时会增长和收缩,但不会恢复原始图案。在足够长的时间后,检查堆栈并找到要更改的最后一个堆栈值的地址 我不需要便携式解决方案,只需要dsPIC33EP512MU810和PIC32MX795F512的解决方案。我的后备计划是逐步减小堆栈大小,直到出现堆栈溢出,但这只有在我有一个候选版本时才起作用,我更喜欢一个在整个开发和生产过程中

我需要对嵌入式硬件进行运行时堆栈分析,以确保分配了足够的堆栈空间。我理解基本理论。启动时,使用已知模式(如all 0xFF或0xAA)初始化堆栈,然后允许程序运行。堆栈在运行时会增长和收缩,但不会恢复原始图案。在足够长的时间后,检查堆栈并找到要更改的最后一个堆栈值的地址


我不需要便携式解决方案,只需要dsPIC33EP512MU810和PIC32MX795F512的解决方案。我的后备计划是逐步减小堆栈大小,直到出现堆栈溢出,但这只有在我有一个候选版本时才起作用,我更喜欢一个在整个开发和生产过程中持续监控的解决方案。

我相信你知道,等待堆栈溢出是最糟糕的解决方案。溢出可能会导致任何行为,包括什么都不做(!),反转数字符号,更改逻辑流,以及仅在上周五下雨的周二才执行所有这些操作。这一切都是随机的,你无法知道它是否发生在你身上

你有操作系统(即使是简单的操作系统)吗?如果是这样,您可以创建一个低优先级任务来监视另一个任务堆栈的保护字节(您已知的模式),并在它们不在预期值时让它做一些事情


如果没有操作系统,那么您将转向静态分析,而不是动态分析。您应该能够从链接器输出中清除关于最坏情况深度的有用信息,这些信息应该给出每个调用的堆栈使用情况,并且知道调用依赖关系图。它不会告诉你所有的事情,因为它不包括叠加在函数调用之上的中断,但它应该让你非常接近。取最坏情况编号,添加最坏情况中断编号,然后填充它以确保…

这是我在XC16编译器上使用的dsPIC33EP512MU810的代码。通过创建一个自动变量,我在堆栈顶部附近获得访问权限,然后增加几个字节(
stack\u VAR\u PAD
),并用保护字节填充堆栈的其余部分

#define STACK_VAR_PAD           0x0020
#define TOP_OF_STACK_ADDR       0x4000
#define STACK_GUARD_BYTE        0xEE

void WriteStackGuardBytes(void)
{
    static __eds__ char * ptr;
    static unsigned int start_addr;
    static unsigned int addr;

    //Use a variable on the stack
    char stack_var;

    ptr = &stack_var;
    //Casting to 32-bit first supresses complier warning
    //This chip uses a 16-bit address space
    start_addr = (unsigned long int)ptr + STACK_VAR_PAD;

    for (addr = start_addr; addr < TOP_OF_STACK_ADDR; addr++)
    {
        *((unsigned int *)(addr)) = STACK_GUARD_BYTE;
    }
}

unsigned int ReadStackGuardBytes(void)
{
    static __eds__ char * ptr;
    static unsigned int start_addr;
    static unsigned int addr;
    static unsigned int top_addr;

    //Use a variable on the stack here
    char stack_var;

    ptr = &stack_var;
    //Casting to 32-bit first supresses complier warning
    //This chip uses a 16-bit address space
    start_addr = (unsigned long int)ptr;
    top_addr = start_addr;

    for (addr = start_addr; addr < TOP_OF_STACK_ADDR; addr++)
    {
        if (*((unsigned int *)(addr)) != STACK_GUARD_BYTE)
        {
            top_addr = addr;
        }
    }

    return TOP_OF_STACK_ADDR - top_addr;
}
#定义堆栈变量焊盘0x0020
#定义\u堆栈的顶部\u地址0x4000
#定义堆栈保护字节0xEE
void WriteStackGuardBytes(void)
{
静态uuu eds uuuu char*ptr;
静态无符号整数起始地址;
静态无符号整数地址;
//在堆栈上使用变量
字符栈;
ptr=&stack_var;
//强制转换为32位第一会抑制编译器警告
//该芯片使用16位地址空间
start_addr=(无符号长整数)ptr+STACK_VAR_PAD;
对于(addr=start\u addr;addr

链接器声明堆栈在
0x8000
处停止(我设置该设置以生成映射文件),但我看到0直到
0x4000
,然后垃圾数据超过该值。我完全理解堆栈的内容是不确定的,但我也用这种方法确定我的堆栈永远不会超过
0x1500
左右,因此只检查
0x4000
对我有效。

我从dsPICEP系列的“DrRobotNinja”中获得了上述代码的一些错误,大多数情况下,使用16位变量+将地址增加2而不是1,通过保持字对齐来停止地址错误

#define STACK_VAR_PAD           0x0020
#define TOP_OF_STACK_ADDR       SPLIM
#define STACK_GUARD_BYTE        0xA1DE

void WriteStackGuardBytes(void)
{
    static __eds__ int * ptr;
    static unsigned int start_addr;
    static unsigned int addr;

    //Use a variable on the stack
    int stack_var;

    ptr = &stack_var;
    //Casting to 32-bit first supresses complier warning
    //This chip uses a 16-bit address space
    start_addr = (unsigned long int)ptr + STACK_VAR_PAD;

    for (addr = start_addr; addr < TOP_OF_STACK_ADDR; addr += 2)
    {
        *((unsigned int *)(addr)) = STACK_GUARD_BYTE;
    }
}

unsigned int ReadStackGuardBytes(void)
{
    static __eds__ int * ptr;
    static unsigned int start_addr;
    static unsigned int addr;
    static unsigned int top_addr;

    //Use a variable on the stack here
    int stack_var;

    ptr = &stack_var;
    //Casting to 32-bit first supresses complier warning
    //This chip uses a 16-bit address space
    start_addr = (unsigned long int)ptr;
    top_addr = start_addr;

    for (addr = start_addr; addr < TOP_OF_STACK_ADDR; addr += 2)
    {
        if (*((unsigned int *)(addr)) != STACK_GUARD_BYTE)
        {
            top_addr = addr;
        }
        else
        {
            break; //make this more robust and search for 2-3 consecutive 
        }
    }

    return TOP_OF_STACK_ADDR - top_addr;
}
#定义堆栈变量焊盘0x0020
#定义\u堆栈\u ADDR SPLIM的顶部\u
#定义堆栈\保护\字节0xA1DE
void WriteStackGuardBytes(void)
{
静态uuu eds uuuu int*ptr;
静态无符号整数起始地址;
静态无符号整数地址;
//在堆栈上使用变量
int-stack_-var;
ptr=&stack_var;
//强制转换为32位第一会抑制编译器警告
//该芯片使用16位地址空间
start_addr=(无符号长整数)ptr+STACK_VAR_PAD;
对于(addr=start\u addr;addr
Microchip有一个基于硬件的堆栈溢出异常,因此该行为定义良好。我没有操作系统,我更喜欢编写低级别的事件驱动代码:低优先级任务可以很容易地插入计时器中断。我已经分析了调用依赖关系,但我希望验证我的分析是否正确。核心问题是我不知道如何获得对堆栈上字节的读/写访问权。我知道自动变量被推到堆栈中,但是