Skip to content
Open
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
1 change: 1 addition & 0 deletions Documentation/debugging/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ This page contains a collection of guides on how to debug problems with NuttX.
coresight.rst
stackcheck.rst
stackrecord.rst
stackusage.rst
disabling_stackdumpdebug.rst
debuggingflash_nuttxonarm.rst
cortexmhardfaults.rst
Expand Down
159 changes: 159 additions & 0 deletions Documentation/debugging/stackusage.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
===========================
Static Stack Usage Analysis
===========================

Overview
========

``tools/stackusage.py`` performs static stack usage analysis by reading
DWARF ``.debug_frame`` data from an ELF file. It extracts per-function
stack sizes from CFA (Canonical Frame Address) offsets and optionally
builds a call graph via disassembly to compute worst-case total stack
depth.

- **Self** – stack bytes used by the function itself (max CFA offset).
- **Total** – worst-case stack depth through the deepest call chain
(self + callees). A marker prefix flags uncertain values.

Dependencies
============

The tool invokes standard toolchain binaries:

- **readelf** – symbol table and DWARF frame info
- **objdump** – disassembly for call graph analysis
- **addr2line** – source file and line resolution

Both GNU and LLVM toolchains are supported. Use ``-p`` to set the
toolchain prefix (e.g. ``-p arm-none-eabi-`` for GCC,
``-p llvm-`` for LLVM).

The ELF must contain DWARF debug info (``-g`` or ``-gdwarf``).
No special Kconfig option is needed.

Usage
=====

Analyze a native ELF (no prefix needed)::

python3 tools/stackusage.py nuttx

Cross-compiled ELF with GCC toolchain::

python3 tools/stackusage.py -p arm-none-eabi- nuttx

Cross-compiled ELF with LLVM toolchain::

python3 tools/stackusage.py -p llvm- nuttx

Show top 20 functions::

python3 tools/stackusage.py -p arm-none-eabi- -n 20 nuttx

Estimate recursion depth of 10::

python3 tools/stackusage.py -p arm-none-eabi- -r 10 nuttx

Command Line Options
====================

.. code-block:: text

positional arguments:
elf path to ELF file with DWARF debug info

options:
-p, --prefix PREFIX toolchain prefix (e.g. arm-none-eabi- or llvm-)
-n, --rank N show top N functions (default: 0 = all)
-r, --recursion-depth N
assumed recursion depth (default: 0)

Text Output
===========

The default output is an aligned table. Each function's deepest
backtrace is shown with one frame per row. The ``Self`` column shows
each frame's own stack cost. The ``Backtrace`` column shows the
function name followed by its code size in parentheses (when available
from the symbol table), e.g. ``main(128)``. The entry point of each
call chain is suffixed with ``~``.

Example (``nucleo-f429zi:trace``, ``-n 3``)::

Total Self Backtrace File:Line
----- ---- --------------------------- -------------------------------------------
@2344 56 telnetd_main(236)~ apps/system/telnetd/telnetd.c:42
^24 nsh_telnetmain(128) apps/nshlib/nsh_telnetd.c:48
^48 nsh_session(400) apps/nshlib/nsh_session.c:73
...
@224 nsh_parse_cmdparm(1024) apps/nshlib/nsh_parse.c:2362
@96 nsh_execute(512) apps/nshlib/nsh_parse.c:510
^56 nsh_builtin(320) apps/nshlib/nsh_builtin.c:76
88 exec_builtin(256) apps/builtin/exec_builtin.c:61
...
^64 file_vopen(192) nuttx/fs/vfs/fs_open.c:124
...
@2328 16 sh_main(64)~ apps/system/nsh/sh_main.c:40
16 nsh_system_ctty(96) apps/nshlib/nsh_system.c:105
^32 nsh_system_(160) apps/nshlib/nsh_system.c:41
^48 nsh_session(400) apps/nshlib/nsh_session.c:73
...
@2312 24 nsh_main(80)~ apps/system/nsh/nsh_main.c:54
^24 nsh_consolemain(48) apps/nshlib/nsh_consolemain.c:65
^48 nsh_session(400) apps/nshlib/nsh_session.c:73
...

Uncertainty markers on both Total and Self columns indicate the most
significant reason:

======= ==========================================
Marker Meaning
======= ==========================================
``~`` entry point of the call chain (suffix)
``?`` no DWARF data (self counted as zero)
``*`` dynamic stack (alloca or VLA)
``@`` recursion detected
``^`` indirect call (function pointer)
======= ==========================================

Uncertainty Reasons
===================

====================================== =========================================
Reason Description
====================================== =========================================
recursion: A->B->...->A Recursive cycle detected. Use ``-r N``
to estimate.
indirect call (function pointer) Callee unknown at compile time.
no DWARF data No ``.debug_frame`` entry; self counted
as zero.
dynamic stack (alloca/VLA) Function uses ``alloca()`` or
variable-length arrays; self is a
minimum.
====================================== =========================================

Uncertainty propagates upward: if any callee in the deepest path is
uncertain the caller is also marked uncertain.

Recursion Depth Estimation
==========================

By default (``-r 0``) recursive back-edges contribute zero stack.
With ``-r N`` (N > 0) the tool estimates::

cycle_body_cost × N

For example ``A(64) -> B(32) -> A``::

cycle_body_cost = 64 + 32 = 96
-r 10 → 96 × 10 = 960 bytes

The result is still marked uncertain.

Supported Architectures
=======================

Any architecture supported by the toolchain's ``readelf``,
``objdump``, and ``addr2line`` is supported. This includes
ARM, AArch64, x86, x86_64, MIPS, RISC-V, Xtensa, PowerPC, SPARC,
TriCore, SuperH, and others.
2 changes: 1 addition & 1 deletion Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2631,7 +2631,7 @@ config STACK_USAGE
---help---
Generate an extra file that specifies the maximum amount of stack used,
on a per-function basis. Please use https://github.com/HBehrens/puncover
or tools/showstack.sh to generate the more useful report.
to generate the more useful report.

config STACK_USAGE_WARNING
int "Detect use of large stack variables"
Expand Down
47 changes: 0 additions & 47 deletions tools/showstack.sh

This file was deleted.

Loading
Loading