【问题标题】:How to debug a stack overflow in C in IAR Workbench如何在 IAR Workbench 中调试 C 中的堆栈溢出
【发布时间】:2012-11-06 03:35:05
【问题描述】:

我正在使用 IAR Embedded Workbench IDE 和 TI CC2540 蓝牙低功耗 8051 芯片进行 C 项目。

在处理项目时,我似乎遇到了大量的 XData 堆栈和 Idata 堆栈溢出,我很难确定溢出的来源。我正在通过 UART 端口处理大量字符串。

我想知道是否有人对如何确保在分配内存后释放内存并确保我保持在堆栈和堆的边界内有任何提示。

谢谢

【问题讨论】:

  • 知道你的堆栈大小,检查代码看看你的函数中是否使用了任何非静态的大数组或结构,这很可能导致堆栈溢出。
  • 您是否使用堆栈视图来监控堆栈使用情况?它会告诉您堆栈中有哪些项目,以及它有多满。
  • 所以现在,我有一个大型结构,我根据需要动态分配和释放,并作为指针传递。我从来没有真正一次创建过一个以上的这些结构。该结构还包含一个指向字符串的指针,我也分配和释放该字符串。静态创建这个结构有区别吗?我看不出你如何拥有这个结构的静态声明并通过引用传递它。

标签: c debugging memory-leaks stack-overflow iar


【解决方案1】:

好吧,为了避免堆栈溢出,你应该避免以下事情:

1)递归(在嵌入式系统中使用递归不是一个好主意)

2)尽量避免动态分配。在大多数情况下,您不需要它。

在汽车中,有几条用于对 ECU 进行编程的规则称为 MISRA 规则,这些规则建议不要使用动态分配的内存和递归。这是link

IAR Embedded Workbench 是少数支持 MISRA C 的 IDE 之一。尝试启用 MISRA C 选项(这可能表明您的问题所在)。看看它是如何完成的here

【讨论】:

  • 我同意你关于动态分配的看法。我删除了所有动态分配数组的实例,问题似乎已经最小化了一点
  • 您也可以尝试从链接器修改堆栈段大小。搜索您的链接器文件并修改 STACK_SEGMENT 的长度(据我所知)。这样,您可能不会再遇到堆栈溢出问题。
【解决方案2】:

来自this TI's forum,只是试图阐明 TI 的 2540/1 堆栈大小。

编译项目后,您可以查看“.map”文件(输出文件夹)的底部。

例如心率示例项目:

108 019 bytes of CODE memory
     26 bytes of DATA memory (+ 73 absolute )
  6 089 bytes of XDATA memory
    192 bytes of IDATA memory
      8 bits of BIT memory
    702 bytes of CONST memory

此信息很有用,因为它告诉项目正在使用的代码空间(CODE 内存)和 RAM(XDATA 内存)的总量。 CODE 存储器加上 CONST 存储器的总和不得超过器件的最大闪存大小(128KB 或 256KB,取决于 CC2540/41 的版本)。 XDATA 内存的大小不得超过 7936 字节,因为 CC2540/41 包含 8kB 的 SRAM(保留 256 字节)。

在密切注意 XDATA 不超过 ~8k 的同时,您可能需要调整定义代码的缓冲区/大数组。最小的 SimpleBLEPeripheral 应用程序本身消耗接近 6-7k 的内存,除此之外,还有足够的空间为您的应用程序资源分配一些内存。

[我知道,答案很晚,但可能对其他读者有所帮助]。

【讨论】:

    【解决方案3】:

    您可以在链接器配置 (.icf) 文件中更改堆栈和堆大小。项目-> 选项-> 链接器-> 配置。可以在内置编辑器中进行微小的更改,但它太可悲了,您应该只使用文本编辑器。

    在那里你会看到类似的东西:

    define block CSTACK with alignment = 8, size = 0x0400 {};
    define block HEAP with alignment = 8, size = 0x0200 {};
    place in MY_RAM_region {block CSTACK, block HEAP};
    

    您可以根据需要进行更改。我认为可以将 HEAP 大小设置为零。那么所有的 malloc 调用都会在运行时失败,但是酷孩子无论如何都不在嵌入式系统中使用动态内存。

    如何估计堆栈大小? EWB 手册建议将此添加到您的 .icf:

    check that size(block CSTACK) >= 
          maxstack("Program Entry") + totalstack("interrupt") + 100;
    

    如果 CSTACK 太小,这假设会引发错误(100 只是一个捏造因素。)在我的情况下,链接器只是抛出错误“我无法计算出你的堆栈大小”。

    IAR 的 .icf 格式让我想起了 AppleScript(不是很好)。

    【讨论】:

      【解决方案4】:

      我不知道对于 IAR 的非 arm 版本是否可以正常工作,我可以分享我们的方法:

      在启动文件中,我们只需使用 IAR 用来测量堆栈使用情况的模式编辑 RAM 的初始化:

          LDR R1, =__RAM_START
          LDR R2, =__RAM_END
      
          SUBS    R2, R2, R1
          SUBS    R2, #1
          BLE .LC5
      
          MOVS    R0, #0xCDCDCDCD ;; <- LOOK HERE!
          MOVS    R3, #4
      .LC4:
          STR R0, [R1]
          ADD R1, R1, R3
          SUBS R2, #4
          BGE .LC4
      

      然后在我的节点的选项中,在链接器->高级中我们标记启用堆栈使用分析。 在 IDE 选项中,我们选择“启用图形堆栈”等。

      现在,在调试会话中,我们启用堆栈的图形表示,选择 View-> Stack。

      通过这种方法,您还可以转储整个 RAM 并找出 0xCDCD 模式的位置和位置。

      另一种方法是在我们的 uC 中使用 DWT 或 MPU 来监视总线访问跨越边界并触发异常。通过这种方法,您可以准确地看到堆栈溢出时谁在做什么。

      再说一遍,这是一种为 ARM 量身定制的方法,我不知道这是否适用于您的系统。

      K.R.

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-28
        • 2010-10-20
        • 1970-01-01
        • 2015-02-13
        • 2012-12-20
        相关资源
        最近更新 更多