bb
May 15, 2026 · View on GitHub
bb
Benowin Blanc — Windows through a detective's lens.
(Name credits go to my beloved spouse. ꨄ︎)
A set of command-line tools that parse Windows SDK and PHNT headers via libclang
and let you inspect what's actually in them: struct layouts, field offsets,
enum values, constants, #define macros, and function declarations with full ABI breakdowns — the works.
Think of it as dt + x from WinDbg, but you don't need a debugger running,
and it works against any SDK version, architecture, or PHNT release you throw at it.
Try bb viewer in your browser
bb-viewer — a vanilla TypeScript SPA built with Bun, powered by bb's JSON exports.
Browse 8,000+ functions, 5,000+ types, and 25,000+ constants from the Windows SDK and PHNT headers across all architectures (amd64, x86, arm64, arm) — with ABI layouts, memory visualizations, C expressions, and an interactive type graph. No install required.
![]() |
![]() |
| Dashboard — stats, charts, top types | CreateFileW — ABI layout, metadata, known values |
bb-typesStruct and class layouts, right in your terminal
|
bb-constsConstants, enums, and macro definitions
|
bb-types-tuiInteractive struct browser
|
bb-consts-tuiInteractive constant browser
|
What is this?
Windows ships with thousands of C/C++ headers (the Windows SDK) that define every struct, enum, constant, macro, and function the OS exposes. Separately, the community-maintained PHNT (Process Hacker NT headers) documents internal structures and syscalls that Microsoft doesn't publish.
bb parses these headers with libclang and gives you fast, searchable, pretty-printed access to all of it — struct layouts, constant values, function ABIs with per-parameter register/stack locations, and more (hell, even TUIs!) — no debugger, no IDE, no digging through .h files by hand.
|
You might want this if you...
|
Quick start
Building
On a Windows host, you will need the following:
- Visual Studio 2019/2022 Build Tools
- LLVM + Clang (libclang.dll) version >=18.1
- Rust 2024 edition
- uv (Python package + project manager —
winget install --id=astral-sh.uv -e). Plain Python >=3.10 also works as a fallback.
Afterwards, you may produce the binaries by invoking the following command:
.\update-submodules.ps1 # init + generate submodule data
cargo build --release
The project uses two submodules, managed by update-submodules.ps1:
| Submodule | Purpose | Required for | Setup |
|---|---|---|---|
| phnt | PHNT NT header generation (phnt-single-header) | --phnt flag | .\update-submodules.ps1 phnt |
| sparse | MSDN API metadata (sparse) — embeds both the SDK and driver datasets | Enriched function views | .\update-submodules.ps1 sparse |
You can update them individually or all at once (.\update-submodules.ps1). Both support env var overrides for custom data:
| Env var | What it does |
|---|---|
BB_PHNT_HEADER | Use a custom phnt.h instead of generating from the submodule |
BB_SPARSE_SDK_JSON | Use a pre-generated sdk-api.json instead of running sparse in SDK mode (alias: BB_SPARSE_JSON) |
BB_SPARSE_DRIVER_JSON | Use a pre-generated driver-docs.json instead of running sparse in driver mode |
BB_NO_CACHE | Bypass the on-disk AST cache (parse from headers every time) |
AST cache
After the first bb-funcs / bb-types / bb-consts invocation, the parsed
translation unit is saved (via clang_saveTranslationUnit) under
%LOCALAPPDATA%\bb\ast\<sha256>.ast. Subsequent runs with the same SDK
- arch + mode load the AST directly and skip libclang's full re-parse. Typical numbers on this SDK / WDK combo:
| invocation | cold | warm |
|---|---|---|
--mode user --name CreateFileW | 10.3s | 5.5s |
--mode user --name __nonexistent | 4.8s | 3.8s |
--mode kernel --name __nonexistent | 2.4s | 1.3s |
The cache key hashes the synthetic header content, every clang
argument, and the bb-sdk crate version — any change to header config,
SDK install path, target arch, or a bb-sdk release invalidates
automatically. Saved ASTs are ~80 MB; delete the bb/ast/ directory
to nuke them, or set BB_NO_CACHE=1 to bypass per-invocation.
First commands
Inspect a struct layout:
bb-types --struct _PEB
Recurse into nested types:
bb-types --phnt --struct _PEB --depth 2
Search for constants by wildcard:
bb-consts --name GENERIC_*
Scope to a specific enum:
bb-consts --enum _MINIDUMP_TYPE
Use Enum::Constant syntax to search within enums:
bb-consts --name "_MINIDUMP_TYPE::*"
Target a different architecture from your host:
bb-types --arch arm64 --struct _CONTEXT
Inspect a function's ABI breakdown:
bb-funcs --name CreateFileW
List exported functions from a header:
bb-funcs --name "Create*" --filter fileapi.h --exported
Filter functions with SQL WHERE clauses:
bb-funcs --where "params > 3 AND return_type = 'BOOL'"
bb-funcs --where "name LIKE '%File%' AND is_exported = true"
Filter kernel/driver functions by IRQL constraint:
bb-funcs --mode kernel --name "Wdf*" --irql "<= DISPATCH_LEVEL"
bb-funcs --mode kernel --irql PASSIVE_LEVEL
Export as JSON or SQLite for your own tooling:
bb-types --arch arm64 --struct _CONTEXT --json
bb-consts --name "PROCESS_*" --json
bb-funcs --name "Nt*" --phnt --json
# or export to SQLite
bb-funcs --name "Create*" --sqlite funcs.db
bb-types --struct "_*" --sqlite types.db
JSON mode in bb-types performs full nested type expansion, producing all matched types alongside their deduplicated referenced_types — regardless of the --depth flag. SQLite exports mirror the same level of detail as JSON.
Typo? Both CLIs suggest close matches:
bb-types --struct _PBE
error: no structs matching '_PBE'
did you mean?
_ABC
_PSP
_PEB
The tools
CLI applications
|
TUI applications
|
Libraries
|
Web viewer
| What it does | |
|---|---|
| bb-viewer | Web explorer for bb's JSON output — functions, types, constants, type graph |
Supported headers
Windows SDKUses whatever version is available in your Developer Command Prompt environment. User mode — Win32 + COM IDL surface (click to expand)Winsock 2, networking (winhttp, wininet, iphlpapi, dhcpsapi, dns, ldap, snmp, ws2spi, http server, p2p alt, mprapi, rtmv2), security (acl, sddl, wincrypt, bcrypt, ncrypt, authz, wintrust, certenroll, cryptxml, slpublic, msdrm, winbio), shell/UI (shobjidl, shobjidl_core, commctrl, commdlg, uxtheme, dwmapi, magnification, prsht, interactioncontext, winwlx, highlevelmonitorconfigurationapi), GDI helpers (icm, fci), Media Foundation (mfapi, mfidl, mfreadwrite, mfmediaengine), Core Audio (mmdeviceapi, audioclient, audiopolicy), DirectShow (strmif, vfw), Direct3D 11/12 + DXGI 1.6 + d3dcompiler, UI Automation, Bluetooth, XInput, ETW + TraceLogging + TDH, BITS, Windows Update, MSI (msi, msiquery), Task Scheduler, DBGENG (debugger engine), AD (iads, adshlp, dsgetdc), PDH, WIA, WMP, COM+ (azroles, comsvcs, xpsobjectmodel, msinkaut, tom), virtdisk, fltuser (filter manager user side), peerdist, EAP (eapmethodpeerapis), WinUSB, projfs, WER, WMI consumers (wbemcli), Image helpers (traceloggingprovider, perflib), LM DFS, pathcch, traffic, sphelper (excluded — see notes), strsafe, intsafe, ntmsapi, mscat, drt, npapi, wdspxe / wdstpdi / wdsclientapi, roerrorapi, wtsapi32, lmaccess, setupapi, cfgmgr32, wlanapi + ras + rasdlg, powrprof, gpedit, oleauto, appmodel, hbaapi, propvarutil, propsys, traffic, mstcpip, windns, wincred, userenv, ktmw32, sapi, cfapi, diagnosticdataquery, clfsw32, usp10, winevt, Kernel mode — NT / WDF / NDIS / streaming (click to expand)Built on the Excluded (with rationale)Each is documented inline in
All four mode combinations ( |
PHNTThe Process Hacker NT headers, embedded at compile time. Exposes internal NT structures and constants that the public SDK doesn't ship. Supports version targeting from Win2000 through Win11 22H2:
PHNT mode auto-inherits the full Windows SDK umbrella — |
Header coverage
Measured against the documented MSDN free-function surface that bb-sparse embeds (sdk-api for user mode, windows-driver-docs-ddi for kernel) — see cargo test -p bb-tests sparse_coverage_dump -- --ignored --nocapture to run it yourself. Interface methods aren't counted because bb-funcs filters on EntityKind::FunctionDecl, and IDL vtables surface those as function-pointer fields inside IFoo::Vtbl structs.
| mode | funcs | types | consts | enums | free-func coverage |
|---|---|---|---|---|---|
| user | 15,701 | 15,808 | 44,966 | 2,926 | 75.2% |
| kernel | 4,884 | 3,298 | 19,893 | 735 | 62.4% |
| phnt user | 17,424 | 17,338 | 48,073 | 3,167 | — |
| phnt kern | 4,885 | 3,721 | 20,472 | 776 | — |
Architecture support
All tools support cross-compilation via --arch — inspect layouts and ABIs for any target from any host:
| Flag | Target | Notes |
|---|---|---|
amd64 | x86_64-pc-windows-msvc | Default |
x86 | i686-pc-windows-msvc | |
arm64 | aarch64-pc-windows-msvc | |
arm | thumbv7-pc-windows-msvc |
bb-types --arch arm64 --struct _CONTEXT
How it works
The flow is described below:
We use bb-sdk to discover (or gather) the SDK environment, then we generate a SDK-specific "synthetic header" (also known as an Unsaved/CXUnsavedFile in the Clang-world) which will be passed through partial compilation with libclang.dll and in turn give us a TranslationUnit.
From the translation unit, we lift the AST entities into bb-clang serializable objects, and we use the information that we expose there to develop the tools.
For functions, bb-clang computes the full ABI layout: which register or stack slot each parameter occupies, per architecture and calling convention (cdecl, stdcall, fastcall). bb-funcs enriches this with MSDN metadata (DLL, lib, min Windows version, and — for kernel/WDF DDIs — IRQL constraints, KMDF/UMDF versions, etc.) from sparse and cross-references known constant values for each parameter. SQL WHERE clause filtering is supported via bb-sql.
For macros specifically, bb-consts does a two-pass resolution: first pass evaluates simple literals and variables, second pass substitutes known constant names into unresolved macro token streams before re-evaluating. This handles things like #define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF).





