aboutsummaryrefslogtreecommitdiff
path: root/lldb
diff options
context:
space:
mode:
Diffstat (limited to 'lldb')
-rw-r--r--lldb/cmake/modules/LLDBFramework.cmake2
-rw-r--r--lldb/docs/resources/lldbgdbremote.md51
-rw-r--r--lldb/include/lldb/lldb-enumerations.h2
-rw-r--r--lldb/packages/Python/lldbsuite/test/gdbclientutils.py70
-rw-r--r--lldb/source/Commands/CommandOptionsProcessLaunch.cpp4
-rw-r--r--lldb/source/Commands/Options.td5
-rw-r--r--lldb/source/Host/freebsd/Host.cpp3
-rw-r--r--lldb/source/Host/macosx/objcxx/Host.mm32
-rw-r--r--lldb/source/Host/windows/MainLoopWindows.cpp6
-rw-r--r--lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp13
-rw-r--r--lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp19
-rw-r--r--lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp4
-rw-r--r--lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp9
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp16
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp5
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp2
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp2
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp15
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/MsvcStlAtomic.cpp2
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp84
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h7
-rw-r--r--lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp2
-rw-r--r--lldb/source/Plugins/Process/Utility/LinuxSignals.cpp2
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp44
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp10
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h3
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp31
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp64
-rw-r--r--lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp91
-rw-r--r--lldb/test/API/functionalities/unwind/cortex-m-exception/TestCortexMExceptionUnwind.py4
-rw-r--r--lldb/test/API/macosx/debugserver-multimemread/Makefile3
-rw-r--r--lldb/test/API/macosx/debugserver-multimemread/TestDebugserverMultiMemRead.py102
-rw-r--r--lldb/test/API/macosx/debugserver-multimemread/main.c14
-rw-r--r--lldb/test/API/macosx/mte/Makefile9
-rw-r--r--lldb/test/API/macosx/mte/TestDarwinMTE.py14
-rw-r--r--lldb/test/API/tools/lldb-dap/attach-commands/Makefile3
-rw-r--r--lldb/test/API/tools/lldb-dap/attach-commands/TestDAP_attachCommands.py147
-rw-r--r--lldb/test/API/tools/lldb-dap/attach-commands/main.c30
-rw-r--r--lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py205
-rw-r--r--lldb/test/API/tools/lldb-dap/attach/main.c11
-rw-r--r--lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py3
-rw-r--r--lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py35
-rw-r--r--lldb/test/Shell/SymbolFile/NativePDB/local-variables-registers.s4
-rw-r--r--lldb/test/Shell/SymbolFile/NativePDB/simple-types.cpp29
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.cpp121
-rw-r--r--lldb/tools/debugserver/source/RNBRemote.h2
-rw-r--r--lldb/tools/lldb-dap/ProtocolUtils.cpp8
-rw-r--r--lldb/tools/lldb-mcp/lldb-mcp.cpp2
-rw-r--r--lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp22
49 files changed, 952 insertions, 416 deletions
diff --git a/lldb/cmake/modules/LLDBFramework.cmake b/lldb/cmake/modules/LLDBFramework.cmake
index c6f00ed..23d9d49 100644
--- a/lldb/cmake/modules/LLDBFramework.cmake
+++ b/lldb/cmake/modules/LLDBFramework.cmake
@@ -68,8 +68,6 @@ if(NOT APPLE_EMBEDDED)
)
endif()
-find_program(unifdef_EXECUTABLE unifdef)
-
# Wrap output in a target, so lldb-framework can depend on it.
add_custom_target(liblldb-resource-headers DEPENDS lldb-sbapi-dwarf-enums ${lldb_staged_headers})
set_target_properties(liblldb-resource-headers PROPERTIES FOLDER "LLDB/Resources")
diff --git a/lldb/docs/resources/lldbgdbremote.md b/lldb/docs/resources/lldbgdbremote.md
index 93fb0c9..f0c5e6b 100644
--- a/lldb/docs/resources/lldbgdbremote.md
+++ b/lldb/docs/resources/lldbgdbremote.md
@@ -738,6 +738,57 @@ This is a performance optimization, which speeds up debugging by avoiding
multiple round-trips for retrieving thread information. The information from this
packet can be retrieved using a combination of `qThreadStopInfo` and `m` packets.
+### MultiMemRead
+
+Read memory from multiple memory ranges.
+
+This packet has one argument:
+
+* `ranges`: a list of pairs of numbers, formatted in base-16. Each pair is
+separated by a `,`, as is each number in each pair. The first number of the
+pair denotes the base address of the memory read, the second denotes the number
+of bytes to be read. The list must end with a `;`.
+
+The reply packet starts with a comma-separated list of numbers formatted in
+base-16, denoting how many bytes were read from each range, in the same order
+as the request packet. The list is followed by a `;`, followed by a sequence of
+bytes containing binary encoded data for all memory that was read. The length
+of the binary encodeed data, after being decoded as required by the GDB remote
+protocol, must be equal to the sum of the numbers provided at the start of the
+reply. The order of the binary data is the same as the order of the ranges in
+the request packet.
+
+If some part of a range is not readable, the stub may perform a partial read of
+a prefix of the range. In other words, partial reads will only ever be from the
+start of the range, never the middle or end. Support for partial reads depends
+on the debug stub.
+
+If, by applying the rules above, the stub has read zero bytes from a range, it
+must return a length of zero for that range in the reply packet; no bytes for
+this memory range are included in the sequence of bytes that follows.
+
+A stub that supports this packet must include `MultiMemRead+` in the reply to
+`qSupported`.
+
+```
+send packet: $MultiMemRead:ranges:100a00,4,200200,a0,400000,4;
+read packet: $4,0,2;<binary encoding of abcd1000><binary encoding of eeff>
+```
+
+In the example above, the first read produced `abcd1000`, the read of `a0`
+bytes from address `200200` failed to read any bytes, and the third read
+produced two bytes – `eeff` – out of the four requested.
+
+```
+send packet: $MultiMemRead:ranges:100a00,0;
+read packet: $0;
+```
+
+In the example above, a read of zero bytes was requested.
+
+**Priority to Implement:** Only required for performance, the debugger will
+fall back to doing separate read requests if this packet is unavailable.
+
## QEnvironment:NAME=VALUE
Setup the environment up for a new child process that will soon be
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index fec9fde..1a7db8f 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -130,6 +130,8 @@ FLAGS_ENUM(LaunchFlags){
eLaunchFlagInheritTCCFromParent =
(1u << 12), ///< Don't make the inferior responsible for its own TCC
///< permissions but instead inherit them from its parent.
+ eLaunchFlagMemoryTagging =
+ (1u << 13), ///< Launch process with memory tagging explicitly enabled.
};
/// Thread Run Modes.
diff --git a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
index 53e991a..1a2860a 100644
--- a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
+++ b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
@@ -1,3 +1,4 @@
+from abc import ABC, abstractmethod
import ctypes
import errno
import io
@@ -5,6 +6,7 @@ import threading
import socket
import traceback
from lldbsuite.support import seven
+from typing import Optional, List, Tuple
def checksum(message):
@@ -86,7 +88,7 @@ class MockGDBServerResponder:
handles any packet not recognized in the common packet handling code.
"""
- registerCount = 40
+ registerCount: int = 40
class RESPONSE_DISCONNECT:
pass
@@ -95,7 +97,7 @@ class MockGDBServerResponder:
pass
def __init__(self):
- self.packetLog = []
+ self.packetLog: List[str] = []
def respond(self, packet):
"""
@@ -241,7 +243,7 @@ class MockGDBServerResponder:
def qHostInfo(self):
return "ptrsize:8;endian:little;"
- def qEcho(self):
+ def qEcho(self, num: int):
return "E04"
def qQueryGDBServer(self):
@@ -262,10 +264,10 @@ class MockGDBServerResponder:
def D(self, packet):
return "OK"
- def readRegisters(self):
+ def readRegisters(self) -> str:
return "00000000" * self.registerCount
- def readRegister(self, register):
+ def readRegister(self, register: int) -> str:
return "00000000"
def writeRegisters(self, registers_hex):
@@ -305,7 +307,9 @@ class MockGDBServerResponder:
# SIGINT is 2, return type is 2 digit hex string
return "S02"
- def qXferRead(self, obj, annex, offset, length):
+ def qXferRead(
+ self, obj: str, annex: str, offset: int, length: int
+ ) -> Tuple[Optional[str], bool]:
return None, False
def _qXferResponse(self, data, has_more):
@@ -373,15 +377,17 @@ class MockGDBServerResponder:
pass
-class ServerChannel:
+class ServerChannel(ABC):
"""
A wrapper class for TCP or pty-based server.
"""
- def get_connect_address(self):
+ @abstractmethod
+ def get_connect_address(self) -> str:
"""Get address for the client to connect to."""
- def get_connect_url(self):
+ @abstractmethod
+ def get_connect_url(self) -> str:
"""Get URL suitable for process connect command."""
def close_server(self):
@@ -393,10 +399,12 @@ class ServerChannel:
def close_connection(self):
"""Close all resources used by the accepted connection."""
- def recv(self):
+ @abstractmethod
+ def recv(self) -> bytes:
"""Receive a data packet from the connected client."""
- def sendall(self, data):
+ @abstractmethod
+ def sendall(self, data: bytes) -> None:
"""Send the data to the connected client."""
@@ -427,11 +435,11 @@ class ServerSocket(ServerChannel):
self._connection.close()
self._connection = None
- def recv(self):
+ def recv(self) -> bytes:
assert self._connection is not None
return self._connection.recv(4096)
- def sendall(self, data):
+ def sendall(self, data: bytes) -> None:
assert self._connection is not None
return self._connection.sendall(data)
@@ -443,10 +451,10 @@ class TCPServerSocket(ServerSocket):
)[0]
super().__init__(family, type, proto, addr)
- def get_connect_address(self):
+ def get_connect_address(self) -> str:
return "[{}]:{}".format(*self._server_socket.getsockname())
- def get_connect_url(self):
+ def get_connect_url(self) -> str:
return "connect://" + self.get_connect_address()
@@ -454,10 +462,10 @@ class UnixServerSocket(ServerSocket):
def __init__(self, addr):
super().__init__(socket.AF_UNIX, socket.SOCK_STREAM, 0, addr)
- def get_connect_address(self):
+ def get_connect_address(self) -> str:
return self._server_socket.getsockname()
- def get_connect_url(self):
+ def get_connect_url(self) -> str:
return "unix-connect://" + self.get_connect_address()
@@ -471,7 +479,7 @@ class PtyServerSocket(ServerChannel):
self._primary = io.FileIO(primary, "r+b")
self._secondary = io.FileIO(secondary, "r+b")
- def get_connect_address(self):
+ def get_connect_address(self) -> str:
libc = ctypes.CDLL(None)
libc.ptsname.argtypes = (ctypes.c_int,)
libc.ptsname.restype = ctypes.c_char_p
@@ -484,7 +492,7 @@ class PtyServerSocket(ServerChannel):
self._secondary.close()
self._primary.close()
- def recv(self):
+ def recv(self) -> bytes:
try:
return self._primary.read(4096)
except OSError as e:
@@ -493,8 +501,8 @@ class PtyServerSocket(ServerChannel):
return b""
raise
- def sendall(self, data):
- return self._primary.write(data)
+ def sendall(self, data: bytes) -> None:
+ self._primary.write(data)
class MockGDBServer:
@@ -527,18 +535,21 @@ class MockGDBServer:
self._thread.join()
self._thread = None
- def get_connect_address(self):
+ def get_connect_address(self) -> str:
+ assert self._socket is not None
return self._socket.get_connect_address()
- def get_connect_url(self):
+ def get_connect_url(self) -> str:
+ assert self._socket is not None
return self._socket.get_connect_url()
def run(self):
+ assert self._socket is not None
# For testing purposes, we only need to worry about one client
# connecting just one time.
try:
self._socket.accept()
- except:
+ except Exception:
traceback.print_exc()
return
self._shouldSendAck = True
@@ -553,7 +564,7 @@ class MockGDBServer:
self._receive(data)
except self.TerminateConnectionException:
pass
- except Exception as e:
+ except Exception:
print(
"An exception happened when receiving the response from the gdb server. Closing the client..."
)
@@ -586,7 +597,9 @@ class MockGDBServer:
Once a complete packet is found at the front of self._receivedData,
its data is removed form self._receivedData.
"""
+ assert self._receivedData is not None
data = self._receivedData
+ assert self._receivedDataOffset is not None
i = self._receivedDataOffset
data_len = len(data)
if data_len == 0:
@@ -639,10 +652,13 @@ class MockGDBServer:
self._receivedDataOffset = 0
return packet
- def _sendPacket(self, packet):
- self._socket.sendall(seven.bitcast_to_bytes(frame_packet(packet)))
+ def _sendPacket(self, packet: str):
+ assert self._socket is not None
+ framed_packet = seven.bitcast_to_bytes(frame_packet(packet))
+ self._socket.sendall(framed_packet)
def _handlePacket(self, packet):
+ assert self._socket is not None
if packet is self.PACKET_ACK:
# Ignore ACKs from the client. For the future, we can consider
# adding validation code to make sure the client only sends ACKs
diff --git a/lldb/source/Commands/CommandOptionsProcessLaunch.cpp b/lldb/source/Commands/CommandOptionsProcessLaunch.cpp
index 21d94d6..8ae20bd 100644
--- a/lldb/source/Commands/CommandOptionsProcessLaunch.cpp
+++ b/lldb/source/Commands/CommandOptionsProcessLaunch.cpp
@@ -127,6 +127,10 @@ Status CommandOptionsProcessLaunch::SetOptionValue(
break;
}
+ case 'M':
+ launch_info.GetFlags().Set(eLaunchFlagMemoryTagging);
+ break;
+
case 'c':
if (!option_arg.empty())
launch_info.SetShell(FileSpec(option_arg));
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index 595b3d0..a9f054e 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -1173,6 +1173,11 @@ let Command = "process launch" in {
Arg<"Boolean">,
Desc<"Set whether to shell expand arguments to the process when "
"launching.">;
+ def process_launch_memory_tagging
+ : Option<"memory-tagging", "M">,
+ Desc<"Set whether to explicitly enable memory tagging when launching "
+ "the process. Requires hardware support. "
+ "(Only supported on Darwin.)">;
}
let Command = "process attach" in {
diff --git a/lldb/source/Host/freebsd/Host.cpp b/lldb/source/Host/freebsd/Host.cpp
index fa7efad..dfdbfea 100644
--- a/lldb/source/Host/freebsd/Host.cpp
+++ b/lldb/source/Host/freebsd/Host.cpp
@@ -18,8 +18,6 @@
#include <dlfcn.h>
#include <execinfo.h>
-#include "llvm/Object/ELF.h"
-
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
@@ -32,6 +30,7 @@
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StreamString.h"
+#include "llvm/Object/ELF.h"
#include "llvm/TargetParser/Host.h"
namespace lldb_private {
diff --git a/lldb/source/Host/macosx/objcxx/Host.mm b/lldb/source/Host/macosx/objcxx/Host.mm
index 3c1d117..96a282c 100644
--- a/lldb/source/Host/macosx/objcxx/Host.mm
+++ b/lldb/source/Host/macosx/objcxx/Host.mm
@@ -1210,6 +1210,38 @@ static Status LaunchProcessPosixSpawn(const char *exe_path,
}
}
+ if (launch_info.GetFlags().Test(eLaunchFlagMemoryTagging)) {
+ // The following function configures the spawn attributes to launch the
+ // process with memory tagging explicitly enabled. We look it up
+ // dynamically since it is only available on newer OS. Does nothing on
+ // hardware which does not support MTE.
+ //
+ // int posix_spawnattr_set_use_sec_transition_shims_np(
+ // posix_spawnattr_t *attr, uint32_t flags);
+ //
+ using posix_spawnattr_set_use_sec_transition_shims_np_t =
+ int (*)(posix_spawnattr_t *attr, uint32_t flags);
+ auto posix_spawnattr_enable_memory_tagging_fn =
+ (posix_spawnattr_set_use_sec_transition_shims_np_t)dlsym(
+ RTLD_DEFAULT, "posix_spawnattr_set_use_sec_transition_shims_np");
+ if (posix_spawnattr_enable_memory_tagging_fn) {
+ error = Status(posix_spawnattr_enable_memory_tagging_fn(&attr, 0),
+ eErrorTypePOSIX);
+ if (error.Fail()) {
+ LLDB_LOG(log,
+ "error: {0}, "
+ "posix_spawnattr_set_use_sec_transition_shims_np(&attr, 0)",
+ error);
+ return error;
+ }
+ } else {
+ LLDB_LOG(log,
+ "error: posix_spawnattr_set_use_sec_transition_shims_np not "
+ "available",
+ error);
+ }
+ }
+
// Don't set the binpref if a shell was provided. After all, that's only
// going to affect what version of the shell is launched, not what fork of
// the binary is launched. We insert "arch --arch <ARCH> as part of the
diff --git a/lldb/source/Host/windows/MainLoopWindows.cpp b/lldb/source/Host/windows/MainLoopWindows.cpp
index c0b1079..9b7df10 100644
--- a/lldb/source/Host/windows/MainLoopWindows.cpp
+++ b/lldb/source/Host/windows/MainLoopWindows.cpp
@@ -55,11 +55,7 @@ public:
if (m_monitor_thread.joinable()) {
m_stopped = true;
SetEvent(m_ready);
- // Keep trying to cancel ReadFile() until the thread exits.
- do {
- CancelIoEx(m_handle, /*lpOverlapped=*/NULL);
- } while (WaitForSingleObject(m_monitor_thread.native_handle(), 1) ==
- WAIT_TIMEOUT);
+ CancelIoEx(m_handle, /*lpOverlapped=*/NULL);
m_monitor_thread.join();
}
CloseHandle(m_event);
diff --git a/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp b/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp
index e6c8c8b..7bf99ce 100644
--- a/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp
+++ b/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp
@@ -597,15 +597,16 @@ bool ABISysV_loongarch::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
return llvm::StringSwitch<bool>(name)
// integer ABI names
- .Cases("ra", "sp", "fp", true)
- .Cases("s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", true)
+ .Cases({"ra", "sp", "fp"}, true)
+ .Cases({"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9"}, true)
// integer hardware names
- .Cases("r1", "r3", "r22", true)
- .Cases("r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "31", true)
+ .Cases({"r1", "r3", "r22"}, true)
+ .Cases({"r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "31"},
+ true)
// floating point ABI names
- .Cases("fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", is_hw_fp)
+ .Cases({"fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7"}, is_hw_fp)
// floating point hardware names
- .Cases("f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", is_hw_fp)
+ .Cases({"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"}, is_hw_fp)
.Default(false);
}
diff --git a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
index b313ca0..822c93d 100644
--- a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
+++ b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
@@ -783,21 +783,22 @@ bool ABISysV_riscv::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
bool is_callee_saved =
llvm::StringSwitch<bool>(name)
// integer ABI names
- .Cases("ra", "sp", "fp", true)
- .Cases("s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9",
+ .Cases({"ra", "sp", "fp"}, true)
+ .Cases({"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9"},
true)
- .Cases("s10", "s11", true)
+ .Cases({"s10", "s11"}, true)
// integer hardware names
- .Cases("x1", "x2", "x8", "x9", "x18", "x19", "x20", "x21", "x22",
+ .Cases({"x1", "x2", "x8", "x9", "x18", "x19", "x20", "x21", "x22"},
true)
- .Cases("x23", "x24", "x25", "x26", "x27", true)
+ .Cases({"x23", "x24", "x25", "x26", "x27"}, true)
// floating point ABI names
- .Cases("fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
+ .Cases({"fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7"},
is_hw_fp)
- .Cases("fs8", "fs9", "fs10", "fs11", is_hw_fp)
+ .Cases({"fs8", "fs9", "fs10", "fs11"}, is_hw_fp)
// floating point hardware names
- .Cases("f8", "f9", "f18", "f19", "f20", "f21", "f22", "f23", is_hw_fp)
- .Cases("f24", "f25", "f26", "f27", is_hw_fp)
+ .Cases({"f8", "f9", "f18", "f19", "f20", "f21", "f22", "f23"},
+ is_hw_fp)
+ .Cases({"f24", "f25", "f26", "f27"}, is_hw_fp)
.Default(false);
return is_callee_saved;
diff --git a/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp b/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp
index 7646ccd..effb3de 100644
--- a/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp
+++ b/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp
@@ -929,8 +929,8 @@ bool ABISysV_x86_64::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
std::string Name = std::string(reg_info->name);
bool IsCalleeSaved =
llvm::StringSwitch<bool>(Name)
- .Cases("r12", "r13", "r14", "r15", "rbp", "ebp", "rbx", "ebx", true)
- .Cases("rip", "eip", "rsp", "esp", "sp", "fp", "pc", true)
+ .Cases({"r12", "r13", "r14", "r15", "rbp", "ebp", "rbx", "ebx"}, true)
+ .Cases({"rip", "eip", "rsp", "esp", "sp", "fp", "pc"}, true)
.Default(false);
return IsCalleeSaved;
}
diff --git a/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp
index 56df6f6..339012c 100644
--- a/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp
+++ b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp
@@ -797,10 +797,11 @@ bool ABIWindows_x86_64::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
std::string Name = std::string(reg_info->name);
bool IsCalleeSaved =
llvm::StringSwitch<bool>(Name)
- .Cases("rbx", "ebx", "rbp", "ebp", "rdi", "edi", "rsi", "esi", true)
- .Cases("rsp", "esp", "r12", "r13", "r14", "r15", "sp", "fp", true)
- .Cases("xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12",
- "xmm13", "xmm14", "xmm15", true)
+ .Cases({"rbx", "ebx", "rbp", "ebp", "rdi", "edi", "rsi", "esi"}, true)
+ .Cases({"rsp", "esp", "r12", "r13", "r14", "r15", "sp", "fp"}, true)
+ .Cases({"xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12",
+ "xmm13", "xmm14", "xmm15"},
+ true)
.Default(false);
return IsCalleeSaved;
}
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
index 92094c0..e3b6ff8 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
@@ -332,8 +332,7 @@ CompilerType ClangASTImporter::DeportType(TypeSystemClang &dst,
DeclContextOverride decl_context_override;
if (auto *t = ClangUtil::GetQualType(src_type)->getAs<TagType>())
- decl_context_override.OverrideAllDeclsFromContainingFunction(
- t->getOriginalDecl());
+ decl_context_override.OverrideAllDeclsFromContainingFunction(t->getDecl());
CompleteTagDeclsScope complete_scope(*this, &dst.getASTContext(),
&src_ctxt->getASTContext());
@@ -393,7 +392,7 @@ bool ClangASTImporter::CanImport(const CompilerType &type) {
case clang::Type::Record:
return CanImport(qual_type->getAsCXXRecordDecl());
case clang::Type::Enum:
- return CanImport(llvm::cast<clang::EnumType>(qual_type)->getOriginalDecl());
+ return CanImport(llvm::cast<clang::EnumType>(qual_type)->getDecl());
case clang::Type::ObjCObject:
case clang::Type::ObjCInterface: {
const clang::ObjCObjectType *objc_class_type =
@@ -452,7 +451,7 @@ bool ClangASTImporter::Import(const CompilerType &type) {
case clang::Type::Enum: {
clang::EnumDecl *enum_decl =
- llvm::cast<clang::EnumType>(qual_type)->getOriginalDecl();
+ llvm::cast<clang::EnumType>(qual_type)->getDecl();
if (enum_decl) {
if (GetDeclOrigin(enum_decl).Valid())
return CompleteAndFetchChildren(qual_type);
@@ -591,7 +590,7 @@ bool ExtractBaseOffsets(const ASTRecordLayout &record_layout,
return false;
DeclFromUser<RecordDecl> origin_base_record(
- origin_base_record_type->getOriginalDecl());
+ origin_base_record_type->getDecl());
if (origin_base_record.IsInvalid())
return false;
@@ -722,8 +721,7 @@ bool ClangASTImporter::importRecordLayoutFromOrigin(
QualType base_type = bi->getType();
const RecordType *base_record_type = base_type->getAs<RecordType>();
- DeclFromParser<RecordDecl> base_record(
- base_record_type->getOriginalDecl());
+ DeclFromParser<RecordDecl> base_record(base_record_type->getDecl());
DeclFromParser<CXXRecordDecl> base_cxx_record =
DynCast<CXXRecordDecl>(base_record);
@@ -855,7 +853,7 @@ bool ClangASTImporter::CompleteAndFetchChildren(clang::QualType type) {
Log *log = GetLog(LLDBLog::Expressions);
if (const TagType *tag_type = type->getAs<TagType>()) {
- TagDecl *tag_decl = tag_type->getOriginalDecl();
+ TagDecl *tag_decl = tag_type->getDecl();
DeclOrigin decl_origin = GetDeclOrigin(tag_decl);
@@ -923,7 +921,7 @@ bool ClangASTImporter::RequireCompleteType(clang::QualType type) {
return false;
if (const TagType *tag_type = type->getAs<TagType>()) {
- TagDecl *tag_decl = tag_type->getOriginalDecl();
+ TagDecl *tag_decl = tag_type->getDecl();
if (tag_decl->getDefinition())
return true;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
index 21a9307..ebe7be4 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -223,7 +223,7 @@ TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) {
continue;
TagDecl *candidate_tag_decl =
- tag_type->getOriginalDecl()->getDefinitionOrSelf();
+ tag_type->getDecl()->getDefinitionOrSelf();
if (TypeSystemClang::GetCompleteDecl(
&candidate_tag_decl->getASTContext(), candidate_tag_decl))
@@ -250,8 +250,7 @@ TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) {
if (!tag_type)
continue;
- TagDecl *candidate_tag_decl =
- tag_type->getOriginalDecl()->getDefinitionOrSelf();
+ TagDecl *candidate_tag_decl = tag_type->getDecl()->getDefinitionOrSelf();
if (TypeSystemClang::GetCompleteDecl(&candidate_tag_decl->getASTContext(),
candidate_tag_decl))
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
index 8a68282..833bc3b 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -1561,7 +1561,7 @@ ClangExpressionDeclMap::AddExpressionVariable(NameSearchContext &context,
if (const clang::Type *parser_type = parser_opaque_type.getTypePtr()) {
if (const TagType *tag_type = dyn_cast<TagType>(parser_type))
- CompleteType(tag_type->getOriginalDecl()->getDefinitionOrSelf());
+ CompleteType(tag_type->getDecl()->getDefinitionOrSelf());
if (const ObjCObjectPointerType *objc_object_ptr_type =
dyn_cast<ObjCObjectPointerType>(parser_type))
CompleteType(objc_object_ptr_type->getInterfaceDecl());
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp
index 6f57c18..794b194 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp
@@ -153,7 +153,7 @@ NameSearchContext::AddTypeDecl(const CompilerType &clang_type) {
return (NamedDecl *)typedef_name_decl;
} else if (const TagType *tag_type = qual_type->getAs<TagType>()) {
- TagDecl *tag_decl = tag_type->getOriginalDecl()->getDefinitionOrSelf();
+ TagDecl *tag_decl = tag_type->getDecl()->getDefinitionOrSelf();
m_decls.push_back(tag_decl);
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
index 4b183a8..5588208 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
@@ -52,7 +52,7 @@ private:
ValueObject *m_tree = nullptr;
size_t m_num_elements = 0;
ValueObject *m_next_element = nullptr;
- std::vector<std::pair<ValueObject *, uint64_t>> m_elements_cache;
+ std::vector<ValueObject *> m_elements_cache;
};
class LibCxxUnorderedMapIteratorSyntheticFrontEnd
@@ -192,26 +192,25 @@ lldb::ValueObjectSP lldb_private::formatters::
return nullptr;
}
}
- m_elements_cache.push_back(
- {value_sp.get(), hash_sp->GetValueAsUnsigned(0)});
+ m_elements_cache.push_back(value_sp.get());
m_next_element = node_sp->GetChildMemberWithName("__next_").get();
if (!m_next_element || m_next_element->GetValueAsUnsigned(0) == 0)
m_next_element = nullptr;
}
- std::pair<ValueObject *, uint64_t> val_hash = m_elements_cache[idx];
- if (!val_hash.first)
+ ValueObject *val_hash = m_elements_cache[idx];
+ if (!val_hash)
return lldb::ValueObjectSP();
StreamString stream;
stream.Printf("[%" PRIu64 "]", (uint64_t)idx);
DataExtractor data;
Status error;
- val_hash.first->GetData(data, error);
+ val_hash->GetData(data, error);
if (error.Fail())
return lldb::ValueObjectSP();
const bool thread_and_frame_only_if_stopped = true;
- ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock(
- thread_and_frame_only_if_stopped);
+ ExecutionContext exe_ctx =
+ val_hash->GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped);
return CreateValueObjectFromData(stream.GetString(), data, exe_ctx,
m_element_type);
}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlAtomic.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlAtomic.cpp
index c871861..020ba1016 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlAtomic.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlAtomic.cpp
@@ -50,7 +50,7 @@ llvm::Expected<uint32_t> lldb_private::formatters::
lldb::ValueObjectSP
lldb_private::formatters::MsvcStlAtomicSyntheticFrontEnd::GetChildAtIndex(
uint32_t idx) {
- if (idx == 0)
+ if (idx == 0 && m_storage && m_element_type.IsValid())
return m_storage->Cast(m_element_type)->Clone(ConstString("Value"));
return nullptr;
}
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
index cc0c9e7..6d8f41a 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
@@ -14,6 +14,7 @@
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/lldb-enumerations.h"
+#include "llvm/ADT/Sequence.h"
using namespace lldb;
using namespace lldb_private;
@@ -266,22 +267,47 @@ bool ClassDescriptorV2::method_list_t::Read(Process *process,
return true;
}
-bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr,
- lldb::addr_t relative_selector_base_addr,
- bool is_small, bool has_direct_sel) {
- size_t ptr_size = process->GetAddressByteSize();
- size_t size = GetSize(process, is_small);
+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_private::Process *process = m_runtime.GetProcess();
+ if (!process)
+ return {};
- DataBufferHeap buffer(size, '\0');
- Status error;
+ const size_t size = method_t::GetSize(process, is_small);
+ const size_t num_methods = addresses.size();
- process->ReadMemory(addr, buffer.GetBytes(), size, error);
- if (error.Fail()) {
- return false;
+ llvm::SmallVector<uint8_t, 0> buffer(num_methods * size, 0);
+ llvm::DenseSet<uint32_t> failed_indices;
+
+ for (auto [idx, addr] : llvm::enumerate(addresses)) {
+ Status error;
+ process->ReadMemory(addr, buffer.data() + idx * size, size, error);
+ if (error.Fail())
+ failed_indices.insert(idx);
}
- DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
- ptr_size);
+ llvm::SmallVector<method_t, 0> methods;
+ methods.reserve(num_methods);
+ for (auto [idx, addr] : llvm::enumerate(addresses)) {
+ if (failed_indices.contains(idx))
+ continue;
+ DataExtractor extractor(buffer.data() + idx * size, size,
+ process->GetByteOrder(),
+ process->GetAddressByteSize());
+ methods.push_back(method_t());
+ methods.back().Read(extractor, process, addr, relative_selector_base_addr,
+ is_small, has_direct_sel);
+ }
+
+ return methods;
+}
+
+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::offset_t cursor = 0;
if (is_small) {
@@ -291,11 +317,11 @@ bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr,
m_name_ptr = addr + nameref_offset;
+ Status error;
if (!has_direct_sel) {
// The SEL offset points to a SELRef. We need to dereference twice.
- m_name_ptr = process->ReadUnsignedIntegerFromMemory(m_name_ptr, ptr_size,
- 0, error);
- if (!error.Success())
+ 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;
@@ -308,13 +334,13 @@ bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr,
m_imp_ptr = extractor.GetAddress_unchecked(&cursor);
}
+ Status error;
process->ReadCStringFromMemory(m_name_ptr, m_name, error);
- if (error.Fail()) {
+ if (error.Fail())
return false;
- }
process->ReadCStringFromMemory(m_types_ptr, m_types, error);
- return !error.Fail();
+ return error.Success();
}
bool ClassDescriptorV2::ivar_list_t::Read(Process *process, lldb::addr_t addr) {
@@ -447,17 +473,19 @@ ClassDescriptorV2::GetMethodList(Process *process,
bool ClassDescriptorV2::ProcessMethodList(
std::function<bool(const char *, const char *)> const &instance_method_func,
ClassDescriptorV2::method_list_t &method_list) const {
- lldb_private::Process *process = m_runtime.GetProcess();
- auto method = std::make_unique<method_t>();
- lldb::addr_t relative_selector_base_addr =
- m_runtime.GetRelativeSelectorBaseAddr();
- for (uint32_t i = 0, e = method_list.m_count; i < e; ++i) {
- method->Read(process, method_list.m_first_ptr + (i * method_list.m_entsize),
- relative_selector_base_addr, method_list.m_is_small,
- method_list.m_has_direct_selector);
- if (instance_method_func(method->m_name.c_str(), method->m_types.c_str()))
+ auto idx_to_method_addr = [&](uint32_t idx) {
+ return method_list.m_first_ptr + (idx * method_list.m_entsize);
+ };
+ llvm::SmallVector<addr_t> addresses = llvm::to_vector(llvm::map_range(
+ llvm::seq<uint32_t>(method_list.m_count), idx_to_method_addr));
+
+ llvm::SmallVector<method_t, 0> methods =
+ ReadMethods(addresses, m_runtime.GetRelativeSelectorBaseAddr(),
+ method_list.m_is_small, method_list.m_has_direct_selector);
+
+ for (const auto &method : methods)
+ if (instance_method_func(method.m_name.c_str(), method.m_types.c_str()))
break;
- }
return true;
}
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
index 920a5eb..78b3311 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
@@ -172,11 +172,16 @@ private:
+ field_size; // IMP imp;
}
- bool Read(Process *process, lldb::addr_t addr,
+ bool Read(DataExtractor &extractor, Process *process, lldb::addr_t addr,
lldb::addr_t relative_selector_base_addr, bool is_small,
bool has_direct_sel);
};
+ 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;
+
struct ivar_list_t {
uint32_t m_entsize;
uint32_t m_count;
diff --git a/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp b/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp
index 15981a2..a8d18f7 100644
--- a/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp
+++ b/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp
@@ -47,7 +47,7 @@ void GDBRemoteSignals::Reset() {
AddSignal(25, "SIGXFSZ", false, true, true, "file size limit exceeded");
AddSignal(26, "SIGVTALRM", false, true, true, "virtual time alarm");
AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm");
- AddSignal(28, "SIGWINCH", false, true, true, "window size changes");
+ AddSignal(28, "SIGWINCH", false, false, false, "window size changes");
AddSignal(29, "SIGLOST", false, true, true, "resource lost");
AddSignal(30, "SIGUSR1", false, true, true, "user defined signal 1");
AddSignal(31, "SIGUSR2", false, true, true, "user defined signal 2");
diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp
index 5346bab..dbbfc6a 100644
--- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp
+++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp
@@ -160,7 +160,7 @@ void LinuxSignals::Reset() {
ADD_LINUX_SIGNAL(25, "SIGXFSZ", false, true, true, "file size limit exceeded");
ADD_LINUX_SIGNAL(26, "SIGVTALRM", false, true, true, "virtual time alarm");
ADD_LINUX_SIGNAL(27, "SIGPROF", false, false, false, "profiling time alarm");
- ADD_LINUX_SIGNAL(28, "SIGWINCH", false, true, true, "window size changes");
+ ADD_LINUX_SIGNAL(28, "SIGWINCH", false, false, false, "window size changes");
ADD_LINUX_SIGNAL(29, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL");
ADD_LINUX_SIGNAL(30, "SIGPWR", false, true, true, "power failure");
ADD_LINUX_SIGNAL(31, "SIGSYS", false, true, true, "invalid system call");
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
index e0f3971..c361b2a 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
@@ -9,6 +9,7 @@
#include "RegisterContextFreeBSD_x86_64.h"
#include "RegisterContextFreeBSD_i386.h"
#include "RegisterContextPOSIX_x86.h"
+#include "llvm/Support/Threading.h"
#include <vector>
using namespace lldb_private;
@@ -69,40 +70,34 @@ struct UserArea {
#include "RegisterInfos_x86_64.h"
#undef DECLARE_REGISTER_INFOS_X86_64_STRUCT
-static std::vector<lldb_private::RegisterInfo> &GetSharedRegisterInfoVector() {
- static std::vector<lldb_private::RegisterInfo> register_infos;
- return register_infos;
-}
-
-static const RegisterInfo *
-GetRegisterInfo_i386(const lldb_private::ArchSpec &arch) {
- static std::vector<lldb_private::RegisterInfo> g_register_infos(
- GetSharedRegisterInfoVector());
-
- // Allocate RegisterInfo only once
- if (g_register_infos.empty()) {
- // Copy the register information from base class
- std::unique_ptr<RegisterContextFreeBSD_i386> reg_interface(
- new RegisterContextFreeBSD_i386(arch));
- const RegisterInfo *base_info = reg_interface->GetRegisterInfo();
- g_register_infos.insert(g_register_infos.end(), &base_info[0],
- &base_info[k_num_registers_i386]);
+static std::vector<lldb_private::RegisterInfo> &
+GetSharedRegisterInfoVector_i386(const lldb_private::ArchSpec &arch) {
+ static std::vector<lldb_private::RegisterInfo> g_register_infos;
+ static llvm::once_flag g_initialized;
+ llvm::call_once(g_initialized, [&]() {
+ if (g_register_infos.empty()) {
+ // Copy the register information from base class
+ std::unique_ptr<RegisterContextFreeBSD_i386> reg_interface(
+ new RegisterContextFreeBSD_i386(arch));
+ const RegisterInfo *base_info = reg_interface->GetRegisterInfo();
+ g_register_infos.insert(g_register_infos.end(), &base_info[0],
+ &base_info[k_num_registers_i386]);
// Include RegisterInfos_x86_64 to update the g_register_infos structure
// with x86_64 offsets.
#define UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
#include "RegisterInfos_x86_64.h"
#undef UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
- }
-
- return &g_register_infos[0];
+ }
+ });
+ return g_register_infos;
}
static const RegisterInfo *
PrivateGetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
switch (target_arch.GetMachine()) {
case llvm::Triple::x86:
- return GetRegisterInfo_i386(target_arch);
+ return &GetSharedRegisterInfoVector_i386(target_arch)[0];
case llvm::Triple::x86_64:
return g_register_infos_x86_64;
default:
@@ -116,9 +111,10 @@ PrivateGetRegisterCount(const lldb_private::ArchSpec &target_arch) {
switch (target_arch.GetMachine()) {
case llvm::Triple::x86:
// This vector should have already been filled.
- assert(!GetSharedRegisterInfoVector().empty() &&
+ assert(!GetSharedRegisterInfoVector_i386(target_arch).empty() &&
"i386 register info vector not filled.");
- return static_cast<uint32_t>(GetSharedRegisterInfoVector().size());
+ return static_cast<uint32_t>(
+ GetSharedRegisterInfoVector_i386(target_arch).size());
case llvm::Triple::x86_64:
return static_cast<uint32_t>(sizeof(g_register_infos_x86_64) /
sizeof(g_register_infos_x86_64[0]));
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 7d2bd45..11f164c 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -211,6 +211,12 @@ bool GDBRemoteCommunicationClient::GetReverseStepSupported() {
return m_supports_reverse_step == eLazyBoolYes;
}
+bool GDBRemoteCommunicationClient::GetMultiMemReadSupported() {
+ if (m_supports_multi_mem_read == eLazyBoolCalculate)
+ GetRemoteQSupported();
+ return m_supports_multi_mem_read == eLazyBoolYes;
+}
+
bool GDBRemoteCommunicationClient::QueryNoAckModeSupported() {
if (m_supports_not_sending_acks == eLazyBoolCalculate) {
m_send_acks = true;
@@ -339,6 +345,7 @@ void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) {
m_supported_async_json_packets_is_valid = false;
m_supported_async_json_packets_sp.reset();
m_supports_jModulesInfo = true;
+ m_supports_multi_mem_read = eLazyBoolCalculate;
}
// These flags should be reset when we first connect to a GDB server and when
@@ -365,6 +372,7 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
m_x_packet_state.reset();
m_supports_reverse_continue = eLazyBoolNo;
m_supports_reverse_step = eLazyBoolNo;
+ m_supports_multi_mem_read = eLazyBoolNo;
m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if
// not, we assume no limit
@@ -424,6 +432,8 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
m_supports_reverse_continue = eLazyBoolYes;
else if (x == "ReverseStep+")
m_supports_reverse_step = eLazyBoolYes;
+ else if (x == "MultiMemRead+")
+ m_supports_multi_mem_read = eLazyBoolYes;
// Look for a list of compressions in the features list e.g.
// qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-
// deflate,lzma
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index a765e95..ad590a2 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -342,6 +342,8 @@ public:
bool GetReverseStepSupported();
+ bool GetMultiMemReadSupported();
+
LazyBool SupportsAllocDeallocMemory() // const
{
// Uncomment this to have lldb pretend the debug server doesn't respond to
@@ -574,6 +576,7 @@ protected:
std::optional<xPacketState> m_x_packet_state;
LazyBool m_supports_reverse_continue = eLazyBoolCalculate;
LazyBool m_supports_reverse_step = eLazyBoolCalculate;
+ LazyBool m_supports_multi_mem_read = eLazyBoolCalculate;
bool m_supports_qProcessInfoPID : 1, m_supports_qfProcessInfo : 1,
m_supports_qUserName : 1, m_supports_qGroupName : 1,
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
index 888bd89..6c66d86 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
@@ -946,17 +946,21 @@ lldb_private::npdb::GetCompilerTypeForSimpleKind(SimpleTypeKind kind) {
case SimpleTypeKind::Complex64:
return lldb::eBasicTypeDoubleComplex;
case SimpleTypeKind::Complex32:
+ case SimpleTypeKind::Complex32PartialPrecision:
return lldb::eBasicTypeFloatComplex;
- case SimpleTypeKind::Float128:
case SimpleTypeKind::Float80:
return lldb::eBasicTypeLongDouble;
+ case SimpleTypeKind::Float128:
+ return lldb::eBasicTypeFloat128;
case SimpleTypeKind::Float64:
return lldb::eBasicTypeDouble;
case SimpleTypeKind::Float32:
+ case SimpleTypeKind::Float32PartialPrecision:
return lldb::eBasicTypeFloat;
case SimpleTypeKind::Float16:
return lldb::eBasicTypeHalf;
case SimpleTypeKind::Int128:
+ case SimpleTypeKind::Int128Oct:
return lldb::eBasicTypeInt128;
case SimpleTypeKind::Int64:
case SimpleTypeKind::Int64Quad:
@@ -967,6 +971,7 @@ lldb_private::npdb::GetCompilerTypeForSimpleKind(SimpleTypeKind kind) {
case SimpleTypeKind::Int16Short:
return lldb::eBasicTypeShort;
case SimpleTypeKind::UInt128:
+ case SimpleTypeKind::UInt128Oct:
return lldb::eBasicTypeUnsignedInt128;
case SimpleTypeKind::UInt64:
case SimpleTypeKind::UInt64Quad:
@@ -985,16 +990,27 @@ lldb_private::npdb::GetCompilerTypeForSimpleKind(SimpleTypeKind kind) {
return lldb::eBasicTypeVoid;
case SimpleTypeKind::WideCharacter:
return lldb::eBasicTypeWChar;
- default:
+
+ // Not supported.
+ case SimpleTypeKind::Float48:
+ case SimpleTypeKind::Complex16:
+ case SimpleTypeKind::Complex48:
+ case SimpleTypeKind::Complex128:
+ case SimpleTypeKind::NotTranslated:
+ case SimpleTypeKind::None:
return lldb::eBasicTypeInvalid;
}
+ return lldb::eBasicTypeInvalid;
}
size_t lldb_private::npdb::GetTypeSizeForSimpleKind(SimpleTypeKind kind) {
switch (kind) {
case SimpleTypeKind::Boolean128:
+ case SimpleTypeKind::Complex128:
case SimpleTypeKind::Int128:
+ case SimpleTypeKind::Int128Oct:
case SimpleTypeKind::UInt128:
+ case SimpleTypeKind::UInt128Oct:
case SimpleTypeKind::Float128:
return 16;
case SimpleTypeKind::Complex80:
@@ -1008,10 +1024,15 @@ size_t lldb_private::npdb::GetTypeSizeForSimpleKind(SimpleTypeKind kind) {
case SimpleTypeKind::Int64:
case SimpleTypeKind::Int64Quad:
return 8;
+ case SimpleTypeKind::Complex48:
+ case SimpleTypeKind::Float48:
+ return 6;
case SimpleTypeKind::Boolean32:
case SimpleTypeKind::Character32:
case SimpleTypeKind::Complex32:
+ case SimpleTypeKind::Complex32PartialPrecision:
case SimpleTypeKind::Float32:
+ case SimpleTypeKind::Float32PartialPrecision:
case SimpleTypeKind::Int32:
case SimpleTypeKind::Int32Long:
case SimpleTypeKind::UInt32Long:
@@ -1020,6 +1041,7 @@ size_t lldb_private::npdb::GetTypeSizeForSimpleKind(SimpleTypeKind kind) {
return 4;
case SimpleTypeKind::Boolean16:
case SimpleTypeKind::Character16:
+ case SimpleTypeKind::Complex16:
case SimpleTypeKind::Float16:
case SimpleTypeKind::Int16:
case SimpleTypeKind::Int16Short:
@@ -1035,10 +1057,13 @@ size_t lldb_private::npdb::GetTypeSizeForSimpleKind(SimpleTypeKind kind) {
case SimpleTypeKind::SByte:
case SimpleTypeKind::Character8:
return 1;
+
case SimpleTypeKind::Void:
- default:
+ case SimpleTypeKind::None:
+ case SimpleTypeKind::NotTranslated:
return 0;
}
+ return 0;
}
PdbTypeSymId lldb_private::npdb::GetBestPossibleDecl(PdbTypeSymId id,
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index 7e275f1..ecd3188 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -152,14 +152,24 @@ static bool IsFunctionEpilogue(const CompilandIndexItem &cci,
return false;
}
+// See llvm::codeview::TypeIndex::simpleTypeName as well as strForPrimitiveTi
+// from the original pdbdump:
+// https://github.com/microsoft/microsoft-pdb/blob/805655a28bd8198004be2ac27e6e0290121a5e89/pdbdump/pdbdump.cpp#L1896-L1974
+//
+// For 64bit integers we use "long long" like DIA instead of "__int64".
static llvm::StringRef GetSimpleTypeName(SimpleTypeKind kind) {
switch (kind) {
case SimpleTypeKind::Boolean128:
- case SimpleTypeKind::Boolean16:
- case SimpleTypeKind::Boolean32:
+ return "__bool128";
case SimpleTypeKind::Boolean64:
+ return "__bool64";
+ case SimpleTypeKind::Boolean32:
+ return "__bool32";
+ case SimpleTypeKind::Boolean16:
+ return "__bool16";
case SimpleTypeKind::Boolean8:
return "bool";
+
case SimpleTypeKind::Byte:
case SimpleTypeKind::UnsignedCharacter:
return "unsigned char";
@@ -168,57 +178,81 @@ static llvm::StringRef GetSimpleTypeName(SimpleTypeKind kind) {
case SimpleTypeKind::SignedCharacter:
case SimpleTypeKind::SByte:
return "signed char";
- case SimpleTypeKind::Character16:
- return "char16_t";
case SimpleTypeKind::Character32:
return "char32_t";
+ case SimpleTypeKind::Character16:
+ return "char16_t";
case SimpleTypeKind::Character8:
return "char8_t";
+
+ case SimpleTypeKind::Complex128:
+ return "_Complex __float128";
case SimpleTypeKind::Complex80:
+ return "_Complex long double";
case SimpleTypeKind::Complex64:
+ return "_Complex double";
+ case SimpleTypeKind::Complex48:
+ return "_Complex __float48";
case SimpleTypeKind::Complex32:
- return "complex";
+ case SimpleTypeKind::Complex32PartialPrecision:
+ return "_Complex float";
+ case SimpleTypeKind::Complex16:
+ return "_Complex _Float16";
+
case SimpleTypeKind::Float128:
+ return "__float128";
case SimpleTypeKind::Float80:
return "long double";
case SimpleTypeKind::Float64:
return "double";
+ case SimpleTypeKind::Float48:
+ return "__float48";
case SimpleTypeKind::Float32:
+ case SimpleTypeKind::Float32PartialPrecision:
return "float";
case SimpleTypeKind::Float16:
- return "single";
+ return "_Float16";
+
+ case SimpleTypeKind::Int128Oct:
case SimpleTypeKind::Int128:
return "__int128";
case SimpleTypeKind::Int64:
case SimpleTypeKind::Int64Quad:
- return "int64_t";
+ return "long long";
+ case SimpleTypeKind::Int32Long:
+ return "long";
case SimpleTypeKind::Int32:
return "int";
case SimpleTypeKind::Int16:
+ case SimpleTypeKind::Int16Short:
return "short";
+
+ case SimpleTypeKind::UInt128Oct:
case SimpleTypeKind::UInt128:
return "unsigned __int128";
case SimpleTypeKind::UInt64:
case SimpleTypeKind::UInt64Quad:
- return "uint64_t";
- case SimpleTypeKind::HResult:
- return "HRESULT";
+ return "unsigned long long";
case SimpleTypeKind::UInt32:
return "unsigned";
case SimpleTypeKind::UInt16:
case SimpleTypeKind::UInt16Short:
return "unsigned short";
- case SimpleTypeKind::Int32Long:
- return "long";
case SimpleTypeKind::UInt32Long:
return "unsigned long";
+
+ case SimpleTypeKind::HResult:
+ return "HRESULT";
case SimpleTypeKind::Void:
return "void";
case SimpleTypeKind::WideCharacter:
return "wchar_t";
- default:
+
+ case SimpleTypeKind::None:
+ case SimpleTypeKind::NotTranslated:
return "";
}
+ return "";
}
static bool IsClassRecord(TypeLeafKind kind) {
@@ -598,8 +632,8 @@ lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti,
uint64_t uid = toOpaqueUid(PdbTypeSymId(ti, false));
if (ti == TypeIndex::NullptrT()) {
Declaration decl;
- return MakeType(uid, ConstString("std::nullptr_t"), 0, nullptr,
- LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,
+ return MakeType(uid, ConstString("decltype(nullptr)"), std::nullopt,
+ nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct,
Type::ResolveState::Full);
}
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 12cabff..82dfe7e 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -2629,7 +2629,7 @@ TypeSystemClang::GetDeclContextForType(clang::QualType type) {
case clang::Type::Enum:
case clang::Type::Record:
return llvm::cast<clang::TagType>(qual_type)
- ->getOriginalDecl()
+ ->getDecl()
->getDefinitionOrSelf();
default:
break;
@@ -2879,8 +2879,7 @@ bool TypeSystemClang::IsAnonymousType(lldb::opaque_compiler_type_t type) {
if (const clang::RecordType *record_type =
llvm::dyn_cast_or_null<clang::RecordType>(
qual_type.getTypePtrOrNull())) {
- if (const clang::RecordDecl *record_decl =
- record_type->getOriginalDecl()) {
+ if (const clang::RecordDecl *record_decl = record_type->getDecl()) {
return record_decl->isAnonymousStructOrUnion();
}
}
@@ -3121,7 +3120,7 @@ TypeSystemClang::IsHomogeneousAggregate(lldb::opaque_compiler_type_t type,
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
if (record_type) {
if (const clang::RecordDecl *record_decl =
- record_type->getOriginalDecl()->getDefinition()) {
+ record_type->getDecl()->getDefinition()) {
// We are looking for a structure that contains only floating point
// types
clang::RecordDecl::field_iterator field_pos,
@@ -3301,7 +3300,7 @@ bool TypeSystemClang::IsEnumerationType(lldb::opaque_compiler_type_t type,
GetCanonicalQualType(type)->getCanonicalTypeInternal());
if (enum_type) {
- IsIntegerType(enum_type->getOriginalDecl()
+ IsIntegerType(enum_type->getDecl()
->getDefinitionOrSelf()
->getIntegerType()
.getAsOpaquePtr(),
@@ -3529,7 +3528,7 @@ bool TypeSystemClang::IsDefined(lldb::opaque_compiler_type_t type) {
const clang::TagType *tag_type =
llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
if (tag_type) {
- if (clang::TagDecl *tag_decl = tag_type->getOriginalDecl()->getDefinition())
+ if (clang::TagDecl *tag_decl = tag_type->getDecl()->getDefinition())
return tag_decl->isCompleteDefinition();
return false;
} else {
@@ -3782,7 +3781,7 @@ bool TypeSystemClang::IsBeingDefined(lldb::opaque_compiler_type_t type) {
clang::QualType qual_type(GetCanonicalQualType(type));
const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type);
if (tag_type)
- return tag_type->getOriginalDecl()->isEntityBeingDefined();
+ return tag_type->getDecl()->isEntityBeingDefined();
return false;
}
@@ -3988,7 +3987,7 @@ TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type,
if (pointee_or_element_clang_type)
pointee_or_element_clang_type->SetCompilerType(
weak_from_this(), llvm::cast<clang::EnumType>(qual_type)
- ->getOriginalDecl()
+ ->getDecl()
->getDefinitionOrSelf()
->getIntegerType()
.getAsOpaquePtr());
@@ -4228,7 +4227,7 @@ TypeSystemClang::GetTypeClass(lldb::opaque_compiler_type_t type) {
case clang::Type::Record: {
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getOriginalDecl();
+ const clang::RecordDecl *record_decl = record_type->getDecl();
if (record_decl->isUnion())
return lldb::eTypeClassUnion;
else if (record_decl->isStruct())
@@ -4704,9 +4703,9 @@ CompilerType TypeSystemClang::CreateTypedef(
clang::TagDecl *tdecl = nullptr;
if (!qual_type.isNull()) {
if (const clang::RecordType *rt = qual_type->getAs<clang::RecordType>())
- tdecl = rt->getOriginalDecl();
+ tdecl = rt->getDecl();
if (const clang::EnumType *et = qual_type->getAs<clang::EnumType>())
- tdecl = et->getOriginalDecl();
+ tdecl = et->getDecl();
}
// Check whether this declaration is an anonymous struct, union, or enum,
@@ -5386,7 +5385,7 @@ TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type,
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
const clang::RecordDecl *record_decl =
- record_type->getOriginalDecl()->getDefinitionOrSelf();
+ record_type->getDecl()->getDefinitionOrSelf();
const clang::CXXRecordDecl *cxx_record_decl =
llvm::dyn_cast<clang::CXXRecordDecl>(record_decl);
@@ -5583,7 +5582,7 @@ void TypeSystemClang::ForEachEnumerator(
llvm::dyn_cast<clang::EnumType>(GetCanonicalQualType(type));
if (enum_type) {
const clang::EnumDecl *enum_decl =
- enum_type->getOriginalDecl()->getDefinitionOrSelf();
+ enum_type->getDecl()->getDefinitionOrSelf();
if (enum_decl) {
CompilerType integer_type = GetType(enum_decl->getIntegerType());
@@ -5615,7 +5614,7 @@ uint32_t TypeSystemClang::GetNumFields(lldb::opaque_compiler_type_t type) {
llvm::dyn_cast<clang::RecordType>(qual_type.getTypePtr());
if (record_type) {
clang::RecordDecl *record_decl =
- record_type->getOriginalDecl()->getDefinition();
+ record_type->getDecl()->getDefinition();
if (record_decl) {
count = std::distance(record_decl->field_begin(),
record_decl->field_end());
@@ -5730,7 +5729,7 @@ CompilerType TypeSystemClang::GetFieldAtIndex(lldb::opaque_compiler_type_t type,
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
const clang::RecordDecl *record_decl =
- record_type->getOriginalDecl()->getDefinitionOrSelf();
+ record_type->getDecl()->getDefinitionOrSelf();
uint32_t field_idx = 0;
clang::RecordDecl::field_iterator field, field_end;
for (field = record_decl->field_begin(),
@@ -5916,7 +5915,7 @@ CompilerType TypeSystemClang::GetDirectBaseClassAtIndex(
llvm::cast<clang::CXXRecordDecl>(
base_class->getType()
->castAs<clang::RecordType>()
- ->getOriginalDecl());
+ ->getDecl());
if (base_class->isVirtual())
*bit_offset_ptr =
record_layout.getVBaseClassOffset(base_class_decl)
@@ -6011,7 +6010,7 @@ CompilerType TypeSystemClang::GetVirtualBaseClassAtIndex(
llvm::cast<clang::CXXRecordDecl>(
base_class->getType()
->castAs<clang::RecordType>()
- ->getOriginalDecl());
+ ->getDecl());
*bit_offset_ptr =
record_layout.getVBaseClassOffset(base_class_decl)
.getQuantity() *
@@ -6042,7 +6041,7 @@ TypeSystemClang::GetStaticFieldWithName(lldb::opaque_compiler_type_t type,
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
const clang::RecordDecl *record_decl =
- record_type->getOriginalDecl()->getDefinitionOrSelf();
+ record_type->getDecl()->getDefinitionOrSelf();
clang::DeclarationName decl_name(&getASTContext().Idents.get(name));
for (NamedDecl *decl : record_decl->lookup(decl_name)) {
@@ -6271,7 +6270,7 @@ llvm::Expected<CompilerType> TypeSystemClang::GetChildCompilerTypeAtIndex(
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(parent_qual_type.getTypePtr());
const clang::RecordDecl *record_decl =
- record_type->getOriginalDecl()->getDefinitionOrSelf();
+ record_type->getDecl()->getDefinitionOrSelf();
const clang::ASTRecordLayout &record_layout =
getASTContext().getASTRecordLayout(record_decl);
uint32_t child_idx = 0;
@@ -6292,7 +6291,7 @@ llvm::Expected<CompilerType> TypeSystemClang::GetChildCompilerTypeAtIndex(
base_class_decl = llvm::cast<clang::CXXRecordDecl>(
base_class->getType()
->getAs<clang::RecordType>()
- ->getOriginalDecl())
+ ->getDecl())
->getDefinitionOrSelf();
if (!TypeSystemClang::RecordHasFields(base_class_decl))
continue;
@@ -6303,7 +6302,7 @@ llvm::Expected<CompilerType> TypeSystemClang::GetChildCompilerTypeAtIndex(
base_class_decl = llvm::cast<clang::CXXRecordDecl>(
base_class->getType()
->getAs<clang::RecordType>()
- ->getOriginalDecl())
+ ->getDecl())
->getDefinitionOrSelf();
if (base_class->isVirtual()) {
@@ -6766,7 +6765,7 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName(
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
const clang::RecordDecl *record_decl =
- record_type->getOriginalDecl()->getDefinitionOrSelf();
+ record_type->getDecl()->getDefinitionOrSelf();
assert(record_decl);
uint32_t child_idx = 0;
@@ -6833,7 +6832,7 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName(
child_indexes.push_back(child_idx);
parent_record_decl = elem.Base->getType()
->castAs<clang::RecordType>()
- ->getOriginalDecl()
+ ->getDecl()
->getDefinitionOrSelf();
}
}
@@ -6969,7 +6968,7 @@ TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
const clang::RecordDecl *record_decl =
- record_type->getOriginalDecl()->getDefinitionOrSelf();
+ record_type->getDecl()->getDefinitionOrSelf();
assert(record_decl);
uint32_t child_idx = 0;
@@ -6988,7 +6987,7 @@ TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type,
llvm::cast<clang::CXXRecordDecl>(
base_class->getType()
->castAs<clang::RecordType>()
- ->getOriginalDecl())
+ ->getDecl())
->getDefinitionOrSelf();
if (omit_empty_base_classes &&
!TypeSystemClang::RecordHasFields(base_class_decl))
@@ -7109,7 +7108,7 @@ TypeSystemClang::GetDirectNestedTypeWithName(lldb::opaque_compiler_type_t type,
const clang::RecordType *record_type =
llvm::cast<clang::RecordType>(qual_type.getTypePtr());
const clang::RecordDecl *record_decl =
- record_type->getOriginalDecl()->getDefinitionOrSelf();
+ record_type->getDecl()->getDefinitionOrSelf();
clang::DeclarationName decl_name(&getASTContext().Idents.get(name));
for (NamedDecl *decl : record_decl->lookup(decl_name)) {
@@ -7135,7 +7134,7 @@ bool TypeSystemClang::IsTemplateType(lldb::opaque_compiler_type_t type) {
const clang::Type *clang_type = ClangUtil::GetQualType(ct).getTypePtr();
if (auto *cxx_record_decl = dyn_cast<clang::TagType>(clang_type))
return isa<clang::ClassTemplateSpecializationDecl>(
- cxx_record_decl->getOriginalDecl());
+ cxx_record_decl->getDecl());
return false;
}
@@ -7338,7 +7337,7 @@ clang::EnumDecl *TypeSystemClang::GetAsEnumDecl(const CompilerType &type) {
const clang::EnumType *enutype =
llvm::dyn_cast<clang::EnumType>(ClangUtil::GetCanonicalQualType(type));
if (enutype)
- return enutype->getOriginalDecl()->getDefinitionOrSelf();
+ return enutype->getDecl()->getDefinitionOrSelf();
return nullptr;
}
@@ -7346,7 +7345,7 @@ clang::RecordDecl *TypeSystemClang::GetAsRecordDecl(const CompilerType &type) {
const clang::RecordType *record_type =
llvm::dyn_cast<clang::RecordType>(ClangUtil::GetCanonicalQualType(type));
if (record_type)
- return record_type->getOriginalDecl()->getDefinitionOrSelf();
+ return record_type->getDecl()->getDefinitionOrSelf();
return nullptr;
}
@@ -7428,7 +7427,7 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType(
if (const clang::TagType *TagT =
field->getType()->getAs<clang::TagType>()) {
if (clang::RecordDecl *Rec =
- llvm::dyn_cast<clang::RecordDecl>(TagT->getOriginalDecl()))
+ llvm::dyn_cast<clang::RecordDecl>(TagT->getDecl()))
if (!Rec->getDeclName()) {
Rec->setAnonymousStructOrUnion(true);
field->setImplicit();
@@ -7514,7 +7513,7 @@ void TypeSystemClang::BuildIndirectFields(const CompilerType &type) {
continue;
clang::RecordDecl *field_record_decl =
- field_record_type->getOriginalDecl()->getDefinition();
+ field_record_type->getDecl()->getDefinition();
if (!field_record_decl)
continue;
@@ -7656,8 +7655,7 @@ void TypeSystemClang::SetIntegerInitializerForVariable(
// If the variable is an enum type, take the underlying integer type as
// the type of the integer literal.
if (const EnumType *enum_type = qt->getAs<EnumType>()) {
- const EnumDecl *enum_decl =
- enum_type->getOriginalDecl()->getDefinitionOrSelf();
+ const EnumDecl *enum_decl = enum_type->getDecl()->getDefinitionOrSelf();
qt = enum_decl->getIntegerType();
}
// Bools are handled separately because the clang AST printer handles bools
@@ -8317,7 +8315,7 @@ bool TypeSystemClang::SetHasExternalStorage(lldb::opaque_compiler_type_t type,
case clang::Type::Enum: {
clang::EnumDecl *enum_decl =
- llvm::cast<clang::EnumType>(qual_type)->getOriginalDecl();
+ llvm::cast<clang::EnumType>(qual_type)->getDecl();
if (enum_decl) {
enum_decl->setHasExternalLexicalStorage(has_extern);
enum_decl->setHasExternalVisibleStorage(has_extern);
@@ -8355,7 +8353,7 @@ bool TypeSystemClang::StartTagDeclarationDefinition(const CompilerType &type) {
if (!qual_type.isNull()) {
const clang::TagType *tag_type = qual_type->getAs<clang::TagType>();
if (tag_type) {
- clang::TagDecl *tag_decl = tag_type->getOriginalDecl();
+ clang::TagDecl *tag_decl = tag_type->getDecl();
if (tag_decl) {
tag_decl->startDefinition();
return true;
@@ -8390,8 +8388,7 @@ bool TypeSystemClang::CompleteTagDeclarationDefinition(
// the definition.
const clang::TagType *tag_type = qual_type->getAs<clang::TagType>();
if (tag_type) {
- clang::TagDecl *tag_decl =
- tag_type->getOriginalDecl()->getDefinitionOrSelf();
+ clang::TagDecl *tag_decl = tag_type->getDecl()->getDefinitionOrSelf();
if (auto *cxx_record_decl = llvm::dyn_cast<CXXRecordDecl>(tag_decl)) {
// If we have a move constructor declared but no copy constructor we
@@ -8426,8 +8423,7 @@ bool TypeSystemClang::CompleteTagDeclarationDefinition(
if (!enutype)
return false;
- clang::EnumDecl *enum_decl =
- enutype->getOriginalDecl()->getDefinitionOrSelf();
+ clang::EnumDecl *enum_decl = enutype->getDecl()->getDefinitionOrSelf();
if (enum_decl->isCompleteDefinition())
return true;
@@ -8485,8 +8481,7 @@ clang::EnumConstantDecl *TypeSystemClang::AddEnumerationValueToEnumerationType(
clang::EnumConstantDecl *enumerator_decl =
clang::EnumConstantDecl::CreateDeserialized(getASTContext(),
GlobalDeclID());
- clang::EnumDecl *enum_decl =
- enutype->getOriginalDecl()->getDefinitionOrSelf();
+ clang::EnumDecl *enum_decl = enutype->getDecl()->getDefinitionOrSelf();
enumerator_decl->setDeclContext(enum_decl);
if (name && name[0])
enumerator_decl->setDeclName(&getASTContext().Idents.get(name));
@@ -8521,8 +8516,7 @@ CompilerType TypeSystemClang::GetEnumerationIntegerType(CompilerType type) {
if (!enum_type)
return CompilerType();
- return GetType(
- enum_type->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType());
+ return GetType(enum_type->getDecl()->getDefinitionOrSelf()->getIntegerType());
}
CompilerType
@@ -8630,8 +8624,7 @@ static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s,
uint32_t bitfield_bit_size) {
const clang::EnumType *enutype =
llvm::cast<clang::EnumType>(qual_type.getTypePtr());
- const clang::EnumDecl *enum_decl =
- enutype->getOriginalDecl()->getDefinitionOrSelf();
+ const clang::EnumDecl *enum_decl = enutype->getDecl()->getDefinitionOrSelf();
lldb::offset_t offset = byte_offset;
bool qual_type_is_signed = qual_type->isSignedIntegerOrEnumerationType();
const uint64_t enum_svalue =
@@ -8907,7 +8900,7 @@ void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type,
GetCompleteType(type);
auto *record_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());
- const clang::RecordDecl *record_decl = record_type->getOriginalDecl();
+ const clang::RecordDecl *record_decl = record_type->getDecl();
if (level == eDescriptionLevelVerbose)
record_decl->dump(llvm_ostrm);
else {
@@ -8919,7 +8912,7 @@ void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type,
default: {
if (auto *tag_type =
llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr())) {
- if (clang::TagDecl *tag_decl = tag_type->getOriginalDecl()) {
+ if (clang::TagDecl *tag_decl = tag_type->getDecl()) {
if (level == eDescriptionLevelVerbose)
tag_decl->dump(llvm_ostrm);
else
@@ -8959,7 +8952,7 @@ void TypeSystemClang::DumpTypeName(const CompilerType &type) {
case clang::Type::Enum: {
clang::EnumDecl *enum_decl =
- llvm::cast<clang::EnumType>(qual_type)->getOriginalDecl();
+ llvm::cast<clang::EnumType>(qual_type)->getDecl();
if (enum_decl) {
printf("enum %s", enum_decl->getName().str().c_str());
}
@@ -9825,7 +9818,7 @@ bool TypeSystemClang::IsForcefullyCompleted(lldb::opaque_compiler_type_t type) {
llvm::dyn_cast<clang::RecordType>(qual_type.getTypePtr());
if (record_type) {
const clang::RecordDecl *record_decl =
- record_type->getOriginalDecl()->getDefinitionOrSelf();
+ record_type->getDecl()->getDefinitionOrSelf();
if (std::optional<ClangASTMetadata> metadata = GetMetadata(record_decl))
return metadata->IsForcefullyCompleted();
}
diff --git a/lldb/test/API/functionalities/unwind/cortex-m-exception/TestCortexMExceptionUnwind.py b/lldb/test/API/functionalities/unwind/cortex-m-exception/TestCortexMExceptionUnwind.py
index fc7bfe4..50ea173 100644
--- a/lldb/test/API/functionalities/unwind/cortex-m-exception/TestCortexMExceptionUnwind.py
+++ b/lldb/test/API/functionalities/unwind/cortex-m-exception/TestCortexMExceptionUnwind.py
@@ -44,10 +44,6 @@ class TestCortexMExceptionUnwind(TestBase):
thread = process.GetThreadAtIndex(0)
self.assertTrue(thread.IsValid())
- # We have 4 named stack frames and two unnamed
- # frames above that. The topmost two stack frames
- # were not interesting for this test, so I didn't
- # create symbols for them.
self.assertEqual(thread.GetNumFrames(), 3)
stackframe_names = [
"exception_catcher",
diff --git a/lldb/test/API/macosx/debugserver-multimemread/Makefile b/lldb/test/API/macosx/debugserver-multimemread/Makefile
new file mode 100644
index 0000000..1049594
--- /dev/null
+++ b/lldb/test/API/macosx/debugserver-multimemread/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git a/lldb/test/API/macosx/debugserver-multimemread/TestDebugserverMultiMemRead.py b/lldb/test/API/macosx/debugserver-multimemread/TestDebugserverMultiMemRead.py
new file mode 100644
index 0000000..6caa5f8
--- /dev/null
+++ b/lldb/test/API/macosx/debugserver-multimemread/TestDebugserverMultiMemRead.py
@@ -0,0 +1,102 @@
+"""
+Tests debugserver support for MultiMemRead.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+@skipUnlessDarwin
+@skipIfOutOfTreeDebugserver
+class TestCase(TestBase):
+ def send_process_packet(self, packet_str):
+ self.runCmd(f"proc plugin packet send {packet_str}", check=False)
+ # The output is of the form:
+ # packet: <packet_str>
+ # response: <response>
+ reply = self.res.GetOutput().split("\n")
+ packet = reply[0].strip()
+ response = reply[1].strip()
+
+ self.assertTrue(packet.startswith("packet: "))
+ self.assertTrue(response.startswith("response: "))
+ return response[len("response: ") :]
+
+ def check_invalid_packet(self, packet_str):
+ reply = self.send_process_packet("packet_str")
+ self.assertEqual(reply, "E03")
+
+ def test_packets(self):
+ self.build()
+ source_file = lldb.SBFileSpec("main.c")
+ target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
+ self, "break here", source_file
+ )
+
+ reply = self.send_process_packet("qSupported")
+ self.assertIn("MultiMemRead+", reply)
+
+ mem_address_var = thread.frames[0].FindVariable("memory")
+ self.assertTrue(mem_address_var)
+ mem_address = mem_address_var.GetValueAsUnsigned() + 42
+
+ # no ":"
+ self.check_invalid_packet("MultiMemRead")
+ # missing ranges
+ self.check_invalid_packet("MultiMemRead:")
+ # needs at least one range
+ self.check_invalid_packet("MultiMemRead:ranges:")
+ # needs at least one range
+ self.check_invalid_packet("MultiMemRead:ranges:,")
+ # a range is a pair of numbers
+ self.check_invalid_packet("MultiMemRead:ranges:10")
+ # a range is a pair of numbers
+ self.check_invalid_packet("MultiMemRead:ranges:10,")
+ # range list must end with ;
+ self.check_invalid_packet("MultiMemRead:ranges:10,2")
+ self.check_invalid_packet("MultiMemRead:ranges:10,2,")
+ self.check_invalid_packet("MultiMemRead:ranges:10,2,3")
+ # ranges are pairs of numbers.
+ self.check_invalid_packet("MultiMemRead:ranges:10,2,3;")
+ # unrecognized field
+ self.check_invalid_packet("MultiMemRead:ranges:10,2;blah:;")
+ # unrecognized field
+ self.check_invalid_packet("MultiMemRead:blah:;ranges:10,2;")
+
+ # Zero-length reads are ok.
+ reply = self.send_process_packet("MultiMemRead:ranges:0,0;")
+ self.assertEqual(reply, "0;")
+
+ # Debugserver is permissive with trailing commas.
+ reply = self.send_process_packet("MultiMemRead:ranges:10,2,;")
+ self.assertEqual(reply, "0;")
+ reply = self.send_process_packet(f"MultiMemRead:ranges:{mem_address:x},2,;")
+ self.assertEqual(reply, "2;ab")
+
+ reply = self.send_process_packet("MultiMemRead:ranges:10,2;")
+ self.assertEqual(reply, "0;")
+ reply = self.send_process_packet(f"MultiMemRead:ranges:{mem_address:x},0;")
+ self.assertEqual(reply, "0;")
+ reply = self.send_process_packet(f"MultiMemRead:ranges:{mem_address:x},2;")
+ self.assertEqual(reply, "2;ab")
+ reply = self.send_process_packet(
+ f"MultiMemRead:ranges:{mem_address:x},2,{mem_address+2:x},4;"
+ )
+ self.assertEqual(reply, "2,4;abcdef")
+ reply = self.send_process_packet(
+ f"MultiMemRead:ranges:{mem_address:x},2,{mem_address+2:x},4,{mem_address+6:x},8;"
+ )
+ self.assertEqual(reply, "2,4,8;abcdefghijklmn")
+
+ # Test zero length in the middle.
+ reply = self.send_process_packet(
+ f"MultiMemRead:ranges:{mem_address:x},2,{mem_address+2:x},0,{mem_address+6:x},8;"
+ )
+ self.assertEqual(reply, "2,0,8;abghijklmn")
+ # Test zero length in the end.
+ reply = self.send_process_packet(
+ f"MultiMemRead:ranges:{mem_address:x},2,{mem_address+2:x},4,{mem_address+6:x},0;"
+ )
+ self.assertEqual(reply, "2,4,0;abcdef")
diff --git a/lldb/test/API/macosx/debugserver-multimemread/main.c b/lldb/test/API/macosx/debugserver-multimemread/main.c
new file mode 100644
index 0000000..44cdd47
--- /dev/null
+++ b/lldb/test/API/macosx/debugserver-multimemread/main.c
@@ -0,0 +1,14 @@
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+ char *memory = malloc(1024);
+ memset(memory, '-', 1024);
+ // Write "interesting" characters at an offset from the memory filled with
+ // `-`. This way, if we read outside the range in either direction, we should
+ // find `-`s`.
+ int offset = 42;
+ for (int i = offset; i < offset + 14; i++)
+ memory[i] = 'a' + (i - offset);
+ return 0; // break here
+}
diff --git a/lldb/test/API/macosx/mte/Makefile b/lldb/test/API/macosx/mte/Makefile
index cb20942..d614e0f 100644
--- a/lldb/test/API/macosx/mte/Makefile
+++ b/lldb/test/API/macosx/mte/Makefile
@@ -1,12 +1,15 @@
C_SOURCES := main.c
-EXE := uaf_mte
+EXE := uaf
-all: uaf_mte sign
+binary-plain: uaf
+binary-entitled: uaf sign
+
+all: binary-entitled
include Makefile.rules
-sign: mte-entitlements.plist uaf_mte
+sign: mte-entitlements.plist uaf
ifeq ($(OS),Darwin)
codesign -s - -f --entitlements $^
endif
diff --git a/lldb/test/API/macosx/mte/TestDarwinMTE.py b/lldb/test/API/macosx/mte/TestDarwinMTE.py
index 489e24a..a70b4b4 100644
--- a/lldb/test/API/macosx/mte/TestDarwinMTE.py
+++ b/lldb/test/API/macosx/mte/TestDarwinMTE.py
@@ -7,13 +7,25 @@ from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
import lldbsuite.test.cpu_feature as cpu_feature
-exe_name = "uaf_mte" # Must match Makefile
+exe_name = "uaf" # Must match Makefile
class TestDarwinMTE(TestBase):
NO_DEBUG_INFO_TESTCASE = True
@skipUnlessFeature(cpu_feature.AArch64.MTE)
+ def test_process_launch_memory_tagging(self):
+ self.build(make_targets=["binary-plain"])
+ self.createTestTarget(self.getBuildArtifact(exe_name))
+
+ self.expect("process launch", substrs=["exited with status = 0"])
+
+ self.expect(
+ "process launch --memory-tagging",
+ substrs=["stopped", "stop reason = EXC_ARM_MTE_TAG_FAULT"],
+ )
+
+ @skipUnlessFeature(cpu_feature.AArch64.MTE)
def test_tag_fault(self):
self.build()
exe = self.getBuildArtifact(exe_name)
diff --git a/lldb/test/API/tools/lldb-dap/attach-commands/Makefile b/lldb/test/API/tools/lldb-dap/attach-commands/Makefile
new file mode 100644
index 0000000..1049594
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/attach-commands/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
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
new file mode 100644
index 0000000..ed373f2
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/attach-commands/TestDAP_attachCommands.py
@@ -0,0 +1,147 @@
+"""
+Test lldb-dap attach commands
+"""
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+import lldbdap_testcase
+import time
+
+
+class TestDAP_attachCommands(lldbdap_testcase.DAPTestCaseBase):
+ @skipIfNetBSD # Hangs on NetBSD as well
+ def test_commands(self):
+ """
+ Tests the "initCommands", "preRunCommands", "stopCommands",
+ "exitCommands", "terminateCommands" and "attachCommands"
+ that can be passed during attach.
+
+ "initCommands" are a list of LLDB commands that get executed
+ before the target is created.
+ "preRunCommands" are a list of LLDB commands that get executed
+ after the target has been created and before the launch.
+ "stopCommands" are a list of LLDB commands that get executed each
+ time the program stops.
+ "exitCommands" are a list of LLDB commands that get executed when
+ the process exits
+ "attachCommands" are a list of LLDB commands that get executed and
+ must have a valid process in the selected target in LLDB after
+ they are done executing. This allows custom commands to create any
+ kind of debug session.
+ "terminateCommands" are a list of LLDB commands that get executed when
+ the debugger session terminates.
+ """
+ program = self.build_and_create_debug_adapter_for_attach()
+
+ # Here we just create a target and launch the process as a way to test
+ # if we are able to use attach commands to create any kind of a target
+ # and use it for debugging
+ attachCommands = [
+ 'target create -d "%s"' % (program),
+ "process launch --stop-at-entry",
+ ]
+ initCommands = ["target list", "platform list"]
+ preRunCommands = ["image list a.out", "image dump sections a.out"]
+ postRunCommands = ["help trace", "help process trace"]
+ stopCommands = ["frame variable", "thread backtrace"]
+ exitCommands = ["expr 2+3", "expr 3+4"]
+ terminateCommands = ["expr 4+2"]
+ self.attach(
+ program=program,
+ attachCommands=attachCommands,
+ initCommands=initCommands,
+ preRunCommands=preRunCommands,
+ stopCommands=stopCommands,
+ exitCommands=exitCommands,
+ terminateCommands=terminateCommands,
+ postRunCommands=postRunCommands,
+ )
+ # Get output from the console. This should contain both the
+ # "initCommands" and the "preRunCommands".
+ output = self.get_console()
+ # Verify all "initCommands" were found in console output
+ self.verify_commands("initCommands", output, initCommands)
+ # Verify all "preRunCommands" were found in console output
+ self.verify_commands("preRunCommands", output, preRunCommands)
+ # Verify all "postRunCommands" were found in console output
+ self.verify_commands("postRunCommands", output, postRunCommands)
+
+ functions = ["main"]
+ 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])
+ self.verify_commands("stopCommands", output, stopCommands)
+
+ # Continue after launch and hit the "pause()" call and stop the target.
+ # Get output from the console. This should contain both the
+ # "stopCommands" that were run after we stop.
+ self.do_continue()
+ time.sleep(0.5)
+ self.dap_server.request_pause()
+ self.dap_server.wait_for_stopped()
+ output = self.collect_console(timeout=10, pattern=stopCommands[-1])
+ self.verify_commands("stopCommands", output, stopCommands)
+
+ # Continue until the program exits
+ self.continue_to_exit()
+ # Get output from the console. This should contain both the
+ # "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)
+ self.verify_commands("terminateCommands", output, terminateCommands)
+
+ def test_attach_command_process_failures(self):
+ """
+ Tests that a 'attachCommands' is expected to leave the debugger's
+ selected target with a valid process.
+ """
+ program = self.build_and_create_debug_adapter_for_attach()
+ attachCommands = ['script print("oops, forgot to attach to a process...")']
+ resp = self.attach(
+ program=program,
+ attachCommands=attachCommands,
+ expectFailure=True,
+ )
+ self.assertFalse(resp["success"])
+ self.assertIn(
+ "attachCommands failed to attach to a process",
+ resp["body"]["error"]["format"],
+ )
+
+ @skipIfNetBSD # Hangs on NetBSD as well
+ def test_terminate_commands(self):
+ """
+ Tests that the "terminateCommands", that can be passed during
+ attach, are run when the debugger is disconnected.
+ """
+ program = self.build_and_create_debug_adapter_for_attach()
+
+ # Here we just create a target and launch the process as a way to test
+ # if we are able to use attach commands to create any kind of a target
+ # and use it for debugging
+ attachCommands = [
+ 'target create -d "%s"' % (program),
+ "process launch --stop-at-entry",
+ ]
+ terminateCommands = ["expr 4+2"]
+ self.attach(
+ program=program,
+ attachCommands=attachCommands,
+ terminateCommands=terminateCommands,
+ disconnectAutomatically=False,
+ )
+ self.get_console()
+ # Once it's disconnected the console should contain the
+ # "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/attach-commands/main.c b/lldb/test/API/tools/lldb-dap/attach-commands/main.c
new file mode 100644
index 0000000..f56d5d5
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/attach-commands/main.c
@@ -0,0 +1,30 @@
+#include "attach.h"
+#include <stdio.h>
+#ifdef _WIN32
+#include <process.h>
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+int main(int argc, char const *argv[]) {
+ lldb_enable_attach();
+
+ if (argc >= 2) {
+ // Create the synchronization token.
+ FILE *f = fopen(argv[1], "wx");
+ if (!f)
+ return 1;
+ fputs("\n", f);
+ fflush(f);
+ fclose(f);
+ }
+
+ printf("pid = %i\n", getpid());
+#ifdef _WIN32
+ Sleep(10 * 1000);
+#else
+ sleep(10);
+#endif
+ return 0; // breakpoint 1
+}
diff --git a/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py b/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py
index c54e21c..5331a9f 100644
--- a/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py
+++ b/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py
@@ -11,50 +11,35 @@ import threading
import time
-def spawn_and_wait(program, delay):
- if delay:
- time.sleep(delay)
- process = subprocess.Popen(
- [program], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
- )
- process.wait()
-
-
class TestDAP_attach(lldbdap_testcase.DAPTestCaseBase):
- def set_and_hit_breakpoint(self, continueToExit=True):
- source = "main.c"
- breakpoint1_line = line_number(source, "// breakpoint 1")
- lines = [breakpoint1_line]
- # Set breakpoint in the thread function so we can step the threads
- breakpoint_ids = self.set_source_breakpoints(source, lines)
- self.assertEqual(
- len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
- )
- # Test binary will sleep for 10s, offset the breakpoint timeout
- # accordingly.
- timeout_offset = 10
- self.continue_to_breakpoints(
- breakpoint_ids, timeout=timeout_offset + self.DEFAULT_TIMEOUT
+ def spawn(self, args):
+ self.process = subprocess.Popen(
+ args,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
)
- if continueToExit:
- self.continue_to_exit()
- @skipIfNetBSD # Hangs on NetBSD as well
+ def spawn_and_wait(self, program, delay):
+ time.sleep(delay)
+ self.spawn([program])
+ self.process.wait()
+
+ def continue_and_verify_pid(self):
+ self.do_continue()
+ out, _ = self.process.communicate("foo")
+ self.assertIn(f"pid = {self.process.pid}", out)
+
def test_by_pid(self):
"""
Tests attaching to a process by process ID.
"""
program = self.build_and_create_debug_adapter_for_attach()
- self.process = subprocess.Popen(
- [program],
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- )
+ self.spawn([program])
self.attach(pid=self.process.pid)
- self.set_and_hit_breakpoint(continueToExit=True)
+ self.continue_and_verify_pid()
- @skipIfNetBSD # Hangs on NetBSD as well
def test_by_name(self):
"""
Tests attaching to a process by process name.
@@ -65,24 +50,20 @@ class TestDAP_attach(lldbdap_testcase.DAPTestCaseBase):
pid_file_path = lldbutil.append_to_process_working_directory(
self, "pid_file_%d" % (int(time.time()))
)
-
- popen = self.spawnSubprocess(program, [pid_file_path])
+ self.spawn([program, pid_file_path])
lldbutil.wait_for_file_on_target(self, pid_file_path)
self.attach(program=program)
- self.set_and_hit_breakpoint(continueToExit=True)
+ self.continue_and_verify_pid()
- @skipUnlessDarwin
- @skipIfNetBSD # Hangs on NetBSD as well
def test_by_name_waitFor(self):
"""
- Tests attaching to a process by process name and waiting for the
- next instance of a process to be launched, ignoring all current
- ones.
+ Tests waiting for, and attaching to a process by process name that
+ doesn't exist yet.
"""
program = self.build_and_create_debug_adapter_for_attach()
self.spawn_thread = threading.Thread(
- target=spawn_and_wait,
+ target=self.spawn_and_wait,
args=(
program,
1.0,
@@ -90,140 +71,4 @@ class TestDAP_attach(lldbdap_testcase.DAPTestCaseBase):
)
self.spawn_thread.start()
self.attach(program=program, waitFor=True)
- self.set_and_hit_breakpoint(continueToExit=True)
-
- @skipIfNetBSD # Hangs on NetBSD as well
- def test_commands(self):
- """
- Tests the "initCommands", "preRunCommands", "stopCommands",
- "exitCommands", "terminateCommands" and "attachCommands"
- that can be passed during attach.
-
- "initCommands" are a list of LLDB commands that get executed
- before the target is created.
- "preRunCommands" are a list of LLDB commands that get executed
- after the target has been created and before the launch.
- "stopCommands" are a list of LLDB commands that get executed each
- time the program stops.
- "exitCommands" are a list of LLDB commands that get executed when
- the process exits
- "attachCommands" are a list of LLDB commands that get executed and
- must have a valid process in the selected target in LLDB after
- they are done executing. This allows custom commands to create any
- kind of debug session.
- "terminateCommands" are a list of LLDB commands that get executed when
- the debugger session terminates.
- """
- program = self.build_and_create_debug_adapter_for_attach()
-
- # Here we just create a target and launch the process as a way to test
- # if we are able to use attach commands to create any kind of a target
- # and use it for debugging
- attachCommands = [
- 'target create -d "%s"' % (program),
- "process launch --stop-at-entry",
- ]
- initCommands = ["target list", "platform list"]
- preRunCommands = ["image list a.out", "image dump sections a.out"]
- postRunCommands = ["help trace", "help process trace"]
- stopCommands = ["frame variable", "thread backtrace"]
- exitCommands = ["expr 2+3", "expr 3+4"]
- terminateCommands = ["expr 4+2"]
- self.attach(
- program=program,
- attachCommands=attachCommands,
- initCommands=initCommands,
- preRunCommands=preRunCommands,
- stopCommands=stopCommands,
- exitCommands=exitCommands,
- terminateCommands=terminateCommands,
- postRunCommands=postRunCommands,
- )
- # Get output from the console. This should contain both the
- # "initCommands" and the "preRunCommands".
- output = self.get_console()
- # Verify all "initCommands" were found in console output
- self.verify_commands("initCommands", output, initCommands)
- # Verify all "preRunCommands" were found in console output
- self.verify_commands("preRunCommands", output, preRunCommands)
- # Verify all "postRunCommands" were found in console output
- self.verify_commands("postRunCommands", output, postRunCommands)
-
- functions = ["main"]
- 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])
- self.verify_commands("stopCommands", output, stopCommands)
-
- # Continue after launch and hit the "pause()" call and stop the target.
- # Get output from the console. This should contain both the
- # "stopCommands" that were run after we stop.
- self.do_continue()
- time.sleep(0.5)
- self.dap_server.request_pause()
- self.dap_server.wait_for_stopped()
- output = self.collect_console(timeout=10, pattern=stopCommands[-1])
- self.verify_commands("stopCommands", output, stopCommands)
-
- # Continue until the program exits
- self.continue_to_exit()
- # Get output from the console. This should contain both the
- # "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)
- self.verify_commands("terminateCommands", output, terminateCommands)
-
- def test_attach_command_process_failures(self):
- """
- Tests that a 'attachCommands' is expected to leave the debugger's
- selected target with a valid process.
- """
- program = self.build_and_create_debug_adapter_for_attach()
- attachCommands = ['script print("oops, forgot to attach to a process...")']
- resp = self.attach(
- program=program,
- attachCommands=attachCommands,
- expectFailure=True,
- )
- self.assertFalse(resp["success"])
- self.assertIn(
- "attachCommands failed to attach to a process",
- resp["body"]["error"]["format"],
- )
-
- @skipIfNetBSD # Hangs on NetBSD as well
- def test_terminate_commands(self):
- """
- Tests that the "terminateCommands", that can be passed during
- attach, are run when the debugger is disconnected.
- """
- program = self.build_and_create_debug_adapter_for_attach()
-
- # Here we just create a target and launch the process as a way to test
- # if we are able to use attach commands to create any kind of a target
- # and use it for debugging
- attachCommands = [
- 'target create -d "%s"' % (program),
- "process launch --stop-at-entry",
- ]
- terminateCommands = ["expr 4+2"]
- self.attach(
- program=program,
- attachCommands=attachCommands,
- terminateCommands=terminateCommands,
- disconnectAutomatically=False,
- )
- self.get_console()
- # Once it's disconnected the console should contain the
- # "terminateCommands"
- self.dap_server.request_disconnect(terminateDebuggee=True)
- output = self.collect_console(
- timeout=1.0,
- pattern=terminateCommands[0],
- )
- self.verify_commands("terminateCommands", output, terminateCommands)
+ self.continue_and_verify_pid()
diff --git a/lldb/test/API/tools/lldb-dap/attach/main.c b/lldb/test/API/tools/lldb-dap/attach/main.c
index f56d5d5..e14cf71 100644
--- a/lldb/test/API/tools/lldb-dap/attach/main.c
+++ b/lldb/test/API/tools/lldb-dap/attach/main.c
@@ -2,7 +2,6 @@
#include <stdio.h>
#ifdef _WIN32
#include <process.h>
-#include <windows.h>
#else
#include <unistd.h>
#endif
@@ -20,11 +19,9 @@ int main(int argc, char const *argv[]) {
fclose(f);
}
+ // Wait on input from stdin.
+ getchar();
+
printf("pid = %i\n", getpid());
-#ifdef _WIN32
- Sleep(10 * 1000);
-#else
- sleep(10);
-#endif
- return 0; // breakpoint 1
+ return 0;
}
diff --git a/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py
index 08c225b..6008a0c 100644
--- a/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py
+++ b/lldb/test/API/tools/lldb-dap/stackTraceDisassemblyDisplay/TestDAP_stackTraceDisassemblyDisplay.py
@@ -29,7 +29,7 @@ class TestDAP_stackTraceMissingSourcePath(lldbdap_testcase.DAPTestCaseBase):
"""
Build the program and run until the breakpoint is hit, and return the stack frames.
"""
- other_source_file = "other.c"
+ other_source_file = self.getBuildArtifact("other.c")
with delete_file_on_exit(other_source_file):
with open(other_source_file, "w") as f:
f.write(OTHER_C_SOURCE_CODE)
@@ -169,3 +169,4 @@ class TestDAP_stackTraceMissingSourcePath(lldbdap_testcase.DAPTestCaseBase):
self.verify_frames_source(
frames, main_frame_assembly=False, other_frame_assembly=False
)
+ self.continue_to_exit()
diff --git a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
index 13a69460..977d6ce 100644
--- a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
+++ b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
@@ -65,6 +65,11 @@ class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase):
self.assertNotIn(
key, actual, 'key "%s" is not expected in %s' % (key, actual)
)
+ isReadOnly = verify_dict.get("readOnly", False)
+ attributes = actual.get("presentationHint", {}).get("attributes", [])
+ self.assertEqual(
+ isReadOnly, "readOnly" in attributes, "%s %s" % (verify_dict, actual)
+ )
hasVariablesReference = "variablesReference" in actual
varRef = None
if hasVariablesReference:
@@ -179,8 +184,9 @@ class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase):
"children": {
"x": {"equals": {"type": "int", "value": "11"}},
"y": {"equals": {"type": "int", "value": "22"}},
- "buffer": {"children": buffer_children},
+ "buffer": {"children": buffer_children, "readOnly": True},
},
+ "readOnly": True,
},
"x": {"equals": {"type": "int"}},
}
@@ -444,8 +450,10 @@ class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase):
"buffer": {
"children": buffer_children,
"equals": {"indexedVariables": 16},
+ "readOnly": True,
},
},
+ "readOnly": True,
},
"x": {
"equals": {"type": "int"},
@@ -528,7 +536,7 @@ class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase):
"children": {
"x": {"equals": {"type": "int", "value": "11"}},
"y": {"equals": {"type": "int", "value": "22"}},
- "buffer": {"children": buffer_children},
+ "buffer": {"children": buffer_children, "readOnly": True},
},
}
@@ -622,11 +630,17 @@ class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase):
# "[raw]" child.
raw_child_count = 1 if enableSyntheticChildDebugging else 0
verify_locals = {
- "small_array": {"equals": {"indexedVariables": 5}},
- "large_array": {"equals": {"indexedVariables": 200}},
- "small_vector": {"equals": {"indexedVariables": 5 + raw_child_count}},
- "large_vector": {"equals": {"indexedVariables": 200 + raw_child_count}},
- "pt": {"missing": ["indexedVariables"]},
+ "small_array": {"equals": {"indexedVariables": 5}, "readOnly": True},
+ "large_array": {"equals": {"indexedVariables": 200}, "readOnly": True},
+ "small_vector": {
+ "equals": {"indexedVariables": 5 + raw_child_count},
+ "readOnly": True,
+ },
+ "large_vector": {
+ "equals": {"indexedVariables": 200 + raw_child_count},
+ "readOnly": True,
+ },
+ "pt": {"missing": ["indexedVariables"], "readOnly": True},
}
self.verify_variables(verify_locals, locals)
@@ -640,7 +654,10 @@ class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase):
"[4]": {"equals": {"type": "int", "value": "0"}},
}
if enableSyntheticChildDebugging:
- verify_children["[raw]"] = ({"contains": {"type": ["vector"]}},)
+ verify_children["[raw]"] = {
+ "contains": {"type": ["vector"]},
+ "readOnly": True,
+ }
children = self.dap_server.request_variables(locals[2]["variablesReference"])[
"body"
@@ -660,7 +677,7 @@ class TestDAP_variables(lldbdap_testcase.DAPTestCaseBase):
return_name: {"equals": {"type": "int", "value": "300"}},
"argc": {},
"argv": {},
- "pt": {},
+ "pt": {"readOnly": True},
"x": {},
"return_result": {"equals": {"type": "int"}},
}
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/local-variables-registers.s b/lldb/test/Shell/SymbolFile/NativePDB/local-variables-registers.s
index fe2f397..b44b99a 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/local-variables-registers.s
+++ b/lldb/test/Shell/SymbolFile/NativePDB/local-variables-registers.s
@@ -578,12 +578,12 @@ main: # @main
# CHECK: (lldb) image lookup -a 0x14000104e -v
# CHECK: LineEntry: [0x000000014000104e-0x0000000140001050): C:\src\test\a.cpp:1004
# CHECK-NEXT: Symbol: id = {{.*}}, range = [0x0000000140001011-0x0000000140001050), name="main"
-# CHECK-NEXT: Variable: id = {{.*}}, name = "simple_type1", type = "int64_t", valid ranges = <block>, location = [0x000000014000104e, 0x000000014000104f) -> DW_OP_reg26 XMM9, DW_OP_piece 0x4, DW_OP_reg24 XMM7, DW_OP_piece 0x4
+# CHECK-NEXT: Variable: id = {{.*}}, name = "simple_type1", type = "long long", valid ranges = <block>, location = [0x000000014000104e, 0x000000014000104f) -> DW_OP_reg26 XMM9, DW_OP_piece 0x4, DW_OP_reg24 XMM7, DW_OP_piece 0x4
# CHECK-EMPTY:
# CHECK: (lldb) image lookup -a 0x14000104f -v
# CHECK: LineEntry: [0x000000014000104e-0x0000000140001050): C:\src\test\a.cpp:1004
# CHECK-NEXT: Symbol: id = {{.*}}, range = [0x0000000140001011-0x0000000140001050), name="main"
-# CHECK-NEXT: Variable: id = {{.*}}, name = "simple_type1", type = "int64_t", valid ranges = <block>, location = [0x000000014000104f, 0x0000000140001050) -> DW_OP_reg26 XMM9, DW_OP_piece 0x4, DW_OP_piece 0x4
+# CHECK-NEXT: Variable: id = {{.*}}, name = "simple_type1", type = "long long", valid ranges = <block>, location = [0x000000014000104f, 0x0000000140001050) -> DW_OP_reg26 XMM9, DW_OP_piece 0x4, DW_OP_piece 0x4
# CHECK-EMPTY:
.Ltmp26:
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/simple-types.cpp b/lldb/test/Shell/SymbolFile/NativePDB/simple-types.cpp
index 403cd29..3781194 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/simple-types.cpp
+++ b/lldb/test/Shell/SymbolFile/NativePDB/simple-types.cpp
@@ -58,20 +58,28 @@ int main() {
MyStruct my_struct;
+ _Float16 f16;
+
+ _Complex float cf;
+ _Complex double cd;
+
+ __int128 i128;
+ unsigned __int128 ui128;
+
decltype(nullptr) np;
}
-// CHECK-DAG: Type{{.*}} , name = "std::nullptr_t", size = 0, compiler_type = 0x{{[0-9a-f]+}} nullptr_t
+// CHECK-DAG: Type{{.*}} , name = "decltype(nullptr)", compiler_type = 0x{{[0-9a-f]+}} nullptr_t
// CHECK-DAG: Type{{.*}} , name = "bool", size = 1, compiler_type = 0x{{[0-9a-f]+}} _Bool
// CHECK-DAG: Type{{.*}} , name = "char", size = 1, compiler_type = 0x{{[0-9a-f]+}} char
// CHECK-DAG: Type{{.*}} , name = "unsigned char", size = 1, compiler_type = 0x{{[0-9a-f]+}} unsigned char
// CHECK-DAG: Type{{.*}} , name = "char8_t", size = 1, compiler_type = 0x{{[0-9a-f]+}} char8_t
-// CHECK-DAG: Type{{.*}} , size = 2, compiler_type = 0x{{[0-9a-f]+}} short
-// CHECK-DAG: Type{{.*}} , name = "const volatile ", size = 2, compiler_type = 0x{{[0-9a-f]+}} const volatile short
-// CHECK-DAG: Type{{.*}} , name = "const ", size = 2, compiler_type = 0x{{[0-9a-f]+}} const short
-// CHECK-DAG: Type{{.*}} , name = "volatile ", size = 2, compiler_type = 0x{{[0-9a-f]+}} volatile short
+// CHECK-DAG: Type{{.*}} , name = "short", size = 2, compiler_type = 0x{{[0-9a-f]+}} short
+// CHECK-DAG: Type{{.*}} , name = "const volatile short", size = 2, compiler_type = 0x{{[0-9a-f]+}} const volatile short
+// CHECK-DAG: Type{{.*}} , name = "const short", size = 2, compiler_type = 0x{{[0-9a-f]+}} const short
+// CHECK-DAG: Type{{.*}} , name = "volatile short", size = 2, compiler_type = 0x{{[0-9a-f]+}} volatile short
// CHECK-DAG: Type{{.*}} , name = "unsigned short", size = 2, compiler_type = 0x{{[0-9a-f]+}} unsigned short
// CHECK-DAG: Type{{.*}} , name = "wchar_t", size = 2, compiler_type = 0x{{[0-9a-f]+}} wchar_t
@@ -83,12 +91,19 @@ int main() {
// CHECK-DAG: Type{{.*}} , name = "unsigned long", size = 4, compiler_type = 0x{{[0-9a-f]+}} unsigned long
// CHECK-DAG: Type{{.*}} , name = "char32_t", size = 4, compiler_type = 0x{{[0-9a-f]+}} char32_t
-// CHECK-DAG: Type{{.*}} , name = "int64_t", size = 8, compiler_type = 0x{{[0-9a-f]+}} long long
-// CHECK-DAG: Type{{.*}} , name = "uint64_t", size = 8, compiler_type = 0x{{[0-9a-f]+}} unsigned long long
+// CHECK-DAG: Type{{.*}} , name = "long long", size = 8, compiler_type = 0x{{[0-9a-f]+}} long long
+// CHECK-DAG: Type{{.*}} , name = "unsigned long long", size = 8, compiler_type = 0x{{[0-9a-f]+}} unsigned long long
+// CHECK-DAG: Type{{.*}} , name = "__int128", size = 16, compiler_type = 0x{{[0-9a-f]+}} __int128
+// CHECK-DAG: Type{{.*}} , name = "unsigned __int128", size = 16, compiler_type = 0x{{[0-9a-f]+}} unsigned __int128
+
+// CHECK-DAG: Type{{.*}} , name = "_Float16", size = 2, compiler_type = 0x{{[0-9a-f]+}} __fp16
// CHECK-DAG: Type{{.*}} , name = "float", size = 4, compiler_type = 0x{{[0-9a-f]+}} float
// CHECK-DAG: Type{{.*}} , name = "const float", size = 4, compiler_type = 0x{{[0-9a-f]+}} const float
+// CHECK-DAG: Type{{.*}} , name = "_Complex float", size = 4, compiler_type = 0x{{[0-9a-f]+}} _Complex float
+// CHECK-DAG: Type{{.*}} , name = "_Complex double", size = 8, compiler_type = 0x{{[0-9a-f]+}} _Complex double
+
// CHECK-DAG: Type{{.*}} , name = "ReturnedStruct1", size = 1, decl = simple-types.cpp:21, compiler_type = 0x{{[0-9a-f]+}} struct ReturnedStruct1 {
// CHECK-DAG: Type{{.*}} , name = "ReturnedStruct2", size = 1, decl = simple-types.cpp:22, compiler_type = 0x{{[0-9a-f]+}} struct ReturnedStruct2 {
// CHECK-DAG: Type{{.*}} , name = "MyStruct", size = 1, decl = simple-types.cpp:24, compiler_type = 0x{{[0-9a-f]+}} struct MyStruct {
diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp
index b06c6bf..b2d7937 100644
--- a/lldb/tools/debugserver/source/RNBRemote.cpp
+++ b/lldb/tools/debugserver/source/RNBRemote.cpp
@@ -170,6 +170,20 @@ static uint64_t decode_uint64(const char *p, int base, char **end = nullptr,
return addr;
}
+/// Attempts to parse a prefix of `number_str` as a uint64_t. If
+/// successful, the number is returned and the prefix is dropped from
+/// `number_str`.
+static std::optional<uint64_t> extract_u64(std::string_view &number_str) {
+ char *str_end = nullptr;
+ errno = 0;
+ uint64_t number = strtoull(number_str.data(), &str_end, 16);
+ if (errno != 0)
+ return std::nullopt;
+ assert(str_end);
+ number_str.remove_prefix(str_end - number_str.data());
+ return number;
+}
+
static void append_hex_value(std::ostream &ostrm, const void *buf,
size_t buf_size, bool swap) {
int i;
@@ -204,6 +218,25 @@ static void append_hexified_string(std::ostream &ostrm,
}
}
+/// Returns true if `str` starts with `prefix`.
+static bool starts_with(std::string_view str, std::string_view prefix) {
+ return str.substr(0, prefix.size()) == prefix;
+}
+
+/// Splits `list_str` into multiple string_views separated by `,`.
+static std::vector<std::string_view>
+parse_comma_separated_list(std::string_view list_str) {
+ std::vector<std::string_view> list;
+ while (!list_str.empty()) {
+ auto pos = list_str.find(',');
+ list.push_back(list_str.substr(0, pos));
+ if (pos == list_str.npos)
+ break;
+ list_str.remove_prefix(pos + 1);
+ }
+ return list;
+}
+
// from System.framework/Versions/B/PrivateHeaders/sys/codesign.h
extern "C" {
#define CS_OPS_STATUS 0 /* return status */
@@ -270,6 +303,11 @@ void RNBRemote::CreatePacketTable() {
"Read memory"));
t.push_back(Packet(read_register, &RNBRemote::HandlePacket_p, NULL, "p",
"Read one register"));
+ // Careful: this *must* come before the `M` packet, as debugserver matches
+ // packet prefixes against known packet names. Inverting the order would match
+ // `MultiMemRead` as an `M` packet.
+ t.push_back(Packet(multi_mem_read, &RNBRemote::HandlePacket_MultiMemRead,
+ NULL, "MultiMemRead", "Read multiple memory addresses"));
t.push_back(Packet(write_memory, &RNBRemote::HandlePacket_M, NULL, "M",
"Write memory"));
t.push_back(Packet(write_register, &RNBRemote::HandlePacket_P, NULL, "P",
@@ -3150,6 +3188,88 @@ rnb_err_t RNBRemote::HandlePacket_m(const char *p) {
return SendPacket(ostrm.str());
}
+rnb_err_t RNBRemote::HandlePacket_MultiMemRead(const char *p) {
+ const std::string_view packet_name("MultiMemRead:");
+ std::string_view packet(p);
+
+ if (!starts_with(packet, packet_name))
+ return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,
+ "Invalid MultiMemRead packet prefix");
+
+ packet.remove_prefix(packet_name.size());
+
+ const std::string_view ranges_prefix("ranges:");
+ if (!starts_with(packet, ranges_prefix))
+ return HandlePacket_ILLFORMED(__FILE__, __LINE__, packet.data(),
+ "Missing 'ranges' in MultiMemRead packet");
+ packet.remove_prefix(ranges_prefix.size());
+
+ std::vector<std::pair<nub_addr_t, std::size_t>> ranges;
+ std::size_t total_length = 0;
+
+ // Ranges should have the form: <addr>,<size>[,<addr>,<size>]*;
+ auto end_of_ranges_pos = packet.find(';');
+ if (end_of_ranges_pos == packet.npos)
+ return HandlePacket_ILLFORMED(__FILE__, __LINE__, packet.data(),
+ "MultiMemRead missing end of ranges marker");
+
+ std::vector<std::string_view> numbers_list =
+ parse_comma_separated_list(packet.substr(0, end_of_ranges_pos));
+ packet.remove_prefix(end_of_ranges_pos + 1);
+
+ // Ranges are pairs, so the number of elements must be even.
+ if (numbers_list.size() % 2 == 1)
+ return HandlePacket_ILLFORMED(
+ __FILE__, __LINE__, p,
+ "MultiMemRead has an odd number of numbers for the ranges");
+
+ for (unsigned idx = 0; idx < numbers_list.size(); idx += 2) {
+ std::optional<uint64_t> maybe_addr = extract_u64(numbers_list[idx]);
+ std::optional<uint64_t> maybe_length = extract_u64(numbers_list[idx + 1]);
+ if (!maybe_addr || !maybe_length)
+ return HandlePacket_ILLFORMED(__FILE__, __LINE__, packet.data(),
+ "Invalid MultiMemRead range");
+ // A sanity check that the packet requested is not too large or a negative
+ // number.
+ if (*maybe_length > 4 * 1024 * 1024)
+ return HandlePacket_ILLFORMED(__FILE__, __LINE__, packet.data(),
+ "MultiMemRead length is too large");
+
+ ranges.emplace_back(*maybe_addr, *maybe_length);
+ total_length += *maybe_length;
+ }
+
+ if (ranges.empty())
+ return HandlePacket_ILLFORMED(__FILE__, __LINE__, p,
+ "MultiMemRead has an empty range list");
+
+ if (!packet.empty())
+ return HandlePacket_ILLFORMED(
+ __FILE__, __LINE__, p, "MultiMemRead packet has unrecognized fields");
+
+ std::vector<std::vector<uint8_t>> buffers;
+ buffers.reserve(ranges.size());
+ for (auto [base_addr, length] : ranges) {
+ buffers.emplace_back(length, 0);
+ nub_size_t bytes_read = DNBProcessMemoryRead(m_ctx.ProcessID(), base_addr,
+ length, buffers.back().data());
+ buffers.back().resize(bytes_read);
+ }
+
+ std::ostringstream reply_stream;
+ bool first = true;
+ for (const std::vector<uint8_t> &buffer : buffers) {
+ reply_stream << (first ? "" : ",") << std::hex << buffer.size();
+ first = false;
+ }
+ reply_stream << ';';
+
+ for (const std::vector<uint8_t> &buffer : buffers)
+ binary_encode_data_vector(reply_stream, buffer);
+
+ return SendPacket(reply_stream.str());
+}
+
// Read memory, sent it up as binary data.
// Usage: xADDR,LEN
// ADDR and LEN are both base 16.
@@ -3503,6 +3623,7 @@ rnb_err_t RNBRemote::HandlePacket_qSupported(const char *p) {
if (supports_memory_tagging())
reply << "memory-tagging+;";
+ reply << "MultiMemRead+;";
return SendPacket(reply.str().c_str());
}
diff --git a/lldb/tools/debugserver/source/RNBRemote.h b/lldb/tools/debugserver/source/RNBRemote.h
index cf1c978..b32c00a 100644
--- a/lldb/tools/debugserver/source/RNBRemote.h
+++ b/lldb/tools/debugserver/source/RNBRemote.h
@@ -136,6 +136,7 @@ public:
query_transfer, // 'qXfer:'
json_query_dyld_process_state, // 'jGetDyldProcessState'
enable_error_strings, // 'QEnableErrorStrings'
+ multi_mem_read, // 'MultiMemRead'
unknown_type
};
// clang-format on
@@ -216,6 +217,7 @@ public:
rnb_err_t HandlePacket_last_signal(const char *p);
rnb_err_t HandlePacket_m(const char *p);
rnb_err_t HandlePacket_M(const char *p);
+ rnb_err_t HandlePacket_MultiMemRead(const char *p);
rnb_err_t HandlePacket_x(const char *p);
rnb_err_t HandlePacket_X(const char *p);
rnb_err_t HandlePacket_z(const char *p);
diff --git a/lldb/tools/lldb-dap/ProtocolUtils.cpp b/lldb/tools/lldb-dap/ProtocolUtils.cpp
index 775c82f..868c67c 100644
--- a/lldb/tools/lldb-dap/ProtocolUtils.cpp
+++ b/lldb/tools/lldb-dap/ProtocolUtils.cpp
@@ -301,6 +301,14 @@ Variable CreateVariable(lldb::SBValue v, int64_t var_ref, bool format_hex,
if (lldb::addr_t addr = v.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS)
var.memoryReference = addr;
+ bool is_readonly = v.GetType().IsAggregateType() ||
+ v.GetValueType() == lldb::eValueTypeRegisterSet;
+ if (is_readonly) {
+ if (!var.presentationHint)
+ var.presentationHint = {VariablePresentationHint()};
+ var.presentationHint->attributes.push_back("readOnly");
+ }
+
return var;
}
diff --git a/lldb/tools/lldb-mcp/lldb-mcp.cpp b/lldb/tools/lldb-mcp/lldb-mcp.cpp
index 68e9872..3fc3622 100644
--- a/lldb/tools/lldb-mcp/lldb-mcp.cpp
+++ b/lldb/tools/lldb-mcp/lldb-mcp.cpp
@@ -85,6 +85,8 @@ FileSpec driverPath() {
llvm::Error launch() {
FileSpec lldb_exec = driverPath();
lldb_private::ProcessLaunchInfo info;
+ info.SetMonitorProcessCallback(
+ &lldb_private::ProcessLaunchInfo::NoOpMonitorCallback);
info.SetExecutableFile(lldb_exec,
/*add_exe_file_as_first_arg=*/true);
info.GetArguments().AppendArgument("-O");
diff --git a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
index f940229..012eae0 100644
--- a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
+++ b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
@@ -639,3 +639,25 @@ TEST_F(GDBRemoteCommunicationClientTest, CalculateMD5) {
EXPECT_EQ(expected_high, result->high());
}
#endif
+
+TEST_F(GDBRemoteCommunicationClientTest, MultiMemReadSupported) {
+ std::future<bool> async_result = std::async(std::launch::async, [&] {
+ StringExtractorGDBRemote qSupported_packet_request;
+ server.GetPacket(qSupported_packet_request);
+ server.SendPacket("MultiMemRead+;");
+ return true;
+ });
+ ASSERT_TRUE(client.GetMultiMemReadSupported());
+ async_result.wait();
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, MultiMemReadNotSupported) {
+ std::future<bool> async_result = std::async(std::launch::async, [&] {
+ StringExtractorGDBRemote qSupported_packet_request;
+ server.GetPacket(qSupported_packet_request);
+ server.SendPacket(";");
+ return true;
+ });
+ ASSERT_FALSE(client.GetMultiMemReadSupported());
+ async_result.wait();
+}