trace is a static analysis tool for C and C++ codebases. It runs a custom preprocessor, parses translation units with tree-sitter, performs Andersen-style field-sensitive pointer analysis, and exports call graphs and interprocedural argument-flow facts to SQLite.
Typical uses:
- Find direct and indirect call targets (function pointers, vtables, struct op tables).
- Trace argument flow from call-site actuals to callee formals.
- Query results with
trace inspect, ad-hoc SQL, or programmatic C API (trace-capi).
# Build CLI binary
cargo build --release
# binary: target/release/trace
# Or build C API library (staticlib and cdylib)
cargo build -p trace-capi --release
# library: target/release/libtrace_capi.{so,dylib,dll,a}Run the workspace test suite:
cargo test --workspacetrace analyze ./tests/fixtures/direct_call -o /tmp/trace.db
trace inspect /tmp/trace.db calls
trace inspect /tmp/trace.db calls --from main
trace inspect /tmp/trace.db calls --from caller --to helperAnalyze a large tree (parallel indexing, minimal SQLite export):
trace analyze /path/to/project -o /tmp/project.db --jobs 8cargo run -p trace-cli --release --example conditional_coverage -- /path/to/project > coverage.tsvThe reporting example records conditional branches and scans BUILD.gn,
*.gni and *.gn for direct string entries in defines = [...] and defines += [...].
GN_DEFINE TSV rows retain the macro name, whether a value was supplied, the
value, file, entry line, confidence, and enclosing GN conditions. No inferred
define is applied. See GN evidence for ranking and limits;
scripts/gen_conditional_coverage_report.py renders these candidates alongside
the conditional coverage report.
Analyze every C/C++ file (.c, .cpp, .cc, .cxx) under TARGET and write results to SQLite.
trace analyze [OPTIONS] <TARGET>
| Option | Description |
|---|---|
<TARGET> |
Root directory to scan recursively for *.c / *.cpp / *.cc / *.cxx files. |
-o, --output <PATH> |
Output database path. Default: trace.db. |
--include <PATH> |
Add a preprocessor #include search path. Repeatable. |
-D <NAME> |
Define preprocessor macro NAME=1. Repeatable. |
-D <NAME=VALUE> |
Define macro with explicit value. Repeatable. Overrides the language predefines (__cplusplus, __STDC_VERSION__, __STDC__) when the name matches. |
--jobs <N> |
Parallel jobs for indexing (parse + lower). Default: logical CPU count. |
--timeout-secs <N> |
Watchdog: abort the process after N seconds (exit 124). Useful when probing hang-prone trees. |
--full-export |
Export full IR detail: all types, all variables, PAG locations. Slower and produces a larger database. |
--debug-points-to |
Retain points-to sets during analysis and export the points_to debug table (requires PAG in memory). Implies keeping location data needed for export. |
--models <FILE> |
Load a TOML function-model file (interprocedural summaries for bodyless callees, e.g. memcpy_s). Repeatable; later files override earlier entries and built-ins. See docs/ANALYSIS.md. |
--dep <PATH> |
Treat a directory as a dependency root: a tree the target builds against but that is not under analysis (repeatable). Its headers contribute declarations — types, class definitions, inheritance, prototypes, declared return types — while its sources are never translation units. Function bodies and variable initializers are skipped during lowering, so they contribute no call sites or value flow. See the note below. |
--explore |
Enable bounded conditional-variant exploration. Discovers candidate macro definitions from project GN files (BUILD.gn, *.gni), evaluates semantic feasibility of excluded #if/#ifdef/#elif arms, preprocesses and lowers feasible variants independently, and unions their facts into the merged program (preserving body and call facts plus struct fields across configurations; conditional signatures retain the base arity, see limits). Off by default. |
--explore-budget <N> |
Maximum additional configurations per translation unit (default: 4). Budget diagnostics count omitted candidate activation goals, not proven reachable configurations. |
--no-ipc |
Disable IPC proxy→stub bridge edge detection (enabled by default). Bridge edges are synthetic (resolution = 'ipc', call_site_id = NULL) and connect a *Proxy* method to its *Stub* handler across the opaque Binder boundary. See docs/IPC_ROADMAP.md. |
Progress output (stderr):
discover: 618 TUs, 200 headers under /path
include-graph: 818 files, 1200 include edges
warm: 1/90 /path/foo.h
parse: 0 orphan headers, 618 TUs (jobs=8)
index: 24.2s (618 files, 11442 functions, 48406 flow)
analyze: 0.3s (25478 edges, 3468 indirect)
export: 0.1s
analysis complete: 11442 functions, 25478 call edges, 25803 arg-flow edges -> trace.db
Examples
# HDF-style tree with extra include roots
trace analyze ~/drivers_hdf_core -o /tmp/hdf.db \
--include ~/drivers_hdf_core/framework/core/common/include \
-D __LITEOS__ -D CONFIG_XXX=1
# Debug pointer analysis
trace analyze ./my_app -o /tmp/debug.db --debug-points-to --full-export
# Use a compilation database outside the source tree
trace analyze ./my_app --compile-commands ./out/compile_commands.json -o /tmp/app.dbNotes
.cand.cpp-family files are indexed as translation units. Headers are pulled in via#includeduring preprocessing, not analyzed as standalone TUs. A C++ unit is preprocessed with__cplusplus(201703L) and__STDC__predefined, a C unit with__STDC__and__STDC_VERSION__(201710L), so#ifdef __cplusplustakes the C++ arm in.cppunits and the C arm in.cunits, headers included. C++ support is a pragmatic first step — see docs/ANALYSIS.md for scope and imprecision.- Line numbers in the database refer to original files on disk (resolved through the preprocessor's
LineMap); call sites inside macro expansions attribute to the expansion site. - Compilation database — automatically reads
compile_commands.jsonat the target root, thenbuild/compile_commands.json, or an explicit--compile-commands PATH. Each entry supplies its working directory, ordered-I/-iquote/-isystempaths, ordered-D/-U,-include, and-x/-std. MSVCcl/clang-clpreprocessing switches (/I,/D,/U,/FI,/TC,/TP,/Tc,/Tp,/std:) are also supported. All commands for a source contribute facts, even without--explore. CLI--includepaths precede database-Ipaths and CLI-Dvalues override database macros. Files without a usable entry retain inferred configuration; a database is never required. See compilation database support. staticfunctions (internal linkage) and file-scopestaticvariables are resolved within the defining translation unit.staticlocals inside functions are tracked asfn_staticstorage.- Dependency roots (
--dep <PATH>) separate what the target uses from what it is. A dependency's headers are reached and merged for their declarations — smart-pointer wrappers such assptr<T>, base classes, external interfaces — so a wrapper-typed receiver resolves on the wrapped class rather than producing an edge on the wrapper. Its sources are never translation units, its unreached headers are never indexed as standalone units, and a body written in a dependency header merges as a declaration (is_defined = 0) with no call sites, locals, value flow or return flow. Files and functions from a dependency root export withis_dep = 1;trace inspect calls --exclude-depsdrops the edges that touch them. A dependency root nested inside the analysis root is fine; one that contains or equals it is rejected at startup, since every source would become a dependency and nothing would be left to analyze.
| Context | IR / export | Call / flow resolution |
|---|---|---|
File-scope static function |
linkage = internal |
Direct calls and CallReturn via scope-aware name lookup (file + name) |
File-scope static variable |
kind = file_static |
Persistent PAG location; name lookup scoped to its file and the files including it |
Function-local static variable |
kind = fn_static |
Persistent PAG location within enclosing function |
External (non-static) symbols |
linkage = external |
Global fn_by_name / global_by_name tables |
Same identifier in different .c files (each static) gets distinct IR ids; resolution uses the call site's file.
Query an existing analysis database.
trace inspect <DB> calls [--from FN] [--to FN] [--file SUBSTR] [--exclude-deps]
Edges print as `caller (file:line) -> callee [deffile] (resolution)` — the
`[deffile]` bracket distinguishes same-name (e.g. `static`) functions defined
in different files; `--file` filters ordinary edges by call-site or callee
file. A synthetic edge has no call site, so its caller definition file is used
instead.
| Option | Description |
|---|---|
<DB> |
Path to SQLite file produced by trace analyze. |
--from <FN> |
Filter edges where the caller name equals FN or ends with ::FN (C++ qualified methods). _ and % in FN are literal, not LIKE wildcards. |
--to <FN> |
Filter edges where the callee name equals FN or ends with ::FN. Same escaping as --from. |
--file <SUBSTR> |
Filter ordinary edges by call-site or callee file; synthetic edges by caller or callee definition file. |
--callgraph-filter <FILE> |
JSON file listing regex patterns over function names; edges whose caller and callee both fail to match are hidden. |
--exclude-deps |
Hide call edges whose caller or callee comes from a dependency root (is_dep = 1). Requires a v4 database. |
Both filters may be combined. Output format:
CallerFn -> CalleeFn (direct|indirect|ambiguous) at line N
Only call_edges are listed. Unresolved indirect call sites appear in call_sites but produce no line here unless an edge exists.
Examples
trace inspect /tmp/hdf.db calls --from NetIfSetAddr
trace inspect /tmp/hdf.db calls --from HdfSbufReadBuffer
trace inspect /tmp/hdf.db calls --to LiteNetSetIpAddrWhen the full call graph is too large but you only care about a handful of functions (e.g. memory-related ones), pass a filter config and only edges whose caller or callee matches are printed. The database and analysis stay untouched; the filter is purely a display adapter.
{ "functions": ["malloc", "free", "calloc", "realloc", "memcpy", "memset"] }trace inspect /tmp/hdf.db calls --callgraph-filter mem.jsonFor unresolved indirect calls, query SQL directly (see below).
Print the transitive callees or callers of the function containing a line.
trace inspect <DB> callgraph --file SUBSTR --line N [--depth N] [--direction down|up]
| Option | Description |
|---|---|
--file <SUBSTR> |
File path substring to disambiguate same-name functions. |
--line <N> |
A line inside the function of interest. |
--depth <N> |
Maximum BFS depth (default 3). |
--direction |
down = callees (default), up = callers. |
--format |
Output format: text (default), json, graphviz, or mermaid. |
--callgraph-filter <FILE> |
JSON file listing regex patterns over function names; edges whose caller and callee both fail to match are hidden, nodes left without any surviving edge are pruned. The start function (the root) is always kept even when it does not match, so the query anchor stays visible. |
The start function is chosen among definitions whose [line_start, line_end]
contains --line. Edges are labeled with their resolution (direct,
indirect, external, ambiguous) and call-site locations; repeated
callees print (see above; also file:line).
Examples
trace inspect /tmp/hdf.db callgraph --file devsvc_manager.c --line 120 --depth 2
trace inspect /tmp/hdf.db callgraph --file hdf_service_record.c --line 20 --direction up
trace inspect /tmp/hdf.db callgraph --file allocator.c --line 44 --callgraph-filter mem.jsonFind all simple call paths (chains) between two functions no longer than --depth.
trace inspect <DB> callchain [--from FN|FILE:LINE] [--to FN|FILE:LINE] [--depth N] [--limit N]
| Option | Description |
|---|---|
--from <FN> |
Start function name, C++ qualified suffix, or FILE:LINE (e.g. main or main.c:10). |
--to <FN> |
Target function name, C++ qualified suffix, or FILE:LINE (e.g. target or worker.c:25). |
--from-file <SUBSTR>, --from-line <N> |
File and line locating the start function. |
--to-file <SUBSTR>, --to-line <N> |
File and line locating the target function. |
--depth <N> |
Maximum path length in call hops (default 5). |
--direction |
down = callers -> callees (default), up = callees -> callers. |
--limit <N> |
Maximum number of chains to return (default 100, 0 for unlimited). |
--format |
Output format: text (default), json, graphviz, or mermaid. |
--callgraph-filter |
Path to JSON filter config file ({"functions": ["regex", ...]}). |
Examples
trace inspect /tmp/trace.db callchain --from main --to target --depth 3
trace inspect /tmp/trace.db callchain --from main.c:10 --to target.c:20
trace inspect /tmp/trace.db callchain --from caller --to helper --format mermaidWalk the PAG value-flow graph from a variable declaration.
trace inspect <DB> dataflow --file SUBSTR --line N --col C [--depth N] [--direction down|up]
| Option | Description |
|---|---|
--file <SUBSTR> |
File path substring. |
--line <N>, --col <C> |
Position near a variable declaration (use sites are not recorded). |
--depth <N> |
Maximum BFS depth (default 3). |
--direction |
down = where the value flows (default), up = where it came from. |
--format |
Output format: text (default), json, graphviz, or mermaid. |
Edges show how values move: copy, addr_of, load, store, gep,
points_to (variable → storage), and call_arg (argument passing into a
callee formal). Function-pointer values appear as fn:<name> nodes.
The same C parameter may exist as several IR variables (one per TU that sees its declaration). If nothing flows through the queried copy, the traversal automatically widens to same-name parameters of the same function record (after merge all copies share one function entry).
Examples
trace inspect /tmp/hdf.db dataflow --file can_test.c --line 33 --col 31
trace inspect /tmp/hdf.db dataflow --file usb_raw_io.c --line 331 --col 23 --depth 4Both callgraph and dataflow accept --format text|json|graphviz|mermaid
(text is the default). text is the indented view shown above; the other
formats emit machine-readable graphs of the same traversal — same nodes,
same edges, same depth limit and truncation semantics. trace inspect dataflow
prints its candidate/fallback note: hints on stderr in every format.
All examples below run the same query on /tmp/hpp.db
(tests/fixtures/hpp_designated_dispatch):
trace inspect /tmp/hpp.db callgraph --file hpp_designated_dispatch/launch.cpp --line 5 --depth 3--format text (default)
callgraph from launch (launch.cpp:5-5) (callees, depth 3):
* launch (launch.cpp:5)
-indirect-> DispatchToMessage (target.cpp:1) (launch.cpp:5)
2 functions, 1 edges
--format json — a single JSON document with title, direction,
depth, truncated, summary, nodes, and edges:
{
"title": "callgraph from launch (launch.cpp:5-5) (callees, depth 3):",
"direction": "callees",
"depth": 3,
"truncated": false,
"summary": "2 functions, 1 edges",
"nodes": [
{
"id": 0,
"depth": 0,
"label": "launch (launch.cpp:5)",
"detail": "launch.cpp:5"
},
{
"id": 1,
"depth": 1,
"label": "DispatchToMessage (target.cpp:1)",
"detail": "target.cpp:1"
}
],
"edges": [
{
"from": 0,
"to": 1,
"label": "indirect",
"site": "launch.cpp:5"
}
]
}--format graphviz — a DOT digraph renderable with dot:
trace inspect /tmp/hpp.db callgraph --file hpp_designated_dispatch/launch.cpp --line 5 --depth 3 --format graphviz > call.dot
dot -Tsvg call.dot -o call.svgdigraph "callgraph from launch (launch.cpp:5-5) (callees, depth 3):" {
rankdir="TB";
node [shape=box];
n0 [label="launch (launch.cpp:5)"];
n1 [label="DispatchToMessage (target.cpp:1)"];
n0 -> n1 [label="indirect (launch.cpp:5)"];
}--format mermaid — a Mermaid flowchart for GitHub/Markdown or
mmdc:
```mermaid
flowchart TD
%% callgraph from launch (launch.cpp:5-5) (callees, depth 3):
n0["launch (launch.cpp:5)"]
n1["DispatchToMessage (target.cpp:1)"]
n0 -->|"indirect (launch.cpp:5)"| n1
```The same flag applies to dataflow:
trace inspect /tmp/hpp.db dataflow --file hpp_designated_dispatch/launch.cpp --line 5 --col 12 --format mermaid
Every format escapes special characters (quote/backslash for DOT, HTML
entities for Mermaid, JSON via serde_json), so arbitrary C++ names and
file paths stay valid input.
discover .c/.cpp → preprocess → parse → lower IR → build PAG → solve → export SQLite
| Stage | What happens |
|---|---|
| Index | Discover .c / .cpp files, preprocess TUs (custom preprocessor), parse with tree-sitter (C or C++ grammar per TU), lower to IR (functions, variables, flow constraints, call sites). |
| Analyze | Build pointer assignment graph (PAG), run Andersen-style solver, resolve direct calls by name (including file-local static functions), indirect calls via points-to to function locations. |
| Export | Write SQLite (minimal by default). |
Analysis is may-analysis (sound over-approximation): if a call target is possible, it may appear as an edge.
| Mode | Flags | Database contents |
|---|---|---|
| Minimal (default) | (none) | analysis_run, files, functions, filtered call_sites, call_edges, arg_flow_edges, PAG-referenced variables, flow graph (flow_nodes / flow_edges), diagnostics. |
| Full IR | --full-export |
Minimal plus all types, all variables, PAG locations. |
| Points-to debug | --debug-points-to |
Adds points_to table (and retains PAG during analysis). Use with --full-export for complete debug dumps. |
The flow-graph tables are always exported because trace inspect dataflow
queries them directly.
call_sites rows are written when any of the following holds:
- The site has at least one
call_edge. - The site has at least one
arg_flow_edge. - The site is an indirect call (
is_direct = 0), including unresolved function-pointer calls.
So unresolved indirect sites (e.g. sbuf->impl->readBuffer before a fix) still appear in call_sites even with zero call_edges.
Schema version: v3. Foreign keys are declared in DDL; exports temporarily disable FK enforcement for bulk load speed.
analysis_run
files ─┬─ functions ─┬─ call_sites ─ arg_flow_edges → variables
│ └─ call_edges → functions (caller and callee)
└─ variables ─ flow_nodes ─ flow_edges → flow_nodes
(fn_id → functions, type_id → types)
types
locations (full export / debug)
points_to (debug only)
diagnostics
Metadata for one trace analyze invocation.
| Column | Type | Description |
|---|---|---|
id |
INTEGER PK | Run id (always 1 per file). |
trace_version |
TEXT | Full binary identity: package version, source revision, dirty state, and build date. |
schema_version |
INTEGER | Database layout version (currently 4). |
target_root |
TEXT | Absolute or normalized <TARGET> path. |
created_at |
TEXT | Unix timestamp (seconds). |
options_json |
TEXT | JSON: include_paths, defines, dep_roots, include_points_to, full_detail. |
| Column | Type | Description |
|---|---|---|
id |
INTEGER PK | Internal file id. |
path |
TEXT UNIQUE | Source file path. |
sha256 |
TEXT | Content hash (may be empty in current export). |
is_dep |
INTEGER | 1 if file resides under a dependency root (--dep), 0 otherwise. |
| Column | Type | Description |
|---|---|---|
id |
INTEGER PK | Internal function id. |
name |
TEXT | Linkage-visible name (may duplicate across TUs before merge; ids differ). |
file_id |
INTEGER FK → files |
Defining or primary declaration file. |
line_start |
INTEGER | Start line (original file). |
line_end |
INTEGER | End line of the definition body; equals line_start for prototypes/synthesized externals. |
linkage |
TEXT | external, internal, or none. |
signature |
TEXT | Placeholder signature string (fn_<name>). |
is_defined |
INTEGER | 1 if a body exists under the analyzed root; 0 covers prototypes and synthesized externals (libc, macro-referenced logging backends, dependency declarations). |
is_dep |
INTEGER | 1 if function originates from a dependency root (--dep), 0 otherwise. |
Index: functions(name).
One row per collected call (direct name call or indirect/function-pointer syntax).
| Column | Type | Description |
|---|---|---|
id |
INTEGER PK | Call site id (matches IR CallSiteId). |
caller_fn_id |
INTEGER FK → functions |
Containing function. |
file_id |
INTEGER FK → files |
File containing the call. |
line |
INTEGER | Line (original file). |
col |
INTEGER | Column. |
callee_text |
TEXT | Surface syntax, e.g. foo, p->handler, ndImpl->interFace->setIpAddr. |
is_direct |
INTEGER | 1 = direct call by name; 0 = indirect / fn-ptr / unresolved name. |
Resolved caller → callee edges (one row per target; indirect sites may have multiple rows).
| Column | Type | Description |
|---|---|---|
id |
INTEGER PK | Edge id. |
call_site_id |
INTEGER FK → call_sites |
Call site this edge resolves; NULL for synthetic IPC bridge edges. |
caller_fn_id |
INTEGER FK → functions |
Resolved caller function. |
callee_fn_id |
INTEGER FK → functions |
Resolved target function. |
resolution |
TEXT | direct, indirect, ambiguous, external (statically resolved but bodyless under the analyzed root), or ipc (synthetic proxy→stub bridge edge — no source call site, caller is the proxy method). |
Indexes: call_edges(callee_fn_id), call_edges(call_site_id).
Maps actual arguments at a call site to callee formal parameters (when wired by analysis). Each row has either a variable actual or a function-pointer actual.
| Column | Type | Description |
|---|---|---|
id |
INTEGER PK | Edge id. |
call_site_id |
INTEGER FK → call_sites |
Call site. |
arg_index |
INTEGER | Zero-based parameter position the argument binds to. For a C++ member function or constructor, position 0 is the implicit this and the first explicit argument is at 1. |
actual_var_id |
INTEGER FK → variables |
Variable passed at call site (NULL when actual is a function). |
actual_fn_id |
INTEGER FK → functions |
Function passed as fn-ptr actual (NULL when actual is a variable). |
formal_var_id |
INTEGER FK → variables |
Callee parameter variable. |
A function name with several internal-linkage C++ overloads (static or in an anonymous namespace) is passed as each of them: one row per overload at the same call_site_id, arg_index and formal_var_id.
Index: arg_flow_edges(call_site_id).
Present in full export; in minimal export, only variables referenced by the flow graph / arg-flow edges.
| Column | Type | Description |
|---|---|---|
id |
INTEGER PK | Variable id. |
name |
TEXT | Source name or synthetic temp (_gepN, _loadN, …). |
kind |
TEXT | global, file_static, fn_static, param, local. |
fn_id |
INTEGER FK → functions |
Enclosing function (NULL for globals). |
type_id |
INTEGER FK → types |
Type id. |
file_id |
INTEGER FK → files |
Declaration file. |
line |
INTEGER | Declaration line. |
col |
INTEGER | Declaration column (start of the declarator). |
PAG value-flow nodes used by trace inspect dataflow. Always exported.
| Column | Type | Description |
|---|---|---|
id |
INTEGER PK | PAG node id (same id space as points_to.var_node_id). |
kind |
TEXT | var, loc, call_target (indirect-call site node), or terminator (function-model clears event). |
label |
TEXT | Variable name, loc:…, or fn:…. |
detail |
TEXT | Extra context (variable kind, enclosing function, …). |
var_id |
INTEGER FK → variables |
Owning variable (NULL for function locations). |
fn_id |
INTEGER FK → functions |
Enclosing function, when known. |
Index: flow_nodes(var_id).
Directed value-flow edges (value flows src → dst). Always exported.
| Column | Type | Description |
|---|---|---|
id |
INTEGER PK | Edge id. |
src_node |
INTEGER FK → flow_nodes |
Source node. |
dst_node |
INTEGER FK → flow_nodes |
Destination node. |
kind |
TEXT | copy, addr_of, load, store, gep, dlsym, points_to, call_arg, or terminates (function-model clears event). |
Indexes: flow_edges(src_node), flow_edges(dst_node).
Exported only with --full-export.
| Column | Type | Description |
|---|---|---|
id |
INTEGER PK | Type id. |
kind |
TEXT | void, int, struct, ptr, fn_ptr, … |
name |
TEXT | Display name. |
size |
INTEGER | Layout size in bytes. |
layout_json |
TEXT | JSON field layout for structs/unions. |
PAG abstract memory locations. Exported with --full-export.
| Column | Type | Description |
|---|---|---|
id |
INTEGER PK | Location id. |
kind |
TEXT | e.g. global, local, field_summary, function, string_lit. |
desc |
TEXT | Human-readable description. |
type_id |
INTEGER FK → types |
Optional type. |
Maps PAG variable nodes to abstract locations. Exported with --debug-points-to.
| Column | Type | Description |
|---|---|---|
var_node_id |
INTEGER | PAG node id. |
loc_id |
INTEGER FK → locations |
Points-to target. |
Primary key: (var_node_id, loc_id).
Preprocessor, parse, and analysis messages. preprocess rows carry the preprocessor's own
severity and point at the file and line where the condition occurred (a nested header, not the
including translation unit); one row per distinct (file, line, message).
| Column | Type | Description |
|---|---|---|
id |
INTEGER PK | Diagnostic id. |
severity |
TEXT | error, warning, info. |
file_id |
INTEGER FK → files |
Optional file. |
line |
INTEGER | Line number. |
message |
TEXT | Message text. |
stage |
TEXT | preprocess, parse, or analysis. |
SELECT callee.name, ce.resolution, cs.line, cs.callee_text
FROM call_edges ce
LEFT JOIN call_sites cs ON cs.id = ce.call_site_id
JOIN functions caller ON caller.id = ce.caller_fn_id
JOIN functions callee ON callee.id = ce.callee_fn_id
WHERE caller.name = 'HdfSbufReadBuffer';SELECT caller.name, cs.line, cs.callee_text
FROM call_sites cs
JOIN functions caller ON caller.id = cs.caller_fn_id
LEFT JOIN call_edges ce ON ce.call_site_id = cs.id
WHERE cs.is_direct = 0 AND ce.id IS NULL
ORDER BY caller.name, cs.line;SELECT caller.name, callee.name, cs.line
FROM call_edges ce
JOIN call_sites cs ON cs.id = ce.call_site_id
JOIN functions caller ON caller.id = ce.caller_fn_id
JOIN functions callee ON callee.id = ce.callee_fn_id
WHERE ce.resolution = 'indirect'
AND cs.callee_text LIKE '%readBuffer%';SELECT caller.name, ce.resolution, cs.line
FROM call_edges ce
LEFT JOIN call_sites cs ON cs.id = ce.call_site_id
JOIN functions caller ON caller.id = ce.caller_fn_id
JOIN functions callee ON callee.id = ce.callee_fn_id
WHERE callee.name = 'LiteNetSetIpAddr';SELECT cs.line, af.arg_index, av.name AS actual, fv.name AS formal
FROM arg_flow_edges af
JOIN call_sites cs ON cs.id = af.call_site_id
JOIN variables av ON av.id = af.actual_var_id
JOIN variables fv ON fv.id = af.formal_var_id
WHERE af.actual_var_id IS NOT NULL;SELECT cs.line, af.arg_index, f.name AS actual_fn, fv.name AS formal
FROM arg_flow_edges af
JOIN call_sites cs ON cs.id = af.call_site_id
JOIN functions f ON f.id = af.actual_fn_id
JOIN variables fv ON fv.id = af.formal_var_id
WHERE af.actual_fn_id IS NOT NULL;crates/
trace-preproc/ Custom C preprocessor (#include, #define, conditionals)
trace-parse/ tree-sitter parsing, IR lowering, TU merge
trace-ir/ Shared IR (types, symbols, flow constraints)
trace-analysis/ PAG construction, Andersen solver, call graph
trace-db/ SQLite schema and export
trace-cli/ `trace` binary (`analyze`, `inspect`)
docs/ Design docs (architecture, analysis, preprocessor, schema)
tests/fixtures/ Integration test C corpora
- C++ first step — namespaces, overloads (arity), classes/virtual dispatch (including virtual bases),
finalclass/method devirtualization, ctors/dtors, implicitthis->method(), smart-pointer unwrap through a declaredoperator->(shared_ptr, and OHOSsptr/RefPtror HDIAutoPtralike, the wrapper keeping its own members for.) or, for a wrapper whose body is not in the tree, through its single class argument, and callables (std::function, lambdas,operator()) are modeled; type-based overload ranking and templates beyond name-stripping are not (see docs/ANALYSIS.md). Next slices from hiview: docs/CPP_ROADMAP.md. - May-analysis — indirect calls can list multiple targets; absence of an edge does not prove unreachability.
- No path sensitivity — all branches and paths are merged.
- Preprocessor subset — not gcc/clang compatible for all extensions, and no compiler is impersonated (
__GNUC__/__clang__stay undefined; only the language's own__cplusplus/__STDC__/__STDC_VERSION__are predefined); see docs/PREPROCESSOR.md. - Build environment — compilation databases locate existing files; they do not supply missing SDK, standard-library or generated headers. Supply additional roots with
--dep/--includeas needed. Compiler-specific target builtins and response files are not modeled. - Configuration coverage — without database entries or
--explore, indexing uses one inferred configuration. A name no-Dor reached#definebinds resolves to0in#if; the default exclusions are measured in docs/CONDITIONAL_COVERAGE.md. Explicit database commands are all merged; exploratory configurations remain bounded by--explore-budget. - Original line attribution — entities attribute to original source files on disk via the preprocessor's
LineMap(call sites inside macro expansions attribute to the expansion site's origin; headers are deduplicated across translation units).
- Architecture
- Analysis algorithm
- Preprocessor spec
- C API (
trace-capi) - Conditional-compilation coverage (eval corpora)
- SQLite schema (detailed)
- Roadmap
- C++ next slices (hiview)
- Contributing
- Code of Conduct
- Agent guide
- License
See CONTRIBUTING.md for development setup, testing, and pull-request guidelines, and CODE_OF_CONDUCT.md for our community standards.
This project is licensed under the MIT License.
