find_call_path
Trace how one C/C++ function reaches another, returning up to 5 shortest call paths including indirect edges via function pointers, ISRs, constructors, and event-loop dispatch.
Instructions
Find call paths between two C/C++ functions via BFS in the libclang call graph, including function-pointer edges, ISR vector registrations, implicit constructors, and synthetic dispatch edges (event loops, thread starts). libclang-powered: follows function-pointer edges and ISR vector registrations that text-based search cannot resolve.
Use to answer "how does A reach B?" — e.g. tracing how a high-level
event handler eventually calls a low-level driver. Returns up to 5
shortest paths, each with depth (edge count) and chain
(e.g. "main → app_run → modem_init").
Edge types traversed: The BFS includes call, indirect
(function pointers / ISRs), implicit_construct (global/static
object constructors), and dispatch (synthetic edges through event
loops like EventQueue::dispatch_forever and thread starts like
Thread::start).
Limitations:
Dispatch bridges: callbacks registered through
EventQueue::call_every,k_work_submit, orxTimerStartreach their dispatch entry point (dispatch_forever,z_work_q_main) through a built-in map for mbed-os, Zephyr, and FreeRTOS. Add other RTOS patterns in[call_graph.dispatch_bridges](.fw-context/config.toml); a bridge whose entry symbol is not in the index is skipped silently.Ambiguous fallback names: for a call that libclang cannot resolve (template-obscured
_timeout.attach(...)), a source-line regex matches the method name. When several methods share that unqualified name and neither the receiver field type nor the caller class disambiguates, fw-context creates NO edge — conservative, to avoid false paths.Global constructors: file-scope
implicit_constructedges hang off a synthetic<global ctors>node betweenmainand every global constructor. Any query that can reachmainuses it, not only a query that starts atmain.
On an empty result that you expected to hold a path: look for async
dispatch (search_bodies("call_every"), search_bodies("attach")),
trace the intermediate symbols with find_callers, raise
max_depth, and check the function-pointer wiring with
find_indirect_call_sites / find_indirect_targets.
For one-sided exploration use find_all_callers_recursive (who reaches
this?) or find_callees_recursive (what does this reach?).
For exact call-graph verification use find_callers or
find_references.
Read-only. No side effects. Requires both symbols to be in the index
and refs enabled (fw-context index — refs on by default).
Args: from_name: Starting symbol for path search. to_name: Target symbol to find path to. project_root: Project root. Auto-detected if omitted. project: Project name or project_id — call list_projects to get them. Use it to ask about a project that is not the project of the current directory. It is an alternative to project_root, which takes a root path. Give one of the two, not both. max_depth: Maximum BFS depth for path search (default 10). No clamp holds this number. What bounds a deep search is the node budget of the walk — 5000 expansions — thus a large depth gives up on that budget and not on the depth. variant: Build variant (multi-build project). Omit to use default_variant. One query answers for ONE build. image: Sysbuild image within the variant. Required when the variant holds several: each image is a separate program.
Returns:
At most 5 paths, each a dict with: depth (edge count, int), chain (str —
e.g. "main → app_run → modem_init"), target_usr (str — the USR
of the symbol the path ends at, which tells two overloads apart).
When no path exists within the depth limit, the list holds one
info dict.
When *to_name* matches more than one symbol, the search reaches
all of them. A ``warning`` dict then comes first and names the
symbols, and each path carries ``target_qualified_name`` next to
``target_usr``. Give the full qualified name to ask about one
symbol only.
Never empty: one dict with ``error`` (cannot resolve) or ``info``
(no results) replaces the results. Check both keys first.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| image | No | Sysbuild image within the variant. Required when the variant holds several: each image is a separate program. | |
| project | No | Project name or project_id — call list_projects to get them. Use it to ask about a project that is not the project of the current directory. It is an alternative to project_root, which takes a root path. Give one of the two, not both. | |
| to_name | Yes | Target symbol to find path to. | |
| variant | No | Build variant (multi-build project). Omit to use default_variant. One query answers for ONE build. | |
| from_name | Yes | Starting symbol for path search. | |
| max_depth | No | Maximum BFS depth for path search (default 10). | |
| project_root | No | Project root. Auto-detected if omitted. This field also accepts a project name or a project_id, but project is the clear field for those. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |