aboutsummaryrefslogtreecommitdiff
path: root/lldb
diff options
context:
space:
mode:
Diffstat (limited to 'lldb')
-rwxr-xr-xlldb/examples/python/performance.py9
-rw-r--r--lldb/examples/summaries/cocoa/CFString.py7
-rw-r--r--lldb/include/lldb/Utility/AnsiTerminal.h11
-rw-r--r--lldb/include/lldb/Utility/XcodeSDK.h2
-rw-r--r--lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py55
-rw-r--r--lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py79
-rw-r--r--lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py1
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp27
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h9
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp2
-rw-r--r--lldb/source/Utility/XcodeSDK.cpp10
-rw-r--r--lldb/test/API/commands/expression/import-std-module/array/TestArrayFromStdModule.py3
-rw-r--r--lldb/test/API/tools/lldb-dap/attach-commands/TestDAP_attachCommands.py6
-rw-r--r--lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py4
-rw-r--r--lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py2
-rw-r--r--lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py2
-rw-r--r--lldb/test/API/tools/lldb-dap/io/TestDAP_io.py10
-rw-r--r--lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py22
-rw-r--r--lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py12
-rw-r--r--lldb/test/API/tools/lldb-dap/module/TestDAP_module.py4
-rw-r--r--lldb/test/API/tools/lldb-dap/output/TestDAP_output.py2
-rw-r--r--lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_console.py2
-rw-r--r--lldb/tools/lldb-dap/Handler/RequestHandler.cpp4
-rw-r--r--lldb/tools/lldb-dap/JSONUtils.cpp15
-rw-r--r--lldb/tools/lldb-dap/JSONUtils.h7
-rw-r--r--lldb/tools/lldb-dap/Options.td6
-rw-r--r--lldb/tools/lldb-dap/Protocol/ProtocolRequests.h1
-rw-r--r--lldb/tools/lldb-dap/package.json5
-rw-r--r--lldb/tools/lldb-dap/tool/lldb-dap.cpp98
-rw-r--r--lldb/unittests/Utility/XcodeSDKTest.cpp1
-rw-r--r--lldb/utils/lui/lldbutil.py4
31 files changed, 278 insertions, 144 deletions
diff --git a/lldb/examples/python/performance.py b/lldb/examples/python/performance.py
index b86b5a5..c3181b6 100755
--- a/lldb/examples/python/performance.py
+++ b/lldb/examples/python/performance.py
@@ -16,7 +16,6 @@ import resource
import sys
import subprocess
import time
-import types
# ----------------------------------------------------------------------
# Code that auto imports LLDB
@@ -121,19 +120,19 @@ class BreakpointAction(Action):
self.breakpoints.append(breakpoint)
else:
if module:
- if isinstance(module, types.ListType):
+ if isinstance(module, list):
for module_path in module:
self.modules.Append(lldb.SBFileSpec(module_path, False))
- elif isinstance(module, types.StringTypes):
+ elif isinstance(module, str):
self.modules.Append(lldb.SBFileSpec(module, False))
if name:
# "file" can be a list or a string
if file:
- if isinstance(file, types.ListType):
+ if isinstance(file, list):
self.files = lldb.SBFileSpecList()
for f in file:
self.files.Append(lldb.SBFileSpec(f, False))
- elif isinstance(file, types.StringTypes):
+ elif isinstance(file, str):
self.files.Append(lldb.SBFileSpec(file, False))
self.breakpoints.append(
self.target.BreakpointCreateByName(name, self.modules, self.files)
diff --git a/lldb/examples/summaries/cocoa/CFString.py b/lldb/examples/summaries/cocoa/CFString.py
index 74bd927..02b6706 100644
--- a/lldb/examples/summaries/cocoa/CFString.py
+++ b/lldb/examples/summaries/cocoa/CFString.py
@@ -11,11 +11,6 @@ import lldb
import lldb.runtime.objc.objc_runtime
import lldb.formatters.Logger
-try:
- unichr
-except NameError:
- unichr = chr
-
def CFString_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger()
@@ -107,7 +102,7 @@ class CFStringSynthProvider:
value = b1 * 256 + b0
else:
value = b0 * 256 + b1
- pystr = pystr + unichr(value)
+ pystr = pystr + chr(value)
# read max_len unicode values, not max_len bytes
max_len = max_len - 1
return pystr
diff --git a/lldb/include/lldb/Utility/AnsiTerminal.h b/lldb/include/lldb/Utility/AnsiTerminal.h
index 41acac7..aaaf94c 100644
--- a/lldb/include/lldb/Utility/AnsiTerminal.h
+++ b/lldb/include/lldb/Utility/AnsiTerminal.h
@@ -72,6 +72,17 @@
#define ANSI_ESC_START_LEN 2
+// Cursor Position, set cursor to position [l, c] (default = [1, 1]).
+#define ANSI_CSI_CUP(...) ANSI_ESC_START #__VA_ARGS__ "H"
+// Reset cursor to position.
+#define ANSI_CSI_RESET_CURSOR ANSI_CSI_CUP()
+// Erase In Display.
+#define ANSI_CSI_ED(opt) ANSI_ESC_START #opt "J"
+// Erase complete viewport.
+#define ANSI_CSI_ERASE_VIEWPORT ANSI_CSI_ED(2)
+// Erase scrollback.
+#define ANSI_CSI_ERASE_SCROLLBACK ANSI_CSI_ED(3)
+
// OSC (Operating System Commands)
// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
#define OSC_ESCAPE_START "\033"
diff --git a/lldb/include/lldb/Utility/XcodeSDK.h b/lldb/include/lldb/Utility/XcodeSDK.h
index 5b345a4..5f89019 100644
--- a/lldb/include/lldb/Utility/XcodeSDK.h
+++ b/lldb/include/lldb/Utility/XcodeSDK.h
@@ -38,7 +38,7 @@ public:
watchOS,
XRSimulator,
XROS,
- bridgeOS,
+ BridgeOS,
Linux,
unknown = -1
};
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
index 8eb64b4..a3d924d 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
@@ -27,6 +27,10 @@ from typing import (
Literal,
)
+# set timeout based on whether ASAN was enabled or not. Increase
+# timeout by a factor of 10 if ASAN is enabled.
+DEFAULT_TIMEOUT = 10 * (10 if ("ASAN_OPTIONS" in os.environ) else 1)
+
## DAP type references
@@ -282,26 +286,24 @@ class DebugCommunication(object):
def collect_output(
self,
category: str,
- timeout: float,
pattern: Optional[str] = None,
clear=True,
) -> str:
"""Collect output from 'output' events.
Args:
category: The category to collect.
- timeout: The max duration for collecting output.
pattern:
Optional, if set, return once this pattern is detected in the
collected output.
Returns:
The collected output.
"""
- deadline = time.monotonic() + timeout
+ deadline = time.monotonic() + DEFAULT_TIMEOUT
output = self.get_output(category, clear)
while deadline >= time.monotonic() and (
pattern is None or pattern not in output
):
- event = self.wait_for_event(["output"], timeout=deadline - time.monotonic())
+ event = self.wait_for_event(["output"])
if not event: # Timeout or EOF
break
output += self.get_output(category, clear=clear)
@@ -339,7 +341,7 @@ class DebugCommunication(object):
self,
*,
predicate: Optional[Callable[[ProtocolMessage], bool]] = None,
- timeout: Optional[float] = None,
+ timeout: Optional[float] = DEFAULT_TIMEOUT,
) -> Optional[ProtocolMessage]:
"""Processes received packets from the adapter.
Updates the DebugCommunication stateful properties based on the received
@@ -555,25 +557,20 @@ class DebugCommunication(object):
return cast(Optional[Response], self._recv_packet(predicate=predicate))
- def wait_for_event(
- self, filter: List[str] = [], timeout: Optional[float] = None
- ) -> Optional[Event]:
+ def wait_for_event(self, filter: List[str] = []) -> Optional[Event]:
"""Wait for the first event that matches the filter."""
def predicate(p: ProtocolMessage):
return p["type"] == "event" and p["event"] in filter
return cast(
- Optional[Event], self._recv_packet(predicate=predicate, timeout=timeout)
+ Optional[Event],
+ self._recv_packet(predicate=predicate),
)
- def wait_for_stopped(
- self, timeout: Optional[float] = None
- ) -> Optional[List[Event]]:
+ def wait_for_stopped(self) -> Optional[List[Event]]:
stopped_events = []
- stopped_event = self.wait_for_event(
- filter=["stopped", "exited"], timeout=timeout
- )
+ stopped_event = self.wait_for_event(filter=["stopped", "exited"])
while stopped_event:
stopped_events.append(stopped_event)
# If we exited, then we are done
@@ -582,26 +579,28 @@ class DebugCommunication(object):
# Otherwise we stopped and there might be one or more 'stopped'
# events for each thread that stopped with a reason, so keep
# checking for more 'stopped' events and return all of them
- stopped_event = self.wait_for_event(
- filter=["stopped", "exited"], timeout=0.25
+ # Use a shorter timeout for additional stopped events
+ def predicate(p: ProtocolMessage):
+ return p["type"] == "event" and p["event"] in ["stopped", "exited"]
+
+ stopped_event = cast(
+ Optional[Event], self._recv_packet(predicate=predicate, timeout=0.25)
)
return stopped_events
- def wait_for_breakpoint_events(self, timeout: Optional[float] = None):
+ def wait_for_breakpoint_events(self):
breakpoint_events: list[Event] = []
while True:
- event = self.wait_for_event(["breakpoint"], timeout=timeout)
+ event = self.wait_for_event(["breakpoint"])
if not event:
break
breakpoint_events.append(event)
return breakpoint_events
- def wait_for_breakpoints_to_be_verified(
- self, breakpoint_ids: list[str], timeout: Optional[float] = None
- ):
+ def wait_for_breakpoints_to_be_verified(self, breakpoint_ids: list[str]):
"""Wait for all breakpoints to be verified. Return all unverified breakpoints."""
while any(id not in self.resolved_breakpoints for id in breakpoint_ids):
- breakpoint_event = self.wait_for_event(["breakpoint"], timeout=timeout)
+ breakpoint_event = self.wait_for_event(["breakpoint"])
if breakpoint_event is None:
break
@@ -614,14 +613,14 @@ class DebugCommunication(object):
)
]
- def wait_for_exited(self, timeout: Optional[float] = None):
- event_dict = self.wait_for_event(["exited"], timeout=timeout)
+ def wait_for_exited(self):
+ event_dict = self.wait_for_event(["exited"])
if event_dict is None:
raise ValueError("didn't get exited event")
return event_dict
- def wait_for_terminated(self, timeout: Optional[float] = None):
- event_dict = self.wait_for_event(["terminated"], timeout)
+ def wait_for_terminated(self):
+ event_dict = self.wait_for_event(["terminated"])
if event_dict is None:
raise ValueError("didn't get terminated event")
return event_dict
@@ -1610,7 +1609,7 @@ class DebugAdapterServer(DebugCommunication):
# new messages will arrive and it should shutdown on its
# own.
process.stdin.close()
- process.wait(timeout=20)
+ process.wait(timeout=DEFAULT_TIMEOUT)
except subprocess.TimeoutExpired:
process.kill()
process.wait()
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
index f7b1ed8..29935bb 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
@@ -18,7 +18,7 @@ import base64
class DAPTestCaseBase(TestBase):
# set timeout based on whether ASAN was enabled or not. Increase
# timeout by a factor of 10 if ASAN is enabled.
- DEFAULT_TIMEOUT = 10 * (10 if ("ASAN_OPTIONS" in os.environ) else 1)
+ DEFAULT_TIMEOUT = dap_server.DEFAULT_TIMEOUT
NO_DEBUG_INFO_TESTCASE = True
def create_debug_adapter(
@@ -118,11 +118,9 @@ class DAPTestCaseBase(TestBase):
self.wait_for_breakpoints_to_resolve(breakpoint_ids)
return breakpoint_ids
- def wait_for_breakpoints_to_resolve(
- self, breakpoint_ids: list[str], timeout: Optional[float] = DEFAULT_TIMEOUT
- ):
+ def wait_for_breakpoints_to_resolve(self, breakpoint_ids: list[str]):
unresolved_breakpoints = self.dap_server.wait_for_breakpoints_to_be_verified(
- breakpoint_ids, timeout
+ breakpoint_ids
)
self.assertEqual(
len(unresolved_breakpoints),
@@ -134,11 +132,10 @@ class DAPTestCaseBase(TestBase):
self,
predicate: Callable[[], bool],
delay: float = 0.5,
- timeout: float = DEFAULT_TIMEOUT,
) -> bool:
"""Repeatedly run the predicate until either the predicate returns True
or a timeout has occurred."""
- deadline = time.monotonic() + timeout
+ deadline = time.monotonic() + self.DEFAULT_TIMEOUT
while deadline > time.monotonic():
if predicate():
return True
@@ -155,15 +152,13 @@ class DAPTestCaseBase(TestBase):
if key in self.dap_server.capabilities:
self.assertEqual(self.dap_server.capabilities[key], False, msg)
- def verify_breakpoint_hit(
- self, breakpoint_ids: List[Union[int, str]], timeout: float = DEFAULT_TIMEOUT
- ):
+ def verify_breakpoint_hit(self, breakpoint_ids: List[Union[int, str]]):
"""Wait for the process we are debugging to stop, and verify we hit
any breakpoint location in the "breakpoint_ids" array.
"breakpoint_ids" should be a list of breakpoint ID strings
(["1", "2"]). The return value from self.set_source_breakpoints()
or self.set_function_breakpoints() can be passed to this function"""
- stopped_events = self.dap_server.wait_for_stopped(timeout)
+ stopped_events = self.dap_server.wait_for_stopped()
normalized_bp_ids = [str(b) for b in breakpoint_ids]
for stopped_event in stopped_events:
if "body" in stopped_event:
@@ -186,11 +181,11 @@ class DAPTestCaseBase(TestBase):
f"breakpoint not hit, wanted breakpoint_ids {breakpoint_ids} in stopped_events {stopped_events}",
)
- def verify_all_breakpoints_hit(self, breakpoint_ids, timeout=DEFAULT_TIMEOUT):
+ def verify_all_breakpoints_hit(self, breakpoint_ids):
"""Wait for the process we are debugging to stop, and verify we hit
all of the breakpoint locations in the "breakpoint_ids" array.
"breakpoint_ids" should be a list of int breakpoint IDs ([1, 2])."""
- stopped_events = self.dap_server.wait_for_stopped(timeout)
+ stopped_events = self.dap_server.wait_for_stopped()
for stopped_event in stopped_events:
if "body" in stopped_event:
body = stopped_event["body"]
@@ -208,12 +203,12 @@ class DAPTestCaseBase(TestBase):
return
self.assertTrue(False, f"breakpoints not hit, stopped_events={stopped_events}")
- def verify_stop_exception_info(self, expected_description, timeout=DEFAULT_TIMEOUT):
+ def verify_stop_exception_info(self, expected_description):
"""Wait for the process we are debugging to stop, and verify the stop
reason is 'exception' and that the description matches
'expected_description'
"""
- stopped_events = self.dap_server.wait_for_stopped(timeout)
+ stopped_events = self.dap_server.wait_for_stopped()
for stopped_event in stopped_events:
if "body" in stopped_event:
body = stopped_event["body"]
@@ -338,26 +333,14 @@ class DAPTestCaseBase(TestBase):
def get_important(self):
return self.dap_server.get_output("important")
- def collect_stdout(
- self, timeout: float = DEFAULT_TIMEOUT, pattern: Optional[str] = None
- ) -> str:
- return self.dap_server.collect_output(
- "stdout", timeout=timeout, pattern=pattern
- )
+ def collect_stdout(self, pattern: Optional[str] = None) -> str:
+ return self.dap_server.collect_output("stdout", pattern=pattern)
- def collect_console(
- self, timeout: float = DEFAULT_TIMEOUT, pattern: Optional[str] = None
- ) -> str:
- return self.dap_server.collect_output(
- "console", timeout=timeout, pattern=pattern
- )
+ def collect_console(self, pattern: Optional[str] = None) -> str:
+ return self.dap_server.collect_output("console", pattern=pattern)
- def collect_important(
- self, timeout: float = DEFAULT_TIMEOUT, pattern: Optional[str] = None
- ) -> str:
- return self.dap_server.collect_output(
- "important", timeout=timeout, pattern=pattern
- )
+ def collect_important(self, pattern: Optional[str] = None) -> str:
+ return self.dap_server.collect_output("important", pattern=pattern)
def get_local_as_int(self, name, threadId=None):
value = self.dap_server.get_local_variable_value(name, threadId=threadId)
@@ -393,14 +376,13 @@ class DAPTestCaseBase(TestBase):
targetId=None,
waitForStop=True,
granularity="statement",
- timeout=DEFAULT_TIMEOUT,
):
response = self.dap_server.request_stepIn(
threadId=threadId, targetId=targetId, granularity=granularity
)
self.assertTrue(response["success"])
if waitForStop:
- return self.dap_server.wait_for_stopped(timeout)
+ return self.dap_server.wait_for_stopped()
return None
def stepOver(
@@ -408,7 +390,6 @@ class DAPTestCaseBase(TestBase):
threadId=None,
waitForStop=True,
granularity="statement",
- timeout=DEFAULT_TIMEOUT,
):
response = self.dap_server.request_next(
threadId=threadId, granularity=granularity
@@ -417,40 +398,40 @@ class DAPTestCaseBase(TestBase):
response["success"], f"next request failed: response {response}"
)
if waitForStop:
- return self.dap_server.wait_for_stopped(timeout)
+ return self.dap_server.wait_for_stopped()
return None
- def stepOut(self, threadId=None, waitForStop=True, timeout=DEFAULT_TIMEOUT):
+ def stepOut(self, threadId=None, waitForStop=True):
self.dap_server.request_stepOut(threadId=threadId)
if waitForStop:
- return self.dap_server.wait_for_stopped(timeout)
+ return self.dap_server.wait_for_stopped()
return None
def do_continue(self): # `continue` is a keyword.
resp = self.dap_server.request_continue()
self.assertTrue(resp["success"], f"continue request failed: {resp}")
- def continue_to_next_stop(self, timeout=DEFAULT_TIMEOUT):
+ def continue_to_next_stop(self):
self.do_continue()
- return self.dap_server.wait_for_stopped(timeout)
+ return self.dap_server.wait_for_stopped()
- def continue_to_breakpoint(self, breakpoint_id: str, timeout=DEFAULT_TIMEOUT):
- self.continue_to_breakpoints((breakpoint_id), timeout)
+ def continue_to_breakpoint(self, breakpoint_id: str):
+ self.continue_to_breakpoints((breakpoint_id))
- def continue_to_breakpoints(self, breakpoint_ids, timeout=DEFAULT_TIMEOUT):
+ def continue_to_breakpoints(self, breakpoint_ids):
self.do_continue()
- self.verify_breakpoint_hit(breakpoint_ids, timeout)
+ self.verify_breakpoint_hit(breakpoint_ids)
- def continue_to_exception_breakpoint(self, filter_label, timeout=DEFAULT_TIMEOUT):
+ def continue_to_exception_breakpoint(self, filter_label):
self.do_continue()
self.assertTrue(
- self.verify_stop_exception_info(filter_label, timeout),
+ self.verify_stop_exception_info(filter_label),
'verify we got "%s"' % (filter_label),
)
- def continue_to_exit(self, exitCode=0, timeout=DEFAULT_TIMEOUT):
+ def continue_to_exit(self, exitCode=0):
self.do_continue()
- stopped_events = self.dap_server.wait_for_stopped(timeout)
+ stopped_events = self.dap_server.wait_for_stopped()
self.assertEqual(
len(stopped_events), 1, "stopped_events = {}".format(stopped_events)
)
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
index aea6b9f..5ba642b 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
@@ -931,6 +931,7 @@ class GdbRemoteTestCaseBase(Base, metaclass=GdbRemoteTestCaseFactory):
"QNonStop",
"SupportedWatchpointTypes",
"SupportedCompressions",
+ "MultiMemRead",
]
def parse_qSupported_response(self, context):
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
index 6d8f41a..460c503 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
@@ -260,6 +260,7 @@ bool ClassDescriptorV2::method_list_t::Read(Process *process,
uint32_t entsize = extractor.GetU32_unchecked(&cursor);
m_is_small = (entsize & 0x80000000) != 0;
m_has_direct_selector = (entsize & 0x40000000) != 0;
+ m_has_relative_types = (entsize & 0x20000000) != 0;
m_entsize = entsize & 0xfffc;
m_count = extractor.GetU32_unchecked(&cursor);
m_first_ptr = addr + cursor;
@@ -269,8 +270,9 @@ bool ClassDescriptorV2::method_list_t::Read(Process *process,
llvm::SmallVector<ClassDescriptorV2::method_t, 0>
ClassDescriptorV2::ReadMethods(llvm::ArrayRef<lldb::addr_t> addresses,
- lldb::addr_t relative_selector_base_addr,
- bool is_small, bool has_direct_sel) const {
+ lldb::addr_t relative_string_base_addr,
+ bool is_small, bool has_direct_sel,
+ bool has_relative_types) const {
lldb_private::Process *process = m_runtime.GetProcess();
if (!process)
return {};
@@ -297,8 +299,8 @@ ClassDescriptorV2::ReadMethods(llvm::ArrayRef<lldb::addr_t> addresses,
process->GetByteOrder(),
process->GetAddressByteSize());
methods.push_back(method_t());
- methods.back().Read(extractor, process, addr, relative_selector_base_addr,
- is_small, has_direct_sel);
+ methods.back().Read(extractor, process, addr, relative_string_base_addr,
+ is_small, has_direct_sel, has_relative_types);
}
return methods;
@@ -306,8 +308,9 @@ ClassDescriptorV2::ReadMethods(llvm::ArrayRef<lldb::addr_t> addresses,
bool ClassDescriptorV2::method_t::Read(DataExtractor &extractor,
Process *process, lldb::addr_t addr,
- lldb::addr_t relative_selector_base_addr,
- bool is_small, bool has_direct_sel) {
+ lldb::addr_t relative_string_base_addr,
+ bool is_small, bool has_direct_sel,
+ bool has_relative_types) {
lldb::offset_t cursor = 0;
if (is_small) {
@@ -323,10 +326,13 @@ bool ClassDescriptorV2::method_t::Read(DataExtractor &extractor,
m_name_ptr = process->ReadPointerFromMemory(m_name_ptr, error);
if (error.Fail())
return false;
- } else if (relative_selector_base_addr != LLDB_INVALID_ADDRESS) {
- m_name_ptr = relative_selector_base_addr + nameref_offset;
+ } else if (relative_string_base_addr != LLDB_INVALID_ADDRESS) {
+ m_name_ptr = relative_string_base_addr + nameref_offset;
}
- m_types_ptr = addr + 4 + types_offset;
+ if (has_relative_types)
+ m_types_ptr = relative_string_base_addr + types_offset;
+ else
+ m_types_ptr = addr + 4 + types_offset;
m_imp_ptr = addr + 8 + imp_offset;
} else {
m_name_ptr = extractor.GetAddress_unchecked(&cursor);
@@ -481,7 +487,8 @@ bool ClassDescriptorV2::ProcessMethodList(
llvm::SmallVector<method_t, 0> methods =
ReadMethods(addresses, m_runtime.GetRelativeSelectorBaseAddr(),
- method_list.m_is_small, method_list.m_has_direct_selector);
+ method_list.m_is_small, method_list.m_has_direct_selector,
+ method_list.m_has_relative_types);
for (const auto &method : methods)
if (instance_method_func(method.m_name.c_str(), method.m_types.c_str()))
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
index 78b3311..0fff9af 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
@@ -143,6 +143,7 @@ private:
uint16_t m_entsize;
bool m_is_small;
bool m_has_direct_selector;
+ bool m_has_relative_types;
uint32_t m_count;
lldb::addr_t m_first_ptr;
@@ -173,14 +174,14 @@ private:
}
bool Read(DataExtractor &extractor, Process *process, lldb::addr_t addr,
- lldb::addr_t relative_selector_base_addr, bool is_small,
- bool has_direct_sel);
+ lldb::addr_t relative_string_base_addr, bool is_small,
+ bool has_direct_sel, bool has_relative_types);
};
llvm::SmallVector<method_t, 0>
ReadMethods(llvm::ArrayRef<lldb::addr_t> addresses,
- lldb::addr_t relative_selector_base_addr, bool is_small,
- bool has_direct_sel) const;
+ lldb::addr_t relative_string_base_addr, bool is_small,
+ bool has_direct_sel, bool has_relative_types) const;
struct ivar_list_t {
uint32_t m_entsize;
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
index cd72454..5aad447 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -1150,7 +1150,7 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType(
case XcodeSDK::Type::XRSimulator:
case XcodeSDK::Type::XROS:
// FIXME: Pass the right argument once it exists.
- case XcodeSDK::Type::bridgeOS:
+ case XcodeSDK::Type::BridgeOS:
case XcodeSDK::Type::Linux:
case XcodeSDK::Type::unknown:
if (Log *log = GetLog(LLDBLog::Host)) {
diff --git a/lldb/source/Utility/XcodeSDK.cpp b/lldb/source/Utility/XcodeSDK.cpp
index 2040791..89e05de 100644
--- a/lldb/source/Utility/XcodeSDK.cpp
+++ b/lldb/source/Utility/XcodeSDK.cpp
@@ -38,8 +38,8 @@ static llvm::StringRef GetName(XcodeSDK::Type type) {
return "XRSimulator";
case XcodeSDK::XROS:
return "XROS";
- case XcodeSDK::bridgeOS:
- return "bridgeOS";
+ case XcodeSDK::BridgeOS:
+ return "BridgeOS";
case XcodeSDK::Linux:
return "Linux";
case XcodeSDK::unknown:
@@ -83,8 +83,8 @@ static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) {
return XcodeSDK::XRSimulator;
if (name.consume_front("XROS"))
return XcodeSDK::XROS;
- if (name.consume_front("bridgeOS"))
- return XcodeSDK::bridgeOS;
+ if (name.consume_front("BridgeOS"))
+ return XcodeSDK::BridgeOS;
if (name.consume_front("Linux"))
return XcodeSDK::Linux;
static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1,
@@ -204,7 +204,7 @@ std::string XcodeSDK::GetCanonicalName(XcodeSDK::Info info) {
case XROS:
name = "xros";
break;
- case bridgeOS:
+ case BridgeOS:
name = "bridgeos";
break;
case Linux:
diff --git a/lldb/test/API/commands/expression/import-std-module/array/TestArrayFromStdModule.py b/lldb/test/API/commands/expression/import-std-module/array/TestArrayFromStdModule.py
index ed028a1..4aea800 100644
--- a/lldb/test/API/commands/expression/import-std-module/array/TestArrayFromStdModule.py
+++ b/lldb/test/API/commands/expression/import-std-module/array/TestArrayFromStdModule.py
@@ -11,6 +11,9 @@ class TestCase(TestBase):
@add_test_categories(["libc++"])
@skipIf(compiler=no_match("clang"))
@skipIf(macos_version=["<", "15.0"])
+ @skipIf(
+ bugnumber="ASTImport of lambdas not supported: https://github.com/llvm/llvm-project/issues/149477"
+ )
def test(self):
self.build()
diff --git a/lldb/test/API/tools/lldb-dap/attach-commands/TestDAP_attachCommands.py b/lldb/test/API/tools/lldb-dap/attach-commands/TestDAP_attachCommands.py
index ed373f2..9e29f07 100644
--- a/lldb/test/API/tools/lldb-dap/attach-commands/TestDAP_attachCommands.py
+++ b/lldb/test/API/tools/lldb-dap/attach-commands/TestDAP_attachCommands.py
@@ -71,7 +71,7 @@ class TestDAP_attachCommands(lldbdap_testcase.DAPTestCaseBase):
breakpoint_ids = self.set_function_breakpoints(functions)
self.assertEqual(len(breakpoint_ids), len(functions), "expect one breakpoint")
self.continue_to_breakpoints(breakpoint_ids)
- output = self.collect_console(timeout=10, pattern=stopCommands[-1])
+ output = self.collect_console(pattern=stopCommands[-1])
self.verify_commands("stopCommands", output, stopCommands)
# Continue after launch and hit the "pause()" call and stop the target.
@@ -81,7 +81,7 @@ class TestDAP_attachCommands(lldbdap_testcase.DAPTestCaseBase):
time.sleep(0.5)
self.dap_server.request_pause()
self.dap_server.wait_for_stopped()
- output = self.collect_console(timeout=10, pattern=stopCommands[-1])
+ output = self.collect_console(pattern=stopCommands[-1])
self.verify_commands("stopCommands", output, stopCommands)
# Continue until the program exits
@@ -90,7 +90,6 @@ class TestDAP_attachCommands(lldbdap_testcase.DAPTestCaseBase):
# "exitCommands" that were run after the second breakpoint was hit
# and the "terminateCommands" due to the debugging session ending
output = self.collect_console(
- timeout=10.0,
pattern=terminateCommands[0],
)
self.verify_commands("exitCommands", output, exitCommands)
@@ -141,7 +140,6 @@ class TestDAP_attachCommands(lldbdap_testcase.DAPTestCaseBase):
# "terminateCommands"
self.dap_server.request_disconnect(terminateDebuggee=True)
output = self.collect_console(
- timeout=1.0,
pattern=terminateCommands[0],
)
self.verify_commands("terminateCommands", output, terminateCommands)
diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py
index 151ad76..beab4d6 100644
--- a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py
+++ b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py
@@ -82,14 +82,14 @@ class TestDAP_breakpointEvents(lldbdap_testcase.DAPTestCaseBase):
)
# Flush the breakpoint events.
- self.dap_server.wait_for_breakpoint_events(timeout=5)
+ self.dap_server.wait_for_breakpoint_events()
# Continue to the breakpoint
self.continue_to_breakpoints(dap_breakpoint_ids)
verified_breakpoint_ids = []
unverified_breakpoint_ids = []
- for breakpoint_event in self.dap_server.wait_for_breakpoint_events(timeout=5):
+ for breakpoint_event in self.dap_server.wait_for_breakpoint_events():
breakpoint = breakpoint_event["body"]["breakpoint"]
id = breakpoint["id"]
if breakpoint["verified"]:
diff --git a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py
index e722fce..14789a6 100644
--- a/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py
+++ b/lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py
@@ -46,7 +46,7 @@ class TestDAP_cancel(lldbdap_testcase.DAPTestCaseBase):
# Use a relatively short timeout since this is only to ensure the
# following request is queued.
- blocking_seq = self.async_blocking_request(duration=1.0)
+ blocking_seq = self.async_blocking_request(duration=self.DEFAULT_TIMEOUT / 10)
# Use a longer timeout to ensure we catch if the request was interrupted
# properly.
pending_seq = self.async_blocking_request(duration=self.DEFAULT_TIMEOUT / 2)
diff --git a/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py b/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py
index e61d248..f53813a 100644
--- a/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py
+++ b/lldb/test/API/tools/lldb-dap/commands/TestDAP_commands.py
@@ -23,7 +23,6 @@ class TestDAP_commands(lldbdap_testcase.DAPTestCaseBase):
exitCommands=["?" + command_quiet, command_not_quiet],
)
full_output = self.collect_console(
- timeout=1.0,
pattern=command_not_quiet,
)
self.assertNotIn(command_quiet, full_output)
@@ -51,7 +50,6 @@ class TestDAP_commands(lldbdap_testcase.DAPTestCaseBase):
expectFailure=True,
)
full_output = self.collect_console(
- timeout=1.0,
pattern=command_abort_on_error,
)
self.assertNotIn(command_quiet, full_output)
diff --git a/lldb/test/API/tools/lldb-dap/io/TestDAP_io.py b/lldb/test/API/tools/lldb-dap/io/TestDAP_io.py
index af5c62a..9fbe9aa 100644
--- a/lldb/test/API/tools/lldb-dap/io/TestDAP_io.py
+++ b/lldb/test/API/tools/lldb-dap/io/TestDAP_io.py
@@ -44,7 +44,7 @@ class TestDAP_io(lldbdap_testcase.DAPTestCaseBase):
"""
process = self.launch()
process.stdin.close()
- self.assertEqual(process.wait(timeout=5.0), EXIT_SUCCESS)
+ self.assertEqual(process.wait(timeout=self.DEFAULT_TIMEOUT), EXIT_SUCCESS)
def test_invalid_header(self):
"""
@@ -54,7 +54,7 @@ class TestDAP_io(lldbdap_testcase.DAPTestCaseBase):
process = self.launch()
process.stdin.write(b"not the correct message header")
process.stdin.close()
- self.assertEqual(process.wait(timeout=5.0), EXIT_FAILURE)
+ self.assertEqual(process.wait(timeout=self.DEFAULT_TIMEOUT), EXIT_FAILURE)
def test_partial_header(self):
"""
@@ -64,7 +64,7 @@ class TestDAP_io(lldbdap_testcase.DAPTestCaseBase):
process = self.launch()
process.stdin.write(b"Content-Length: ")
process.stdin.close()
- self.assertEqual(process.wait(timeout=5.0), EXIT_FAILURE)
+ self.assertEqual(process.wait(timeout=self.DEFAULT_TIMEOUT), EXIT_FAILURE)
def test_incorrect_content_length(self):
"""
@@ -74,7 +74,7 @@ class TestDAP_io(lldbdap_testcase.DAPTestCaseBase):
process = self.launch()
process.stdin.write(b"Content-Length: abc")
process.stdin.close()
- self.assertEqual(process.wait(timeout=5.0), EXIT_FAILURE)
+ self.assertEqual(process.wait(timeout=self.DEFAULT_TIMEOUT), EXIT_FAILURE)
def test_partial_content_length(self):
"""
@@ -84,4 +84,4 @@ class TestDAP_io(lldbdap_testcase.DAPTestCaseBase):
process = self.launch()
process.stdin.write(b"Content-Length: 10\r\n\r\n{")
process.stdin.close()
- self.assertEqual(process.wait(timeout=5.0), EXIT_FAILURE)
+ self.assertEqual(process.wait(timeout=self.DEFAULT_TIMEOUT), EXIT_FAILURE)
diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py
index ceef95df..8db2316 100644
--- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py
+++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py
@@ -632,7 +632,27 @@ class TestDAP_launch(lldbdap_testcase.DAPTestCaseBase):
program = self.getBuildArtifact("a.out")
with tempfile.NamedTemporaryFile("rt") as f:
- self.launch(program, stdio=[None, f.name, None])
+ self.launch(program, stdio=[None, f.name])
+ self.continue_to_exit()
+ lines = f.readlines()
+ self.assertIn(
+ program, lines[0], "make sure program path is in first argument"
+ )
+
+ @skipIfAsan
+ @skipIfWindows
+ @skipIf(oslist=["linux"], archs=no_match(["x86_64"]))
+ def test_stdio_redirection_and_console(self):
+ """
+ Test stdio redirection and console.
+ """
+ self.build_and_create_debug_adapter()
+ program = self.getBuildArtifact("a.out")
+
+ with tempfile.NamedTemporaryFile("rt") as f:
+ self.launch(
+ program, console="integratedTerminal", stdio=[None, f.name, None]
+ )
self.continue_to_exit()
lines = f.readlines()
self.assertIn(
diff --git a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py
index bb835af..1f4afab 100644
--- a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py
+++ b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py
@@ -23,15 +23,15 @@ class TestDAP_module_event(lldbdap_testcase.DAPTestCaseBase):
self.continue_to_breakpoints(breakpoint_ids)
# We're now stopped at breakpoint 1 before the dlopen. Flush all the module events.
- event = self.dap_server.wait_for_event(["module"], 0.25)
+ event = self.dap_server.wait_for_event(["module"])
while event is not None:
- event = self.dap_server.wait_for_event(["module"], 0.25)
+ event = self.dap_server.wait_for_event(["module"])
# Continue to the second breakpoint, before the dlclose.
self.continue_to_breakpoints(breakpoint_ids)
# Make sure we got a module event for libother.
- event = self.dap_server.wait_for_event(["module"], 5)
+ event = self.dap_server.wait_for_event(["module"])
self.assertIsNotNone(event, "didn't get a module event")
module_name = event["body"]["module"]["name"]
module_id = event["body"]["module"]["id"]
@@ -42,7 +42,7 @@ class TestDAP_module_event(lldbdap_testcase.DAPTestCaseBase):
self.continue_to_breakpoints(breakpoint_ids)
# Make sure we got a module event for libother.
- event = self.dap_server.wait_for_event(["module"], 5)
+ event = self.dap_server.wait_for_event(["module"])
self.assertIsNotNone(event, "didn't get a module event")
reason = event["body"]["reason"]
self.assertEqual(reason, "removed")
@@ -55,8 +55,4 @@ class TestDAP_module_event(lldbdap_testcase.DAPTestCaseBase):
self.assertListEqual(list(module_data.keys()), required_keys)
self.assertEqual(module_data["name"], "", "expects empty name.")
- # Make sure we do not send another event
- event = self.dap_server.wait_for_event(["module"], 3)
- self.assertIsNone(event, "expects no events.")
-
self.continue_to_exit()
diff --git a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py
index c5a6837..0ed53da 100644
--- a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py
+++ b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py
@@ -67,7 +67,7 @@ class TestDAP_module(lldbdap_testcase.DAPTestCaseBase):
# Collect all the module names we saw as events.
module_new_names = []
module_changed_names = []
- module_event = self.dap_server.wait_for_event(["module"], 1)
+ module_event = self.dap_server.wait_for_event(["module"])
while module_event is not None:
reason = module_event["body"]["reason"]
if reason == "new":
@@ -75,7 +75,7 @@ class TestDAP_module(lldbdap_testcase.DAPTestCaseBase):
elif reason == "changed":
module_changed_names.append(module_event["body"]["module"]["name"])
- module_event = self.dap_server.wait_for_event(["module"], 1)
+ module_event = self.dap_server.wait_for_event(["module"])
# Make sure we got an event for every active module.
self.assertNotEqual(len(module_new_names), 0)
diff --git a/lldb/test/API/tools/lldb-dap/output/TestDAP_output.py b/lldb/test/API/tools/lldb-dap/output/TestDAP_output.py
index fe978a9..0065258 100644
--- a/lldb/test/API/tools/lldb-dap/output/TestDAP_output.py
+++ b/lldb/test/API/tools/lldb-dap/output/TestDAP_output.py
@@ -29,7 +29,7 @@ class TestDAP_output(lldbdap_testcase.DAPTestCaseBase):
self.continue_to_breakpoints(breakpoint_ids)
# Ensure partial messages are still sent.
- output = self.collect_stdout(timeout=1.0, pattern="abcdef")
+ output = self.collect_stdout(pattern="abcdef")
self.assertTrue(output and len(output) > 0, "expect program stdout")
self.continue_to_exit()
diff --git a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_console.py b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_console.py
index 6748379..e1ad142 100644
--- a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_console.py
+++ b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_console.py
@@ -105,7 +105,7 @@ class TestDAP_restart_console(lldbdap_testcase.DAPTestCaseBase):
# Restart and check that we still get a stopped event before reaching
# main.
self.dap_server.request_restart()
- stopped_events = self.dap_server.wait_for_stopped(timeout=20)
+ stopped_events = self.dap_server.wait_for_stopped()
self.verify_stopped_on_entry(stopped_events)
# continue to main
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index 7738913..e7d9b89 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -57,7 +57,7 @@ SetupIORedirection(const std::vector<std::optional<std::string>> &stdio,
size_t n = std::max(stdio.size(), static_cast<size_t>(3));
for (size_t i = 0; i < n; i++) {
std::optional<std::string> path;
- if (stdio.size() < i)
+ if (stdio.size() <= i)
path = stdio.back();
else
path = stdio[i];
@@ -107,7 +107,7 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest(
arguments.configuration.program, arguments.args, arguments.env,
- arguments.cwd, comm_file.m_path, debugger_pid,
+ arguments.cwd, comm_file.m_path, debugger_pid, arguments.stdio,
arguments.console == protocol::eConsoleExternalTerminal);
dap.SendReverseRequest<LogFailureResponseHandler>("runInTerminal",
std::move(reverse_request));
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index 4f26599..71e91f8 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -866,7 +866,8 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit) {
llvm::json::Object CreateRunInTerminalReverseRequest(
llvm::StringRef program, const std::vector<std::string> &args,
const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
- llvm::StringRef comm_file, lldb::pid_t debugger_pid, bool external) {
+ llvm::StringRef comm_file, lldb::pid_t debugger_pid,
+ const std::vector<std::optional<std::string>> &stdio, bool external) {
llvm::json::Object run_in_terminal_args;
if (external) {
// This indicates the IDE to open an external terminal window.
@@ -885,6 +886,18 @@ llvm::json::Object CreateRunInTerminalReverseRequest(
}
req_args.push_back("--launch-target");
req_args.push_back(program.str());
+ if (!stdio.empty()) {
+ req_args.push_back("--stdio");
+ std::stringstream ss;
+ for (const std::optional<std::string> &file : stdio) {
+ if (file)
+ ss << *file;
+ ss << ":";
+ }
+ std::string files = ss.str();
+ files.pop_back();
+ req_args.push_back(std::move(files));
+ }
req_args.insert(req_args.end(), args.begin(), args.end());
run_in_terminal_args.try_emplace("args", req_args);
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index e9094f6..0c865a3 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -388,6 +388,10 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit);
/// launcher uses it on Linux tell the kernel that it should allow the
/// debugger process to attach.
///
+/// \param[in] stdio
+/// An array of file paths for redirecting the program's standard IO
+/// streams.
+///
/// \param[in] external
/// If set to true, the program will run in an external terminal window
/// instead of IDE's integrated terminal.
@@ -398,7 +402,8 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit);
llvm::json::Object CreateRunInTerminalReverseRequest(
llvm::StringRef program, const std::vector<std::string> &args,
const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
- llvm::StringRef comm_file, lldb::pid_t debugger_pid, bool external);
+ llvm::StringRef comm_file, lldb::pid_t debugger_pid,
+ const std::vector<std::optional<std::string>> &stdio, bool external);
/// Create a "Terminated" JSON object that contains statistics
///
diff --git a/lldb/tools/lldb-dap/Options.td b/lldb/tools/lldb-dap/Options.td
index c8492c6..5e9dd7a 100644
--- a/lldb/tools/lldb-dap/Options.td
+++ b/lldb/tools/lldb-dap/Options.td
@@ -47,6 +47,12 @@ def debugger_pid: S<"debugger-pid">,
HelpText<"The PID of the lldb-dap instance that sent the launchInTerminal "
"request when using --launch-target.">;
+def stdio: S<"stdio">,
+ MetaVarName<"<stdin:stdout:stderr:...>">,
+ HelpText<"An array of file paths for redirecting the program's standard IO "
+ "streams. A colon-separated list of entries. Empty value means no "
+ "redirection.">;
+
def repl_mode
: S<"repl-mode">,
MetaVarName<"<mode>">,
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index 92dada2..a85a68b 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -300,6 +300,7 @@ struct LaunchRequestArguments {
/// terminal or external terminal.
Console console = eConsoleInternal;
+ /// An array of file paths for redirecting the program's standard IO streams.
std::vector<std::optional<std::string>> stdio;
/// @}
diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json
index e961c2e..3f0f150 100644
--- a/lldb/tools/lldb-dap/package.json
+++ b/lldb/tools/lldb-dap/package.json
@@ -626,7 +626,10 @@
"stdio": {
"type": "array",
"items": {
- "type": "string"
+ "type": [
+ "string",
+ "null"
+ ]
},
"description": "The stdio property specifies the redirection targets for the debuggee's stdio streams. A null value redirects a stream to the default debug terminal. String can be a path to file, named pipe or TTY device. If less than three values are provided, the list will be padded with the last value. Specifying more than three values will create additional file descriptors (4, 5, etc.).",
"default": []
diff --git a/lldb/tools/lldb-dap/tool/lldb-dap.cpp b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
index 93446c0..45caa1a 100644
--- a/lldb/tools/lldb-dap/tool/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
@@ -16,15 +16,19 @@
#include "lldb/API/SBStream.h"
#include "lldb/Host/Config.h"
#include "lldb/Host/File.h"
+#include "lldb/Host/FileSystem.h"
#include "lldb/Host/MainLoop.h"
#include "lldb/Host/MainLoopBase.h"
#include "lldb/Host/MemoryMonitor.h"
#include "lldb/Host/Socket.h"
+#include "lldb/Utility/AnsiTerminal.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/UriParser.h"
#include "lldb/lldb-forward.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Option/Arg.h"
@@ -42,8 +46,10 @@
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <condition_variable>
+#include <cstddef>
#include <cstdio>
#include <cstdlib>
+#include <exception>
#include <fcntl.h>
#include <map>
#include <memory>
@@ -69,6 +75,7 @@ typedef int socklen_t;
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <termios.h>
#include <unistd.h>
#endif
@@ -143,6 +150,74 @@ static void PrintVersion() {
llvm::outs() << "liblldb: " << lldb::SBDebugger::GetVersionString() << '\n';
}
+#if not defined(_WIN32)
+struct FDGroup {
+ int GetFlags() const {
+ if (read && write)
+ return O_NOCTTY | O_CREAT | O_RDWR;
+ if (read)
+ return O_NOCTTY | O_RDONLY;
+ return O_NOCTTY | O_CREAT | O_WRONLY | O_TRUNC;
+ }
+
+ std::vector<int> fds;
+ bool read = false;
+ bool write = false;
+};
+
+static llvm::Error RedirectToFile(const FDGroup &fdg, llvm::StringRef file) {
+ if (!fdg.read && !fdg.write)
+ return llvm::Error::success();
+ int target_fd = lldb_private::FileSystem::Instance().Open(
+ file.str().c_str(), fdg.GetFlags(), 0666);
+ if (target_fd == -1)
+ return llvm::errorCodeToError(
+ std::error_code(errno, std::generic_category()));
+ for (int fd : fdg.fds) {
+ if (target_fd == fd)
+ continue;
+ if (::dup2(target_fd, fd) == -1)
+ return llvm::errorCodeToError(
+ std::error_code(errno, std::generic_category()));
+ }
+ ::close(target_fd);
+ return llvm::Error::success();
+}
+
+static llvm::Error
+SetupIORedirection(const llvm::SmallVectorImpl<llvm::StringRef> &files) {
+ llvm::SmallDenseMap<llvm::StringRef, FDGroup> groups;
+ for (size_t i = 0; i < files.size(); i++) {
+ if (files[i].empty())
+ continue;
+ auto group = groups.find(files[i]);
+ if (group == groups.end())
+ group = groups.insert({files[i], {{static_cast<int>(i)}}}).first;
+ else
+ group->second.fds.push_back(i);
+ switch (i) {
+ case 0:
+ group->second.read = true;
+ break;
+ case 1:
+ case 2:
+ group->second.write = true;
+ break;
+ default:
+ group->second.read = true;
+ group->second.write = true;
+ break;
+ }
+ }
+ for (const auto &[file, group] : groups) {
+ if (llvm::Error err = RedirectToFile(group, file))
+ return llvm::createStringError(
+ llvm::formatv("{0}: {1}", file, llvm::toString(std::move(err))));
+ }
+ return llvm::Error::success();
+}
+#endif
+
// If --launch-target is provided, this instance of lldb-dap becomes a
// runInTerminal launcher. It will ultimately launch the program specified in
// the --launch-target argument, which is the original program the user wanted
@@ -165,6 +240,7 @@ static void PrintVersion() {
static llvm::Error LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg,
llvm::StringRef comm_file,
lldb::pid_t debugger_pid,
+ llvm::StringRef stdio,
char *argv[]) {
#if defined(_WIN32)
return llvm::createStringError(
@@ -179,6 +255,25 @@ static llvm::Error LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg,
(void)prctl(PR_SET_PTRACER, debugger_pid, 0, 0, 0);
#endif
+ lldb_private::FileSystem::Initialize();
+ if (!stdio.empty()) {
+ llvm::SmallVector<llvm::StringRef, 3> files;
+ stdio.split(files, ':');
+ while (files.size() < 3)
+ files.push_back(files.back());
+ if (llvm::Error err = SetupIORedirection(files))
+ return err;
+ } else if ((isatty(STDIN_FILENO) != 0) &&
+ llvm::StringRef(getenv("TERM")).starts_with_insensitive("xterm")) {
+ // Clear the screen.
+ llvm::outs() << ANSI_CSI_RESET_CURSOR ANSI_CSI_ERASE_VIEWPORT
+ ANSI_CSI_ERASE_SCROLLBACK;
+ // VS Code will reuse the same terminal for the same debug configuration
+ // between runs. Clear the input buffer prior to starting the new process so
+ // prior input is not carried forward to the new debug session.
+ tcflush(STDIN_FILENO, TCIFLUSH);
+ }
+
RunInTerminalLauncherCommChannel comm_channel(comm_file);
if (llvm::Error err = comm_channel.NotifyPid())
return err;
@@ -484,9 +579,10 @@ int main(int argc, char *argv[]) {
break;
}
}
+ llvm::StringRef stdio = input_args.getLastArgValue(OPT_stdio);
if (llvm::Error err =
LaunchRunInTerminalTarget(*target_arg, comm_file->getValue(), pid,
- argv + target_args_pos)) {
+ stdio, argv + target_args_pos)) {
llvm::errs() << llvm::toString(std::move(err)) << '\n';
return EXIT_FAILURE;
}
diff --git a/lldb/unittests/Utility/XcodeSDKTest.cpp b/lldb/unittests/Utility/XcodeSDKTest.cpp
index de9f91a..a8a597b 100644
--- a/lldb/unittests/Utility/XcodeSDKTest.cpp
+++ b/lldb/unittests/Utility/XcodeSDKTest.cpp
@@ -27,6 +27,7 @@ TEST(XcodeSDKTest, ParseTest) {
EXPECT_EQ(XcodeSDK("AppleTVOS.sdk").GetType(), XcodeSDK::AppleTVOS);
EXPECT_EQ(XcodeSDK("WatchSimulator.sdk").GetType(), XcodeSDK::WatchSimulator);
EXPECT_EQ(XcodeSDK("WatchOS.sdk").GetType(), XcodeSDK::watchOS);
+ EXPECT_EQ(XcodeSDK("BridgeOS.sdk").GetType(), XcodeSDK::BridgeOS);
EXPECT_EQ(XcodeSDK("XRSimulator.sdk").GetType(), XcodeSDK::XRSimulator);
EXPECT_EQ(XcodeSDK("XROS.sdk").GetType(), XcodeSDK::XROS);
EXPECT_EQ(XcodeSDK("Linux.sdk").GetType(), XcodeSDK::Linux);
diff --git a/lldb/utils/lui/lldbutil.py b/lldb/utils/lui/lldbutil.py
index 140317a..589acae 100644
--- a/lldb/utils/lui/lldbutil.py
+++ b/lldb/utils/lui/lldbutil.py
@@ -951,7 +951,7 @@ def get_GPRs(frame):
from lldbutil import get_GPRs
regs = get_GPRs(frame)
for reg in regs:
- print "%s => %s" % (reg.GetName(), reg.GetValue())
+ print("%s => %s" % (reg.GetName(), reg.GetValue()))
...
"""
return get_registers(frame, "general purpose")
@@ -965,7 +965,7 @@ def get_FPRs(frame):
from lldbutil import get_FPRs
regs = get_FPRs(frame)
for reg in regs:
- print "%s => %s" % (reg.GetName(), reg.GetValue())
+ print("%s => %s" % (reg.GetName(), reg.GetValue()))
...
"""
return get_registers(frame, "floating point")