Skip to main content
Glama

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, or xTimerStart reach 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_construct edges hang off a synthetic <global ctors> node between main and every global constructor. Any query that can reach main uses it, not only a query that starts at main.

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

TableJSON Schema
NameRequiredDescriptionDefault
imageNoSysbuild image within the variant. Required when the variant holds several: each image is a separate program.
projectNoProject 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_nameYesTarget symbol to find path to.
variantNoBuild variant (multi-build project). Omit to use default_variant. One query answers for ONE build.
from_nameYesStarting symbol for path search.
max_depthNoMaximum BFS depth for path search (default 10).
project_rootNoProject 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

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed5 schema fields changedv0.32.0
    • addedInput schema / properties / from_name / minLength
      Added value: +1
    • changedInput schema / properties / image / description
      Previous value: -"Sysbuild image name within the variant (multi-project). Omit for all images of the variant."New value: +"Sysbuild image within the variant. Required when the variant holds several: each image is a separate program."
    • addedInput schema / properties / max_depth / minimum
      Added value: +1
    • addedInput schema / properties / to_name / minLength
      Added value: +1
    • changedInput schema / properties / variant / description
      Previous value: -"Build variant name (multi-project). Omit to use default_variant or fail-closed. Use '*' for all variants."New value: +"Build variant (multi-build project). Omit to use default_variant. One query answers for ONE build."
  2. Changed3 schema fields changedv0.30.0
    • addedInput schema / additionalProperties
      Added value: +false
    • addedInput schema / properties / project
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "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.",
      +  "title": "Project"
      +}
    • changedInput schema / properties / project_root / description
      Previous value: -"Project root. Auto-detected if omitted."New value: +"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."
  3. Changed2 schema fields changedv0.25.3
    • addedInput schema / properties / image
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Sysbuild image name within the variant (multi-project). Omit for all images of the variant.",
      +  "title": "Image"
      +}
    • addedInput schema / properties / variant
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Build variant name (multi-project). Omit to use default_variant or fail-closed. Use '*' for all variants.",
      +  "title": "Variant"
      +}
  4. First observedv0.1.0

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses read-only status, no side effects, and prerequisites (symbols in index, refs enabled). It details limitations (dispatch bridge skipping, ambiguous fallback name conservatism, global constructor synthetic node) and explains the node-budget behavior of max_depth. This is far beyond typical descriptions and leaves no critical behavioral ambiguity.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is lengthy but logically structured with headers (Edge types, Limitations, empty-result guidance, alternatives, args). Every section adds necessary detail for a complex tool. It is front-loaded with the core purpose and returns structure, and while a bit long, it is not bloated; each sentence earns its place. Slightly trimmed could earn a 5, but this is still strong.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description fully covers the return format (at most 5 paths, each with depth, chain, target_usr; warning and info dicts; never empty) and edge cases (overloaded symbols, ambiguous names). It also includes troubleshooting guidance, prerequisites, and limitations. For a tool with 7 parameters and no annotations, this is remarkably complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Even though schema coverage is 100%, the description adds substantial meaning: max_depth's lack of clamping and its interaction with the 5000-expansion node budget, project vs. project_root as mutual alternatives, image required when variant holds multiple images, and the note that one query answers for one build. These nuances are not in the schema and materially improve invocation correctness.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a precise verb+resource statement: 'Find call paths between two C/C++ functions via BFS in the libclang call graph.' It names the specific edge types (function pointers, ISRs, implicit constructors, dispatch) and contrasts with siblings like find_all_callers_recursive and find_callees_recursive, making the tool's unique scope unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states the intended use case ('how does A reach B?') and gives a concrete example. It also names alternatives for one-sided exploration (find_all_callers_recursive, find_callees_recursive) and exact verification (find_callers, find_references), and includes troubleshooting steps for empty results. This is exemplary when-to-use vs. when-not-to guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.