Skip to content

[lldb-dap] Added "port" property to vscode "attach" command. #91570

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 44 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
960351c
[lldb][test] Add the ability to extract the variable value out of the…
Nov 17, 2023
94c7680
Merge branch 'llvm:main' into main
santhoshe447 Nov 17, 2023
3235090
Merge branch 'llvm:main' into main
santhoshe447 Dec 12, 2023
ff9077f
Merge branch 'llvm:main' into main
santhoshe447 Dec 12, 2023
fa762d2
Merge branch 'llvm:main' into main
santhoshe447 Dec 12, 2023
09ff158
Merge branch 'llvm:main' into main
santhoshe447 May 3, 2024
ab44a69
[lldb-dap] Added "port" property to vscode "attach" command.
May 3, 2024
ef4f016
Merge branch 'llvm:main' into main
santhoshe447 May 3, 2024
35ba7f7
Merge branch 'llvm:main' into main
santhoshe447 May 6, 2024
bd38f88
Merge branch 'llvm:main' into main
santhoshe447 May 7, 2024
f65a580
Merge branch 'llvm:main' into main
santhoshe447 May 7, 2024
5763225
Merge branch 'llvm:main' into main
santhoshe447 May 7, 2024
bb18d6d
Merge branch 'llvm:main' into main
santhoshe447 May 7, 2024
1b1ae2b
Merge branch 'llvm:main' into main
santhoshe447 May 7, 2024
a2e4580
Merge branch 'llvm:main' into main
santhoshe447 May 8, 2024
3795dcd
Merge branch 'llvm:main' into main
santhoshe447 May 8, 2024
628fa40
Merge branch 'llvm:main' into main
santhoshe447 May 8, 2024
4e2e524
[lldb-dap] Added "port" property to vscode "attach" command.
May 8, 2024
4774f58
Merge branch 'llvm:main' into main
santhoshe447 May 9, 2024
175f1d3
[lldb-dap] Added "port" property to vscode "attach" command.
May 9, 2024
a6e9f66
Merge branch 'llvm:main' into main
santhoshe447 May 9, 2024
e5c0aed
Resolved code format issue.
May 9, 2024
c502203
Resolved code format errors.
May 9, 2024
89800a8
Merge branch 'llvm:main' into main
santhoshe447 May 15, 2024
c1bf2bd
[lldb-dap] Added "port" property to vscode "attach" command - Address…
May 15, 2024
5590afc
[lldb-dap] Added "port" property to vscode "attach" command - fix cod…
May 15, 2024
afcce33
Merge branch 'llvm:main' into main
santhoshe447 May 20, 2024
281c281
Merge branch 'llvm:main' into main
santhoshe447 May 24, 2024
624b789
Merge branch 'llvm:main' into main
santhoshe447 May 28, 2024
023b51e
[lldb-dap] Added "port" property to vscode "attach" command - resolve…
May 28, 2024
d19eb88
[lldb-dap] Added "port" property to vscode "attach" command -resolved…
May 28, 2024
16c37cd
Merge branch 'llvm:main' into main
santhoshe447 May 30, 2024
599a5ca
Merge branch 'llvm:main' into main
santhoshe447 May 30, 2024
fe9a4b6
[lldb-dap] Added "port" property to vscode "attach" command. #91570
May 30, 2024
c91b02d
[lldb-dap] Added "port" property to vscode "attach" command.
May 30, 2024
35ad541
Merge branch 'llvm:main' into main
santhoshe447 Jun 4, 2024
8e3f3a5
Merge branch 'llvm:main' into main
santhoshe447 Jun 4, 2024
de29728
[lldb-dap] Added "port" property to vscode "attach" command - address…
Jun 4, 2024
ac84b53
[lldb-dap] Added "port" property to vscode "attach" command - resolve…
Jun 4, 2024
7d1319c
Merge branch 'llvm:main' into main
santhoshe447 Jun 7, 2024
2a0eb9d
Merge branch 'llvm:main' into main
santhoshe447 Jun 10, 2024
08f40aa
[lldb-dap] Added "port" property to vscode "attach" command - fixed …
Jun 10, 2024
2a0bc63
[lldb-dap] Added "port" property to vscode "attach" command - resolve…
Jun 10, 2024
656c34a
[lldb-dap] Added "port" property to vscode "attach" command.
Jun 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,8 @@ def request_attach(
coreFile=None,
postRunCommands=None,
sourceMap=None,
gdbRemotePort=None,
gdbRemoteHostname=None,
):
args_dict = {}
if pid is not None:
Expand Down Expand Up @@ -601,6 +603,10 @@ def request_attach(
args_dict["postRunCommands"] = postRunCommands
if sourceMap:
args_dict["sourceMap"] = sourceMap
if gdbRemotePort is not None:
args_dict["gdb-remote-port"] = gdbRemotePort
if gdbRemoteHostname is not None:
args_dict["gdb-remote-hostname"] = gdbRemoteHostname
command_dict = {"command": "attach", "type": "request", "arguments": args_dict}
return self.send_recv(command_dict)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

import dap_server
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbplatformutil
import lldbgdbserverutils


class DAPTestCaseBase(TestBase):
Expand Down Expand Up @@ -297,6 +299,8 @@ def attach(
sourceMap=None,
sourceInitFile=False,
expectFailure=False,
gdbRemotePort=None,
gdbRemoteHostname=None,
):
"""Build the default Makefile target, create the DAP debug adaptor,
and attach to the process.
Expand Down Expand Up @@ -327,6 +331,8 @@ def cleanup():
coreFile=coreFile,
postRunCommands=postRunCommands,
sourceMap=sourceMap,
gdbRemotePort=gdbRemotePort,
gdbRemoteHostname=gdbRemoteHostname,
)
if expectFailure:
return response
Expand Down Expand Up @@ -483,3 +489,18 @@ def build_and_launch(
launchCommands=launchCommands,
expectFailure=expectFailure,
)

def getBuiltinDebugServerTool(self):
# Tries to find simulation/lldb-server/gdbserver tool path.
server_tool = None
if lldbplatformutil.getPlatform() == "linux":
server_tool = lldbgdbserverutils.get_lldb_server_exe()
if server_tool is None:
self.dap_server.request_disconnect(terminateDebuggee=True)
self.assertIsNotNone(server_tool, "lldb-server not found.")
elif lldbplatformutil.getPlatform() == "macosx":
server_tool = lldbgdbserverutils.get_debugserver_exe()
if server_tool is None:
self.dap_server.request_disconnect(terminateDebuggee=True)
self.assertIsNotNone(server_tool, "debugserver not found.")
return server_tool
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from lldbsuite.test import configuration
from textwrap import dedent
import shutil
import select


def _get_support_exe(basename):
Expand Down Expand Up @@ -969,3 +970,148 @@ def __str__(self):
self._output_queue,
self._accumulated_output,
)


# A class representing a pipe for communicating with debug server.
# This class includes menthods to open the pipe and read the port number from it.
if lldbplatformutil.getHostPlatform() == "windows":
import ctypes
import ctypes.wintypes
from ctypes.wintypes import BOOL, DWORD, HANDLE, LPCWSTR, LPDWORD, LPVOID

kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)

PIPE_ACCESS_INBOUND = 1
FILE_FLAG_FIRST_PIPE_INSTANCE = 0x00080000
FILE_FLAG_OVERLAPPED = 0x40000000
PIPE_TYPE_BYTE = 0
PIPE_REJECT_REMOTE_CLIENTS = 8
INVALID_HANDLE_VALUE = -1
ERROR_ACCESS_DENIED = 5
ERROR_IO_PENDING = 997

class OVERLAPPED(ctypes.Structure):
_fields_ = [
("Internal", LPVOID),
("InternalHigh", LPVOID),
("Offset", DWORD),
("OffsetHigh", DWORD),
("hEvent", HANDLE),
]

def __init__(self):
super(OVERLAPPED, self).__init__(
Internal=0, InternalHigh=0, Offset=0, OffsetHigh=0, hEvent=None
)

LPOVERLAPPED = ctypes.POINTER(OVERLAPPED)

CreateNamedPipe = kernel32.CreateNamedPipeW
CreateNamedPipe.restype = HANDLE
CreateNamedPipe.argtypes = (
LPCWSTR,
DWORD,
DWORD,
DWORD,
DWORD,
DWORD,
DWORD,
LPVOID,
)

ConnectNamedPipe = kernel32.ConnectNamedPipe
ConnectNamedPipe.restype = BOOL
ConnectNamedPipe.argtypes = (HANDLE, LPOVERLAPPED)

CreateEvent = kernel32.CreateEventW
CreateEvent.restype = HANDLE
CreateEvent.argtypes = (LPVOID, BOOL, BOOL, LPCWSTR)

GetOverlappedResultEx = kernel32.GetOverlappedResultEx
GetOverlappedResultEx.restype = BOOL
GetOverlappedResultEx.argtypes = (HANDLE, LPOVERLAPPED, LPDWORD, DWORD, BOOL)

ReadFile = kernel32.ReadFile
ReadFile.restype = BOOL
ReadFile.argtypes = (HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED)

CloseHandle = kernel32.CloseHandle
CloseHandle.restype = BOOL
CloseHandle.argtypes = (HANDLE,)

class Pipe(object):
def __init__(self, prefix):
while True:
self.name = "lldb-" + str(random.randrange(1e10))
full_name = "\\\\.\\pipe\\" + self.name
self._handle = CreateNamedPipe(
full_name,
PIPE_ACCESS_INBOUND
| FILE_FLAG_FIRST_PIPE_INSTANCE
| FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_REJECT_REMOTE_CLIENTS,
1,
4096,
4096,
0,
None,
)
if self._handle != INVALID_HANDLE_VALUE:
break
if ctypes.get_last_error() != ERROR_ACCESS_DENIED:
raise ctypes.WinError(ctypes.get_last_error())

self._overlapped = OVERLAPPED()
self._overlapped.hEvent = CreateEvent(None, True, False, None)
result = ConnectNamedPipe(self._handle, self._overlapped)
assert result == 0
if ctypes.get_last_error() != ERROR_IO_PENDING:
raise ctypes.WinError(ctypes.get_last_error())

def finish_connection(self, timeout):
if not GetOverlappedResultEx(
self._handle,
self._overlapped,
ctypes.byref(DWORD(0)),
timeout * 1000,
True,
):
raise ctypes.WinError(ctypes.get_last_error())

def read(self, size, timeout):
buf = ctypes.create_string_buffer(size)
if not ReadFile(
self._handle, ctypes.byref(buf), size, None, self._overlapped
):
if ctypes.get_last_error() != ERROR_IO_PENDING:
raise ctypes.WinError(ctypes.get_last_error())
read = DWORD(0)
if not GetOverlappedResultEx(
self._handle, self._overlapped, ctypes.byref(read), timeout * 1000, True
):
raise ctypes.WinError(ctypes.get_last_error())
return buf.raw[0 : read.value]

def close(self):
CloseHandle(self._overlapped.hEvent)
CloseHandle(self._handle)

else:

class Pipe(object):
def __init__(self, prefix):
self.name = os.path.join(prefix, "stub_port_number")
os.mkfifo(self.name)
self._fd = os.open(self.name, os.O_RDONLY | os.O_NONBLOCK)

def finish_connection(self, timeout):
pass

def read(self, size, timeout):
(readers, _, _) = select.select([self._fd], [], [], timeout)
if self._fd not in readers:
raise TimeoutError
return os.read(self._fd, size)

def close(self):
os.close(self._fd)
160 changes: 160 additions & 0 deletions lldb/test/API/tools/lldb-dap/attach/TestDAP_attachByPortNum.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
"""
Test lldb-dap "port" configuration to "attach" request
"""


import dap_server
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
from lldbsuite.test import lldbplatformutil
from lldbgdbserverutils import Pipe
import lldbdap_testcase
import os
import shutil
import subprocess
import tempfile
import threading
import sys
import socket


class TestDAP_attachByPortNum(lldbdap_testcase.DAPTestCaseBase):
default_timeout = 20

def set_and_hit_breakpoint(self, continueToExit=True):
source = "main.c"
main_source_path = os.path.join(os.getcwd(), source)
breakpoint1_line = line_number(main_source_path, "// breakpoint 1")
lines = [breakpoint1_line]
# Set breakpoint in the thread function so we can step the threads
breakpoint_ids = self.set_source_breakpoints(main_source_path, lines)
self.assertEqual(
len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
)
self.continue_to_breakpoints(breakpoint_ids)
if continueToExit:
self.continue_to_exit()

def get_debug_server_command_line_args(self):
args = []
if lldbplatformutil.getPlatform() == "linux":
args = ["gdbserver"]
elif lldbplatformutil.getPlatform() == "macosx":
args = ["--listen"]
if lldb.remote_platform:
args += ["*:0"]
else:
args += ["localhost:0"]
return args

def get_debug_server_pipe(self):
pipe = Pipe(self.getBuildDir())
self.addTearDownHook(lambda: pipe.close())
pipe.finish_connection(self.default_timeout)
return pipe

@skipIfWindows
@skipIfNetBSD
def test_by_port(self):
"""
Tests attaching to a process by port.
"""
self.build_and_create_debug_adaptor()
program = self.getBuildArtifact("a.out")

debug_server_tool = self.getBuiltinDebugServerTool()

pipe = self.get_debug_server_pipe()
args = self.get_debug_server_command_line_args()
args += [program]
args += ["--named-pipe", pipe.name]

self.process = self.spawnSubprocess(
debug_server_tool, args, install_remote=False
)

# Read the port number from the debug server pipe.
port = pipe.read(10, self.default_timeout)
# Trim null byte, convert to int
port = int(port[:-1])
self.assertIsNotNone(
port, " Failed to read the port number from debug server pipe"
)

self.attach(program=program, gdbRemotePort=port, sourceInitFile=True)
self.set_and_hit_breakpoint(continueToExit=True)
self.process.terminate()

@skipIfWindows
@skipIfNetBSD
def test_by_port_and_pid(self):
"""
Tests attaching to a process by process ID and port number.
"""
self.build_and_create_debug_adaptor()
program = self.getBuildArtifact("a.out")

# It is not necessary to launch "lldb-server" to obtain the actual port and pid for attaching.
# However, when providing the port number and pid directly, "lldb-dap" throws an error message, which is expected.
# So, used random pid and port numbers here.

pid = 1354
port = 1234

response = self.attach(
program=program,
pid=pid,
gdbRemotePort=port,
sourceInitFile=True,
expectFailure=True,
)
if not (response and response["success"]):
self.assertFalse(
response["success"], "The user can't specify both pid and port"
)

@skipIfWindows
@skipIfNetBSD
def test_by_invalid_port(self):
"""
Tests attaching to a process by invalid port number 0.
"""
self.build_and_create_debug_adaptor()
program = self.getBuildArtifact("a.out")

port = 0
response = self.attach(
program=program, gdbRemotePort=port, sourceInitFile=True, expectFailure=True
)
if not (response and response["success"]):
self.assertFalse(
response["success"],
"The user can't attach with invalid port (%s)" % port,
)

@skipIfWindows
@skipIfNetBSD
def test_by_illegal_port(self):
"""
Tests attaching to a process by illegal/greater port number 65536
"""
self.build_and_create_debug_adaptor()
program = self.getBuildArtifact("a.out")

port = 65536
args = [program]
debug_server_tool = self.getBuiltinDebugServerTool()
self.process = self.spawnSubprocess(
debug_server_tool, args, install_remote=False
)

response = self.attach(
program=program, gdbRemotePort=port, sourceInitFile=True, expectFailure=True
)
if not (response and response["success"]):
self.assertFalse(
response["success"],
"The user can't attach with illegal port (%s)" % port,
)
self.process.terminate()
Loading
Loading