This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
BTrace is a safe, dynamic tracing tool for the Java platform that instruments running Java applications to inject tracing code ("bytecode tracing"). It's similar to DTrace for OpenSolaris but designed specifically for Java.
# Build entire project with distribution packages
./gradlew :btrace-dist:build
# Output locations:
# - Distributions: btrace-dist/build/distributions/ (*.tar.gz, *.zip, *.rpm, *.deb)
# - Exploded binary (BTRACE_HOME): btrace-dist/build/resources/main/# Run all tests
./gradlew test
# Run tests for specific module
./gradlew :btrace-instr:test
./gradlew :btrace-compiler:test
# Run specific test class
./gradlew :btrace-instr:test --tests "*CompilerTest"
# Run specific test method
./gradlew :btrace-instr:test --tests "org.openjdk.btrace.compiler.CompilerTest.testSimple"
# Integration tests (requires dist built first)
./gradlew :btrace-dist:build
./gradlew :integration-tests:test -PintegrationSome instrumentation tests use golden files to verify bytecode correctness. When you intentionally change instrumented bytecode:
# Regenerate all golden files
./gradlew test -PupdateTestData
# Then commit the updated files in btrace-instr/src/test/resources/instrumentorTestData/# Check formatting (runs during build)
./gradlew spotlessCheck
# Auto-format all code (Google Java Format)
./gradlew spotlessApply# Build single module
./gradlew :<module-name>:build
# Build without tests (faster)
./gradlew :<module-name>:build -x testBTrace follows a clear separation between compile-time safety verification and runtime instrumentation:
BTrace Script (.java)
↓
[btrace-compiler] Compile & verify safety
↓
Compiled Script (.class)
↓
[btrace-agent] Load into target JVM
↓
[btrace-instr] Transform target classes
↓
[btrace-runtime] Execute probe code
btrace-compiler - Script compilation and safety verification
- Entry:
Compiler.java- JSR 199 compilation pipeline - Safety:
Verifier.java- Enforces BTrace restrictions (no loops, no allocations, no exceptions, no field assignment) - Post-processing:
Postprocessor.java- Bytecode transformations after compilation - Location:
btrace-compiler/src/main/java/org/openjdk/btrace/compiler/
btrace-agent - Java agent for attaching to target JVMs
- Entry:
Main.java- Implementspremain()andagentmain()for instrumentation - Client management:
Client.java,RemoteClient.java,FileClient.java - Starts server on port 2020 by default to accept client connections
- Location:
btrace-agent/src/main/java/org/openjdk/btrace/agent/
btrace-instr - Bytecode instrumentation using ASM
- Transformer:
BTraceTransformer.java- ClassFileTransformer implementation - Probe factory:
BTraceProbeFactory.java- Creates BTraceProbe instances - Instrumentor:
Instrumentor.java- Main ASM-based bytecode injection logic - 15 specialized instrumentors for different probe types (method entry/exit, field access, allocation, etc.)
- Location:
btrace-instr/src/main/java/org/openjdk/btrace/instr/
btrace-runtime - Runtime services for BTrace scripts
- Factory:
BTraceRuntimes.java- Loads version-specific implementations (JDK 8, 9, 11, 15+) - Base:
BTraceRuntimeImplBase.java- Core runtime services (print, profiling, JMX, etc.) - Multi-version support: Separate implementations in
src/main/java9/,src/main/java11/,src/main/java15/ - Location:
btrace-runtime/src/main/java/org/openjdk/btrace/runtime/
btrace-client - Command-line client tool
- Main:
Main.java- CLI for connecting to agent and submitting scripts - Client:
Client.java- Manages socket connection to agent - Location:
btrace-client/src/main/java/org/openjdk/btrace/client/
btrace-core - Core abstractions and communication
- Wire protocols:
WireProtocol.java- V1 (Java serialization) and V2 (binary, 3-6x faster) - Commands: 20+ command types in
comm/package for agent-client communication - Annotations:
@BTrace,@OnMethod,@OnTimer, etc. inannotations/package - Location:
btrace-core/src/main/java/org/openjdk/btrace/core/
Safety-First Design: Scripts are verified at compile-time to prevent:
- Loops and recursion (no infinite loops in instrumented code)
- Object allocation (minimize GC pressure on target app)
- Exception throwing (don't crash target app)
- Field assignment (maintain immutability)
Instrumentation Pipeline: When a class loads:
BTraceTransformer.transform()checks registered probes- For matching classes,
Instrumentorcreates ASM visitor chain - Each specialized instrumentor handles specific probe types (entry, exit, call, field access, etc.)
- Modified bytecode with injected probe calls is returned
Multi-Version Runtime: The runtime has version-specific implementations to handle JDK differences:
- Base in
src/main/java/(Java 8) - JDK 9+ features in
src/main/java9/ - JDK 11+ features in
src/main/java11/ - JDK 15+ features in
src/main/java15/
Communication: Agent and client communicate via pluggable WireProtocol:
- V1: Java Object Serialization (backward compatible)
- V2: Custom binary protocol (higher performance, 2-5x smaller payloads)
- Auto-negotiation ensures compatibility
Source Compatibility: Java 8 for main code, compiled with Java 11 toolchain
- Set in
common.gradle:sourceCompatibility = 8,targetCompatibility = 8 - Uses Java 11 compiler for better optimization while maintaining Java 8 compatibility
Formatting: Google Java Format via Spotless
- Import order:
java,javax,org.openjdk.btrace,*, then static imports - Always run
./gradlew spotlessApplybefore committing
Testing:
- Unit tests in
src/test/java/named*Test.java - BTrace instrumentation scripts in
src/test/btrace/(compiled with btracec) - Golden files in
src/test/resources/instrumentorTestData/for bytecode verification - Integration tests require full distribution build first
BTrace Script Restrictions (enforced by Verifier.java):
- No
newkeyword (object allocation) - No loops (
for,while,do-while) - No
throwstatements - No field assignment (can read fields, but not write)
- Only whitelisted method calls allowed (BTraceUtils.*, etc.)
- Scripts must be annotated with
@BTrace
Instrumentation Probe Types (@OnMethod locations):
Kind.ENTRY- Method entryKind.RETURN- Method return (normal)Kind.ERROR- Method return (exception)Kind.CALL- Before method callKind.LINE- Specific line numberKind.FIELD_GET/FIELD_SET- Field accessKind.ARRAY_GET/ARRAY_SET- Array accessKind.NEW- Object/array allocation- Plus more (see
Location.java)
ClassFileTransformer Thread Safety: BTraceTransformer uses ReentrantReadWriteLock because:
- Multiple threads can load classes concurrently
- Probe registration (write) vs. class transformation (read) must be coordinated
Performance Considerations:
- Filter-based class matching to avoid unnecessary transforms
- Class metadata caching (
ClassCache.java) - Binary protocol V2 for reduced serialization overhead
- Async command queue with configurable backoff
btrace-core (annotations, wire protocol, commands)
↓
btrace-compiler, btrace-instr, btrace-runtime
↓
btrace-agent (orchestrates everything)
↓
btrace-client, btrace-dist
BTrace scripts are Java files with special annotations. They're compiled separately from regular Java code:
Compilation: Use btracec tool or Gradle tasks
# In tests
./gradlew :btrace-instr:compileTestProbes
./gradlew :integration-tests:compileTestProbes
# In benchmarks
./gradlew :benchmarks:agent-benchmark:btracecExample Script Structure:
@BTrace
public class MyTrace {
@OnMethod(clazz="java.io.FileInputStream", method="<init>")
public static void onFileOpen(@ProbeClassName String className, String fileName) {
BTraceUtils.println("File opened: " + fileName);
}
}Enable Debug Output: BTrace has built-in debug support via DebugSupport.java
- Set system properties or use agent debug flags
- Check
Main.javafor available agent arguments
Test Isolation: Each test should be independent
- Tests run with
cleanTestdependency (always run, never cached) - Integration tests require fresh distribution build
- BTrace agent defaults to port 2020;
ManifestLibsTestsuses port 2022 to avoid contention - Port is configured via
btrace.portsystem property, passed to spawned BTrace processes via-Dbtrace.portand-pCLI flag
Bytecode Verification: If instrumentation tests fail:
- Check if bytecode generation changed
- Regenerate golden files with
-PupdateTestData - Verify the changes are intentional
- Commit updated golden files
ClassLoader Issues: BTrace uses multiple classloaders:
- Bootstrap classpath for agent core (bootstrap section of masked
btrace.jar) - System classpath for client tools
- Target application classloaders remain isolated
- See
Main.javafor bootstrap setup
From Readme.md: Pull requests can only be accepted from signers of the Oracle Contributor Agreement