mirror of
https://github.com/apache/nuttx.git
synced 2026-05-29 04:19:37 +08:00
Documentation/debugging: add stackusage tool documentation
Build Documentation / build-html (push) Has been cancelled
Build Documentation / build-html (push) Has been cancelled
Add RST documentation for the stackusage.py static stack analysis tool, covering usage, command-line options, output format, and markers. Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
This commit is contained in:
committed by
Alan C. Assis
parent
fe217e533b
commit
55e752ada8
@@ -16,6 +16,7 @@ This page contains a collection of guides on how to debug problems with NuttX.
|
|||||||
coresight.rst
|
coresight.rst
|
||||||
stackcheck.rst
|
stackcheck.rst
|
||||||
stackrecord.rst
|
stackrecord.rst
|
||||||
|
stackusage.rst
|
||||||
disabling_stackdumpdebug.rst
|
disabling_stackdumpdebug.rst
|
||||||
debuggingflash_nuttxonarm.rst
|
debuggingflash_nuttxonarm.rst
|
||||||
cortexmhardfaults.rst
|
cortexmhardfaults.rst
|
||||||
|
|||||||
@@ -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.
|
||||||
Reference in New Issue
Block a user