Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

Commit

Permalink
Attach to pid support (#1701)
Browse files Browse the repository at this point in the history
* Fix launcher test

* Attach to pid support

* Address comments.

* Minor tweaks
  • Loading branch information
karthiknadig committed Aug 19, 2019
1 parent e94980f commit 9ece432
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 4 deletions.
42 changes: 42 additions & 0 deletions src/ptvsd/adapter/debuggee.py
Expand Up @@ -80,6 +80,48 @@ def spawn_and_connect(request):
before_accept=lambda address: _parse_request_and_spawn(request, address),
)

def attach_by_pid(request):
"""Start server to receive connection from the debug server injected into the
debuggee process.
"""
def _parse_request_and_inject(request, address):
cmdline = [sys.executable]

host, port = address
ptvsd_args = request("ptvsdArgs", json.array(unicode))
cmdline += [
compat.filename(ptvsd.__main__.__file__),
"--client",
"--host",
host,
"--port",
str(port),
"--pid",
str(request("processId", int))
] + ptvsd_args

log.debug("Launching debugger injector: {0!r}", cmdline)

try:
# This process will immediately exit after injecting debug server
proc = subprocess.Popen(
cmdline,
bufsize=0,
)
except Exception as exc:
raise request.cant_handle("Error launching debug process: {0}", exc)
proc.wait()
if proc.returncode != 0:
raise request.cant_handle(
"Failed to inject debugger with error code: {0}",
proc.returncode,
)

channels.Channels().accept_connection_from_server(
("127.0.0.1", 0),
before_accept=lambda address: _parse_request_and_inject(address),
)


def _parse_request_and_spawn(request, address):
spawn_info = _parse_request(request, address)
Expand Down
9 changes: 6 additions & 3 deletions src/ptvsd/adapter/messages.py
Expand Up @@ -199,9 +199,12 @@ def attach_request(self, request):
_Shared.readonly_attrs.add("terminate_on_disconnect")
self._debug_config(request)

options.host = request("host", options.host)
options.port = request("port", options.port)
_channels.connect_to_server(address=(options.host, options.port))
if "processId" in request:
debuggee.attach_by_pid(request)
else:
options.host = request("host", options.host)
options.port = request("port", options.port)
_channels.connect_to_server(address=(options.host, options.port))

return self._configure(request)

Expand Down
35 changes: 34 additions & 1 deletion tests/ptvsd/common/test_launcher.py
Expand Up @@ -8,6 +8,7 @@
import os.path
import platform
import pytest
import socket
import subprocess
import sys

Expand All @@ -17,10 +18,31 @@
launcher_py = os.path.abspath(launcher.__file__)


class ReceivePid(object):
def start_server(self):
self.listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.listener.bind(("127.0.0.1", 0))
self.listener.listen(1)
self.host, self.port = self.listener.getsockname()
return (self.host, self.port)

def wait_for_pid(self):
try:
sock, _ = self.listener.accept()
finally:
self.listener.close()
try:
data = sock.makefile().read()
finally:
sock.close()
return -1 if data == b"" else int(data)


@pytest.mark.parametrize("run_as", ["program", "module", "code"])
@pytest.mark.parametrize("mode", ["normal", "abnormal", "normal+abnormal", ""])
@pytest.mark.parametrize("seperator", ["seperator", ""])
def test_launcher_parser(mode, seperator, run_as):
@pytest.mark.parametrize("port", ["12345", ""])
def test_launcher_parser(mode, seperator, run_as, port):
args = []

switch = mode.split("+")
Expand All @@ -31,9 +53,13 @@ def test_launcher_parser(mode, seperator, run_as):
if "abnormal" in switch:
args += [launcher.WAIT_ON_ABNORMAL_SWITCH]

if port:
args += [launcher.INTERNAL_PORT_SWITCH, port]

if seperator:
args += ["--"]


if run_as == "file":
expected = ["myscript.py", "--arg1", "--arg2", "--arg3", "--", "more args"]
elif run_as == "module":
Expand Down Expand Up @@ -67,12 +93,17 @@ def code_to_run():

switch = mode.split("+")

pid_server = ReceivePid()
_, port = pid_server.start_server()

if "normal" in switch:
args += [launcher.WAIT_ON_NORMAL_SWITCH]

if "abnormal" in switch:
args += [launcher.WAIT_ON_ABNORMAL_SWITCH]

args += [launcher.INTERNAL_PORT_SWITCH, str(port)]

args += ["--"]

if run_as == "file":
Expand Down Expand Up @@ -110,6 +141,8 @@ def code_to_run():
stdout=subprocess.PIPE,
)

assert pid_server.wait_for_pid() >= -1

if wait_for_user:
outstr = b""
while not outstr.endswith(b". . . "):
Expand Down

0 comments on commit 9ece432

Please sign in to comment.