or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-debugging.mdfile-system.mdframework-integration.mdindex.mdinteractive-console.mdipython-integration.mdprocess-attachment.mdprogrammatic-api.md

process-attachment.mddocs/

0

# Process Attachment

1

2

Remote process attachment and code injection capabilities for debugging already-running Python processes. This functionality enables debugging scenarios where the target process wasn't started with debugging enabled, allowing developers to attach debuggers to production applications and long-running services.

3

4

## Capabilities

5

6

### Process Attachment

7

8

Core functions for attaching the debugger to running Python processes using platform-specific injection techniques.

9

10

```python { .api }

11

def run_python_code(pid, python_code, connect_debugger_tracing=False, show_debug_info=0):

12

"""

13

Inject and execute Python code in a running Python process.

14

15

This is a platform-specific function that routes to the appropriate implementation:

16

- Windows: run_python_code_windows

17

- Linux: run_python_code_linux

18

- macOS: run_python_code_mac

19

20

Parameters:

21

- pid (int): Process ID of the target Python process

22

- python_code (str): Python code to inject and execute (cannot contain single quotes)

23

- connect_debugger_tracing (bool): Whether to enable debugger tracing after injection

24

- show_debug_info (int): Debug information level (0=none, 1=basic, 2=detailed)

25

26

Returns:

27

None: Function executes injection but doesn't return a value

28

29

Raises:

30

- AssertionError: If python_code contains single quotes

31

- RuntimeError: If required libraries/executables are not found or injection fails

32

- Various platform-specific exceptions during injection process

33

"""

34

35

def run_python_code_windows(pid, python_code, connect_debugger_tracing=False, show_debug_info=0):

36

"""Windows-specific implementation of code injection using winappdbg and DLL injection."""

37

38

def run_python_code_linux(pid, python_code, connect_debugger_tracing=False, show_debug_info=0):

39

"""Linux-specific implementation of code injection using gdb and shared libraries."""

40

41

def run_python_code_mac(pid, python_code, connect_debugger_tracing=False, show_debug_info=0):

42

"""macOS-specific implementation of code injection using lldb and dynamic libraries."""

43

```

44

45

### Debugger Attachment Script

46

47

High-level utilities for setting up debugger attachment to running processes.

48

49

```python { .api }

50

def attach(port, host, protocol="", debug_mode=""):

51

"""

52

Attach debugger to the current process and connect to debugger server.

53

54

This function is typically called from code injected into a running process

55

to establish debugger connection.

56

57

Parameters:

58

- port (int): Port number of the debugger server

59

- host (str): Host address of the debugger server

60

- protocol (str): Communication protocol ("", "http", "json")

61

- debug_mode (str): Debug mode configuration

62

63

Returns:

64

None

65

"""

66

67

def get_main_thread_id(unlikely_thread_id=None):

68

"""

69

Identify the main thread in a multi-threaded process.

70

71

Parameters:

72

- unlikely_thread_id: Thread ID to exclude from consideration

73

74

Returns:

75

tuple: (thread_id, critical_warning) - thread ID and any warning message

76

"""

77

```

78

79

### Platform Detection

80

81

Utilities for detecting platform capabilities and requirements for process attachment.

82

83

```python { .api }

84

def is_windows():

85

"""

86

Check if running on Windows platform.

87

88

Returns:

89

bool: True if Windows, False otherwise

90

"""

91

92

def is_linux():

93

"""

94

Check if running on Linux platform.

95

96

Returns:

97

bool: True if Linux, False otherwise

98

"""

99

100

def is_mac():

101

"""

102

Check if running on macOS platform.

103

104

Returns:

105

bool: True if macOS, False otherwise

106

"""

107

108

def get_platform_attachment_library():

109

"""

110

Get the appropriate native library for process attachment.

111

112

Returns:

113

str: Path to platform-specific attachment library (.dll, .so, or .dylib)

114

115

Raises:

116

- RuntimeError: If no compatible library is available for current platform

117

"""

118

```

119

120

## Usage Examples

121

122

### Basic Process Attachment

123

124

```python

125

import os

126

import subprocess

127

from pydevd_attach_to_process.add_code_to_python_process import run_python_code

128

129

# Start a target Python process

130

target_script = """

131

import time

132

counter = 0

133

while True:

134

counter += 1

135

print(f"Counter: {counter}")

136

time.sleep(1)

137

"""

138

139

# Write target script to file

140

with open('target_app.py', 'w') as f:

141

f.write(target_script)

142

143

# Start target process

144

process = subprocess.Popen(['python', 'target_app.py'])

145

target_pid = process.pid

146

147

print(f"Target process started with PID: {target_pid}")

148

149

# Inject debugger setup code into the running process

150

debugger_setup_code = """

151

import pydevd

152

print("Setting up debugger...")

153

pydevd.settrace(

154

host='localhost',

155

port=5678,

156

suspend=False,

157

trace_only_current_thread=False

158

)

159

print("Debugger attached successfully!")

160

"""

161

162

try:

163

result = run_python_code(

164

pid=target_pid,

165

python_code=debugger_setup_code,

166

connect_debugger_tracing=True,

167

show_debug_info=1

168

)

169

170

print(f"Code injection result: {result}")

171

print("You can now connect your IDE to port 5678")

172

173

except Exception as e:

174

print(f"Attachment error: {e}")

175

176

finally:

177

# Clean up

178

process.terminate()

179

os.remove('target_app.py')

180

```

181

182

### Code Injection for Debugging Setup

183

184

```python

185

from pydevd_attach_to_process.add_code_to_python_process import add_code_to_python_process

186

187

# Code to inject for debugger setup

188

debugger_setup_code = """

189

import pydevd

190

print("Setting up debugger...")

191

pydevd.settrace(

192

host='localhost',

193

port=5678,

194

suspend=False,

195

trace_only_current_thread=False

196

)

197

print("Debugger attached successfully!")

198

"""

199

200

# Inject debugger setup code into running process

201

result = add_code_to_python_process(

202

pid=target_pid,

203

python_code=debugger_setup_code,

204

connect_debugger_tracing=True,

205

show_debug_info=1

206

)

207

208

print(f"Code injection result: {result}")

209

```

210

211

### Advanced Process Information and Compatibility

212

213

```python

214

from pydevd_attach_to_process import attach_pydevd

215

import psutil

216

217

def attach_with_compatibility_check(pid, debugger_port):

218

"""

219

Attach to process with comprehensive compatibility checking.

220

"""

221

try:

222

# Get process information

223

process_info = attach_pydevd.get_process_info(pid)

224

225

print(f"Process Information:")

226

print(f" PID: {pid}")

227

print(f" Python Version: {process_info['python_version']}")

228

print(f" Architecture: {process_info['architecture']}")

229

print(f" Executable: {process_info['executable']}")

230

print(f" Compatible: {process_info['compatible']}")

231

232

if not process_info['compatible']:

233

print(f" Incompatibility Reason: {process_info['reason']}")

234

return False

235

236

# Check if process is still running

237

if not psutil.pid_exists(pid):

238

print(f"Process {pid} no longer exists")

239

return False

240

241

# Get additional process details

242

proc = psutil.Process(pid)

243

print(f" Process Name: {proc.name()}")

244

print(f" Memory Usage: {proc.memory_info().rss / 1024 / 1024:.1f} MB")

245

print(f" CPU Percent: {proc.cpu_percent():.1f}%")

246

247

# Attempt attachment

248

print(f"\nAttempting to attach debugger to PID {pid}...")

249

success = attach_pydevd.attach_to_process(

250

pid=pid,

251

debugger_port=debugger_port,

252

timeout=15.0

253

)

254

255

if success:

256

print(f"✓ Successfully attached debugger")

257

print(f" Connect your IDE to localhost:{debugger_port}")

258

return True

259

else:

260

print("✗ Failed to attach debugger")

261

return False

262

263

except Exception as e:

264

print(f"Error during attachment: {e}")

265

return False

266

267

# Usage

268

target_pid = 12345 # Replace with actual PID

269

attach_with_compatibility_check(target_pid, 5678)

270

```

271

272

### Platform-Specific Attachment

273

274

```python

275

from pydevd_attach_to_process import attach_pydevd

276

from pydevd_attach_to_process.add_code_to_python_process import (

277

run_python_code_windows,

278

run_python_code_linux,

279

run_python_code_mac,

280

is_windows,

281

is_linux,

282

is_mac

283

)

284

285

def platform_specific_attach(pid, debugger_code):

286

"""

287

Perform platform-specific code injection and attachment.

288

"""

289

show_debug_info = 2 # Detailed debug information

290

connect_tracing = True

291

292

try:

293

if is_windows():

294

print("Using Windows attachment method...")

295

result = run_python_code_windows(

296

pid, debugger_code, connect_tracing, show_debug_info

297

)

298

elif is_linux():

299

print("Using Linux attachment method...")

300

result = run_python_code_linux(

301

pid, debugger_code, connect_tracing, show_debug_info

302

)

303

elif is_mac():

304

print("Using macOS attachment method...")

305

result = run_python_code_mac(

306

pid, debugger_code, connect_tracing, show_debug_info

307

)

308

else:

309

raise RuntimeError("Unsupported platform for process attachment")

310

311

print(f"Platform-specific attachment result: {result}")

312

return True

313

314

except Exception as e:

315

print(f"Platform-specific attachment failed: {e}")

316

return False

317

318

# Debugger setup code

319

setup_code = """

320

import sys

321

import pydevd

322

323

# Verify Python version compatibility

324

if sys.version_info >= (3, 8):

325

print("Python version compatible, setting up debugger...")

326

pydevd.settrace(

327

host='0.0.0.0',

328

port=5678,

329

suspend=False,

330

stdout_to_server=True,

331

stderr_to_server=True

332

)

333

print("Remote debugger attached and ready!")

334

else:

335

print(f"Python version {sys.version_info} not supported")

336

"""

337

338

# Perform platform-specific attachment

339

platform_specific_attach(target_pid, setup_code)

340

```

341

342

### Production Process Debugging

343

344

```python

345

import time

346

import signal

347

from pydevd_attach_to_process import attach_pydevd

348

349

class ProductionDebugger:

350

def __init__(self, target_pid, debugger_port=5678):

351

self.target_pid = target_pid

352

self.debugger_port = debugger_port

353

self.attached = False

354

355

def safe_attach(self):

356

"""

357

Safely attach to production process with error handling.

358

"""

359

try:

360

# First, verify process exists and is compatible

361

process_info = attach_pydevd.get_process_info(self.target_pid)

362

363

if not process_info['compatible']:

364

raise RuntimeError(f"Process incompatible: {process_info['reason']}")

365

366

# Prepare minimal debugger code

367

minimal_debugger_code = """

368

import pydevd

369

import threading

370

371

def setup_debugger():

372

try:

373

pydevd.settrace(

374

host='localhost',

375

port={port},

376

suspend=False,

377

trace_only_current_thread=False,

378

patch_multiprocessing=False # Don't interfere with child processes

379

)

380

print(f"Debugger attached on port {port}")

381

except Exception as e:

382

print(f"Debugger setup failed: {{e}}")

383

384

# Run in separate thread to avoid blocking main application

385

debug_thread = threading.Thread(target=setup_debugger, daemon=True)

386

debug_thread.start()

387

""".format(port=self.debugger_port)

388

389

# Inject debugger code

390

success = attach_pydevd.attach_to_process(

391

pid=self.target_pid,

392

debugger_port=self.debugger_port,

393

timeout=5.0 # Short timeout for production

394

)

395

396

if success:

397

self.attached = True

398

print(f"✓ Production debugger attached to PID {self.target_pid}")

399

print(f" IDE connection: localhost:{self.debugger_port}")

400

return True

401

else:

402

print("✗ Failed to attach to production process")

403

return False

404

405

except Exception as e:

406

print(f"Production debugging setup failed: {e}")

407

return False

408

409

def detach(self):

410

"""

411

Detach debugger from production process.

412

"""

413

if self.attached:

414

detach_code = """

415

import pydevd

416

try:

417

pydevd.stoptrace()

418

print("Debugger detached successfully")

419

except:

420

pass

421

"""

422

try:

423

attach_pydevd.inject_debugger_code(self.target_pid, detach_code)

424

self.attached = False

425

print(f"Debugger detached from PID {self.target_pid}")

426

except Exception as e:

427

print(f"Failed to detach debugger: {e}")

428

429

# Usage for production debugging

430

production_pid = 98765 # Replace with production process PID

431

432

debugger = ProductionDebugger(production_pid, debugger_port=5679)

433

434

# Set up signal handler for clean detachment

435

def signal_handler(signum, frame):

436

print("\nDetaching debugger...")

437

debugger.detach()

438

exit(0)

439

440

signal.signal(signal.SIGINT, signal_handler)

441

442

# Attach to production process

443

if debugger.safe_attach():

444

print("Production debugging active. Press Ctrl+C to detach.")

445

try:

446

while True:

447

time.sleep(1)

448

except KeyboardInterrupt:

449

pass

450

finally:

451

debugger.detach()

452

```

453

454

## Platform Requirements

455

456

### Windows

457

- Requires `attach_windows.dll` (32-bit) or `attach_windows_amd64.dll` (64-bit)

458

- Administrator privileges may be required for some processes

459

- Compatible with Windows 7+ and Windows Server 2008+

460

461

### Linux

462

- Requires `attach_linux.so` (32-bit) or `attach_linux_amd64.so` (64-bit)

463

- Requires `ptrace` capability (may need `CAP_SYS_PTRACE`)

464

- Compatible with most Linux distributions

465

466

### macOS

467

- Requires `attach_mac.dylib` (32-bit) or `attach_mac_amd64.dylib` (64-bit)

468

- May require disabling System Integrity Protection (SIP) for some scenarios

469

- Compatible with macOS 10.9+

470

471

## Security Considerations

472

473

- **Permissions**: Process attachment requires appropriate system permissions

474

- **Code Injection**: Only inject trusted code into processes

475

- **Production Use**: Use minimal debugger setup to avoid performance impact

476

- **Network Security**: Consider firewall rules for debugger ports

477

- **Process Stability**: Attachment may affect target process performance