Skip to content

0xeb/clangsql

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

clangsql

SQL interface for Clang AST databases. Query C/C++ source code using SQL.

Part of the xsql project family.

Features

  • Parse C/C++ source files with libclang
  • Query AST entities via SQL: functions, classes, methods, variables, enums
  • Multi-translation-unit support with schema prefixes
  • AST caching for fast repeated queries
  • HTTP and MCP server modes for remote analysis
  • Cross-platform: Windows, macOS, Linux
  • Consistent xsql API patterns

Quick Start

# Parse a file and list functions
clangsql main.cpp -e "SELECT name FROM functions"

# With compiler flags
clangsql main.cpp -- -std=c++17 -I./include

# Interactive mode
clangsql main.cpp -i

# Multi-file with schema prefixes (each file gets prefixed tables)
clangsql lib/utils.cpp:utils src/main.cpp:main -i

# Glob patterns for multiple files
clangsql "src/**/*.cpp" -- -std=c++17 -I./include

# CMake project (uses compile_commands.json)
clangsql --compile-commands build/compile_commands.json -i
clangsql --build-dir build -i  # Auto-find compile_commands.json

CLI Reference

clangsql <files...> [options] [clang-args...]

Modes

Mode Command Description
Query clangsql file.cpp -e "SQL" Execute query, exit
REPL clangsql file.cpp -i Interactive mode
HTTP clangsql file.cpp --http [port] Host SQL over HTTP
MCP clangsql file.cpp --mcp [port] Host SQL over MCP (SSE)

Options

Local Options:
  -e <sql>           Execute SQL query and exit
  -i                 Interactive mode (REPL)
  --http [port]      Start HTTP REST server (default: 8080)
  --mcp [port]       Start MCP server over SSE (default: random 9000-9999)
  --bind <addr>      Bind address for server (default: 127.0.0.1)
  --token <token>    Auth token for HTTP server mode
  -h, --help         Show help
  --version          Show version

Project Options:
  --compile-commands <path>  Load compile_commands.json
  --build-dir <path>         Load from build directory
  --project <dir>            Parse entire directory (unified schema)
  --pattern <glob>           File patterns for --project
  --exclude <dir>            Directories to exclude
  'src/**/*.cpp'             Glob pattern for source files

Cache Options:
  --cache            Enable AST caching (faster re-parses)
  --no-cache         Disable AST caching (default)
  --cache-dir <path> Set cache directory
  --clear-cache      Clear all cached AST files
  --cache-verbose    Show cache hit/miss messages

Building

Prerequisites

  • CMake 3.20+
  • C++17 compiler
  • libclang (via vcpkg or system)

Build with vcpkg (recommended)

vcpkg install llvm[clang] nlohmann-json
cmake -B build -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
cmake --build build

Build from a parent project

cmake -S <parent-project-root> -B build
cmake --build build --target clangsql

Standalone build

git submodule update --init external/libxsql
cmake -B build
cmake --build build

AST Caching

Enable caching to avoid re-parsing unchanged files. Recommended for project mode where you'll run multiple queries against the same codebase.

# Enable caching for single file
clangsql main.cpp --cache -e "SELECT name FROM functions"

# Enable caching for project mode (big speedup on re-runs!)
clangsql --project ./src --cache -i

# Show cache hit/miss messages
clangsql --project ./src --cache --cache-verbose -i

# Custom cache directory
clangsql --project ./src --cache-dir /path/to/cache -i

# Clear all cached files
clangsql --clear-cache

Cache location: %LOCALAPPDATA%\clangsql\cache (Windows) or ~/.cache/clangsql (Linux/macOS)

What's validated: Cache is invalidated when source files, any included headers, compiler args, or Clang version change. Each file's mtime is checked, so only modified files are re-parsed.

Analyzing a CMake Project

Any CMake project can generate a compile_commands.json — a database of exact compiler flags for every source file. clangsql uses this to parse your code with the correct includes, defines, and standards, just like your compiler sees it.

Step 1: Generate compile_commands.json

Add -DCMAKE_EXPORT_COMPILE_COMMANDS=ON when configuring your project. This requires a single-config generator like Ninja or Unix Makefiles (Visual Studio generators don't produce it):

# Using clangsql's own source as the example project:
cd clangsql
cmake -B build -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON

This creates build/compile_commands.json — a JSON array with one entry per source file containing the exact compiler command, flags, and include paths.

Step 2: Query with clangsql

# Point clangsql at the compile_commands.json
clangsql --compile-commands build/compile_commands.json -i

# Or just point at the build directory (auto-finds compile_commands.json)
clangsql --build-dir build -i

Each source file from the database is attached as a schema-prefixed set of tables (e.g., main_functions, tables_functions). You can query individual files or join across them.

Step 3: Query your code

-- List all parsed source files
SELECT name FROM pragma_database_list WHERE name != 'main';

-- Functions defined in a specific file
SELECT name, return_type, line FROM tables_functions WHERE is_system = 0;

-- All user-defined classes across the project
SELECT name, kind FROM main_classes WHERE is_system = 0
UNION ALL
SELECT name, kind FROM tables_classes WHERE is_system = 0;

Project mode (unified schema)

For a single merged view without schema prefixes, use --project with --build-dir to combine directory scanning with compile_commands.json flags:

# Unified schema — all files merged into one set of tables
clangsql --project src --build-dir build --cache -i
-- Now tables have no prefix — one unified view
SELECT name, return_type FROM functions WHERE is_system = 0;

-- Functions with their source files
SELECT f.name, fi.path
FROM functions f JOIN files fi ON f.file_id = fi.id
WHERE f.is_system = 0
ORDER BY fi.path, f.line;

Tips

  • Use --cache for repeated queries — first parse writes the cache, subsequent runs skip unchanged files.
  • Use --exclude to skip directories like build, third_party, or external in project mode.
  • Filter with is_system = 0 — without it, you'll get thousands of symbols from system headers.
  • Ninja is recommended over Makefiles for faster builds and better compile_commands.json support on all platforms.

Using clangsql with an AI agent

clangsql is a plain SQL CLI — it does not embed or run its own AI agent. To let an external agent or LLM (Claude, Copilot, or any assistant) drive clangsql, point it at the tool two ways:

  • As a system prompt: feed prompts/clangsql_agent.md to your model as its system/instruction prompt. It documents the full SQL schema, every table and column, and worked query patterns, so the model can translate natural-language questions into clangsql SQL and run them via -e / --http / --mcp.
  • Over MCP: start clangsql file.cpp --mcp and connect any MCP client (see the MCP Server section). The client's own model does the reasoning; clangsql exposes the clangsql_query tool that executes SQL against the parsed AST.

HTTP Server Mode

Host a parsed AST over HTTP for remote querying:

# Start server (default port 8080)
clangsql main.cpp --http

# Query from another terminal
curl -X POST http://localhost:8080/query -d "SELECT name FROM functions"

HTTP REST API

Start an HTTP server for REST-based querying:

# Start HTTP server at launch
clangsql main.cpp --http 8080

Endpoints

Endpoint Method Description
/ GET Welcome message
/help GET API documentation
/status GET Health check
/query POST Execute SQL (body = raw SQL)
/shutdown POST Graceful shutdown

Response Format

All /query responses use the canonical script envelope — single statement = array of one entry:

{
  "success": true,
  "statement_count": <N>,
  "results": [
    { "statement_index": 0, "success": true, "columns": [...], "rows": [...],
      "row_count": <N>, "elapsed_ms": <ms>, "error": null }
  ],
  "row_count_total": <N>,
  "elapsed_ms_total": <ms>,
  "first_error_index": null
}

Bodies can be multi-statement (semicolon-separated); each results[i] has its own columns/rows/row_count/error. Fail-fast is the default; pass ?continue_on_error=1 to run every statement regardless of earlier failures.

MCP Server

Start an MCP (Model Context Protocol) server for integration with Claude Desktop and other MCP clients:

# Start MCP server (random port 9000-9999, or pass an explicit port)
clangsql main.cpp --mcp
clangsql main.cpp --mcp 9123

MCP Tools

Tool Description
clangsql_query Execute a SQL query directly against the parsed AST

Claude Desktop Integration

Add to your Claude Desktop config (the port is printed when the server starts):

{
  "mcpServers": {
    "clangsql": {
      "url": "http://127.0.0.1:<port>/sse"
    }
  }
}

Example Queries

Call Graph Analysis

-- Who calls what (use USR for cross-table joins)
SELECT f.name as caller, c.callee_name as calls
FROM calls c
JOIN functions f ON c.caller_usr = f.usr
WHERE c.is_system = 0;
caller | calls
-------+-------------
main   | Circle
main   | process_data
main   | add

Class Hierarchy

-- Find inheritance tree from base class
WITH RECURSIVE hierarchy AS (
    SELECT usr, name, 0 as depth
    FROM classes WHERE name = 'Shape'
    UNION ALL
    SELECT c.usr, c.name, h.depth + 1
    FROM hierarchy h
    JOIN inheritance i ON i.base_usr = h.usr
    JOIN classes c ON c.usr = i.derived_usr
)
SELECT name, depth FROM hierarchy ORDER BY depth;
name   | depth
-------+------
Shape  | 0
Circle | 1

Virtual Methods

-- Find all virtual and pure virtual methods
SELECT qualified_name, access,
    CASE WHEN is_pure_virtual THEN 'pure'
         WHEN is_virtual THEN 'virtual'
    END as virt
FROM methods
WHERE is_virtual = 1 AND is_system = 0;
qualified_name | access | virt
---------------+--------+--------
Shape::~Shape  | public | virtual
Shape::area    | public | pure
Shape::draw    | public | virtual
Circle::area   | public | virtual
Circle::draw   | public | virtual

Code Metrics

-- Largest functions by line count
SELECT name, end_line - line + 1 as lines
FROM functions
WHERE is_definition = 1 AND is_system = 0
ORDER BY lines DESC;
name         | lines
-------------+------
main         | 9
process_data | 6
add          | 3

Multi-File Analysis

clangsql supports parsing entire projects with multiple translation units. Each file gets a schema prefix, making tables like utils_functions, main_classes, etc.

Cross-file queries work via USR (Unified Symbol Resolution) - a unique identifier consistent across translation units.

# Schema prefix syntax: file.cpp:schema_name
clangsql lib/utils.cpp:utils src/main.cpp:main -i

# Glob patterns (recursive)
clangsql "src/**/*.cpp" -- -std=c++17

# CMake projects with compile_commands.json
cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
clangsql --compile-commands build/compile_commands.json -i
-- Find utils functions that are called from main
SELECT DISTINCT u.name as function_called
FROM utils_functions u
JOIN main_calls c ON c.callee_usr = u.usr
WHERE u.is_system = 0;
function_called
---------------
log_info
compute_area
-- Aggregate function counts across all schemas
SELECT COUNT(*) as total_functions FROM (
    SELECT name FROM utils_functions WHERE is_system = 0
    UNION ALL
    SELECT name FROM main_functions WHERE is_system = 0
);
-- Cross-file inheritance (class in main inherits from utils)
SELECT m.derived_name, u.name as base_class
FROM main_inheritance m
JOIN utils_classes u ON m.base_usr = u.usr;

Class Layout

-- Field offsets in bits
SELECT name, type, access, offset_bits
FROM fields WHERE is_system = 0;
name    | type   | access    | offset_bits
--------+--------+-----------+------------
x       | double | public    | 0
y       | double | public    | 64
name_   | string | protected | 64
radius_ | double | private   | 320

Tables

Core Entities

  • files - Source files (path, is_main_file, is_header, is_system)
  • functions - Functions with USR, name, return_type, line positions
  • parameters - Function parameters (name, type, index_, has_default)
  • classes - Classes, structs, unions (kind, is_abstract)
  • fields - Class data members (type, access, offset_bits)
  • methods - Class methods (access, is_virtual, is_pure_virtual, is_const)
  • variables - Variables (scope_kind: global/local, storage_class)
  • enums - Enums (underlying_type, is_scoped for enum class)
  • enum_values - Enum constants (name, value)

Relationships

  • calls - Call graph (caller_usr, callee_usr, callee_name, is_virtual)
  • inheritance - Class hierarchy (derived_usr, base_usr, access, is_virtual)

All tables have is_system column (1=system header, 0=user code). Always filter with WHERE is_system = 0 for user code only.

Programmatic Usage

#include <clangsql/clangsql.hpp>

// Parse a file
clangsql::Index index;
clangsql::TranslationUnit tu(index.get(), "main.cpp", {"-std=c++17"});

// Query with SQL
clangsql::Session session;
session.attach("main.cpp", "main");
auto result = session.database().exec("SELECT name FROM main.functions");

CMake Integration

find_package(clangsql CONFIG REQUIRED)
target_link_libraries(myapp PRIVATE clangsql::clangsql)

License and Terms of Use

In short: you may read, build, evaluate, benchmark, package, and use unmodified clangsql, including commercially, if you preserve notices and follow the license terms. You may fork or patch it to prepare bug fixes, optimizations, features, tests, or documentation improvements for contribution back within the license's contribution-purpose rules.

You may not maintain a divergent private fork, port, rebrand, clone, API-compatible replacement, competing implementation, or use clangsql as AI input to recreate or improve a derivative implementation without prior written permission from Elias Bachaalany. Independent implementations that are not copied from, materially derived from, or substantially informed by clangsql in the license's defined sense are not prohibited.

Permission requests: open a GitHub issue at 0xeb/clangsql/issues.

If clangsql materially informs a distributed project, preserve the human origin: credit clangsql and Elias Bachaalany visibly in your README/docs and in About/credits UI when applicable. The license includes an examples/FAQ section for common allowed and permission-required uses. Third-party dependencies fetched at build time (libxsql, libclang/LLVM, and their transitive dependencies) remain under their own licenses.

See the full Human-Origin Source License v1.0.

The xsql family

clangsql is part of a family of tools that expose different binary-analysis and debug-information platforms through the same SQL surface, all built on the shared libxsql virtual-table framework. A query you learn against one tool largely carries over to the others.

Reverse-engineering platforms

  • idasql — IDA Pro databases as SQL.
  • bnsql — Binary Ninja databases as SQL.
  • ghidrasql — Ghidra databases as SQL.

Debug info & compiler data

  • pdbsql — Windows PDB symbol files as SQL.
  • dwarfsql — DWARF debug information as SQL.

Core

  • libxsql — the C++ SQLite virtual-table framework every tool above is built on.

About

SQL interface for Clang AST databases

Resources

License

Stars

3 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors