Skip to content

[lldb-dap] Test Gardening, improving DebugCommunication. #141689

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 5 commits into from
May 29, 2025

Conversation

ashgti
Copy link
Contributor

@ashgti ashgti commented May 27, 2025

Improving the readability and correctness of DebugCommunication by adding type annotations to many parts of the library and trying to improve the implementation of a few key areas of the code to better handle correctness.

Specifically, this refactored the DebugCommunication._handle_recv_packet function to ensure consistency with the reader thread when handling state changes and improved the DebugCommunication._recv_packet helper to make it easier to follow by adding some additional helpers.

Improving the readability and correctness of DebugCommunication by adding type annotations to many parts of the library and trying to improve the implementation of a few key areas of the code to better handle correctness.

Specifically, this refactored the `DebugCommunication._handle_recv_packet` function to ensure consistency with the reader thread when handling state changes and improved the `DebugCommunication._recv_packet` helper to make it easier to follow by adding some additional helpers.
@ashgti ashgti requested a review from JDevlieghere as a code owner May 27, 2025 23:44
@llvmbot llvmbot added the lldb label May 27, 2025
@llvmbot
Copy link
Member

llvmbot commented May 27, 2025

@llvm/pr-subscribers-lldb

Author: John Harrison (ashgti)

Changes

Improving the readability and correctness of DebugCommunication by adding type annotations to many parts of the library and trying to improve the implementation of a few key areas of the code to better handle correctness.

Specifically, this refactored the DebugCommunication._handle_recv_packet function to ensure consistency with the reader thread when handling state changes and improved the DebugCommunication._recv_packet helper to make it easier to follow by adding some additional helpers.


Patch is 44.34 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/141689.diff

3 Files Affected:

  • (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py (+317-240)
  • (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py (+13-3)
  • (modified) lldb/test/API/tools/lldb-dap/cancel/TestDAP_cancel.py (+10-17)
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 a028381a0a4f9..cc235f4fe8b1a 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
@@ -12,13 +12,52 @@
 import sys
 import threading
 import time
-from typing import Any, Optional, Union, BinaryIO, TextIO
+from typing import (
+    Any,
+    Optional,
+    Union,
+    BinaryIO,
+    TextIO,
+    TypedDict,
+    Literal,
+    Callable,
+    TypeVar,
+)
 
 ## DAP type references
-Event = dict[str, Any]
-Request = dict[str, Any]
-Response = dict[str, Any]
+
+
+class Event(TypedDict):
+    type: Literal["event"]
+    seq: Literal[0]
+    event: str
+    body: Optional[dict]
+
+
+class Request(TypedDict):
+    type: Literal["request"]
+    seq: int
+    command: str
+    arguments: Optional[dict]
+
+
+class Response(TypedDict):
+    type: Literal["response"]
+    seq: Literal[0]
+    request_seq: int
+    success: bool
+    command: str
+    message: Optional[str]
+    body: Optional[dict]
+
+
+_T = TypeVar("_T")
 ProtocolMessage = Union[Event, Request, Response]
+# An internal type used for tracking protocol messages and an EOF sentinel
+# value. 'None' cannot easily be used as a sentinel because it is a falsey
+# value. When returned outside of DebugCommunication an EOFError is typically
+# converted into 'None'.
+_InternalProtocolMessage = Union[Event, Request, Response, EOFError]
 
 
 def dump_memory(base_addr, data, num_per_line, outfile):
@@ -58,44 +97,42 @@ def dump_memory(base_addr, data, num_per_line, outfile):
         outfile.write("\n")
 
 
-def read_packet(f, verbose=False, trace_file=None):
+def read_packet(
+    f: BinaryIO, verbose=False, trace_file=None
+) -> _InternalProtocolMessage:
     """Decode a JSON packet that starts with the content length and is
     followed by the JSON bytes from a file 'f'. Returns None on EOF.
     """
-    line = f.readline().decode("utf-8")
+    line = f.readline().decode()
     if len(line) == 0:
-        return None  # EOF.
+        return EOFError()  # EOF.
 
     # Watch for line that starts with the prefix
     prefix = "Content-Length: "
     if line.startswith(prefix):
         # Decode length of JSON bytes
         if verbose:
-            print('content: "%s"' % (line))
+            print("content:", line)
         length = int(line[len(prefix) :])
         if verbose:
-            print('length: "%u"' % (length))
+            print("length:", length)
         # Skip empty line
-        line = f.readline()
+        line = f.readline().decode()
         if verbose:
-            print('empty: "%s"' % (line))
+            print("empty:", line)
         # Read JSON bytes
-        json_str = f.read(length)
+        json_str = f.read(length).decode()
         if verbose:
-            print('json: "%s"' % (json_str))
+            print("json:", json_str)
         if trace_file:
-            trace_file.write("from adapter:\n%s\n" % (json_str))
+            trace_file.write(f"from adapter:\n{json_str}\n")
         # Decode the JSON bytes into a python dictionary
         return json.loads(json_str)
 
     raise Exception("unexpected malformed message from lldb-dap: " + line)
 
 
-def packet_type_is(packet, packet_type):
-    return "type" in packet and packet["type"] == packet_type
-
-
-def dump_dap_log(log_file):
+def dump_dap_log(log_file: str):
     print("========= DEBUG ADAPTER PROTOCOL LOGS =========", file=sys.stderr)
     if log_file is None:
         print("no log file available", file=sys.stderr)
@@ -124,8 +161,8 @@ def __init__(
     def __str__(self):
         return f"Source(name={self.name}, path={self.path}), source_reference={self.source_reference})"
 
-    def as_dict(self):
-        source_dict = {}
+    def as_dict(self) -> dict:
+        source_dict: dict[str, Any] = {}
         if self._name is not None:
             source_dict["name"] = self._name
         if self._path is not None:
@@ -141,38 +178,42 @@ def __init__(
         recv: BinaryIO,
         send: BinaryIO,
         init_commands: list[str],
-        log_file: Optional[TextIO] = None,
+        log_file: Optional[str] = None,
     ):
         # For debugging test failures, try setting `trace_file = sys.stderr`.
         self.trace_file: Optional[TextIO] = None
         self.log_file = log_file
         self.send = send
         self.recv = recv
-        self.recv_packets: list[Optional[ProtocolMessage]] = []
+        self.recv_packets: list[_InternalProtocolMessage] = []
         self.recv_condition = threading.Condition()
         self.recv_thread = threading.Thread(target=self._read_packet_thread)
-        self.process_event_body = None
         self.exit_status: Optional[int] = None
+        self.init_commands = init_commands
         self.initialize_body = None
+        self.initialized = False
+        self.configuration_done_sent = False
+        self.process_event_body: Optional[dict] = None
+        self.terminated = False
         self.progress_events: list[Event] = []
-        self.reverse_requests = []
+        self.reverse_requests: list[Request] = []
         self.sequence = 1
-        self.threads = None
-        self.thread_stop_reasons = {}
-        self.recv_thread.start()
         self.output_condition = threading.Condition()
         self.output: dict[str, list[str]] = {}
-        self.configuration_done_sent = False
-        self.initialized = False
-        self.frame_scopes = {}
-        self.init_commands = init_commands
+
+        # debuggee state
+        self.threads = None
+        self.thread_stop_reasons: dict[str, Any] = {}
+        self.frame_scopes: dict[str, Any] = {}
+
+        self.recv_thread.start()
 
     @classmethod
     def encode_content(cls, s: str) -> bytes:
         return ("Content-Length: %u\r\n\r\n%s" % (len(s), s)).encode("utf-8")
 
     @classmethod
-    def validate_response(cls, command, response):
+    def validate_response(cls, command: Request, response: Response):
         if command["command"] != response["command"]:
             raise ValueError("command mismatch in response")
         if command["seq"] != response["request_seq"]:
@@ -224,84 +265,91 @@ def collect_output(self, category, timeout_secs, pattern, clear=True):
                     break
         return collected_output if collected_output else None
 
-    def _enqueue_recv_packet(self, packet: Optional[ProtocolMessage]):
-        self.recv_condition.acquire()
+    def _enqueue_recv_packet(self, packet: Union[ProtocolMessage, EOFError]):
         self.recv_packets.append(packet)
         self.recv_condition.notify()
-        self.recv_condition.release()
 
-    def _handle_recv_packet(self, packet: Optional[ProtocolMessage]) -> bool:
+    def _handle_recv_packet(self, packet: _InternalProtocolMessage) -> bool:
         """Called by the read thread that is waiting for all incoming packets
         to store the incoming packet in "self.recv_packets" in a thread safe
         way. This function will then signal the "self.recv_condition" to
         indicate a new packet is available. Returns True if the caller
         should keep calling this function for more packets.
         """
-        # If EOF, notify the read thread by enqueuing a None.
-        if not packet:
-            self._enqueue_recv_packet(None)
-            return False
-
-        # Check the packet to see if is an event packet
-        keepGoing = True
-        packet_type = packet["type"]
-        if packet_type == "event":
-            event = packet["event"]
-            body = None
-            if "body" in packet:
-                body = packet["body"]
-            # Handle the event packet and cache information from these packets
-            # as they come in
-            if event == "output":
-                # Store any output we receive so clients can retrieve it later.
-                category = body["category"]
-                output = body["output"]
-                self.output_condition.acquire()
-                if category in self.output:
-                    self.output[category] += output
-                else:
-                    self.output[category] = output
-                self.output_condition.notify()
-                self.output_condition.release()
-                # no need to add 'output' event packets to our packets list
-                return keepGoing
-            elif event == "initialized":
-                self.initialized = True
-            elif event == "process":
-                # When a new process is attached or launched, remember the
-                # details that are available in the body of the event
-                self.process_event_body = body
-            elif event == "exited":
-                # Process exited, mark the status to indicate the process is not
-                # alive.
-                self.exit_status = body["exitCode"]
-            elif event == "continued":
-                # When the process continues, clear the known threads and
-                # thread_stop_reasons.
-                all_threads_continued = body.get("allThreadsContinued", True)
-                tid = body["threadId"]
-                if tid in self.thread_stop_reasons:
-                    del self.thread_stop_reasons[tid]
-                self._process_continued(all_threads_continued)
-            elif event == "stopped":
-                # Each thread that stops with a reason will send a
-                # 'stopped' event. We need to remember the thread stop
-                # reasons since the 'threads' command doesn't return
-                # that information.
-                self._process_stopped()
-                tid = body["threadId"]
-                self.thread_stop_reasons[tid] = body
-            elif event.startswith("progress"):
-                # Progress events come in as 'progressStart', 'progressUpdate',
-                # and 'progressEnd' events. Keep these around in case test
-                # cases want to verify them.
-                self.progress_events.append(packet)
-
-        elif packet_type == "response":
-            if packet["command"] == "disconnect":
-                keepGoing = False
-        self._enqueue_recv_packet(packet)
-        return keepGoing
+        # Hold the recv_condition for consistency of debugger state.
+        with self.recv_condition:
+            if isinstance(packet, EOFError):
+                self._enqueue_recv_packet(packet)
+                return False
+
+            keep_going = True
+
+            # Check the packet to see if is an event packet
+            if packet["type"] == "event" and "event" in packet:
+                event = packet["event"]
+                body = packet.get("body")
+                # Handle the event packet and cache DAP stateful information from
+                # these packets as they come in.
+                if event == "output" and body is not None:
+                    # Store any output we receive so clients can retrieve it later.
+                    category = body["category"]
+                    output = body["output"]
+                    self.output_condition.acquire()
+                    if category in self.output:
+                        self.output[category] += output
+                    else:
+                        self.output[category] = output
+                    self.output_condition.notify()
+                    self.output_condition.release()
+                    # no need to add 'output' event packets to our packets list
+                    return keep_going
+                elif event == "initialized":
+                    self.initialized = True
+                elif event == "process" and body is not None:
+                    # When a new process is attached or launched, remember the
+                    # details that are available in the body of the event
+                    self.process_event_body = body
+                elif event == "terminated":
+                    # If we get the 'terminated' event then lldb-dap has exited
+                    # itself.
+                    self.terminated = True
+                elif event == "exited" and body is not None:
+                    # Process exited, mark the status to indicate the process is not
+                    # alive.
+                    self.exit_status = body.get("exitCode", 0)
+                elif event == "continued" and body is not None:
+                    # When the process continues, clear the known threads and
+                    # thread_stop_reasons.
+                    all_threads_continued = body.get("allThreadsContinued", True)
+                    tid = body["threadId"]
+                    if tid in self.thread_stop_reasons:
+                        del self.thread_stop_reasons[tid]
+                    self._process_continued(all_threads_continued)
+                elif event == "stopped" and body is not None:
+                    # Each thread that stops with a reason will send a
+                    # 'stopped' event. We need to remember the thread stop
+                    # reasons since the 'threads' command doesn't return
+                    # that information.
+                    self._process_stopped()
+                    tid = body["threadId"]
+                    self.thread_stop_reasons[tid] = body
+                elif event.startswith("progress"):
+                    # Progress events come in as 'progressStart', 'progressUpdate',
+                    # and 'progressEnd' events. Keep these around in case test
+                    # cases want to verify them.
+                    self.progress_events.append(packet)
+
+            elif packet["type"] == "response":
+                if packet["command"] == "disconnect":
+                    keep_going = False
+
+            elif packet["type"] == "request":
+                # Handle reverse requests and keep processing.
+                self._handle_reverse_request(packet)
+                return keep_going
+
+            self._enqueue_recv_packet(packet)
+            return keep_going
 
     def _process_continued(self, all_threads_continued: bool):
         self.threads = None
@@ -309,14 +357,63 @@ def _process_continued(self, all_threads_continued: bool):
         if all_threads_continued:
             self.thread_stop_reasons = {}
 
-    def send_packet(self, command_dict: Request, set_sequence=True):
+    def _handle_reverse_request(self, request: Request):
+        self.reverse_requests.append(request)
+        arguments = request.get("arguments")
+        if request["command"] == "runInTerminal" and arguments is not None:
+            in_shell = arguments.get("argsCanBeInterpretedByShell", False)
+            proc = subprocess.Popen(
+                arguments["args"],
+                env=arguments.get("env", {}),
+                cwd=arguments["cwd"],
+                stdin=subprocess.DEVNULL,
+                stdout=subprocess.DEVNULL,
+                stderr=subprocess.DEVNULL,
+                shell=in_shell,
+            )
+            body = {}
+            if in_shell:
+                body["shellProcessId"] = proc.pid
+            else:
+                body["processId"] = proc.pid
+            self.send_packet(
+                {
+                    "type": "response",
+                    "seq": 0,
+                    "request_seq": request["seq"],
+                    "success": True,
+                    "command": "runInTerminal",
+                    "message": None,
+                    "body": body,
+                }
+            )
+        elif request["command"] == "startDebugging":
+            self.send_packet(
+                {
+                    "type": "response",
+                    "seq": 0,
+                    "request_seq": request["seq"],
+                    "success": True,
+                    "message": None,
+                    "command": "startDebugging",
+                    "body": {},
+                }
+            )
+        else:
+            desc = 'unknown reverse request "%s"' % (request["command"])
+            raise ValueError(desc)
+
+    def send_packet(self, command_dict: ProtocolMessage) -> int:
         """Take the "command_dict" python dictionary and encode it as a JSON
         string and send the contents as a packet to the VSCode debug
-        adapter"""
+        adapter."""
+        seq = 0
         # Set the sequence ID for this command automatically
-        if set_sequence:
-            command_dict["seq"] = self.sequence
+        if command_dict["type"] == "request":
+            seq = command_dict["seq"] = self.sequence
             self.sequence += 1
+        else:
+            command_dict["seq"] = 0
         # Encode our command dictionary as a JSON string
         json_str = json.dumps(command_dict, separators=(",", ":"))
         if self.trace_file:
@@ -326,104 +423,70 @@ def send_packet(self, command_dict: Request, set_sequence=True):
             # Send the encoded JSON packet and flush the 'send' file
             self.send.write(self.encode_content(json_str))
             self.send.flush()
+        return seq
 
-    def recv_packet(
+    def receive_response(
         self,
-        filter_type: Optional[str] = None,
-        filter_event: Optional[Union[str, list[str]]] = None,
+        seq: int,
+    ) -> Optional[Response]:
+        """Waits for the a response with the associated request_sec."""
+
+        def predicate(p: Response):
+            return p["type"] == "response" and p["request_seq"] == seq
+
+        return self._recv_packet(predicate=predicate)
+
+    def _recv_packet(
+        self,
+        *,
+        predicate: Callable[[_T], bool],
         timeout: Optional[float] = None,
-    ) -> Optional[ProtocolMessage]:
+    ) -> Optional[_T]:
         """Get a JSON packet from the VSCode debug adapter. This function
         assumes a thread that reads packets is running and will deliver
         any received packets by calling handle_recv_packet(...). This
         function will wait for the packet to arrive and return it when
         it does."""
-        while True:
-            try:
-                self.recv_condition.acquire()
-                packet = None
-                while True:
-                    for i, curr_packet in enumerate(self.recv_packets):
-                        if not curr_packet:
-                            raise EOFError
-                        packet_type = curr_packet["type"]
-                        if filter_type is None or packet_type in filter_type:
-                            if filter_event is None or (
-                                packet_type == "event"
-                                and curr_packet["event"] in filter_event
-                            ):
-                                packet = self.recv_packets.pop(i)
-                                break
-                    if packet:
-                        break
-                    # Sleep until packet is received
-                    len_before = len(self.recv_packets)
-                    self.recv_condition.wait(timeout)
-                    len_after = len(self.recv_packets)
-                    if len_before == len_after:
-                        return None  # Timed out
-                return packet
-            except EOFError:
+        with self.recv_condition:
+
+            def _predicate():
+                return next(
+                    filter(
+                        lambda p: isinstance(p, EOFError) or predicate(p),
+                        self.recv_packets,
+                    ),
+                    None,
+                )
+
+            packet = self.recv_condition.wait_for(_predicate, timeout=timeout)
+            if packet is None:  # Timeout
+                return None
+            self.recv_packets.remove(packet)
+            if isinstance(packet, EOFError):
                 return None
-            finally:
-                self.recv_condition.release()
+            return packet
 
-    def send_recv(self, command):
+    def _send_recv(self, command: Request) -> Optional[Response]:
         """Send a command python dictionary as JSON and receive the JSON
         response. Validates that the response is the correct sequence and
-        command in the reply. Any events that are receive...
[truncated]

@ashgti
Copy link
Contributor Author

ashgti commented May 27, 2025

This was split out from #140777 to make a smaller commit.

Comment on lines 412 to 416
if command_dict["type"] == "request":
seq = command_dict["seq"] = self.sequence
self.sequence += 1
else:
command_dict["seq"] = 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if command_dict["type"] == "request":
seq = command_dict["seq"] = self.sequence
self.sequence += 1
else:
command_dict["seq"] = 0
if command_dict["type"] == "request":
seq = self.sequence
self.sequence += 1
command_dict["seq"] = seq

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated with a slightly different version, LMKWYT

"command": "setBreakpoints",
"type": "request",
"seq": 0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we use self.sequence?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The send_packet method will set the seq to the correct value but I need to have this defined or the type checker complains that the 'seq' key is missing.

…yped.

To validate the types:

```
$ pip3 install mypy
$ mypy --python-version 3.8 \
  lldb/packages/Python/lldbsuite/**/*.py \
  lldb/test/API/tools/lldb-dap/**/*.py
```
Copy link
Member

@JDevlieghere JDevlieghere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I think the types and classes will help a lot in the long run.

@ashgti
Copy link
Contributor Author

ashgti commented May 28, 2025

I also filed #141877 to see about running a python type checker as part of the CI job.

@ashgti
Copy link
Contributor Author

ashgti commented May 29, 2025

Looks like my tests failed on the buildkit linux host, looking into why python3.10 failed. They passed on the 'CI Checks / Build and Test Linux' but that has python 3.12.

…g the 'Generic[T]' and making the body/arguments field a plain 'dict'.
@ashgti
Copy link
Contributor Author

ashgti commented May 29, 2025

Okay, the latest version of this worked on buildkit for linux.

I'll submit this, but if we get reports of it failing with other specific versions of python we may need to tweak things a bit.

@ashgti ashgti merged commit 8a49db3 into llvm:main May 29, 2025
10 checks passed
@ashgti ashgti deleted the lldb-dap-test-gardening branch May 29, 2025 16:51
@llvm-ci
Copy link
Collaborator

llvm-ci commented May 29, 2025

LLVM Buildbot has detected a new failure on builder lldb-x86_64-debian running on lldb-x86_64-debian while building lldb at step 6 "test".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/162/builds/23448

Here is the relevant piece of the build log for the reference
Step 6 (test) failure: build (failure)
...
PASS: lldb-api :: functionalities/data-formatter/data-formatter-stl/libstdcpp/vector/TestDataFormatterStdVector.py (108 of 2967)
PASS: lldb-api :: tools/lldb-server/libraries-svr4/TestGdbRemoteLibrariesSvr4Support.py (109 of 2967)
PASS: lldb-api :: lang/cpp/namespace/TestNamespace.py (110 of 2967)
PASS: lldb-api :: functionalities/inferior-assert/TestInferiorAssert.py (111 of 2967)
PASS: lldb-api :: lang/cpp/dynamic-value/TestDynamicValue.py (112 of 2967)
PASS: lldb-api :: tools/lldb-dap/coreFile/TestDAP_coreFile.py (113 of 2967)
PASS: lldb-api :: api/listeners/TestListener.py (114 of 2967)
PASS: lldb-api :: functionalities/breakpoint/thread_plan_user_breakpoint/TestThreadPlanUserBreakpoint.py (115 of 2967)
PASS: lldb-api :: functionalities/thread/step_until/TestStepUntil.py (116 of 2967)
PASS: lldb-api :: functionalities/data-formatter/data-formatter-stl/generic/set/TestDataFormatterGenericSet.py (117 of 2967)
FAIL: lldb-api :: tools/lldb-dap/optimized/TestDAP_optimized.py (118 of 2967)
******************** TEST 'lldb-api :: tools/lldb-dap/optimized/TestDAP_optimized.py' FAILED ********************
Script:
--
/usr/bin/python3 /home/worker/2.0.1/lldb-x86_64-debian/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=/home/worker/2.0.1/lldb-x86_64-debian/build/./lib --env LLVM_INCLUDE_DIR=/home/worker/2.0.1/lldb-x86_64-debian/build/include --env LLVM_TOOLS_DIR=/home/worker/2.0.1/lldb-x86_64-debian/build/./bin --arch x86_64 --build-dir /home/worker/2.0.1/lldb-x86_64-debian/build/lldb-test-build.noindex --lldb-module-cache-dir /home/worker/2.0.1/lldb-x86_64-debian/build/lldb-test-build.noindex/module-cache-lldb/lldb-api --clang-module-cache-dir /home/worker/2.0.1/lldb-x86_64-debian/build/lldb-test-build.noindex/module-cache-clang/lldb-api --executable /home/worker/2.0.1/lldb-x86_64-debian/build/./bin/lldb --compiler /home/worker/2.0.1/lldb-x86_64-debian/build/./bin/clang --dsymutil /home/worker/2.0.1/lldb-x86_64-debian/build/./bin/dsymutil --make /usr/bin/gmake --llvm-tools-dir /home/worker/2.0.1/lldb-x86_64-debian/build/./bin --lldb-obj-root /home/worker/2.0.1/lldb-x86_64-debian/build/tools/lldb --lldb-libs-dir /home/worker/2.0.1/lldb-x86_64-debian/build/./lib --cmake-build-type Release -t /home/worker/2.0.1/lldb-x86_64-debian/llvm-project/lldb/test/API/tools/lldb-dap/optimized -p TestDAP_optimized.py
--
Exit Code: 1

Command Output (stdout):
--
lldb version 21.0.0git (https://github.com/llvm/llvm-project.git revision 8a49db35f45e56c92522c6079e51553e80c07aec)
  clang revision 8a49db35f45e56c92522c6079e51553e80c07aec
  llvm revision 8a49db35f45e56c92522c6079e51553e80c07aec
Skipping the following test categories: ['libc++', 'dsym', 'gmodules', 'debugserver', 'objc']

--
Command Output (stderr):
--
Change dir to: /home/worker/2.0.1/lldb-x86_64-debian/llvm-project/lldb/test/API/tools/lldb-dap/optimized
runCmd: settings clear --all

output: 

runCmd: settings set symbols.enable-external-lookup false

output: 

runCmd: settings set target.inherit-tcc true

output: 

runCmd: settings set target.disable-aslr false

output: 

runCmd: settings set target.detach-on-error false

output: 


@ashgti
Copy link
Contributor Author

ashgti commented May 29, 2025

Looking into the failure on the buildbot.

@llvm-ci
Copy link
Collaborator

llvm-ci commented May 29, 2025

LLVM Buildbot has detected a new failure on builder lldb-aarch64-ubuntu running on linaro-lldb-aarch64-ubuntu while building lldb at step 6 "test".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/59/builds/18540

Here is the relevant piece of the build log for the reference
Step 6 (test) failure: build (failure)
...
UNSUPPORTED: lldb-api :: tools/lldb-dap/breakpoint/TestDAP_setFunctionBreakpoints.py (1170 of 2194)
PASS: lldb-api :: python_api/watchpoint/watchlocation/TestSetWatchlocation.py (1171 of 2194)
PASS: lldb-api :: tools/lldb-dap/commands/TestDAP_commands.py (1172 of 2194)
PASS: lldb-api :: tools/lldb-dap/breakpoint/TestDAP_logpoints.py (1173 of 2194)
PASS: lldb-api :: python_api/process/cancel_attach/TestCancelAttach.py (1174 of 2194)
PASS: lldb-api :: tools/lldb-dap/cancel/TestDAP_cancel.py (1175 of 2194)
PASS: lldb-api :: tools/lldb-dap/console/TestDAP_redirection_to_console.py (1176 of 2194)
PASS: lldb-api :: tools/lldb-dap/completions/TestDAP_completions.py (1177 of 2194)
PASS: lldb-api :: tools/lldb-dap/coreFile/TestDAP_coreFile.py (1178 of 2194)
PASS: lldb-api :: tools/lldb-dap/console/TestDAP_console.py (1179 of 2194)
FAIL: lldb-api :: tools/lldb-dap/disassemble/TestDAP_disassemble.py (1180 of 2194)
******************** TEST 'lldb-api :: tools/lldb-dap/disassemble/TestDAP_disassemble.py' FAILED ********************
Script:
--
/usr/bin/python3.10 /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./lib --env LLVM_INCLUDE_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/include --env LLVM_TOOLS_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin --arch aarch64 --build-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex --lldb-module-cache-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api --clang-module-cache-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-clang/lldb-api --executable /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/lldb --compiler /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/clang --dsymutil /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/dsymutil --make /usr/bin/gmake --llvm-tools-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin --lldb-obj-root /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/tools/lldb --lldb-libs-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./lib --cmake-build-type Release /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/disassemble -p TestDAP_disassemble.py
--
Exit Code: 1

Command Output (stdout):
--
lldb version 21.0.0git (https://github.com/llvm/llvm-project.git revision 8a49db35f45e56c92522c6079e51553e80c07aec)
  clang revision 8a49db35f45e56c92522c6079e51553e80c07aec
  llvm revision 8a49db35f45e56c92522c6079e51553e80c07aec
Skipping the following test categories: ['libc++', 'dsym', 'gmodules', 'debugserver', 'objc']

--
Command Output (stderr):
--
========= DEBUG ADAPTER PROTOCOL LOGS =========
1748538209.713754892 --> (stdio) {"command":"initialize","type":"request","arguments":{"adapterID":"lldb-native","clientID":"vscode","columnsStartAt1":true,"linesStartAt1":true,"locale":"en-us","pathFormat":"path","supportsRunInTerminalRequest":true,"supportsVariablePaging":true,"supportsVariableType":true,"supportsStartDebuggingRequest":true,"supportsProgressReporting":true,"$__lldb_sourceInitFile":false},"seq":1}
1748538209.715912819 <-- (stdio) {"body":{"$__lldb_version":"lldb version 21.0.0git (https://github.com/llvm/llvm-project.git revision 8a49db35f45e56c92522c6079e51553e80c07aec)\n  clang revision 8a49db35f45e56c92522c6079e51553e80c07aec\n  llvm revision 8a49db35f45e56c92522c6079e51553e80c07aec","completionTriggerCharacters":["."," ","\t"],"exceptionBreakpointFilters":[{"default":false,"filter":"cpp_catch","label":"C++ Catch"},{"default":false,"filter":"cpp_throw","label":"C++ Throw"},{"default":false,"filter":"objc_catch","label":"Objective-C Catch"},{"default":false,"filter":"objc_throw","label":"Objective-C Throw"}],"supportTerminateDebuggee":true,"supportsBreakpointLocationsRequest":true,"supportsCancelRequest":true,"supportsCompletionsRequest":true,"supportsConditionalBreakpoints":true,"supportsConfigurationDoneRequest":true,"supportsDataBreakpoints":true,"supportsDelayedStackTraceLoading":true,"supportsDisassembleRequest":true,"supportsEvaluateForHovers":true,"supportsExceptionInfoRequest":true,"supportsExceptionOptions":true,"supportsFunctionBreakpoints":true,"supportsHitConditionalBreakpoints":true,"supportsInstructionBreakpoints":true,"supportsLogPoints":true,"supportsModulesRequest":true,"supportsReadMemoryRequest":true,"supportsRestartRequest":true,"supportsSetVariable":true,"supportsStepInTargetsRequest":true,"supportsSteppingGranularity":true,"supportsValueFormattingOptions":true},"command":"initialize","request_seq":1,"seq":0,"success":true,"type":"response"}
1748538209.716121674 --> (stdio) {"type":"request","seq":2,"command":"launch","arguments":{"program":"/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/tools/lldb-dap/disassemble/TestDAP_disassemble.test_disassemble/a.out"}}
1748538209.801810503 <-- (stdio) {"command":"launch","request_seq":2,"seq":0,"success":true,"type":"response"}
1748538209.801842213 <-- (stdio) {"body":{"module":{"addressRange":"0xfffff7fc2000","debugInfoSize":"451.3KB","id":"46771E9A-54FF-F825-3560-60BC1C8B4A44-C1108BF8","name":"ld-linux-aarch64.so.1","path":"/usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1","symbolFilePath":"/usr/lib/debug/.build-id/46/771e9a54fff825356060bc1c8b4a44c1108bf8.debug","symbolStatus":"Symbols loaded."},"reason":"new"},"event":"module","seq":0,"type":"event"}
1748538209.801860809 <-- (stdio) {"event":"initialized","seq":0,"type":"event"}
1748538209.801884174 <-- (stdio) {"body":{"module":{"addressRange":"0xfffff7ffb000","id":"4A8F74F7-08C0-3C8C-B911-12040A09904C-51F3DA5C","name":"[vdso]","path":"[vdso]","symbolStatus":"Symbols not found."},"reason":"new"},"event":"module","seq":0,"type":"event"}
1748538209.801925898 <-- (stdio) {"body":{"module":{"addressRange":"0xaaaaaaaa0000","debugInfoSize":"1.4KB","id":"794D80CD","name":"a.out","path":"/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/tools/lldb-dap/disassemble/TestDAP_disassemble.test_disassemble/a.out","symbolFilePath":"/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/tools/lldb-dap/disassemble/TestDAP_disassemble.test_disassemble/a.out","symbolStatus":"Symbols loaded."},"reason":"new"},"event":"module","seq":0,"type":"event"}
1748538209.802203178 --> (stdio) {"command":"setBreakpoints","type":"request","seq":3,"arguments":{"source":{"name":"main.c","path":"main.c"},"sourceModified":false,"lines":[9],"breakpoints":[{"line":9}]}}
1748538209.807792902 <-- (stdio) {"body":{"breakpoints":[{"column":7,"id":1,"instructionReference":"0xAAAAAAAA07F8","line":11,"source":{"name":"main.c","path":"main.c"},"verified":true}]},"command":"setBreakpoints","request_seq":3,"seq":0,"success":true,"type":"response"}
1748538209.807891607 <-- (stdio) {"body":{"breakpoint":{"column":7,"id":1,"instructionReference":"0xAAAAAAAA07F8","line":11,"verified":true},"reason":"changed"},"event":"breakpoint","seq":0,"type":"event"}
1748538209.807916880 --> (stdio) {"command":"configurationDone","type":"request","arguments":{},"seq":4}
1748538209.808000803 <-- (stdio) {"body":{"isLocalProcess":true,"name":"/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/tools/lldb-dap/disassemble/TestDAP_disassemble.test_disassemble/a.out","startMethod":"launch","systemProcessId":2334713},"event":"process","seq":0,"type":"event"}
1748538209.808105230 <-- (stdio) {"command":"configurationDone","request_seq":4,"seq":0,"success":true,"type":"response"}
1748538209.808176041 --> (stdio) {"command":"threads","type":"request","arguments":{},"seq":5}
1748538209.808200359 <-- (stdio) {"body":{"threads":[{"id":2334713,"name":"a.out"}]},"command":"threads","request_seq":5,"seq":0,"success":true,"type":"response"}
1748538209.944819212 <-- (stdio) {"body":{"module":{"addressRange":"0xfffff7cc0000","id":"AD8704B8-637D-63A8-F746-C5E0CDEC8708-40569A81","name":"libgcc_s.so.1","path":"/lib/aarch64-linux-gnu/libgcc_s.so.1","symbolStatus":"Symbols not found."},"reason":"new"},"event":"module","seq":0,"type":"event"}
1748538209.944906950 <-- (stdio) {"body":{"module":{"addressRange":"0xfffff7cf0000","debugInfoSize":"437.8KB","id":"86686E2C-1E7D-044E-EF26-4708ABADA31E-1830BAA5","name":"libm.so.6","path":"/lib/aarch64-linux-gnu/libm.so.6","symbolFilePath":"/usr/lib/debug/.build-id/86/686e2c1e7d044eef264708abada31e1830baa5.debug","symbolStatus":"Symbols loaded."},"reason":"new"},"event":"module","seq":0,"type":"event"}
1748538209.944927216 <-- (stdio) {"body":{"module":{"addressRange":"0xfffff7d90000","id":"A012B2BB-7711-0E84-B266-CD7425B50E57-427ABB02","name":"libstdc++.so.6","path":"/lib/aarch64-linux-gnu/libstdc++.so.6","symbolStatus":"Symbols not found."},"reason":"new"},"event":"module","seq":0,"type":"event"}
1748538209.944978952 <-- (stdio) {"body":{"module":{"addressRange":"0xfffff7b10000","debugInfoSize":"3.4MB","id":"2A450FE7-4D1B-79A3-21CC-1B12337FC31A-2C3FB834","name":"libc.so.6","path":"/lib/aarch64-linux-gnu/libc.so.6","symbolFilePath":"/usr/lib/debug/.build-id/2a/450fe74d1b79a321cc1b12337fc31a2c3fb834.debug","symbolStatus":"Symbols loaded."},"reason":"new"},"event":"module","seq":0,"type":"event"}

@ashgti
Copy link
Contributor Author

ashgti commented May 29, 2025

I'm surprised by some of these failures, since it passed on buildkite and the premerge check that are also on linux x86_64. Trying to understand the reason for these failures.

@da-viper
Copy link
Contributor

same I ran it on my computer x86_64 linux fedora 42 no issues. I will update the TestDAP_optimized.py,
I checked the log and it matched (for TestDAP_optimized`. Will update the test to show the value in the error message.

svkeerthy pushed a commit that referenced this pull request May 29, 2025
Improving the readability and correctness of DebugCommunication by
adding type annotations to many parts of the library and trying to
improve the implementation of a few key areas of the code to better
handle correctness.

Specifically, this refactored the
`DebugCommunication._handle_recv_packet` function to ensure consistency
with the reader thread when handling state changes and improved the
`DebugCommunication._recv_packet` helper to make it easier to follow by
adding some additional helpers.
@da-viper
Copy link
Contributor

The test for disassembly is failing because the test is wrong.

The memory reference can have a corresponding source location. if there is debuginfo installed on the computer or it is downloaded with debuginfod.

# The calling frame (qsort) is coming from a system library, as a result
# we should not have a source location.
_, qsort_assembly = self.disassemble(frameIndex=1)
self.assertNotIn("location", qsort_assembly, "Source location not expected.")
self.assertIn("instruction", pc_assembly, "Assembly instruction missing.")

da-viper added a commit that referenced this pull request May 29, 2025
…142030)

Show the expected value in the error message so we can see the expected
value without searching through the log messages.

Related #141689
google-yfyang pushed a commit to google-yfyang/llvm-project that referenced this pull request May 29, 2025
Improving the readability and correctness of DebugCommunication by
adding type annotations to many parts of the library and trying to
improve the implementation of a few key areas of the code to better
handle correctness.

Specifically, this refactored the
`DebugCommunication._handle_recv_packet` function to ensure consistency
with the reader thread when handling state changes and improved the
`DebugCommunication._recv_packet` helper to make it easier to follow by
adding some additional helpers.
@frederick-vs-ja
Copy link
Contributor

This PR seemingly made disableASLR default to True again.

@DavidSpickett
Copy link
Collaborator

@DavidSpickett
Copy link
Collaborator

The memory reference can have a corresponding source location. if there is debuginfo installed on the computer or it is downloaded with debuginfod.

Sounds like the failure we see:

FAIL: test_generic_evaluate_expressions (TestDAP_evaluate.TestDAP_evaluate)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py", line 228, in test_generic_evaluate_expressions
    self.run_test_evaluate_expressions(enableAutoVariableSummaries=False)
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py", line 117, in run_test_evaluate_expressions
    self.assertEvaluateFailure("list")  # local variable of a_function
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py", line 22, in assertEvaluateFailure
    self.assertNotIn(
AssertionError: 'result' unexpectedly found in {'memoryReference': '0xFFFFF7CB3060', 'result': '0x0000000000000000', 'type': 'int *', 'variablesReference': 7}
Config=aarch64-/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang

We have libdebuginfod installed:

# apt list --installed | grep debug

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

debugedit/now 1:5.0-4build1 arm64 [installed,local]
libdebuginfod-common/now 0.186-1build1 all [installed,local]
libdebuginfod1/now 0.186-1build1 arm64 [installed,local]

We don't have httplib installed though and don't see the URLs env var (https://documentation.ubuntu.com/server/explanation/debugging/about-debuginfod/index.html).

So we could be getting the location from a dev or debug info package from apt.

@DavidSpickett
Copy link
Collaborator

Sorry, the above failure is a different assumption.

Our disassembly test failure is:

======================================================================
FAIL: test_disassemble (TestDAP_disassemble.TestDAP_disassemble)
   Tests the 'disassemble' request.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/disassemble/TestDAP_disassemble.py", line 33, in test_disassemble
    self.assertNotIn("location", qsort_assembly, "Source location not expected.")
AssertionError: 'location' unexpectedly found in {'address': '0xFFFFF7B4BF68', 'column': 7, 'endColumn': 27, 'endLine': 66, 'instruction': '    cmp     w0, #0x0', 'instructionBytes': '1f 00 00 71', 'line': 64, 'location': {'name': 'msort.c', 'path': 'stdlib/msort.c'}} : Source location not expected.
Config=aarch64-/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang
----------------------------------------------------------------------

We have the libc debug symbols installed:

$ apt list --installed | grep libc6

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

libc6-dbg/now 2.35-0ubuntu3.9 arm64 [installed,local]
libc6-dev/now 2.35-0ubuntu3.9 arm64 [installed,local]
libc6/now 2.35-0ubuntu3.9 arm64 [installed,local]

Could the test work with a function marked with nodebug instead? https://clang.llvm.org/docs/AttributeReference.html#nodebug

(perhaps that will still have a source location)

DavidSpickett added a commit that referenced this pull request May 30, 2025
…1689)"

This reverts commit 8a49db3.

Due to failures on Arm and AArch64 Linux:
https://lab.llvm.org/buildbot/#/builders/59/builds/18540
https://lab.llvm.org/buildbot/#/builders/18/builds/16759

  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py", line 22, in assertEvaluateFailure
    self.assertNotIn(
AssertionError: 'result' unexpectedly found in {'memoryReference': '0xFFFFF7CB3060', 'result': '0x0000000000000000', 'type': 'int *', 'variablesReference': 7}

FAIL: test_generic_evaluate_expressions (TestDAP_evaluate.TestDAP_evaluate)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py", line 228, in test_generic_evaluate_expressions
    self.run_test_evaluate_expressions(enableAutoVariableSummaries=False)
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py", line 117, in run_test_evaluate_expressions
    self.assertEvaluateFailure("list")  # local variable of a_function
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py", line 22, in assertEvaluateFailure
    self.assertNotIn(
AssertionError: 'result' unexpectedly found in {'memoryReference': '0xFFFFF7CB3060', 'result': '0x0000000000000000', 'type': 'int *', 'variablesReference': 7}
Config=aarch64-/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang

The second one is because our bots have the libc debug info package installed,
the first, no idea.
@DavidSpickett
Copy link
Collaborator

Reverted, please take a look and fix. Reproducing should be possible by installing the libc debug package, not sure what's going on with the other failure. Let me know if you need me to investigate it locally.

@da-viper
Copy link
Contributor

Changing the test for disassemble to not depend on source location.
#142129

@ashgti
Copy link
Contributor Author

ashgti commented May 30, 2025

This PR seemingly made disableASLR default to True again.

doh... I'll fix this when I make a new attempt at merging this PR in.

Reverted, please take a look and fix. Reproducing should be possible by installing the libc debug package, not sure what's going on with the other failure. Let me know if you need me to investigate it locally.

Taking a look. I'll rebase this on #142129 and see if that fixes it.

sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Jun 3, 2025
Improving the readability and correctness of DebugCommunication by
adding type annotations to many parts of the library and trying to
improve the implementation of a few key areas of the code to better
handle correctness.

Specifically, this refactored the
`DebugCommunication._handle_recv_packet` function to ensure consistency
with the reader thread when handling state changes and improved the
`DebugCommunication._recv_packet` helper to make it easier to follow by
adding some additional helpers.
sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Jun 3, 2025
…lvm#142030)

Show the expected value in the error message so we can see the expected
value without searching through the log messages.

Related llvm#141689
sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Jun 3, 2025
…m#141689)"

This reverts commit 8a49db3.

Due to failures on Arm and AArch64 Linux:
https://lab.llvm.org/buildbot/#/builders/59/builds/18540
https://lab.llvm.org/buildbot/#/builders/18/builds/16759

  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py", line 22, in assertEvaluateFailure
    self.assertNotIn(
AssertionError: 'result' unexpectedly found in {'memoryReference': '0xFFFFF7CB3060', 'result': '0x0000000000000000', 'type': 'int *', 'variablesReference': 7}

FAIL: test_generic_evaluate_expressions (TestDAP_evaluate.TestDAP_evaluate)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py", line 228, in test_generic_evaluate_expressions
    self.run_test_evaluate_expressions(enableAutoVariableSummaries=False)
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py", line 117, in run_test_evaluate_expressions
    self.assertEvaluateFailure("list")  # local variable of a_function
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/evaluate/TestDAP_evaluate.py", line 22, in assertEvaluateFailure
    self.assertNotIn(
AssertionError: 'result' unexpectedly found in {'memoryReference': '0xFFFFF7CB3060', 'result': '0x0000000000000000', 'type': 'int *', 'variablesReference': 7}
Config=aarch64-/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang

The second one is because our bots have the libc debug info package installed,
the first, no idea.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants