Skip to content

Conversation

anvol
Copy link

@anvol anvol commented Oct 11, 2025

Key Features:

  • OpenOCD Integration: Seamless connection to OpenOCD debug servers (default port 3333)
  • ARM Cortex-M Focus: Optimized for Cortex-M3, M4, M7, and other embedded ARM variants
  • Architecture Auto-Detection: Intelligent detection of target architecture through register analysis and GDB queries
  • Thread-Safe Design: Non-blocking UI with dedicated reader threads and command synchronization
  • Debugging: Breakpoints, stepping, memory access, register inspection, and watch variables/structs in bn views

Technical Implementation Details

Architecture:

  • GdbMiConnector: Handles low-level MI protocol communication, process management, and async event processing. Covered with miparser_test
  • GdbMiAdapter: Implements Binary Ninja's DebugAdapter interface with high-level debugging operations
  • Caching System: Performance-optimized caching for threads, registers, and stack frames
  • Cross-Platform: Proper process handling Linux, macOS, and (maybe) Windows

Key Technical Components:

  • MI protocol parser handling nested structures and complex responses
  • Variable object system for efficient watch variable tracking
  • Hardware breakpoint support for embedded targets
  • Memory access constraints for embedded memory maps

Setup and Configuration

Required Tools:

  • Host System: Linux or macOS with Binary Ninja
  • Debug Probe: ST-Link, J-Link, or other OpenOCD-compatible probe
  • GDB: gdb-multiarch or arm-none-eabi-gdb
  • OpenOCD: Running with target configuration (e.g., STM32F4x)

Typical Workflow:

  1. Start OpenOCD: openocd -f interface/stlink.cfg -f target/stm32f4x.cfg
  2. Export DWARF file for target architecture
  3. Configure adapter settings in Binary Ninja. Specify desired GDB path, connection IP/port and DWARF file
  4. Connect to target through the debugger interface
  5. Set breakpoints, inspect memory, and step through firmware code

Adapter Settings:

  • gdb.path: Path to GDB executable (default: gdb-multiarch)
  • connect.ipAddress: OpenOCD server IP (default: 127.0.0.1)
  • connect.port: OpenOCD GDB port (default: 3333)
  • common.inputFile: Firmware file for base address resolution
  • gdb.symbolFile: ELF or DWARF debug information so gdb would know funcs boundaries and names for backtrace

Testing and Validation

Verified Platforms:

  • Debian 13 with gdb-multiarch
  • macOS 15+ (Apple Silicon) arm-none-eabi-gdb from brew
  • ARM Cortex-M targets (STM32F103 and STM32F401 extensively tested)

Validation Checklist:

  • GDB process launches and terminates correctly
  • Architecture auto-detection for ARM Cortex-M targets
  • Successful connection to OpenOCD
  • Register display and memory access
  • Breakpoint setting and hitting
  • Stepping and control flow
  • Watch variable updates in main ui window
  • Thread and stack frame information
image image image

Benefits for Binary Ninja Community

This implementation significantly enhances Binary Ninja's capabilities for:

  1. Embedded Security Research: Dynamic analysis of IoT devices, automotive systems, and industrial controllers
  2. Firmware Reverse Engineering: Live debugging of embedded binaries with Binary Ninja's advanced analysis features
  3. Hardware-Assisted Analysis: Integration with real hardware through standard debugging probes
  4. Educational Use: Teaching embedded systems and reverse engineering with professional tools

GDB MI now implements most basic functionality
Notify UI that we're connected and ready to serve data
small fixes to handle quit
cleanup
feat(gdb): Refactor event handling and command execution
- An event loop (`EventLoop`) running in a dedicated thread (`m_eventThread`) now handles all asynchronous output from GDB. This replaces the previous callback-based approach (`AsyncRecordHandler`).
- A mutex (`m_gdbCommandMutex`) is now used exclusively within the `SendCommand` method, centralizing locking and preventing race conditions. Higher-level functions no longer manage the lock themselves.
- The target's running state is now managed by a `std::atomic<bool>` (`m_targetRunningAtomic`) for safe access across threads.
- Asynchronous commands (`-exec-run`, `-exec-step`, etc.) are now sent via a new `SendCommandAsync` method, which does not wait for a result, allowing the UI to remain responsive while the target is running.
- Logging has been adjusted, changing many `LogInfo` calls to `LogDebug` to reduce default output verbosity.
- The GDB-MI value parser (`MiValue::parse`) has been rewritten to be more robust and correctly handle complex GDB output formats.
Add watch widget implementation for basic types
MIParser fixes and cleanup
Added unit test for MI parser
Implemented StepOut function
@CLAassistant
Copy link

CLAassistant commented Oct 11, 2025

CLA assistant check
All committers have signed the CLA.

@anvol
Copy link
Author

anvol commented Oct 11, 2025

Implements #874 and partially covers #170

anvol added 3 commits October 11, 2025 16:28
- fix missing default init values
Clear cache on stop/quit/restart
@xusheng6 xusheng6 self-assigned this Oct 17, 2025
@xusheng6 xusheng6 requested a review from Copilot October 17, 2025 08:16
@xusheng6
Copy link
Member

xusheng6 commented Oct 17, 2025

Thanks for the contribution! I had a quick glance and it looks good, I will review it when I get time.

Also I had copilot look at it as well -- I have not gone through them yet, if they are correct, please address them; if they are wrong, please point it out!

Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a comprehensive GDB MI (Machine Interface) adapter for Binary Ninja, specifically optimized for embedded ARM debugging via OpenOCD. The adapter implements the full DebugAdapter interface with thread-safe operations, intelligent architecture detection, and MI protocol parsing.

Key changes:

  • GDB MI protocol parser and connector with async event handling
  • Complete debug adapter implementation supporting breakpoints, stepping, memory access, and register inspection
  • Comprehensive unit tests for MI protocol parsing edge cases
  • Architecture auto-detection for ARM Cortex-M targets

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
core/adapters/gdbmiconnector.h Header defining MI protocol structures and connector interface
core/adapters/gdbmiconnector.cpp MI protocol parser and GDB process management implementation
core/adapters/gdbmiadapter.h Debug adapter interface declarations with caching system
core/adapters/gdbmiadapter.cpp Full debug adapter implementation with OpenOCD-specific functionality
core/tests/miparser_test.cpp Unit tests validating MI protocol parsing for complex nested structures
core/tests/CMakeLists.txt Test build configuration with GoogleTest integration
core/debugger.cpp Registration of new adapter type
core/CMakeLists.txt Build system integration for new adapter files

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

for (;;)
{
ssize_t n = read(m_gdb_stdout_read, buffer, sizeof(buffer));
buffer[n] = 0;
Copy link

Copilot AI Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential buffer overflow: the buffer is declared with size 4096, but writing at index n without bounds checking. If n equals 4096, this writes beyond the buffer. Should check n < sizeof(buffer) before this write.

Suggested change
buffer[n] = 0;
if (n >= 0 && n < (ssize_t)sizeof(buffer))
buffer[n] = 0;
// If n == sizeof(buffer), buffer is not null-terminated

Copilot uses AI. Check for mistakes.

Comment on lines 649 to 650
if (address > 0x60000000) return {};
if (address < 0x08000000) return {};
Copy link

Copilot AI Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magic numbers for memory address ranges should be defined as named constants. Consider defining ARM_CORTEX_MEMORY_MIN and ARM_CORTEX_MEMORY_MAX to make the code more maintainable and document the reasoning.

Copilot uses AI. Check for mistakes.

@anvol
Copy link
Author

anvol commented Oct 17, 2025

  • buffer - confirmed, fixed that locally
  • step - confirmed
  • additionally, GetBreakpointList should be implemented as GDB MI expects it's idx from "-break-list" cmd to remove breakpoint "-break-delete "

Remove all breakpoints at address
Use BackendMessageEventType as output for gdb messages
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants