Skip to content

Commit 4e9ca78

Browse files
Copilotxusheng6
andcommitted
Add CI test for remote debugging on localhost
Co-authored-by: xusheng6 <[email protected]>
1 parent 3afdc4b commit 4e9ca78

File tree

3 files changed

+195
-0
lines changed

3 files changed

+195
-0
lines changed

.github/workflows/test.yml

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: CI Tests
2+
3+
on:
4+
push:
5+
branches: [ dev, main ]
6+
pull_request:
7+
branches: [ dev, main ]
8+
9+
jobs:
10+
test-remote-debugging:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- name: Set up Python
17+
uses: actions/setup-python@v4
18+
with:
19+
python-version: '3.9'
20+
21+
- name: Install system dependencies
22+
run: |
23+
sudo apt-get update
24+
sudo apt-get install -y lldb
25+
26+
- name: Test Remote Debugging Infrastructure
27+
run: |
28+
cd test
29+
python3 -c "
30+
import os
31+
import sys
32+
import time
33+
import platform
34+
import subprocess
35+
import socket
36+
37+
def find_free_port():
38+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
39+
s.bind(('', 0))
40+
s.listen(1)
41+
port = s.getsockname()[1]
42+
return port
43+
44+
port = find_free_port()
45+
host = '127.0.0.1'
46+
47+
# Use helloworld binary for testing
48+
fpath = 'binaries/Linux-x86_64/helloworld'
49+
if not os.path.exists(fpath):
50+
print(f'Test binary not found: {fpath}')
51+
sys.exit(1)
52+
53+
server_cmd = ['lldb-server', 'gdbserver', f'{host}:{port}', fpath]
54+
55+
try:
56+
print(f'Starting lldb-server on {host}:{port} with {fpath}')
57+
server_process = subprocess.Popen(server_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
58+
time.sleep(2)
59+
60+
if server_process.poll() is not None:
61+
stdout, stderr = server_process.communicate()
62+
print(f'lldb-server failed: stdout={stdout.decode()}, stderr={stderr.decode()}')
63+
sys.exit(1)
64+
65+
# Test connection
66+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
67+
s.settimeout(10)
68+
s.connect((host, port))
69+
s.sendall(b'+\\$qSupported#37')
70+
response = s.recv(1024)
71+
72+
if response:
73+
print('✓ Remote debugging test successful: Connected to lldb-server on localhost')
74+
else:
75+
print('✗ No response from lldb-server')
76+
sys.exit(1)
77+
78+
finally:
79+
if server_process and server_process.poll() is None:
80+
server_process.terminate()
81+
server_process.wait(timeout=5)
82+
"

docs/ci-remote-debug-test.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# CI Remote Debugging Test
2+
3+
This document describes the CI test for remote debugging functionality.
4+
5+
## Overview
6+
7+
The CI test validates the remote debugging infrastructure by:
8+
9+
1. Starting an `lldb-server` process on localhost (127.0.0.1)
10+
2. Establishing a connection to the server using GDB remote protocol
11+
3. Verifying basic communication with the debug server
12+
13+
## Test Details
14+
15+
- **Platform**: Linux (Ubuntu) with lldb installed
16+
- **Binary**: Uses the `helloworld` test binary from `test/binaries/Linux-x86_64/`
17+
- **Protocol**: GDB Remote Serial Protocol via `lldb-server gdbserver`
18+
- **Scope**: Infrastructure test - validates that remote debugging setup works
19+
20+
## Running the Test
21+
22+
The test runs automatically in GitHub Actions CI on every push and pull request.
23+
24+
To run manually:
25+
26+
```bash
27+
cd test
28+
python3 -c "
29+
# Test script content from .github/workflows/test.yml
30+
"
31+
```
32+
33+
## Implementation
34+
35+
The test is implemented in:
36+
- `.github/workflows/test.yml` - GitHub Actions workflow
37+
- `test/debugger_test.py` - Additional unit test (when Binary Ninja dependencies are available)
38+
39+
## Purpose
40+
41+
This test ensures that:
42+
- Remote debugging infrastructure components work correctly
43+
- `lldb-server` can start and accept connections
44+
- Basic GDB remote protocol communication functions
45+
- CI environment can validate remote debugging changes

test/debugger_test.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,74 @@ def test_attach(self):
351351

352352
dbg.quit_and_wait()
353353

354+
@unittest.skipIf(platform.system() != 'Linux', 'Remote debugging test only runs on Linux with lldb-server')
355+
def test_remote_debug_localhost(self):
356+
"""Test remote debugging infrastructure by starting lldb-server on localhost"""
357+
import socket
358+
import time
359+
360+
# This test verifies the remote debugging infrastructure works by:
361+
# 1. Starting an lldb-server on localhost
362+
# 2. Verifying it can accept connections
363+
# 3. Testing basic GDB remote protocol communication
364+
365+
# Find an available port
366+
def find_free_port():
367+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
368+
s.bind(('', 0))
369+
s.listen(1)
370+
port = s.getsockname()[1]
371+
return port
372+
373+
port = find_free_port()
374+
host = '127.0.0.1'
375+
376+
# Start lldb-server process in gdbserver mode
377+
fpath = name_to_fpath('helloworld', self.arch)
378+
server_cmd = ['lldb-server', 'gdbserver', f'{host}:{port}', fpath]
379+
380+
server_process = None
381+
try:
382+
# Start the lldb-server
383+
server_process = subprocess.Popen(server_cmd,
384+
stdout=subprocess.PIPE,
385+
stderr=subprocess.PIPE)
386+
387+
# Give the server time to start
388+
time.sleep(2)
389+
390+
# Check if server is still running
391+
if server_process.poll() is not None:
392+
stdout, stderr = server_process.communicate()
393+
self.fail(f"lldb-server failed to start: stdout={stdout.decode()}, stderr={stderr.decode()}")
394+
395+
# Test basic connection to the server
396+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
397+
s.settimeout(10)
398+
s.connect((host, port))
399+
400+
# Send a basic GDB packet to test communication
401+
# '+' acknowledges packets, '$qSupported#37' is a basic query
402+
s.sendall(b'+$qSupported#37')
403+
404+
# Read response
405+
response = s.recv(1024)
406+
self.assertIsNotNone(response)
407+
self.assertGreater(len(response), 0)
408+
409+
# Success - we established a remote debugging connection!
410+
print("Remote debugging test successful: Connected to lldb-server on localhost")
411+
412+
finally:
413+
# Clean up server process
414+
if server_process and server_process.poll() is None:
415+
server_process.terminate()
416+
try:
417+
server_process.wait(timeout=5)
418+
except subprocess.TimeoutExpired:
419+
server_process.kill()
420+
server_process.wait()
421+
354422

355423
@unittest.skipIf(platform.machine() not in ['arm64', 'aarch64'], "Only run arm64 tests on arm Mac or Linux")
356424
class DebuggerArm64Test(DebuggerAPI):

0 commit comments

Comments
 (0)