axf-analyzer
Provides read-only analysis of ARM firmware .axf ELF/DWARF images, including crash address-to-source mapping, disassembly, symbol and memory size ranking, struct layout, call graph, and stack-frame/depth estimation.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
FwAnalyzer (AxFInspector)
Read a firmware .axf like a debugger would: crash addresses, machine code, memory usage, struct layout, stack depth — from one ELF file, with no IDE and no build step.
axf_inspector.py is a dependency-light Python script (one required package) that parses an ELF/DWARF firmware image produced by any ARM toolchain (ARMCC, ARMClang, GCC). It turns the build artifact into structured, machine-readable answers that a human or an AI agent can act on. Every command is read-only.
What it answers
Question | Example |
A HardFault left |
|
What did the compiler emit for this function? |
|
Which functions/data objects eat the most Flash/RAM? |
|
Which static objects are never referenced? |
|
What is the real memory layout of this struct? |
|
How is the image laid out (segments/headers)? |
|
Which ABI / FPU / compiler options was this built with? |
|
Where does this symbol live? |
|
Are two builds identical? |
|
How big is this function's stack frame? How deep can this call chain get? |
|
Each answer can be emitted as plain text (for humans) or --json (for agents/tools).
Related MCP server: toothpick
What it is not
This is a binary-level analyzer. It deliberately does not do source-code analysis:
who calls a function in the source (inlining, dead code, function-pointer call sites) → use grep / your editor
macro expansion, include dependency graphs, variable data flow, cyclomatic complexity → source tooling
--callgraph uses the ELF relocation table and therefore only sees static direct calls after linking. It is not a source call graph.
Requirements
pip install -r requirements.txt # pyelftools (required), capstone (optional)Requirement | Notes |
Python 3.10+ | the script uses PEP 604 type unions |
| ELF/DWARF parsing |
| optional; enables real disassembly, otherwise |
Firmware | DWARF is required for |
Keil/MDK does not need to be installed. Any ELF32/ELF64 .axf works.
On Windows consoles set PYTHONUTF8=1 when paths contain non-ASCII characters.
Build settings for analysis (recommended)
Prefer a dedicated debug build when you analyze firmware: high optimization changes what ends up in the .axf, and several answers become less faithful.
Setting | Why it matters for this tool |
| keeps functions and locals visible; inlining and code motion at |
| required by |
| optional; preserves call edges for |
| optional; more reliable unwind and stack-frame evidence |
no LTO for the analysis build | LTO merges and drops code, weakening call-graph and stack-depth results |
Keep the normal optimized image for release, size ranking, checksum and real stack behaviour; use the analysis build for source correlation, call graph and stack estimates.
Do not ship the analysis image, and do not compare checksums across different optimization levels.
The tool still works on optimized images, but conclusions are weaker — always report the image hash and its build options (
--build-info) alongside a finding.Flag spelling depends on the compiler (ARMCLANG/AC6 and GCC accept the forms above; older ARMCC uses its own equivalents) — set them in Keil or your build system.
Quick start
python axf_inspector.py --axf firmware.axf --addr2line 0x08001234
python axf_inspector.py --axf firmware.axf --disasm main --mixed
python axf_inspector.py --axf firmware.axf --top --type data --region ram
python axf_inspector.py --axf firmware.axf --unused --min-size 64
python axf_inspector.py --axf firmware.axf --struct demo_ctx --expand
python axf_inspector.py --axf firmware.axf --stackframe app_task
python axf_inspector.py --axf firmware.axf --stackdepth main --jsonExample (--addr2line):
0x08001234: main.c:100
└─ inlined from: ring_buffer.h:25 (ring_buffer_push)
└─ inlined from: uart_irq.c:80 (UART_IRQ_Handler)Command reference
python axf_inspector.py --axf <firmware.axf> <mode> [options]Mode | Purpose |
| address → source file:line (inline chain expanded) |
| alias of |
| disassemble a function; |
| one function's stack frame (CFI first, prologue scan fallback) |
| accumulated stack depth along the deepest call chain from |
| symbol size ranking |
| candidates for unreferenced static objects |
| real struct/union layout from DWARF |
| static call tree (direct calls only) |
| program headers / segment map |
| toolchain, architecture, ABI, FPU, alignment |
| absolute address and section of a symbol |
| SHA256 of selected sections (default |
| optional stack-budget audit against your own allocation manifest |
| machine-readable output for every mode |
| per-indirect-edge uncertainty for |
| model multiplier for |
| extra context budget in bytes (legacy alias |
| version / usage |
Stack-depth estimation (not RTOS-bound)
Stack analysis is a pure instruction-level model and makes no assumption about your execution model:
--stackframe FUNCreads CFI rules with an SP-relative CFA when available, otherwise falls back to decoding the Thumb prologue (PUSH/SUB SP/ADD SP). It reports the modelled frame, its source, and the instruction evidence.--stackdepth ENTRYaccumulates frames along the deepest path from any entry symbol:main, an ISR, an RTOS task function, a business function, or a test stub. The tool does not discover entries, infer allocation units, or apply any minimum-stack/alignment policy.--context-bytesadds an explicit budget for exception frames or registers saved by a runtime; default 0 means not included, and it is never inferred.Open-coded results are model values, not runtime peaks:
alloca, register spilling and stack protectors change real usage. Recursion/re-entry means the true worst case is unknown and must be reported as uncertain.
If you already have an allocation budget (bare metal or RTOS), --audit-tasks compares it against the model using a project-owned manifest:
python axf_inspector.py --axf firmware.axf --audit-tasks my-budget.json --project-root . --jsonTemplate: task-audit-template.json (schema_version=2). The arithmetic and status codes (MISSING_SYMBOL, MODEL_OVER_BUDGET, INCOMPLETE, NEEDS_RUNTIME_CHECK) are documented in SKILL.md.
Using it from an AI agent
Two ways, same engine — the MCP server calls axf_inspector.py directly, so CLI and MCP cannot drift.
MCP (preferred)
mcp_server.py is a zero-dependency stdio server exposing 14 read-only tools: axf_file_info, axf_build_info, axf_symbols_top, axf_unused, axf_segments, axf_symbol_addr, axf_checksum, axf_addr2line, axf_disasm, axf_struct, axf_callgraph, axf_stackframe, axf_stackdepth, axf_audit_tasks. The parsed image is cached by (path, size, mtime), so a multi-step investigation parses DWARF once instead of once per command.
Host | Setup |
Claude Code | project |
Codex |
|
OpenCode |
|
any MCP client | stdio server: run |
No extra packages: the server uses only the standard library plus this analyzer.
Skill + CLI (fallback)
SKILL.md is a portable skill definition (name + when-to-use description + commands + safety rules). Put this directory (or just SKILL.md) wherever your agent looks for skills — Claude Code ~/.claude/skills/fw-analyzer/SKILL.md, a DSH skills directory, or any framework that accepts instruction files — then let the agent run the CLI and read --json. This path needs only shell access; it is the right choice when the host has no MCP support.
Repository layout
axf_inspector.py the analyzer (single file, stdlib + pyelftools)
mcp_server.py zero-dependency MCP stdio server (14 tools, image cache)
.mcp.json Claude Code project-scope MCP registration
SKILL.md portable agent skill definition
README.md / README.zh-CN.md this document (English) / Chinese translation
requirements.txt pyelftools (required), capstone (optional)
task-audit-template.json template for the optional --audit-tasks manifest
test_stack_audit.py unit tests for stack-budget maths and evidence handling
test_mcp_server.py MCP transport/tool tests (builds a fixture when armclang is available)Limits and troubleshooting
Symptom | Cause / fix |
| the image was built without |
|
|
Old ARMCC images fail to parse DWARF | DWARF 2/3 images are partially supported; confirm |
Very large | DWARF-rich images are heavy; prefer |
| direct/static calls only — function pointers, tail calls, inlined calls and dead code are invisible |
Inlined code hides lines or call edges | the image is optimized; analyze a dedicated |
| debug info, linker-script symbols and indirect references can look unused; this is a candidate list |
Non-ASCII paths garble on Windows |
|
Development
python -m unittest discover -s . -p "test_*.py" -v
python axf_inspector.py --versionTests cover stack-budget arithmetic, model boundaries, evidence handling and the MCP transport. ELF-based tests build a fixture with Keil's armclang and are skipped when it is absent.
Design notes
One input, no project files: the tool never reads
.uvprojx, never runs a build and never needs Keil.Evidence over guesswork: every number carries its source (CFI, prologue scan, section flags, relocation table, DWARF DIE), and uncertain models are labelled as such.
Read-only by construction: the
.axf, sources and project files are never modified; there is no network access and no output besides stdout.Decoupled by design: nothing assumes a chip model, compiler, section layout or RTOS. The optional audit manifest accepts any execution model.
License
MIT — see LICENSE. Copyright (c) 2026 wimi996123.
This server cannot be deployed
Maintenance
Related MCP Connectors
Ask a codebase what calls what: search, blast radius, paths between symbols, and diffs.
Hunt zero-days by talking to binaries. 40+ tools. Hosted, OAuth + SSO, invite: hi@byteray.ai
Code intelligence platform for AI agents. 20 tools for architecture, security & impact analysis.
Self-hosted MCP server: 26 deterministic dev, security, and EVM tools.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to locally analyze and reverse engineer binaries through a compact 12-tool MCP interface for triage, function discovery, disassembly/decompilation, cross-references, strings/imports, call graphs, memory reads, annotations, and binary diffs.1MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI coding agents to inspect and reverse-engineer large binaries through bounded stdio JSON-RPC 2.0 tools for graph queries, SSA facts, path solving, runtime grounding, and mod scaffolding.1AGPL 3.0
- AlicenseNot gradedqualityCmaintenanceEnables AI agents (and a matching CLI) to inspect native binaries, JavaScript/Electron apps, .NET assemblies, Go/Rust/WASM artifacts, EVM bytecode, SQLite databases, recorded crashes, and websites without source code, explaining how features work and returning the evidence and limitations behind each conclusion. Analysis runs locally, using optional Hopper, Ghidra, or IDA providers for native targets.500,256 npmMIT
- AlicenseNot gradedqualityCmaintenanceExposes 18 typed tools that drive real static-analysis engines (Ghidra, apktool, WABT, TShark, evmole, Rizin) over a single MCP endpoint to decompile binaries, audit APKs, scan EVM contracts, inspect WebAssembly, firmware, SQLite, and pcap data. Every call returns signed, verifiable evidence with an evidence_id, provider identity, SHA-256 artifact digest, and explicit limitations for security research, malware analysis, forensics, and CTF work.MIT