Ruby bindings for the LLDB debugger.
This gem provides Ruby bindings for LLDB (Low Level Debugger), allowing you to access LLDB's debugging functionality from Ruby. It uses FFI (Foreign Function Interface) with a C wrapper around LLDB's C++ API.
- Ruby 3.0 or later
- LLDB 14 or later
- C++17 compatible compiler (gcc 8+ / clang 10+)
- libffi-dev (for the FFI gem)
Ubuntu/Debian:
sudo apt-get install lldb-14 liblldb-14-devFedora/RHEL:
sudo dnf install lldb-develmacOS:
xcode-select --install
# or
brew install llvmAdd this line to your application's Gemfile:
gem 'lldb'And then execute:
bundle installOr install it yourself as:
gem install lldbrequire 'lldb'
# Initialize LLDB
LLDB.initialize
# Create a debugger
debugger = LLDB::Debugger.create
debugger.async = false # Run synchronously
# Create a target from an executable
target = debugger.create_target('./my_program')
# Set a breakpoint at main
bp = target.breakpoint_create_by_name('main')
puts "Breakpoint #{bp.id} created with #{bp.num_locations} locations"
# Launch the process
process = target.launch
# Check if stopped at breakpoint
if process.stopped?
thread = process.selected_thread
frame = thread.selected_frame
puts "Stopped at: #{frame.function_name}"
puts "Location: #{frame.location}"
# Find a variable
var = frame.find_variable('argc')
puts "argc = #{var.value}" if var
# Evaluate an expression
result = frame.evaluate_expression('argc + 1')
puts "argc + 1 = #{result.value}" if result
# Continue execution
process.continue
end
# Clean up
process.kill if process.valid?
LLDB.terminate# By function name
bp = target.breakpoint_create_by_name('main')
# By source location
bp = target.breakpoint_create_by_location('main.c', 10)
# By address
bp = target.breakpoint_create_by_address(0x100001000)
# Configure breakpoint
bp.condition = 'x > 5'
bp.ignore_count = 2
bp.one_shot = true
bp.disable
bp.enablethread = process.selected_thread
# Step over (next line)
thread.step_over
# Step into (enter function)
thread.step_into
# Step out (return from function)
thread.step_out
# Step one instruction
thread.step_instructionframe = thread.selected_frame
# Find a variable by name
var = frame.find_variable('my_variable')
if var && var.valid?
puts "Name: #{var.name}"
puts "Type: #{var.type_name}"
puts "Value: #{var.value}"
puts "Size: #{var.byte_size} bytes"
# For integer types
puts "As integer: #{var.to_i}"
# For complex types with children
if var.might_have_children?
var.each do |child|
puts " #{child.name} = #{child.value}"
end
end
end# Get all threads
process.threads.each do |thread|
puts "Thread #{thread.id}: #{thread.name || 'unnamed'}"
puts " Stop reason: #{thread.stop_reason_name}"
end
# Get the call stack
thread.frames.each_with_index do |frame, i|
puts "##{i}: #{frame.function_name} at #{frame.location}"
endprocess = target.attach(pid: 12345)LLDB::Debugger- Entry point for debugging operationsLLDB::Target- Represents a debug target (executable)LLDB::Process- Represents a running processLLDB::Thread- Represents an execution threadLLDB::Frame- Represents a stack frameLLDB::Breakpoint- Represents a breakpointLLDB::Value- Represents a variable or expression resultLLDB::Module- Represents a loaded moduleLLDB::Error- Represents an error from LLDB
Process states are available in LLDB::State:
INVALID,UNLOADED,CONNECTED,ATTACHING,LAUNCHINGSTOPPED,RUNNING,STEPPING,CRASHED,DETACHED,EXITED,SUSPENDED
Stop reasons are available in LLDB::StopReason:
INVALID,NONE,TRACE,BREAKPOINT,WATCHPOINTSIGNAL,EXCEPTION,EXEC,PLAN_COMPLETE,THREAD_EXITING,INSTRUMENTATION
After checking out the repo, run:
bundle install
cd ext/lldb && ruby extconf.rb && make && cd ../..
bundle exec rspecTo run tests, you need to compile the test fixtures:
gcc -g -O0 -o spec/fixtures/simple spec/fixtures/simple.cBug reports and pull requests are welcome on GitHub.
Dual licensed under the MIT License and Apache License 2.0.