summaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Process
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process')
-rw-r--r--lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp5
-rw-r--r--lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h16
-rw-r--r--lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp15
-rw-r--r--lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h7
-rw-r--r--lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp53
-rw-r--r--lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp7
-rw-r--r--lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h46
-rw-r--r--lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp9
-rw-r--r--lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h43
-rw-r--r--lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h42
-rw-r--r--lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h42
-rw-r--r--lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h38
-rw-r--r--lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp880
-rw-r--r--lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h119
-rw-r--r--lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.cpp29
-rw-r--r--lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h43
-rw-r--r--lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp656
-rw-r--r--lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.h96
-rw-r--r--lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp286
-rw-r--r--lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.h83
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp186
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h12
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp6
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h10
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp1211
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h76
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp22
-rw-r--r--lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h2
-rw-r--r--lldb/source/Plugins/Process/POSIX/CrashReason.cpp25
-rw-r--r--lldb/source/Plugins/Process/POSIX/CrashReason.h2
-rw-r--r--lldb/source/Plugins/Process/Utility/AuxVector.cpp1
-rw-r--r--lldb/source/Plugins/Process/Utility/AuxVector.h1
-rw-r--r--lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp89
-rw-r--r--lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h18
-rw-r--r--lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h291
-rw-r--r--lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp172
-rw-r--r--lldb/source/Plugins/Process/Utility/LinuxProcMaps.h8
-rw-r--r--lldb/source/Plugins/Process/Utility/LinuxSignals.cpp143
-rw-r--r--lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp143
-rw-r--r--lldb/source/Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.cpp278
-rw-r--r--lldb/source/Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.h48
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp7
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp4
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h16
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h12
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h12
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp131
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h53
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp16
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h27
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h4
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h2
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h2
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp107
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h44
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContext_x86.cpp58
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContext_x86.h20
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp104
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h15
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp179
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h45
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h572
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h25
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h47
-rw-r--r--lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h4
-rw-r--r--lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp11
-rw-r--r--lldb/source/Plugins/Process/elf-core/ProcessElfCore.h13
-rw-r--r--lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp4
-rw-r--r--lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h2
-rw-r--r--lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp144
-rw-r--r--lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h14
-rw-r--r--lldb/source/Plugins/Process/elf-core/RegisterUtilities.h4
-rw-r--r--lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp14
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp10
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp86
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h8
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp15
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h13
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp2
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp386
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h21
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp184
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h71
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp109
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h13
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp108
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h15
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp12
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h4
-rw-r--r--lldb/source/Plugins/Process/minidump/MinidumpParser.cpp188
-rw-r--r--lldb/source/Plugins/Process/minidump/MinidumpParser.h3
-rw-r--r--lldb/source/Plugins/Process/minidump/MinidumpTypes.h15
-rw-r--r--lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp193
-rw-r--r--lldb/source/Plugins/Process/minidump/ProcessMinidump.h15
94 files changed, 6249 insertions, 2193 deletions
diff --git a/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp b/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp
index 48dbddb86cca..3accc9cef6ed 100644
--- a/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp
@@ -164,9 +164,7 @@ lldb::RegisterContextSP FreeBSDThread::GetRegisterContext() {
assert(target_arch.GetTriple().getOS() == llvm::Triple::FreeBSD);
switch (target_arch.GetMachine()) {
case llvm::Triple::aarch64:
- break;
case llvm::Triple::arm:
- reg_interface = new RegisterInfoPOSIX_arm(target_arch);
break;
case llvm::Triple::ppc:
#ifndef __powerpc64__
@@ -200,7 +198,8 @@ lldb::RegisterContextSP FreeBSDThread::GetRegisterContext() {
}
case llvm::Triple::arm: {
RegisterContextPOSIXProcessMonitor_arm *reg_ctx =
- new RegisterContextPOSIXProcessMonitor_arm(*this, 0, reg_interface);
+ new RegisterContextPOSIXProcessMonitor_arm(
+ *this, std::make_unique<RegisterInfoPOSIX_arm>(target_arch));
m_posix_thread = reg_ctx;
m_reg_context_sp.reset(reg_ctx);
break;
diff --git a/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h b/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h
index 88fb7f31fe06..5a022c485b68 100644
--- a/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h
+++ b/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h
@@ -34,13 +34,13 @@ public:
~POSIXLimboStopInfo();
- lldb::StopReason GetStopReason() const;
+ lldb::StopReason GetStopReason() const override;
- const char *GetDescription();
+ const char *GetDescription() override;
- bool ShouldStop(lldb_private::Event *event_ptr);
+ bool ShouldStop(lldb_private::Event *event_ptr) override;
- bool ShouldNotify(lldb_private::Event *event_ptr);
+ bool ShouldNotify(lldb_private::Event *event_ptr) override;
};
//===----------------------------------------------------------------------===//
@@ -54,13 +54,13 @@ public:
~POSIXNewThreadStopInfo();
- lldb::StopReason GetStopReason() const;
+ lldb::StopReason GetStopReason() const override;
- const char *GetDescription();
+ const char *GetDescription() override;
- bool ShouldStop(lldb_private::Event *event_ptr);
+ bool ShouldStop(lldb_private::Event *event_ptr) override;
- bool ShouldNotify(lldb_private::Event *event_ptr);
+ bool ShouldNotify(lldb_private::Event *event_ptr) override;
};
#endif
diff --git a/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
index a44080640f6c..a1fe45b84ca2 100644
--- a/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
@@ -70,9 +70,10 @@ UnixSignalsSP &GetFreeBSDSignals() {
lldb::ProcessSP
ProcessFreeBSD::CreateInstance(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
- const FileSpec *crash_file_path) {
+ const FileSpec *crash_file_path,
+ bool can_connect) {
lldb::ProcessSP process_sp;
- if (crash_file_path == NULL)
+ if (crash_file_path == NULL && !can_connect)
process_sp.reset(
new ProcessFreeBSD(target_sp, listener_sp, GetFreeBSDSignals()));
return process_sp;
@@ -165,8 +166,8 @@ Status ProcessFreeBSD::DoResume() {
return Status();
}
-bool ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list,
- ThreadList &new_thread_list) {
+bool ProcessFreeBSD::DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
LLDB_LOGF(log, "ProcessFreeBSD::%s (pid = %" PRIu64 ")", __FUNCTION__,
GetID());
@@ -380,8 +381,7 @@ Status ProcessFreeBSD::DoLaunch(Module *module,
FileSpec stdout_file_spec{};
FileSpec stderr_file_spec{};
- const FileSpec dbg_pts_file_spec{
- launch_info.GetPTY().GetSecondaryName(NULL, 0)};
+ const FileSpec dbg_pts_file_spec{launch_info.GetPTY().GetSecondaryName()};
file_action = launch_info.GetFileActionForFD(STDIN_FILENO);
stdin_file_spec =
@@ -683,6 +683,9 @@ ProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(BreakpointSite *bp_site) {
}
Status ProcessFreeBSD::EnableBreakpointSite(BreakpointSite *bp_site) {
+ if (bp_site->HardwareRequired())
+ return Status("Hardware breakpoints are not supported.");
+
return EnableSoftwareBreakpoint(bp_site);
}
diff --git a/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h b/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
index 536da0c0aa70..b60bcd279021 100644
--- a/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
+++ b/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
@@ -26,7 +26,8 @@ public:
// Static functions.
static lldb::ProcessSP
CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
- const lldb_private::FileSpec *crash_file_path);
+ const lldb_private::FileSpec *crash_file_path,
+ bool can_connect);
static void Initialize();
@@ -117,8 +118,8 @@ public:
virtual uint32_t UpdateThreadListIfNeeded();
- bool UpdateThreadList(lldb_private::ThreadList &old_thread_list,
- lldb_private::ThreadList &new_thread_list) override;
+ bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list) override;
virtual lldb::ByteOrder GetByteOrder() const;
diff --git a/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
index 6a9209d1214c..4637458b53c3 100644
--- a/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
@@ -215,7 +215,7 @@ public:
: m_addr(addr), m_buff(buff), m_size(size), m_error(error),
m_result(result) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
lldb::addr_t m_addr;
@@ -240,7 +240,7 @@ public:
: m_addr(addr), m_buff(buff), m_size(size), m_error(error),
m_result(result) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
lldb::addr_t m_addr;
@@ -303,7 +303,7 @@ public:
const RegisterValue &value, bool &result)
: m_tid(tid), m_offset(offset), m_value(value), m_result(result) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
lldb::tid_t m_tid;
@@ -336,7 +336,7 @@ public:
: m_tid(tid), m_offset(offset), m_size(size), m_value(value),
m_result(result) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
lldb::tid_t m_tid;
@@ -369,7 +369,7 @@ public:
const RegisterValue &value, bool &result)
: m_tid(tid), m_offset(offset), m_value(value), m_result(result) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
lldb::tid_t m_tid;
@@ -400,7 +400,7 @@ public:
ReadGPROperation(lldb::tid_t tid, void *buf, bool &result)
: m_tid(tid), m_buf(buf), m_result(result) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
lldb::tid_t m_tid;
@@ -426,7 +426,7 @@ public:
ReadFPROperation(lldb::tid_t tid, void *buf, bool &result)
: m_tid(tid), m_buf(buf), m_result(result) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
lldb::tid_t m_tid;
@@ -448,7 +448,7 @@ public:
WriteGPROperation(lldb::tid_t tid, void *buf, bool &result)
: m_tid(tid), m_buf(buf), m_result(result) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
lldb::tid_t m_tid;
@@ -470,7 +470,7 @@ public:
WriteFPROperation(lldb::tid_t tid, void *buf, bool &result)
: m_tid(tid), m_buf(buf), m_result(result) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
lldb::tid_t m_tid;
@@ -492,7 +492,7 @@ public:
ResumeOperation(uint32_t signo, bool &result)
: m_signo(signo), m_result(result) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
uint32_t m_signo;
@@ -522,7 +522,7 @@ public:
SingleStepOperation(uint32_t signo, bool &result)
: m_signo(signo), m_result(result) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
uint32_t m_signo;
@@ -549,7 +549,7 @@ public:
LwpInfoOperation(lldb::tid_t tid, void *info, bool &result, int &ptrace_err)
: m_tid(tid), m_info(info), m_result(result), m_err(ptrace_err) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
lldb::tid_t m_tid;
@@ -577,7 +577,7 @@ public:
ThreadSuspendOperation(lldb::tid_t tid, bool suspend, bool &result)
: m_tid(tid), m_suspend(suspend), m_result(result) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
lldb::tid_t m_tid;
@@ -596,7 +596,7 @@ public:
EventMessageOperation(lldb::tid_t tid, unsigned long *message, bool &result)
: m_tid(tid), m_message(message), m_result(result) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
lldb::tid_t m_tid;
@@ -624,7 +624,7 @@ class KillOperation : public Operation {
public:
KillOperation(bool &result) : m_result(result) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
bool &m_result;
@@ -645,7 +645,7 @@ class DetachOperation : public Operation {
public:
DetachOperation(Status &result) : m_error(result) {}
- void Execute(ProcessMonitor *monitor);
+ void Execute(ProcessMonitor *monitor) override;
private:
Status &m_error;
@@ -821,17 +821,14 @@ bool ProcessMonitor::Launch(LaunchArgs *args) {
const FileSpec &working_dir = args->m_working_dir;
PseudoTerminal terminal;
- const size_t err_len = 1024;
- char err_str[err_len];
- ::pid_t pid;
// Propagate the environment if one is not supplied.
Environment::Envp envp =
(args->m_env.empty() ? Host::GetEnvironment() : args->m_env).getEnvp();
- if ((pid = terminal.Fork(err_str, err_len)) == -1) {
- args->m_error.SetErrorToGenericError();
- args->m_error.SetErrorString("Process fork failed.");
+ llvm::Expected<lldb::pid_t> pid = terminal.Fork();
+ if (!pid) {
+ args->m_error = pid.takeError();
goto FINISH;
}
@@ -847,7 +844,7 @@ bool ProcessMonitor::Launch(LaunchArgs *args) {
};
// Child process.
- if (pid == 0) {
+ if (*pid == 0) {
// Trace this process.
if (PTRACE(PT_TRACE_ME, 0, NULL, 0) < 0)
exit(ePtraceFailed);
@@ -892,7 +889,7 @@ bool ProcessMonitor::Launch(LaunchArgs *args) {
// Wait for the child process to to trap on its call to execve.
::pid_t wpid;
int status;
- if ((wpid = waitpid(pid, &status, 0)) < 0) {
+ if ((wpid = waitpid(*pid, &status, 0)) < 0) {
args->m_error.SetErrorToErrno();
goto FINISH;
} else if (WIFEXITED(status)) {
@@ -926,13 +923,13 @@ bool ProcessMonitor::Launch(LaunchArgs *args) {
}
goto FINISH;
}
- assert(WIFSTOPPED(status) && wpid == (::pid_t)pid &&
+ assert(WIFSTOPPED(status) && wpid == (::pid_t)*pid &&
"Could not sync with inferior process.");
#ifdef notyet
// Have the child raise an event on exit. This is used to keep the child in
// limbo until it is destroyed.
- if (PTRACE(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACEEXIT) < 0) {
+ if (PTRACE(PTRACE_SETOPTIONS, *pid, NULL, PTRACE_O_TRACEEXIT) < 0) {
args->m_error.SetErrorToErrno();
goto FINISH;
}
@@ -940,7 +937,7 @@ bool ProcessMonitor::Launch(LaunchArgs *args) {
// Release the master terminal descriptor and pass it off to the
// ProcessMonitor instance. Similarly stash the inferior pid.
monitor->m_terminal_fd = terminal.ReleasePrimaryFileDescriptor();
- monitor->m_pid = pid;
+ monitor->m_pid = *pid;
// Set the terminal fd to be in non blocking mode (it simplifies the
// implementation of ProcessFreeBSD::GetSTDOUT to have a non-blocking
@@ -948,7 +945,7 @@ bool ProcessMonitor::Launch(LaunchArgs *args) {
if (!EnsureFDFlags(monitor->m_terminal_fd, O_NONBLOCK, args->m_error))
goto FINISH;
- process.SendMessage(ProcessMessage::Attach(pid));
+ process.SendMessage(ProcessMessage::Attach(*pid));
FINISH:
return args->m_error.Success();
diff --git a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp
index 4216f68faf5c..afb92e848466 100644
--- a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp
@@ -14,6 +14,7 @@
#include "ProcessMonitor.h"
#include "RegisterContextPOSIXProcessMonitor_arm.h"
#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h"
+#include "Plugins/Process/Utility/lldb-arm-register-enums.h"
using namespace lldb_private;
using namespace lldb;
@@ -21,9 +22,9 @@ using namespace lldb;
#define REG_CONTEXT_SIZE (GetGPRSize())
RegisterContextPOSIXProcessMonitor_arm::RegisterContextPOSIXProcessMonitor_arm(
- Thread &thread, uint32_t concrete_frame_idx,
- lldb_private::RegisterInfoInterface *register_info)
- : RegisterContextPOSIX_arm(thread, concrete_frame_idx, register_info) {}
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_arm> register_info)
+ : RegisterContextPOSIX_arm(thread, std::move(register_info)) {}
ProcessMonitor &RegisterContextPOSIXProcessMonitor_arm::GetMonitor() {
ProcessSP base = CalculateProcess();
diff --git a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h
index b376967df99c..bb455841dff1 100644
--- a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h
+++ b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h
@@ -16,17 +16,17 @@ class RegisterContextPOSIXProcessMonitor_arm : public RegisterContextPOSIX_arm,
public POSIXBreakpointProtocol {
public:
RegisterContextPOSIXProcessMonitor_arm(
- lldb_private::Thread &thread, uint32_t concrete_frame_idx,
- lldb_private::RegisterInfoInterface *register_info);
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_arm> register_info);
protected:
- bool ReadGPR();
+ bool ReadGPR() override;
- bool ReadFPR();
+ bool ReadFPR() override;
- bool WriteGPR();
+ bool WriteGPR() override;
- bool WriteFPR();
+ bool WriteFPR() override;
// lldb_private::RegisterContext
bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
@@ -35,41 +35,45 @@ protected:
const lldb_private::RegisterValue &value);
bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
- lldb_private::RegisterValue &value);
+ lldb_private::RegisterValue &value) override;
bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
- const lldb_private::RegisterValue &value);
+ const lldb_private::RegisterValue &value) override;
- bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+ bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
- bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read,
- bool write);
+ bool write) override;
- bool ClearHardwareWatchpoint(uint32_t hw_index);
+ bool ClearHardwareWatchpoint(uint32_t hw_index) override;
- bool HardwareSingleStep(bool enable);
+ bool HardwareSingleStep(bool enable) override;
// POSIXBreakpointProtocol
- bool UpdateAfterBreakpoint();
+ bool UpdateAfterBreakpoint() override;
- unsigned GetRegisterIndexFromOffset(unsigned offset);
+ unsigned GetRegisterIndexFromOffset(unsigned offset) override;
- bool IsWatchpointHit(uint32_t hw_index);
+ bool IsWatchpointHit(uint32_t hw_index) override;
- bool ClearWatchpointHits();
+ bool ClearWatchpointHits() override;
- lldb::addr_t GetWatchpointAddress(uint32_t hw_index);
+ lldb::addr_t GetWatchpointAddress(uint32_t hw_index) override;
- bool IsWatchpointVacant(uint32_t hw_index);
+ bool IsWatchpointVacant(uint32_t hw_index) override;
bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read,
- bool write, uint32_t hw_index);
+ bool write, uint32_t hw_index) override;
- uint32_t NumSupportedHardwareWatchpoints();
+ uint32_t NumSupportedHardwareWatchpoints() override;
private:
+ RegisterInfoPOSIX_arm::GPR m_gpr_arm;
+
+ RegisterInfoPOSIX_arm::FPU m_fpr;
+
ProcessMonitor &GetMonitor();
};
diff --git a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp
index d3eafae1e6de..39ae0b9b9e7f 100644
--- a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp
@@ -24,7 +24,10 @@ RegisterContextPOSIXProcessMonitor_arm64::
RegisterContextPOSIXProcessMonitor_arm64(
lldb_private::Thread &thread,
std::unique_ptr<RegisterInfoPOSIX_arm64> register_info)
- : RegisterContextPOSIX_arm64(thread, std::move(register_info)) {}
+ : RegisterContextPOSIX_arm64(thread, std::move(register_info)) {
+ ::memset(&m_gpr_arm64, 0, sizeof m_gpr_arm64);
+ ::memset(&m_fpr, 0, sizeof m_fpr);
+}
ProcessMonitor &RegisterContextPOSIXProcessMonitor_arm64::GetMonitor() {
lldb::ProcessSP base = CalculateProcess();
@@ -226,11 +229,11 @@ bool RegisterContextPOSIXProcessMonitor_arm64::UpdateAfterBreakpoint() {
unsigned RegisterContextPOSIXProcessMonitor_arm64::GetRegisterIndexFromOffset(
unsigned offset) {
unsigned reg;
- for (reg = 0; reg < k_num_registers_arm64; reg++) {
+ for (reg = 0; reg < GetRegisterCount(); reg++) {
if (GetRegisterInfo()[reg].byte_offset == offset)
break;
}
- assert(reg < k_num_registers_arm64 && "Invalid register offset.");
+ assert(reg < GetRegisterCount() && "Invalid register offset.");
return reg;
}
diff --git a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h
index f100d905e28f..dcae1d46de9b 100644
--- a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h
+++ b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h
@@ -21,13 +21,13 @@ public:
std::unique_ptr<RegisterInfoPOSIX_arm64> register_info);
protected:
- bool ReadGPR();
+ bool ReadGPR() override;
- bool ReadFPR();
+ bool ReadFPR() override;
- bool WriteGPR();
+ bool WriteGPR() override;
- bool WriteFPR();
+ bool WriteFPR() override;
// lldb_private::RegisterContext
bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
@@ -36,41 +36,46 @@ protected:
const lldb_private::RegisterValue &value);
bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
- lldb_private::RegisterValue &value);
+ lldb_private::RegisterValue &value) override;
bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
- const lldb_private::RegisterValue &value);
+ const lldb_private::RegisterValue &value) override;
- bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+ bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
- bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read,
- bool write);
+ bool write) override;
- bool ClearHardwareWatchpoint(uint32_t hw_index);
+ bool ClearHardwareWatchpoint(uint32_t hw_index) override;
- bool HardwareSingleStep(bool enable);
+ bool HardwareSingleStep(bool enable) override;
// POSIXBreakpointProtocol
- bool UpdateAfterBreakpoint();
+ bool UpdateAfterBreakpoint() override;
- unsigned GetRegisterIndexFromOffset(unsigned offset);
+ unsigned GetRegisterIndexFromOffset(unsigned offset) override;
- bool IsWatchpointHit(uint32_t hw_index);
+ bool IsWatchpointHit(uint32_t hw_index) override;
- bool ClearWatchpointHits();
+ bool ClearWatchpointHits() override;
- lldb::addr_t GetWatchpointAddress(uint32_t hw_index);
+ lldb::addr_t GetWatchpointAddress(uint32_t hw_index) override;
- bool IsWatchpointVacant(uint32_t hw_index);
+ bool IsWatchpointVacant(uint32_t hw_index) override;
bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read,
- bool write, uint32_t hw_index);
+ bool write, uint32_t hw_index) override;
- uint32_t NumSupportedHardwareWatchpoints();
+ uint32_t NumSupportedHardwareWatchpoints() override;
private:
+ RegisterInfoPOSIX_arm64::GPR m_gpr_arm64; // 64-bit general purpose registers.
+
+ RegisterInfoPOSIX_arm64::FPU
+ m_fpr; // floating-point registers including extended register sets.
+
ProcessMonitor &GetMonitor();
};
diff --git a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h
index a482cd3f1e1c..be404cc08c34 100644
--- a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h
+++ b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h
@@ -13,6 +13,8 @@
#include "Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h"
#include "RegisterContextPOSIX.h"
+class ProcessMonitor;
+
class RegisterContextPOSIXProcessMonitor_mips64
: public RegisterContextPOSIX_mips64,
public POSIXBreakpointProtocol {
@@ -22,13 +24,13 @@ public:
lldb_private::RegisterInfoInterface *register_info);
protected:
- bool ReadGPR();
+ bool ReadGPR() override;
- bool ReadFPR();
+ bool ReadFPR() override;
- bool WriteGPR();
+ bool WriteGPR() override;
- bool WriteFPR();
+ bool WriteFPR() override;
// lldb_private::RegisterContext
bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
@@ -37,43 +39,43 @@ protected:
const lldb_private::RegisterValue &value);
bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
- lldb_private::RegisterValue &value);
+ lldb_private::RegisterValue &value) override;
bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
- const lldb_private::RegisterValue &value);
+ const lldb_private::RegisterValue &value) override;
- bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+ bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
- bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read,
- bool write);
+ bool write) override;
- bool ClearHardwareWatchpoint(uint32_t hw_index);
+ bool ClearHardwareWatchpoint(uint32_t hw_index) override;
- bool HardwareSingleStep(bool enable);
+ bool HardwareSingleStep(bool enable) override;
// POSIXBreakpointProtocol
- bool UpdateAfterBreakpoint();
+ bool UpdateAfterBreakpoint() override;
- unsigned GetRegisterIndexFromOffset(unsigned offset);
+ unsigned GetRegisterIndexFromOffset(unsigned offset) override;
- bool IsWatchpointHit(uint32_t hw_index);
+ bool IsWatchpointHit(uint32_t hw_index) override;
- bool ClearWatchpointHits();
+ bool ClearWatchpointHits() override;
- lldb::addr_t GetWatchpointAddress(uint32_t hw_index);
+ lldb::addr_t GetWatchpointAddress(uint32_t hw_index) override;
- bool IsWatchpointVacant(uint32_t hw_index);
+ bool IsWatchpointVacant(uint32_t hw_index) override;
bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read,
- bool write, uint32_t hw_index);
+ bool write, uint32_t hw_index) override;
- uint32_t NumSupportedHardwareWatchpoints();
+ uint32_t NumSupportedHardwareWatchpoints() override;
private:
uint64_t
- m_gpr_mips64[k_num_gpr_registers_mips64]; // general purpose registers.
+ m_gpr_mips64[lldb_private::k_num_gpr_registers_mips64]; // general purpose registers.
ProcessMonitor &GetMonitor();
};
diff --git a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h
index 17b649feebf1..328db4479ce6 100644
--- a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h
+++ b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h
@@ -24,17 +24,17 @@ public:
protected:
bool IsVMX();
- bool ReadGPR();
+ bool ReadGPR() override;
- bool ReadFPR();
+ bool ReadFPR() override;
- bool ReadVMX();
+ bool ReadVMX() override;
- bool WriteGPR();
+ bool WriteGPR() override;
- bool WriteFPR();
+ bool WriteFPR() override;
- bool WriteVMX();
+ bool WriteVMX() override;
// lldb_private::RegisterContext
bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
@@ -43,39 +43,39 @@ protected:
const lldb_private::RegisterValue &value);
bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
- lldb_private::RegisterValue &value);
+ lldb_private::RegisterValue &value) override;
bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
- const lldb_private::RegisterValue &value);
+ const lldb_private::RegisterValue &value) override;
- bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+ bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
- bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read,
- bool write);
+ bool write) override;
- bool ClearHardwareWatchpoint(uint32_t hw_index);
+ bool ClearHardwareWatchpoint(uint32_t hw_index) override;
- bool HardwareSingleStep(bool enable);
+ bool HardwareSingleStep(bool enable) override;
// POSIXBreakpointProtocol
- bool UpdateAfterBreakpoint();
+ bool UpdateAfterBreakpoint() override;
- unsigned GetRegisterIndexFromOffset(unsigned offset);
+ unsigned GetRegisterIndexFromOffset(unsigned offset) override;
- bool IsWatchpointHit(uint32_t hw_index);
+ bool IsWatchpointHit(uint32_t hw_index) override;
- bool ClearWatchpointHits();
+ bool ClearWatchpointHits() override;
- lldb::addr_t GetWatchpointAddress(uint32_t hw_index);
+ lldb::addr_t GetWatchpointAddress(uint32_t hw_index) override;
- bool IsWatchpointVacant(uint32_t hw_index);
+ bool IsWatchpointVacant(uint32_t hw_index) override;
bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read,
- bool write, uint32_t hw_index);
+ bool write, uint32_t hw_index) override;
- uint32_t NumSupportedHardwareWatchpoints();
+ uint32_t NumSupportedHardwareWatchpoints() override;
private:
ProcessMonitor &GetMonitor();
diff --git a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h
index c9dc02a88e01..1afb366eeba3 100644
--- a/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h
+++ b/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h
@@ -22,13 +22,13 @@ public:
lldb_private::RegisterInfoInterface *register_info);
protected:
- bool ReadGPR();
+ bool ReadGPR() override;
- bool ReadFPR();
+ bool ReadFPR() override;
- bool WriteGPR();
+ bool WriteGPR() override;
- bool WriteFPR();
+ bool WriteFPR() override;
// lldb_private::RegisterContext
bool ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
@@ -37,39 +37,39 @@ protected:
const lldb_private::RegisterValue &value);
bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
- lldb_private::RegisterValue &value);
+ lldb_private::RegisterValue &value) override;
bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
- const lldb_private::RegisterValue &value);
+ const lldb_private::RegisterValue &value) override;
- bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+ bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
- bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+ bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read,
- bool write);
+ bool write) override;
- bool ClearHardwareWatchpoint(uint32_t hw_index);
+ bool ClearHardwareWatchpoint(uint32_t hw_index) override;
- bool HardwareSingleStep(bool enable);
+ bool HardwareSingleStep(bool enable) override;
// POSIXBreakpointProtocol
- bool UpdateAfterBreakpoint();
+ bool UpdateAfterBreakpoint() override;
- unsigned GetRegisterIndexFromOffset(unsigned offset);
+ unsigned GetRegisterIndexFromOffset(unsigned offset) override;
- bool IsWatchpointHit(uint32_t hw_index);
+ bool IsWatchpointHit(uint32_t hw_index) override;
- bool ClearWatchpointHits();
+ bool ClearWatchpointHits() override;
- lldb::addr_t GetWatchpointAddress(uint32_t hw_index);
+ lldb::addr_t GetWatchpointAddress(uint32_t hw_index) override;
- bool IsWatchpointVacant(uint32_t hw_index);
+ bool IsWatchpointVacant(uint32_t hw_index) override;
bool SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read,
- bool write, uint32_t hw_index);
+ bool write, uint32_t hw_index) override;
- uint32_t NumSupportedHardwareWatchpoints();
+ uint32_t NumSupportedHardwareWatchpoints() override;
private:
ProcessMonitor &GetMonitor();
diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp
new file mode 100644
index 000000000000..163093c2ab1f
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp
@@ -0,0 +1,880 @@
+//===-- NativeProcessFreeBSD.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeProcessFreeBSD.h"
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <machine/elf.h>
+// clang-format on
+
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Host/HostProcess.h"
+#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/State.h"
+#include "llvm/Support/Errno.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+using namespace llvm;
+
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static Status EnsureFDFlags(int fd, int flags) {
+ Status error;
+
+ int status = fcntl(fd, F_GETFL);
+ if (status == -1) {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ if (fcntl(fd, F_SETFL, status | flags) == -1) {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ return error;
+}
+
+// Public Static Methods
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+NativeProcessFreeBSD::Factory::Launch(ProcessLaunchInfo &launch_info,
+ NativeDelegate &native_delegate,
+ MainLoop &mainloop) const {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+
+ Status status;
+ ::pid_t pid = ProcessLauncherPosixFork()
+ .LaunchProcess(launch_info, status)
+ .GetProcessId();
+ LLDB_LOG(log, "pid = {0:x}", pid);
+ if (status.Fail()) {
+ LLDB_LOG(log, "failed to launch process: {0}", status);
+ return status.ToError();
+ }
+
+ // Wait for the child process to trap on its call to execve.
+ int wstatus;
+ ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
+ assert(wpid == pid);
+ (void)wpid;
+ if (!WIFSTOPPED(wstatus)) {
+ LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",
+ WaitStatus::Decode(wstatus));
+ return llvm::make_error<StringError>("Could not sync with inferior process",
+ llvm::inconvertibleErrorCode());
+ }
+ LLDB_LOG(log, "inferior started, now in stopped state");
+
+ ProcessInstanceInfo Info;
+ if (!Host::GetProcessInfo(pid, Info)) {
+ return llvm::make_error<StringError>("Cannot get process architecture",
+ llvm::inconvertibleErrorCode());
+ }
+
+ // Set the architecture to the exe architecture.
+ LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid,
+ Info.GetArchitecture().GetArchitectureName());
+
+ std::unique_ptr<NativeProcessFreeBSD> process_up(new NativeProcessFreeBSD(
+ pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,
+ Info.GetArchitecture(), mainloop));
+
+ status = process_up->SetupTrace();
+ if (status.Fail())
+ return status.ToError();
+
+ for (const auto &thread : process_up->m_threads)
+ static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
+ process_up->SetState(StateType::eStateStopped, false);
+
+ return std::move(process_up);
+}
+
+llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+NativeProcessFreeBSD::Factory::Attach(
+ lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate,
+ MainLoop &mainloop) const {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ LLDB_LOG(log, "pid = {0:x}", pid);
+
+ // Retrieve the architecture for the running process.
+ ProcessInstanceInfo Info;
+ if (!Host::GetProcessInfo(pid, Info)) {
+ return llvm::make_error<StringError>("Cannot get process architecture",
+ llvm::inconvertibleErrorCode());
+ }
+
+ std::unique_ptr<NativeProcessFreeBSD> process_up(new NativeProcessFreeBSD(
+ pid, -1, native_delegate, Info.GetArchitecture(), mainloop));
+
+ Status status = process_up->Attach();
+ if (!status.Success())
+ return status.ToError();
+
+ return std::move(process_up);
+}
+
+// Public Instance Methods
+
+NativeProcessFreeBSD::NativeProcessFreeBSD(::pid_t pid, int terminal_fd,
+ NativeDelegate &delegate,
+ const ArchSpec &arch,
+ MainLoop &mainloop)
+ : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch) {
+ if (m_terminal_fd != -1) {
+ Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
+ assert(status.Success());
+ }
+
+ Status status;
+ m_sigchld_handle = mainloop.RegisterSignal(
+ SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
+ assert(m_sigchld_handle && status.Success());
+}
+
+// Handles all waitpid events from the inferior process.
+void NativeProcessFreeBSD::MonitorCallback(lldb::pid_t pid, int signal) {
+ switch (signal) {
+ case SIGTRAP:
+ return MonitorSIGTRAP(pid);
+ case SIGSTOP:
+ return MonitorSIGSTOP(pid);
+ default:
+ return MonitorSignal(pid, signal);
+ }
+}
+
+void NativeProcessFreeBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+
+ LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);
+
+ /* Stop Tracking All Threads attached to Process */
+ m_threads.clear();
+
+ SetExitStatus(status, true);
+
+ // Notify delegate that our process has exited.
+ SetState(StateType::eStateExited, true);
+}
+
+void NativeProcessFreeBSD::MonitorSIGSTOP(lldb::pid_t pid) {
+ /* Stop all Threads attached to Process */
+ for (const auto &thread : m_threads) {
+ static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP,
+ nullptr);
+ }
+ SetState(StateType::eStateStopped, true);
+}
+
+void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ struct ptrace_lwpinfo info;
+
+ const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
+ if (siginfo_err.Fail()) {
+ LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);
+ return;
+ }
+ assert(info.pl_event == PL_EVENT_SIGNAL);
+
+ LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, flags = {2:x}", pid,
+ info.pl_lwpid, info.pl_flags);
+ NativeThreadFreeBSD *thread = nullptr;
+
+ if (info.pl_flags & (PL_FLAG_BORN | PL_FLAG_EXITED)) {
+ if (info.pl_flags & PL_FLAG_BORN) {
+ LLDB_LOG(log, "monitoring new thread, tid = {0}", info.pl_lwpid);
+ NativeThreadFreeBSD &t = AddThread(info.pl_lwpid);
+
+ // Technically, the FreeBSD kernel copies the debug registers to new
+ // threads. However, there is a non-negligible delay between acquiring
+ // the DR values and reporting the new thread during which the user may
+ // establish a new watchpoint. In order to ensure that watchpoints
+ // established during this period are propagated to new threads,
+ // explicitly copy the DR value at the time the new thread is reported.
+ //
+ // See also: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=250954
+
+ llvm::Error error = t.CopyWatchpointsFrom(
+ static_cast<NativeThreadFreeBSD &>(*GetCurrentThread()));
+ if (error) {
+ LLDB_LOG(log, "failed to copy watchpoints to new thread {0}: {1}",
+ info.pl_lwpid, llvm::toString(std::move(error)));
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+ } else /*if (info.pl_flags & PL_FLAG_EXITED)*/ {
+ LLDB_LOG(log, "thread exited, tid = {0}", info.pl_lwpid);
+ RemoveThread(info.pl_lwpid);
+ }
+
+ Status error =
+ PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
+ if (error.Fail())
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+
+ if (info.pl_flags & PL_FLAG_EXEC) {
+ Status error = ReinitializeThreads();
+ if (error.Fail()) {
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+
+ // Let our delegate know we have just exec'd.
+ NotifyDidExec();
+
+ for (const auto &thread : m_threads)
+ static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedByExec();
+ SetState(StateType::eStateStopped, true);
+ return;
+ }
+
+ if (info.pl_lwpid > 0) {
+ for (const auto &t : m_threads) {
+ if (t->GetID() == static_cast<lldb::tid_t>(info.pl_lwpid))
+ thread = static_cast<NativeThreadFreeBSD *>(t.get());
+ static_cast<NativeThreadFreeBSD *>(t.get())->SetStoppedWithNoReason();
+ }
+ if (!thread)
+ LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid,
+ info.pl_lwpid);
+ }
+
+ if (info.pl_flags & PL_FLAG_SI) {
+ assert(info.pl_siginfo.si_signo == SIGTRAP);
+ LLDB_LOG(log, "SIGTRAP siginfo: si_code = {0}, pid = {1}",
+ info.pl_siginfo.si_code, info.pl_siginfo.si_pid);
+
+ switch (info.pl_siginfo.si_code) {
+ case TRAP_BRKPT:
+ if (thread) {
+ thread->SetStoppedByBreakpoint();
+ FixupBreakpointPCAsNeeded(*thread);
+ }
+ SetState(StateType::eStateStopped, true);
+ return;
+ case TRAP_TRACE:
+ if (thread) {
+ auto &regctx = static_cast<NativeRegisterContextFreeBSD &>(
+ thread->GetRegisterContext());
+ uint32_t wp_index = LLDB_INVALID_INDEX32;
+ Status error =
+ regctx.GetWatchpointHitIndex(wp_index, LLDB_INVALID_ADDRESS);
+ if (error.Fail())
+ LLDB_LOG(log,
+ "received error while checking for watchpoint hits, pid = "
+ "{0}, LWP = {1}, error = {2}",
+ pid, info.pl_lwpid, error);
+ if (wp_index != LLDB_INVALID_INDEX32) {
+ regctx.ClearWatchpointHit(wp_index);
+ thread->SetStoppedByWatchpoint(wp_index);
+ SetState(StateType::eStateStopped, true);
+ break;
+ }
+
+ thread->SetStoppedByTrace();
+ }
+
+ SetState(StateType::eStateStopped, true);
+ return;
+ }
+ }
+
+ // Either user-generated SIGTRAP or an unknown event that would
+ // otherwise leave the debugger hanging.
+ LLDB_LOG(log, "unknown SIGTRAP, passing to generic handler");
+ MonitorSignal(pid, SIGTRAP);
+}
+
+void NativeProcessFreeBSD::MonitorSignal(lldb::pid_t pid, int signal) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ struct ptrace_lwpinfo info;
+
+ const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info));
+ if (siginfo_err.Fail()) {
+ LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);
+ return;
+ }
+ assert(info.pl_event == PL_EVENT_SIGNAL);
+ // TODO: do we need to handle !PL_FLAG_SI?
+ assert(info.pl_flags & PL_FLAG_SI);
+ assert(info.pl_siginfo.si_signo == signal);
+
+ for (const auto &abs_thread : m_threads) {
+ NativeThreadFreeBSD &thread =
+ static_cast<NativeThreadFreeBSD &>(*abs_thread);
+ assert(info.pl_lwpid >= 0);
+ if (info.pl_lwpid == 0 ||
+ static_cast<lldb::tid_t>(info.pl_lwpid) == thread.GetID())
+ thread.SetStoppedBySignal(info.pl_siginfo.si_signo, &info.pl_siginfo);
+ else
+ thread.SetStoppedWithNoReason();
+ }
+ SetState(StateType::eStateStopped, true);
+}
+
+Status NativeProcessFreeBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr,
+ int data, int *result) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+ Status error;
+ int ret;
+
+ errno = 0;
+ ret =
+ ptrace(req, static_cast<::pid_t>(pid), static_cast<caddr_t>(addr), data);
+
+ if (ret == -1)
+ error.SetErrorToErrno();
+
+ if (result)
+ *result = ret;
+
+ LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret);
+
+ if (error.Fail())
+ LLDB_LOG(log, "ptrace() failed: {0}", error);
+
+ return error;
+}
+
+Status NativeProcessFreeBSD::Resume(const ResumeActionList &resume_actions) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ LLDB_LOG(log, "pid {0}", GetID());
+
+ Status ret;
+
+ int signal = 0;
+ for (const auto &abs_thread : m_threads) {
+ assert(abs_thread && "thread list should not contain NULL threads");
+ NativeThreadFreeBSD &thread =
+ static_cast<NativeThreadFreeBSD &>(*abs_thread);
+
+ const ResumeAction *action =
+ resume_actions.GetActionForThread(thread.GetID(), true);
+ // we need to explicit issue suspend requests, so it is simpler to map it
+ // into proper action
+ ResumeAction suspend_action{thread.GetID(), eStateSuspended,
+ LLDB_INVALID_SIGNAL_NUMBER};
+
+ if (action == nullptr) {
+ LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(),
+ thread.GetID());
+ action = &suspend_action;
+ }
+
+ LLDB_LOG(
+ log,
+ "processing resume action state {0} signal {1} for pid {2} tid {3}",
+ action->state, action->signal, GetID(), thread.GetID());
+
+ switch (action->state) {
+ case eStateRunning:
+ ret = thread.Resume();
+ break;
+ case eStateStepping:
+ ret = thread.SingleStep();
+ break;
+ case eStateSuspended:
+ case eStateStopped:
+ if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)
+ return Status("Passing signal to suspended thread unsupported");
+
+ ret = thread.Suspend();
+ break;
+
+ default:
+ return Status(
+ "NativeProcessFreeBSD::%s (): unexpected state %s specified "
+ "for pid %" PRIu64 ", tid %" PRIu64,
+ __FUNCTION__, StateAsCString(action->state), GetID(), thread.GetID());
+ }
+
+ if (!ret.Success())
+ return ret;
+ if (action->signal != LLDB_INVALID_SIGNAL_NUMBER)
+ signal = action->signal;
+ }
+
+ ret =
+ PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), signal);
+ if (ret.Success())
+ SetState(eStateRunning, true);
+ return ret;
+}
+
+Status NativeProcessFreeBSD::Halt() {
+ Status error;
+
+ if (kill(GetID(), SIGSTOP) != 0)
+ error.SetErrorToErrno();
+ return error;
+}
+
+Status NativeProcessFreeBSD::Detach() {
+ Status error;
+
+ // Stop monitoring the inferior.
+ m_sigchld_handle.reset();
+
+ // Tell ptrace to detach from the process.
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ return error;
+
+ return PtraceWrapper(PT_DETACH, GetID());
+}
+
+Status NativeProcessFreeBSD::Signal(int signo) {
+ Status error;
+
+ if (kill(GetID(), signo))
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Status NativeProcessFreeBSD::Interrupt() { return Halt(); }
+
+Status NativeProcessFreeBSD::Kill() {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ LLDB_LOG(log, "pid {0}", GetID());
+
+ Status error;
+
+ switch (m_state) {
+ case StateType::eStateInvalid:
+ case StateType::eStateExited:
+ case StateType::eStateCrashed:
+ case StateType::eStateDetached:
+ case StateType::eStateUnloaded:
+ // Nothing to do - the process is already dead.
+ LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(),
+ StateAsCString(m_state));
+ return error;
+
+ case StateType::eStateConnected:
+ case StateType::eStateAttaching:
+ case StateType::eStateLaunching:
+ case StateType::eStateStopped:
+ case StateType::eStateRunning:
+ case StateType::eStateStepping:
+ case StateType::eStateSuspended:
+ // We can try to kill a process in these states.
+ break;
+ }
+
+ return PtraceWrapper(PT_KILL, m_pid);
+}
+
+Status NativeProcessFreeBSD::GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) {
+
+ if (m_supports_mem_region == LazyBool::eLazyBoolNo) {
+ // We're done.
+ return Status("unsupported");
+ }
+
+ Status error = PopulateMemoryRegionCache();
+ if (error.Fail()) {
+ return error;
+ }
+
+ lldb::addr_t prev_base_address = 0;
+ // FIXME start by finding the last region that is <= target address using
+ // binary search. Data is sorted.
+ // There can be a ton of regions on pthreads apps with lots of threads.
+ for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end();
+ ++it) {
+ MemoryRegionInfo &proc_entry_info = it->first;
+ // Sanity check assumption that memory map entries are ascending.
+ assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) &&
+ "descending memory map entries detected, unexpected");
+ prev_base_address = proc_entry_info.GetRange().GetRangeBase();
+ UNUSED_IF_ASSERT_DISABLED(prev_base_address);
+ // If the target address comes before this entry, indicate distance to next
+ // region.
+ if (load_addr < proc_entry_info.GetRange().GetRangeBase()) {
+ range_info.GetRange().SetRangeBase(load_addr);
+ range_info.GetRange().SetByteSize(
+ proc_entry_info.GetRange().GetRangeBase() - load_addr);
+ range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
+ return error;
+ } else if (proc_entry_info.GetRange().Contains(load_addr)) {
+ // The target address is within the memory region we're processing here.
+ range_info = proc_entry_info;
+ return error;
+ }
+ // The target memory address comes somewhere after the region we just
+ // parsed.
+ }
+ // If we made it here, we didn't find an entry that contained the given
+ // address. Return the load_addr as start and the amount of bytes betwwen
+ // load address and the end of the memory as size.
+ range_info.GetRange().SetRangeBase(load_addr);
+ range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS);
+ range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+ range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo);
+ return error;
+}
+
+Status NativeProcessFreeBSD::PopulateMemoryRegionCache() {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ // If our cache is empty, pull the latest. There should always be at least
+ // one memory region if memory region handling is supported.
+ if (!m_mem_region_cache.empty()) {
+ LLDB_LOG(log, "reusing {0} cached memory region entries",
+ m_mem_region_cache.size());
+ return Status();
+ }
+
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, static_cast<int>(m_pid)};
+ int ret;
+ size_t len;
+
+ ret = ::sysctl(mib, 4, nullptr, &len, nullptr, 0);
+ if (ret != 0) {
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ return Status("sysctl() for KERN_PROC_VMMAP failed");
+ }
+
+ std::unique_ptr<WritableMemoryBuffer> buf =
+ llvm::WritableMemoryBuffer::getNewMemBuffer(len);
+ ret = ::sysctl(mib, 4, buf->getBufferStart(), &len, nullptr, 0);
+ if (ret != 0) {
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ return Status("sysctl() for KERN_PROC_VMMAP failed");
+ }
+
+ char *bp = buf->getBufferStart();
+ char *end = bp + len;
+ while (bp < end) {
+ auto *kv = reinterpret_cast<struct kinfo_vmentry *>(bp);
+ if (kv->kve_structsize == 0)
+ break;
+ bp += kv->kve_structsize;
+
+ MemoryRegionInfo info;
+ info.Clear();
+ info.GetRange().SetRangeBase(kv->kve_start);
+ info.GetRange().SetRangeEnd(kv->kve_end);
+ info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
+
+ if (kv->kve_protection & VM_PROT_READ)
+ info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
+ else
+ info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+
+ if (kv->kve_protection & VM_PROT_WRITE)
+ info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
+ else
+ info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+
+ if (kv->kve_protection & VM_PROT_EXECUTE)
+ info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
+ else
+ info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+
+ if (kv->kve_path[0])
+ info.SetName(kv->kve_path);
+
+ m_mem_region_cache.emplace_back(info,
+ FileSpec(info.GetName().GetCString()));
+ }
+
+ if (m_mem_region_cache.empty()) {
+ // No entries after attempting to read them. This shouldn't happen. Assume
+ // we don't support map entries.
+ LLDB_LOG(log, "failed to find any vmmap entries, assuming no support "
+ "for memory region metadata retrieval");
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ return Status("not supported");
+ }
+ LLDB_LOG(log, "read {0} memory region entries from process {1}",
+ m_mem_region_cache.size(), GetID());
+ // We support memory retrieval, remember that.
+ m_supports_mem_region = LazyBool::eLazyBoolYes;
+
+ return Status();
+}
+
+size_t NativeProcessFreeBSD::UpdateThreads() { return m_threads.size(); }
+
+Status NativeProcessFreeBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) {
+ if (hardware)
+ return Status("NativeProcessFreeBSD does not support hardware breakpoints");
+ else
+ return SetSoftwareBreakpoint(addr, size);
+}
+
+Status NativeProcessFreeBSD::GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) {
+ Status error = PopulateMemoryRegionCache();
+ if (error.Fail())
+ return error;
+
+ FileSpec module_file_spec(module_path);
+ FileSystem::Instance().Resolve(module_file_spec);
+
+ file_spec.Clear();
+ for (const auto &it : m_mem_region_cache) {
+ if (it.second.GetFilename() == module_file_spec.GetFilename()) {
+ file_spec = it.second;
+ return Status();
+ }
+ }
+ return Status("Module file (%s) not found in process' memory map!",
+ module_file_spec.GetFilename().AsCString());
+}
+
+Status
+NativeProcessFreeBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) {
+ load_addr = LLDB_INVALID_ADDRESS;
+ Status error = PopulateMemoryRegionCache();
+ if (error.Fail())
+ return error;
+
+ FileSpec file(file_name);
+ for (const auto &it : m_mem_region_cache) {
+ if (it.second == file) {
+ load_addr = it.first.GetRange().GetRangeBase();
+ return Status();
+ }
+ }
+ return Status("No load address found for file %s.", file_name.str().c_str());
+}
+
+void NativeProcessFreeBSD::SigchldHandler() {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ // Process all pending waitpid notifications.
+ int status;
+ ::pid_t wait_pid =
+ llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WNOHANG);
+
+ if (wait_pid == 0)
+ return; // We are done.
+
+ if (wait_pid == -1) {
+ Status error(errno, eErrorTypePOSIX);
+ LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
+ }
+
+ WaitStatus wait_status = WaitStatus::Decode(status);
+ bool exited = wait_status.type == WaitStatus::Exit ||
+ (wait_status.type == WaitStatus::Signal &&
+ wait_pid == static_cast<::pid_t>(GetID()));
+
+ LLDB_LOG(log,
+ "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",
+ GetID(), wait_pid, status, exited);
+
+ if (exited)
+ MonitorExited(wait_pid, wait_status);
+ else {
+ assert(wait_status.type == WaitStatus::Stop);
+ MonitorCallback(wait_pid, wait_status.status);
+ }
+}
+
+bool NativeProcessFreeBSD::HasThreadNoLock(lldb::tid_t thread_id) {
+ for (const auto &thread : m_threads) {
+ assert(thread && "thread list should not contain NULL threads");
+ if (thread->GetID() == thread_id) {
+ // We have this thread.
+ return true;
+ }
+ }
+
+ // We don't have this thread.
+ return false;
+}
+
+NativeThreadFreeBSD &NativeProcessFreeBSD::AddThread(lldb::tid_t thread_id) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+ LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id);
+
+ assert(thread_id > 0);
+ assert(!HasThreadNoLock(thread_id) &&
+ "attempted to add a thread by id that already exists");
+
+ // If this is the first thread, save it as the current thread
+ if (m_threads.empty())
+ SetCurrentThreadID(thread_id);
+
+ m_threads.push_back(std::make_unique<NativeThreadFreeBSD>(*this, thread_id));
+ return static_cast<NativeThreadFreeBSD &>(*m_threads.back());
+}
+
+void NativeProcessFreeBSD::RemoveThread(lldb::tid_t thread_id) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+ LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id);
+
+ assert(thread_id > 0);
+ assert(HasThreadNoLock(thread_id) &&
+ "attempted to remove a thread that does not exist");
+
+ for (auto it = m_threads.begin(); it != m_threads.end(); ++it) {
+ if ((*it)->GetID() == thread_id) {
+ m_threads.erase(it);
+ break;
+ }
+ }
+}
+
+Status NativeProcessFreeBSD::Attach() {
+ // Attach to the requested process.
+ // An attach will cause the thread to stop with a SIGSTOP.
+ Status status = PtraceWrapper(PT_ATTACH, m_pid);
+ if (status.Fail())
+ return status;
+
+ int wstatus;
+ // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this
+ // point we should have a thread stopped if waitpid succeeds.
+ if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr, 0)) <
+ 0)
+ return Status(errno, eErrorTypePOSIX);
+
+ // Initialize threads and tracing status
+ // NB: this needs to be called before we set thread state
+ status = SetupTrace();
+ if (status.Fail())
+ return status;
+
+ for (const auto &thread : m_threads)
+ static_cast<NativeThreadFreeBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
+
+ // Let our process instance know the thread has stopped.
+ SetCurrentThreadID(m_threads.front()->GetID());
+ SetState(StateType::eStateStopped, false);
+ return Status();
+}
+
+Status NativeProcessFreeBSD::ReadMemory(lldb::addr_t addr, void *buf,
+ size_t size, size_t &bytes_read) {
+ unsigned char *dst = static_cast<unsigned char *>(buf);
+ struct ptrace_io_desc io;
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY));
+ LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
+
+ bytes_read = 0;
+ io.piod_op = PIOD_READ_D;
+ io.piod_len = size;
+
+ do {
+ io.piod_offs = (void *)(addr + bytes_read);
+ io.piod_addr = dst + bytes_read;
+
+ Status error = NativeProcessFreeBSD::PtraceWrapper(PT_IO, GetID(), &io);
+ if (error.Fail() || io.piod_len == 0)
+ return error;
+
+ bytes_read += io.piod_len;
+ io.piod_len = size - bytes_read;
+ } while (bytes_read < size);
+
+ return Status();
+}
+
+Status NativeProcessFreeBSD::WriteMemory(lldb::addr_t addr, const void *buf,
+ size_t size, size_t &bytes_written) {
+ const unsigned char *src = static_cast<const unsigned char *>(buf);
+ Status error;
+ struct ptrace_io_desc io;
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY));
+ LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size);
+
+ bytes_written = 0;
+ io.piod_op = PIOD_WRITE_D;
+ io.piod_len = size;
+
+ do {
+ io.piod_addr =
+ const_cast<void *>(static_cast<const void *>(src + bytes_written));
+ io.piod_offs = (void *)(addr + bytes_written);
+
+ Status error = NativeProcessFreeBSD::PtraceWrapper(PT_IO, GetID(), &io);
+ if (error.Fail() || io.piod_len == 0)
+ return error;
+
+ bytes_written += io.piod_len;
+ io.piod_len = size - bytes_written;
+ } while (bytes_written < size);
+
+ return error;
+}
+
+llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+NativeProcessFreeBSD::GetAuxvData() const {
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_AUXV, static_cast<int>(GetID())};
+ size_t auxv_size = AT_COUNT * sizeof(Elf_Auxinfo);
+ std::unique_ptr<WritableMemoryBuffer> buf =
+ llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size);
+
+ if (::sysctl(mib, 4, buf->getBufferStart(), &auxv_size, nullptr, 0) != 0)
+ return std::error_code(errno, std::generic_category());
+
+ return buf;
+}
+
+Status NativeProcessFreeBSD::SetupTrace() {
+ // Enable event reporting
+ int events;
+ Status status =
+ PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events));
+ if (status.Fail())
+ return status;
+ events |= PTRACE_LWP;
+ status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events));
+ if (status.Fail())
+ return status;
+
+ return ReinitializeThreads();
+}
+
+Status NativeProcessFreeBSD::ReinitializeThreads() {
+ // Clear old threads
+ m_threads.clear();
+
+ int num_lwps;
+ Status error = PtraceWrapper(PT_GETNUMLWPS, GetID(), nullptr, 0, &num_lwps);
+ if (error.Fail())
+ return error;
+
+ std::vector<lwpid_t> lwp_ids;
+ lwp_ids.resize(num_lwps);
+ error = PtraceWrapper(PT_GETLWPLIST, GetID(), lwp_ids.data(),
+ lwp_ids.size() * sizeof(lwpid_t), &num_lwps);
+ if (error.Fail())
+ return error;
+
+ // Reinitialize from scratch threads and register them in process
+ for (lwpid_t lwp : lwp_ids)
+ AddThread(lwp);
+
+ return error;
+}
diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h
new file mode 100644
index 000000000000..3c7a9400f9c4
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h
@@ -0,0 +1,119 @@
+//===-- NativeProcessFreeBSD.h -------------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeProcessFreeBSD_H_
+#define liblldb_NativeProcessFreeBSD_H_
+
+#include "Plugins/Process/POSIX/NativeProcessELF.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/FileSpec.h"
+
+#include "NativeThreadFreeBSD.h"
+
+namespace lldb_private {
+namespace process_freebsd {
+/// \class NativeProcessFreeBSD
+/// Manages communication with the inferior (debugee) process.
+///
+/// Upon construction, this class prepares and launches an inferior process
+/// for debugging.
+///
+/// Changes in the inferior process state are broadcasted.
+class NativeProcessFreeBSD : public NativeProcessELF {
+public:
+ class Factory : public NativeProcessProtocol::Factory {
+ public:
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate,
+ MainLoop &mainloop) const override;
+
+ llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
+ Attach(lldb::pid_t pid, NativeDelegate &native_delegate,
+ MainLoop &mainloop) const override;
+ };
+
+ // NativeProcessProtocol Interface
+ Status Resume(const ResumeActionList &resume_actions) override;
+
+ Status Halt() override;
+
+ Status Detach() override;
+
+ Status Signal(int signo) override;
+
+ Status Interrupt() override;
+
+ Status Kill() override;
+
+ Status GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) override;
+
+ Status ReadMemory(lldb::addr_t addr, void *buf, size_t size,
+ size_t &bytes_read) override;
+
+ Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
+ size_t &bytes_written) override;
+
+ size_t UpdateThreads() override;
+
+ const ArchSpec &GetArchitecture() const override { return m_arch; }
+
+ Status SetBreakpoint(lldb::addr_t addr, uint32_t size,
+ bool hardware) override;
+
+ // The two following methods are probably not necessary and probably
+ // will never be called. Nevertheless, we implement them right now
+ // to reduce the differences between different platforms and reduce
+ // the risk of the lack of implementation actually breaking something,
+ // at least for the time being.
+ Status GetLoadedModuleFileSpec(const char *module_path,
+ FileSpec &file_spec) override;
+ Status GetFileLoadAddress(const llvm::StringRef &file_name,
+ lldb::addr_t &load_addr) override;
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ GetAuxvData() const override;
+
+ // Interface used by NativeRegisterContext-derived classes.
+ static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
+ int data = 0, int *result = nullptr);
+
+private:
+ MainLoop::SignalHandleUP m_sigchld_handle;
+ ArchSpec m_arch;
+ LazyBool m_supports_mem_region = eLazyBoolCalculate;
+ std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
+
+ // Private Instance Methods
+ NativeProcessFreeBSD(::pid_t pid, int terminal_fd, NativeDelegate &delegate,
+ const ArchSpec &arch, MainLoop &mainloop);
+
+ bool HasThreadNoLock(lldb::tid_t thread_id);
+
+ NativeThreadFreeBSD &AddThread(lldb::tid_t thread_id);
+ void RemoveThread(lldb::tid_t thread_id);
+
+ void MonitorCallback(lldb::pid_t pid, int signal);
+ void MonitorExited(lldb::pid_t pid, WaitStatus status);
+ void MonitorSIGSTOP(lldb::pid_t pid);
+ void MonitorSIGTRAP(lldb::pid_t pid);
+ void MonitorSignal(lldb::pid_t pid, int signal);
+
+ Status PopulateMemoryRegionCache();
+ void SigchldHandler();
+
+ Status Attach();
+ Status SetupTrace();
+ Status ReinitializeThreads();
+};
+
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_NativeProcessFreeBSD_H_
diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.cpp
new file mode 100644
index 000000000000..ac3cc4fe788a
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.cpp
@@ -0,0 +1,29 @@
+//===-- NativeRegisterContextFreeBSD.cpp ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextFreeBSD.h"
+
+#include "Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h"
+
+#include "lldb/Host/common/NativeProcessProtocol.h"
+
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+// clang-format on
+
+NativeProcessFreeBSD &NativeRegisterContextFreeBSD::GetProcess() {
+ return static_cast<NativeProcessFreeBSD &>(m_thread.GetProcess());
+}
+
+::pid_t NativeRegisterContextFreeBSD::GetProcessPid() {
+ return GetProcess().GetID();
+}
diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h
new file mode 100644
index 000000000000..0000484beac9
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h
@@ -0,0 +1,43 @@
+//===-- NativeRegisterContextFreeBSD.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextFreeBSD_h
+#define lldb_NativeRegisterContextFreeBSD_h
+
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
+
+namespace lldb_private {
+namespace process_freebsd {
+
+class NativeProcessFreeBSD;
+
+class NativeRegisterContextFreeBSD
+ : public virtual NativeRegisterContextRegisterInfo {
+public:
+ // This function is implemented in the NativeRegisterContextFreeBSD_*
+ // subclasses to create a new instance of the host specific
+ // NativeRegisterContextFreeBSD. The implementations can't collide as only one
+ // NativeRegisterContextFreeBSD_* variant should be compiled into the final
+ // executable.
+ static NativeRegisterContextFreeBSD *
+ CreateHostNativeRegisterContextFreeBSD(const ArchSpec &target_arch,
+ NativeThreadProtocol &native_thread);
+ virtual llvm::Error
+ CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) = 0;
+
+protected:
+ virtual NativeProcessFreeBSD &GetProcess();
+ virtual ::pid_t GetProcessPid();
+};
+
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextFreeBSD_h
diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp
new file mode 100644
index 000000000000..d5052e7d1b3a
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.cpp
@@ -0,0 +1,656 @@
+//===-- NativeRegisterContextFreeBSD_x86_64.cpp ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#include "NativeRegisterContextFreeBSD_x86_64.h"
+
+// clang-format off
+#include <x86/fpu.h>
+#include <x86/specialreg.h>
+#include <cpuid.h>
+// clang-format on
+
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Status.h"
+
+#include "NativeProcessFreeBSD.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
+
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+
+// x86 64-bit general purpose registers.
+static const uint32_t g_gpr_regnums_x86_64[] = {
+ lldb_rax_x86_64, lldb_rbx_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64,
+ lldb_rdi_x86_64, lldb_rsi_x86_64, lldb_rbp_x86_64, lldb_rsp_x86_64,
+ lldb_r8_x86_64, lldb_r9_x86_64, lldb_r10_x86_64, lldb_r11_x86_64,
+ lldb_r12_x86_64, lldb_r13_x86_64, lldb_r14_x86_64, lldb_r15_x86_64,
+ lldb_rip_x86_64, lldb_rflags_x86_64, lldb_cs_x86_64, lldb_fs_x86_64,
+ lldb_gs_x86_64, lldb_ss_x86_64, lldb_ds_x86_64, lldb_es_x86_64,
+ lldb_eax_x86_64, lldb_ebx_x86_64, lldb_ecx_x86_64, lldb_edx_x86_64,
+ lldb_edi_x86_64, lldb_esi_x86_64, lldb_ebp_x86_64, lldb_esp_x86_64,
+ lldb_r8d_x86_64, // Low 32 bits or r8
+ lldb_r9d_x86_64, // Low 32 bits or r9
+ lldb_r10d_x86_64, // Low 32 bits or r10
+ lldb_r11d_x86_64, // Low 32 bits or r11
+ lldb_r12d_x86_64, // Low 32 bits or r12
+ lldb_r13d_x86_64, // Low 32 bits or r13
+ lldb_r14d_x86_64, // Low 32 bits or r14
+ lldb_r15d_x86_64, // Low 32 bits or r15
+ lldb_ax_x86_64, lldb_bx_x86_64, lldb_cx_x86_64, lldb_dx_x86_64,
+ lldb_di_x86_64, lldb_si_x86_64, lldb_bp_x86_64, lldb_sp_x86_64,
+ lldb_r8w_x86_64, // Low 16 bits or r8
+ lldb_r9w_x86_64, // Low 16 bits or r9
+ lldb_r10w_x86_64, // Low 16 bits or r10
+ lldb_r11w_x86_64, // Low 16 bits or r11
+ lldb_r12w_x86_64, // Low 16 bits or r12
+ lldb_r13w_x86_64, // Low 16 bits or r13
+ lldb_r14w_x86_64, // Low 16 bits or r14
+ lldb_r15w_x86_64, // Low 16 bits or r15
+ lldb_ah_x86_64, lldb_bh_x86_64, lldb_ch_x86_64, lldb_dh_x86_64,
+ lldb_al_x86_64, lldb_bl_x86_64, lldb_cl_x86_64, lldb_dl_x86_64,
+ lldb_dil_x86_64, lldb_sil_x86_64, lldb_bpl_x86_64, lldb_spl_x86_64,
+ lldb_r8l_x86_64, // Low 8 bits or r8
+ lldb_r9l_x86_64, // Low 8 bits or r9
+ lldb_r10l_x86_64, // Low 8 bits or r10
+ lldb_r11l_x86_64, // Low 8 bits or r11
+ lldb_r12l_x86_64, // Low 8 bits or r12
+ lldb_r13l_x86_64, // Low 8 bits or r13
+ lldb_r14l_x86_64, // Low 8 bits or r14
+ lldb_r15l_x86_64, // Low 8 bits or r15
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) -
+ 1 ==
+ k_num_gpr_registers_x86_64,
+ "g_gpr_regnums_x86_64 has wrong number of register infos");
+
+// x86 64-bit floating point registers.
+static const uint32_t g_fpu_regnums_x86_64[] = {
+ lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64,
+ lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64,
+ lldb_fip_x86_64, lldb_foseg_x86_64, lldb_fooff_x86_64,
+ lldb_fdp_x86_64, lldb_mxcsr_x86_64, lldb_mxcsrmask_x86_64,
+ lldb_st0_x86_64, lldb_st1_x86_64, lldb_st2_x86_64,
+ lldb_st3_x86_64, lldb_st4_x86_64, lldb_st5_x86_64,
+ lldb_st6_x86_64, lldb_st7_x86_64, lldb_mm0_x86_64,
+ lldb_mm1_x86_64, lldb_mm2_x86_64, lldb_mm3_x86_64,
+ lldb_mm4_x86_64, lldb_mm5_x86_64, lldb_mm6_x86_64,
+ lldb_mm7_x86_64, lldb_xmm0_x86_64, lldb_xmm1_x86_64,
+ lldb_xmm2_x86_64, lldb_xmm3_x86_64, lldb_xmm4_x86_64,
+ lldb_xmm5_x86_64, lldb_xmm6_x86_64, lldb_xmm7_x86_64,
+ lldb_xmm8_x86_64, lldb_xmm9_x86_64, lldb_xmm10_x86_64,
+ lldb_xmm11_x86_64, lldb_xmm12_x86_64, lldb_xmm13_x86_64,
+ lldb_xmm14_x86_64, lldb_xmm15_x86_64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) -
+ 1 ==
+ k_num_fpr_registers_x86_64,
+ "g_fpu_regnums_x86_64 has wrong number of register infos");
+
+static const uint32_t g_avx_regnums_x86_64[] = {
+ lldb_ymm0_x86_64, lldb_ymm1_x86_64, lldb_ymm2_x86_64, lldb_ymm3_x86_64,
+ lldb_ymm4_x86_64, lldb_ymm5_x86_64, lldb_ymm6_x86_64, lldb_ymm7_x86_64,
+ lldb_ymm8_x86_64, lldb_ymm9_x86_64, lldb_ymm10_x86_64, lldb_ymm11_x86_64,
+ lldb_ymm12_x86_64, lldb_ymm13_x86_64, lldb_ymm14_x86_64, lldb_ymm15_x86_64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) -
+ 1 ==
+ k_num_avx_registers_x86_64,
+ "g_avx_regnums_x86_64 has wrong number of register infos");
+
+static const uint32_t g_mpx_regnums_x86_64[] = {
+ // Note: we currently do not provide them but this is needed to avoid
+ // unnamed groups in SBFrame::GetRegisterContext().
+ lldb_bnd0_x86_64, lldb_bnd1_x86_64, lldb_bnd2_x86_64,
+ lldb_bnd3_x86_64, lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_mpx_regnums_x86_64) / sizeof(g_mpx_regnums_x86_64[0])) -
+ 1 ==
+ k_num_mpx_registers_x86_64,
+ "g_mpx_regnums_x86_64 has wrong number of register infos");
+
+// x86 debug registers.
+static const uint32_t g_dbr_regnums_x86_64[] = {
+ lldb_dr0_x86_64, lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64,
+ lldb_dr4_x86_64, lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) -
+ 1 ==
+ k_num_dbr_registers_x86_64,
+ "g_dbr_regnums_x86_64 has wrong number of register infos");
+
+// x86 32-bit general purpose registers.
+static const uint32_t g_gpr_regnums_i386[] = {
+ lldb_eax_i386, lldb_ebx_i386, lldb_ecx_i386, lldb_edx_i386,
+ lldb_edi_i386, lldb_esi_i386, lldb_ebp_i386, lldb_esp_i386,
+ lldb_eip_i386, lldb_eflags_i386, lldb_cs_i386, lldb_fs_i386,
+ lldb_gs_i386, lldb_ss_i386, lldb_ds_i386, lldb_es_i386,
+ lldb_ax_i386, lldb_bx_i386, lldb_cx_i386, lldb_dx_i386,
+ lldb_di_i386, lldb_si_i386, lldb_bp_i386, lldb_sp_i386,
+ lldb_ah_i386, lldb_bh_i386, lldb_ch_i386, lldb_dh_i386,
+ lldb_al_i386, lldb_bl_i386, lldb_cl_i386, lldb_dl_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) -
+ 1 ==
+ k_num_gpr_registers_i386,
+ "g_gpr_regnums_i386 has wrong number of register infos");
+
+// x86 32-bit floating point registers.
+static const uint32_t g_fpu_regnums_i386[] = {
+ lldb_fctrl_i386, lldb_fstat_i386, lldb_ftag_i386, lldb_fop_i386,
+ lldb_fiseg_i386, lldb_fioff_i386, lldb_foseg_i386, lldb_fooff_i386,
+ lldb_mxcsr_i386, lldb_mxcsrmask_i386, lldb_st0_i386, lldb_st1_i386,
+ lldb_st2_i386, lldb_st3_i386, lldb_st4_i386, lldb_st5_i386,
+ lldb_st6_i386, lldb_st7_i386, lldb_mm0_i386, lldb_mm1_i386,
+ lldb_mm2_i386, lldb_mm3_i386, lldb_mm4_i386, lldb_mm5_i386,
+ lldb_mm6_i386, lldb_mm7_i386, lldb_xmm0_i386, lldb_xmm1_i386,
+ lldb_xmm2_i386, lldb_xmm3_i386, lldb_xmm4_i386, lldb_xmm5_i386,
+ lldb_xmm6_i386, lldb_xmm7_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) -
+ 1 ==
+ k_num_fpr_registers_i386,
+ "g_fpu_regnums_i386 has wrong number of register infos");
+
+static const uint32_t g_avx_regnums_i386[] = {
+ lldb_ymm0_i386, lldb_ymm1_i386, lldb_ymm2_i386, lldb_ymm3_i386,
+ lldb_ymm4_i386, lldb_ymm5_i386, lldb_ymm6_i386, lldb_ymm7_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) -
+ 1 ==
+ k_num_avx_registers_i386,
+ "g_avx_regnums_i386 has wrong number of register infos");
+
+static const uint32_t g_mpx_regnums_i386[] = {
+ // Note: we currently do not provide them but this is needed to avoid
+ // unnamed groups in SBFrame::GetRegisterContext().
+ lldb_bnd0_i386, lldb_bnd1_i386, lldb_bnd2_i386,
+ lldb_bnd3_i386, lldb_bndcfgu_i386, lldb_bndstatus_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_mpx_regnums_i386) / sizeof(g_mpx_regnums_i386[0])) -
+ 1 ==
+ k_num_mpx_registers_i386,
+ "g_mpx_regnums_i386 has wrong number of register infos");
+
+// x86 debug registers.
+static const uint32_t g_dbr_regnums_i386[] = {
+ lldb_dr0_i386, lldb_dr1_i386, lldb_dr2_i386, lldb_dr3_i386,
+ lldb_dr4_i386, lldb_dr5_i386, lldb_dr6_i386, lldb_dr7_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_dbr_regnums_i386) / sizeof(g_dbr_regnums_i386[0])) -
+ 1 ==
+ k_num_dbr_registers_i386,
+ "g_dbr_regnums_i386 has wrong number of register infos");
+
+// Number of register sets provided by this context.
+enum { k_num_register_sets = 5 };
+
+// Register sets for x86 32-bit.
+static const RegisterSet g_reg_sets_i386[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers_i386,
+ g_gpr_regnums_i386},
+ {"Floating Point Registers", "fpu", k_num_fpr_registers_i386,
+ g_fpu_regnums_i386},
+ {"Debug Registers", "dbr", k_num_dbr_registers_i386, g_dbr_regnums_i386},
+ {"Advanced Vector Extensions", "avx", k_num_avx_registers_i386,
+ g_avx_regnums_i386},
+ {"Memory Protection Extensions", "mpx", k_num_mpx_registers_i386,
+ g_mpx_regnums_i386},
+};
+
+// Register sets for x86 64-bit.
+static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64,
+ g_gpr_regnums_x86_64},
+ {"Floating Point Registers", "fpu", k_num_fpr_registers_x86_64,
+ g_fpu_regnums_x86_64},
+ {"Debug Registers", "dbr", k_num_dbr_registers_x86_64,
+ g_dbr_regnums_x86_64},
+ {"Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64,
+ g_avx_regnums_x86_64},
+ {"Memory Protection Extensions", "mpx", k_num_mpx_registers_x86_64,
+ g_mpx_regnums_x86_64},
+};
+
+#define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize())
+
+NativeRegisterContextFreeBSD *
+NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
+ const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {
+ return new NativeRegisterContextFreeBSD_x86_64(target_arch, native_thread);
+}
+
+// NativeRegisterContextFreeBSD_x86_64 members.
+
+static RegisterInfoInterface *
+CreateRegisterInfoInterface(const ArchSpec &target_arch) {
+ if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) {
+ // 32-bit hosts run with a RegisterContextFreeBSD_i386 context.
+ return new RegisterContextFreeBSD_i386(target_arch);
+ } else {
+ assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
+ "Register setting path assumes this is a 64-bit host");
+ // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the
+ // x86_64 register context.
+ return new RegisterContextFreeBSD_x86_64(target_arch);
+ }
+}
+
+NativeRegisterContextFreeBSD_x86_64::NativeRegisterContextFreeBSD_x86_64(
+ const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
+ : NativeRegisterContextRegisterInfo(
+ native_thread, CreateRegisterInfoInterface(target_arch)),
+ m_regset_offsets({0}) {
+ assert(m_gpr.size() == GetRegisterInfoInterface().GetGPRSize());
+ std::array<uint32_t, MaxRegSet + 1> first_regnos;
+
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ first_regnos[FPRegSet] = lldb_fctrl_i386;
+ first_regnos[DBRegSet] = lldb_dr0_i386;
+ break;
+ case llvm::Triple::x86_64:
+ first_regnos[FPRegSet] = lldb_fctrl_x86_64;
+ first_regnos[DBRegSet] = lldb_dr0_x86_64;
+ break;
+ default:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+
+ for (int i : {FPRegSet, DBRegSet})
+ m_regset_offsets[i] = GetRegisterInfoInterface()
+ .GetRegisterInfo()[first_regnos[i]]
+ .byte_offset;
+}
+
+uint32_t NativeRegisterContextFreeBSD_x86_64::GetRegisterSetCount() const {
+ return k_num_register_sets;
+}
+
+const RegisterSet *
+NativeRegisterContextFreeBSD_x86_64::GetRegisterSet(uint32_t set_index) const {
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ return &g_reg_sets_i386[set_index];
+ case llvm::Triple::x86_64:
+ return &g_reg_sets_x86_64[set_index];
+ default:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+}
+
+llvm::Optional<NativeRegisterContextFreeBSD_x86_64::RegSetKind>
+NativeRegisterContextFreeBSD_x86_64::GetSetForNativeRegNum(
+ uint32_t reg_num) const {
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ if (reg_num >= k_first_gpr_i386 && reg_num <= k_last_gpr_i386)
+ return GPRegSet;
+ if (reg_num >= k_first_fpr_i386 && reg_num <= k_last_fpr_i386)
+ return FPRegSet;
+ if (reg_num >= k_first_avx_i386 && reg_num <= k_last_avx_i386)
+ return YMMRegSet;
+ if (reg_num >= k_first_mpxr_i386 && reg_num <= k_last_mpxr_i386)
+ return llvm::None; // MPXR
+ if (reg_num >= k_first_mpxc_i386 && reg_num <= k_last_mpxc_i386)
+ return llvm::None; // MPXC
+ if (reg_num >= k_first_dbr_i386 && reg_num <= k_last_dbr_i386)
+ return DBRegSet; // DBR
+ break;
+ case llvm::Triple::x86_64:
+ if (reg_num >= k_first_gpr_x86_64 && reg_num <= k_last_gpr_x86_64)
+ return GPRegSet;
+ if (reg_num >= k_first_fpr_x86_64 && reg_num <= k_last_fpr_x86_64)
+ return FPRegSet;
+ if (reg_num >= k_first_avx_x86_64 && reg_num <= k_last_avx_x86_64)
+ return YMMRegSet;
+ if (reg_num >= k_first_mpxr_x86_64 && reg_num <= k_last_mpxr_x86_64)
+ return llvm::None; // MPXR
+ if (reg_num >= k_first_mpxc_x86_64 && reg_num <= k_last_mpxc_x86_64)
+ return llvm::None; // MPXC
+ if (reg_num >= k_first_dbr_x86_64 && reg_num <= k_last_dbr_x86_64)
+ return DBRegSet; // DBR
+ break;
+ default:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+
+ llvm_unreachable("Register does not belong to any register set");
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::ReadRegisterSet(RegSetKind set) {
+ switch (set) {
+ case GPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(),
+ m_gpr.data());
+ case FPRegSet:
+#if defined(__x86_64__)
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETFPREGS, m_thread.GetID(),
+ m_fpr.data());
+#else
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETXMMREGS, m_thread.GetID(),
+ m_fpr.data());
+#endif
+ case DBRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETDBREGS, m_thread.GetID(),
+ m_dbr.data());
+ case YMMRegSet:
+ case MPXRegSet: {
+ struct ptrace_xstate_info info;
+ Status ret = NativeProcessFreeBSD::PtraceWrapper(
+ PT_GETXSTATE_INFO, GetProcessPid(), &info, sizeof(info));
+ if (!ret.Success())
+ return ret;
+
+ assert(info.xsave_mask & XFEATURE_ENABLED_X87);
+ assert(info.xsave_mask & XFEATURE_ENABLED_SSE);
+
+ m_xsave_offsets[YMMRegSet] = LLDB_INVALID_XSAVE_OFFSET;
+ if (info.xsave_mask & XFEATURE_ENABLED_YMM_HI128) {
+ uint32_t eax, ecx, edx;
+ __get_cpuid_count(0x0D, 2, &eax, &m_xsave_offsets[YMMRegSet], &ecx, &edx);
+ }
+
+ m_xsave.resize(info.xsave_len);
+ return NativeProcessFreeBSD::PtraceWrapper(PT_GETXSTATE, GetProcessPid(),
+ m_xsave.data(), m_xsave.size());
+ }
+ }
+ llvm_unreachable("NativeRegisterContextFreeBSD_x86_64::ReadRegisterSet");
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::WriteRegisterSet(RegSetKind set) {
+ switch (set) {
+ case GPRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(),
+ m_gpr.data());
+ case FPRegSet:
+#if defined(__x86_64__)
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETFPREGS, m_thread.GetID(),
+ m_fpr.data());
+#else
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETXMMREGS, m_thread.GetID(),
+ m_fpr.data());
+#endif
+ case DBRegSet:
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETDBREGS, m_thread.GetID(),
+ m_dbr.data());
+ case YMMRegSet:
+ case MPXRegSet:
+ // ReadRegisterSet() must always be called before WriteRegisterSet().
+ assert(m_xsave.size() > 0);
+ return NativeProcessFreeBSD::PtraceWrapper(PT_SETXSTATE, GetProcessPid(),
+ m_xsave.data(), m_xsave.size());
+ }
+ llvm_unreachable("NativeRegisterContextFreeBSD_x86_64::WriteRegisterSet");
+}
+
+Status
+NativeRegisterContextFreeBSD_x86_64::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) {
+ Status error;
+
+ if (!reg_info) {
+ error.SetErrorString("reg_info NULL");
+ return error;
+ }
+
+ uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg == LLDB_INVALID_REGNUM) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
+ "register, cannot read directly",
+ reg_info->name);
+ return error;
+ }
+
+ llvm::Optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
+ if (!opt_set) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+ reg_info->name);
+ return error;
+ }
+
+ RegSetKind set = opt_set.getValue();
+ error = ReadRegisterSet(set);
+ if (error.Fail())
+ return error;
+
+ switch (set) {
+ case GPRegSet:
+ case FPRegSet:
+ case DBRegSet: {
+ void *data = GetOffsetRegSetData(set, reg_info->byte_offset);
+ FXSAVE *fpr = reinterpret_cast<FXSAVE *>(m_fpr.data());
+ if (data == &fpr->ftag) // ftag
+ reg_value.SetUInt16(
+ AbridgedToFullTagWord(fpr->ftag, fpr->fstat, fpr->stmm));
+ else
+ reg_value.SetBytes(data, reg_info->byte_size, endian::InlHostByteOrder());
+ break;
+ }
+ case YMMRegSet: {
+ llvm::Optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg);
+ if (!ymm_reg) {
+ error.SetErrorStringWithFormat(
+ "register \"%s\" not supported by CPU/kernel", reg_info->name);
+ } else {
+ YMMReg ymm = XStateToYMM(ymm_reg->xmm, ymm_reg->ymm_hi);
+ reg_value.SetBytes(ymm.bytes, reg_info->byte_size,
+ endian::InlHostByteOrder());
+ }
+ break;
+ }
+ case MPXRegSet:
+ llvm_unreachable("MPX regset should have returned error");
+ }
+
+ return error;
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::WriteRegister(
+ const RegisterInfo *reg_info, const RegisterValue &reg_value) {
+
+ Status error;
+
+ if (!reg_info) {
+ error.SetErrorString("reg_info NULL");
+ return error;
+ }
+
+ uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ if (reg == LLDB_INVALID_REGNUM) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb "
+ "register, cannot read directly",
+ reg_info->name);
+ return error;
+ }
+
+ llvm::Optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
+ if (!opt_set) {
+ // This is likely an internal register for lldb use only and should not be
+ // directly queried.
+ error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
+ reg_info->name);
+ return error;
+ }
+
+ RegSetKind set = opt_set.getValue();
+ error = ReadRegisterSet(set);
+ if (error.Fail())
+ return error;
+
+ switch (set) {
+ case GPRegSet:
+ case FPRegSet:
+ case DBRegSet: {
+ void *data = GetOffsetRegSetData(set, reg_info->byte_offset);
+ FXSAVE *fpr = reinterpret_cast<FXSAVE *>(m_fpr.data());
+ if (data == &fpr->ftag) // ftag
+ fpr->ftag = FullToAbridgedTagWord(reg_value.GetAsUInt16());
+ else
+ ::memcpy(data, reg_value.GetBytes(), reg_value.GetByteSize());
+ break;
+ }
+ case YMMRegSet: {
+ llvm::Optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg);
+ if (!ymm_reg) {
+ error.SetErrorStringWithFormat(
+ "register \"%s\" not supported by CPU/kernel", reg_info->name);
+ } else {
+ YMMReg ymm;
+ ::memcpy(ymm.bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+ YMMToXState(ymm, ymm_reg->xmm, ymm_reg->ymm_hi);
+ }
+ break;
+ }
+ case MPXRegSet:
+ llvm_unreachable("MPX regset should have returned error");
+ }
+
+ return WriteRegisterSet(set);
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::ReadAllRegisterValues(
+ lldb::DataBufferSP &data_sp) {
+ Status error;
+
+ data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
+ error = ReadRegisterSet(GPRegSet);
+ if (error.Fail())
+ return error;
+
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy(dst, m_gpr.data(), GetRegisterInfoInterface().GetGPRSize());
+ dst += GetRegisterInfoInterface().GetGPRSize();
+
+ return error;
+}
+
+Status NativeRegisterContextFreeBSD_x86_64::WriteAllRegisterValues(
+ const lldb::DataBufferSP &data_sp) {
+ Status error;
+
+ if (!data_sp) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextFreeBSD_x86_64::%s invalid data_sp provided",
+ __FUNCTION__);
+ return error;
+ }
+
+ if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
+ error.SetErrorStringWithFormat(
+ "NativeRegisterContextFreeBSD_x86_64::%s data_sp contained mismatched "
+ "data size, expected %zu, actual %" PRIu64,
+ __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
+ return error;
+ }
+
+ uint8_t *src = data_sp->GetBytes();
+ if (src == nullptr) {
+ error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_x86_64::%s "
+ "DataBuffer::GetBytes() returned a null "
+ "pointer",
+ __FUNCTION__);
+ return error;
+ }
+ ::memcpy(m_gpr.data(), src, GetRegisterInfoInterface().GetGPRSize());
+
+ error = WriteRegisterSet(GPRegSet);
+ if (error.Fail())
+ return error;
+ src += GetRegisterInfoInterface().GetGPRSize();
+
+ return error;
+}
+
+llvm::Error NativeRegisterContextFreeBSD_x86_64::CopyHardwareWatchpointsFrom(
+ NativeRegisterContextFreeBSD &source) {
+ auto &r_source = static_cast<NativeRegisterContextFreeBSD_x86_64 &>(source);
+ // NB: This implicitly reads the whole dbreg set.
+ RegisterValue dr7;
+ Status res = r_source.ReadRegister(GetDR(7), dr7);
+ if (!res.Fail()) {
+ // copy dbregs only if any watchpoints were set
+ if ((dr7.GetAsUInt64() & 0xFF) == 0)
+ return llvm::Error::success();
+
+ m_dbr = r_source.m_dbr;
+ res = WriteRegisterSet(DBRegSet);
+ }
+ return res.ToError();
+}
+
+uint8_t *
+NativeRegisterContextFreeBSD_x86_64::GetOffsetRegSetData(RegSetKind set,
+ size_t reg_offset) {
+ uint8_t *base;
+ switch (set) {
+ case GPRegSet:
+ base = m_gpr.data();
+ break;
+ case FPRegSet:
+ base = m_fpr.data();
+ break;
+ case DBRegSet:
+ base = m_dbr.data();
+ break;
+ case YMMRegSet:
+ llvm_unreachable("GetRegSetData() is unsuitable for this regset.");
+ case MPXRegSet:
+ llvm_unreachable("MPX regset should have returned error");
+ }
+ assert(reg_offset >= m_regset_offsets[set]);
+ return base + (reg_offset - m_regset_offsets[set]);
+}
+
+llvm::Optional<NativeRegisterContextFreeBSD_x86_64::YMMSplitPtr>
+NativeRegisterContextFreeBSD_x86_64::GetYMMSplitReg(uint32_t reg) {
+ uint32_t offset = m_xsave_offsets[YMMRegSet];
+ if (offset == LLDB_INVALID_XSAVE_OFFSET)
+ return llvm::None;
+
+ uint32_t reg_index;
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ reg_index = reg - lldb_ymm0_i386;
+ break;
+ case llvm::Triple::x86_64:
+ reg_index = reg - lldb_ymm0_x86_64;
+ break;
+ default:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+
+ auto *fpreg = reinterpret_cast<struct savexmm_ymm *>(m_xsave.data());
+ auto *ymmreg = reinterpret_cast<struct ymmacc *>(m_xsave.data() + offset);
+
+ return YMMSplitPtr{&fpreg->sv_xmm[reg_index], &ymmreg[reg_index]};
+}
+
+#endif // defined(__x86_64__)
diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.h b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.h
new file mode 100644
index 000000000000..673cffd6e849
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_x86_64.h
@@ -0,0 +1,96 @@
+//===-- NativeRegisterContextFreeBSD_x86_64.h -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__i386__) || defined(__x86_64__)
+
+#ifndef lldb_NativeRegisterContextFreeBSD_x86_64_h
+#define lldb_NativeRegisterContextFreeBSD_x86_64_h
+
+// clang-format off
+#include <sys/param.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <machine/reg.h>
+// clang-format on
+
+#include <array>
+
+#include "Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h"
+#include "Plugins/Process/Utility/RegisterContext_x86.h"
+#include "Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.h"
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+#define LLDB_INVALID_XSAVE_OFFSET UINT32_MAX
+
+namespace lldb_private {
+namespace process_freebsd {
+
+class NativeProcessFreeBSD;
+
+class NativeRegisterContextFreeBSD_x86_64
+ : public NativeRegisterContextFreeBSD,
+ public NativeRegisterContextWatchpoint_x86 {
+public:
+ NativeRegisterContextFreeBSD_x86_64(const ArchSpec &target_arch,
+ NativeThreadProtocol &native_thread);
+ uint32_t GetRegisterSetCount() const override;
+
+ const RegisterSet *GetRegisterSet(uint32_t set_index) const override;
+
+ Status ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &reg_value) override;
+
+ Status WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &reg_value) override;
+
+ Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
+
+ Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+ llvm::Error
+ CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override;
+
+private:
+ // Private member types.
+ enum RegSetKind {
+ GPRegSet,
+ FPRegSet,
+ DBRegSet,
+ YMMRegSet,
+ MPXRegSet,
+ MaxRegSet = MPXRegSet,
+ };
+
+ // Private member variables.
+ std::array<uint8_t, sizeof(struct reg)> m_gpr;
+ std::array<uint8_t, 512> m_fpr; // FXSAVE
+ std::array<uint8_t, sizeof(struct dbreg)> m_dbr;
+ std::vector<uint8_t> m_xsave;
+ std::array<uint32_t, MaxRegSet + 1> m_xsave_offsets;
+ std::array<size_t, MaxRegSet + 1> m_regset_offsets;
+
+ llvm::Optional<RegSetKind> GetSetForNativeRegNum(uint32_t reg_num) const;
+
+ Status ReadRegisterSet(RegSetKind set);
+ Status WriteRegisterSet(RegSetKind set);
+
+ uint8_t *GetOffsetRegSetData(RegSetKind set, size_t reg_offset);
+
+ struct YMMSplitPtr {
+ void *xmm;
+ void *ymm_hi;
+ };
+ llvm::Optional<YMMSplitPtr> GetYMMSplitReg(uint32_t reg);
+};
+
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextFreeBSD_x86_64_h
+
+#endif // defined(__x86_64__)
diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp
new file mode 100644
index 000000000000..43494871be07
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp
@@ -0,0 +1,286 @@
+//===-- NativeThreadFreeBSD.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeThreadFreeBSD.h"
+#include "NativeRegisterContextFreeBSD.h"
+
+#include "NativeProcessFreeBSD.h"
+
+#include "Plugins/Process/POSIX/CrashReason.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/State.h"
+#include "llvm/Support/Errno.h"
+
+// clang-format off
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+// clang-format on
+
+#include <sstream>
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_freebsd;
+
+NativeThreadFreeBSD::NativeThreadFreeBSD(NativeProcessFreeBSD &process,
+ lldb::tid_t tid)
+ : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid),
+ m_stop_info(),
+ m_reg_context_up(
+ NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
+ process.GetArchitecture(), *this)),
+ m_stop_description() {}
+
+Status NativeThreadFreeBSD::Resume() {
+ Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID());
+ if (!ret.Success())
+ return ret;
+ ret = NativeProcessFreeBSD::PtraceWrapper(PT_CLEARSTEP, GetID());
+ if (ret.Success())
+ SetRunning();
+ return ret;
+}
+
+Status NativeThreadFreeBSD::SingleStep() {
+ Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID());
+ if (!ret.Success())
+ return ret;
+ ret = NativeProcessFreeBSD::PtraceWrapper(PT_SETSTEP, GetID());
+ if (ret.Success())
+ SetStepping();
+ return ret;
+}
+
+Status NativeThreadFreeBSD::Suspend() {
+ Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_SUSPEND, GetID());
+ if (ret.Success())
+ SetStopped();
+ return ret;
+}
+
+void NativeThreadFreeBSD::SetStoppedBySignal(uint32_t signo,
+ const siginfo_t *info) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+ LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo);
+
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonSignal;
+ m_stop_info.details.signal.signo = signo;
+
+ m_stop_description.clear();
+ if (info) {
+ switch (signo) {
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGFPE:
+ case SIGILL:
+ const auto reason = GetCrashReason(*info);
+ m_stop_description = GetCrashReasonString(reason, *info);
+ break;
+ }
+ }
+}
+
+void NativeThreadFreeBSD::SetStoppedByBreakpoint() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonBreakpoint;
+ m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+void NativeThreadFreeBSD::SetStoppedByTrace() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonTrace;
+ m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+void NativeThreadFreeBSD::SetStoppedByExec() {
+ SetStopped();
+ m_stop_info.reason = StopReason::eStopReasonExec;
+ m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+void NativeThreadFreeBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
+ lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
+
+ std::ostringstream ostr;
+ ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " ";
+ ostr << wp_index;
+
+ ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index);
+
+ SetStopped();
+ m_stop_description = ostr.str();
+ m_stop_info.reason = StopReason::eStopReasonWatchpoint;
+ m_stop_info.details.signal.signo = SIGTRAP;
+}
+
+void NativeThreadFreeBSD::SetStoppedWithNoReason() {
+ SetStopped();
+
+ m_stop_info.reason = StopReason::eStopReasonNone;
+ m_stop_info.details.signal.signo = 0;
+}
+
+void NativeThreadFreeBSD::SetStopped() {
+ const StateType new_state = StateType::eStateStopped;
+ m_state = new_state;
+ m_stop_description.clear();
+}
+
+void NativeThreadFreeBSD::SetRunning() {
+ m_state = StateType::eStateRunning;
+ m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+void NativeThreadFreeBSD::SetStepping() {
+ m_state = StateType::eStateStepping;
+ m_stop_info.reason = StopReason::eStopReasonNone;
+}
+
+std::string NativeThreadFreeBSD::GetName() {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+
+ std::vector<struct kinfo_proc> kp;
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD,
+ static_cast<int>(GetProcess().GetID())};
+
+ while (1) {
+ size_t len = kp.size() * sizeof(struct kinfo_proc);
+ void *ptr = len == 0 ? nullptr : kp.data();
+ int error = ::sysctl(mib, 4, ptr, &len, nullptr, 0);
+ if (ptr == nullptr || (error != 0 && errno == ENOMEM)) {
+ kp.resize(len / sizeof(struct kinfo_proc));
+ continue;
+ }
+ if (error != 0) {
+ len = 0;
+ LLDB_LOG(log, "tid = {0} in state {1} failed to get thread name: {2}",
+ GetID(), m_state, strerror(errno));
+ }
+ kp.resize(len / sizeof(struct kinfo_proc));
+ break;
+ }
+
+ for (auto &procinfo : kp) {
+ if (procinfo.ki_tid == static_cast<lwpid_t>(GetID()))
+ return procinfo.ki_tdname;
+ }
+
+ return "";
+}
+
+lldb::StateType NativeThreadFreeBSD::GetState() { return m_state; }
+
+bool NativeThreadFreeBSD::GetStopReason(ThreadStopInfo &stop_info,
+ std::string &description) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
+ description.clear();
+
+ switch (m_state) {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ case eStateUnloaded:
+ stop_info = m_stop_info;
+ description = m_stop_description;
+
+ return true;
+
+ case eStateInvalid:
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(),
+ StateAsCString(m_state));
+ return false;
+ }
+ llvm_unreachable("unhandled StateType!");
+}
+
+NativeRegisterContextFreeBSD &NativeThreadFreeBSD::GetRegisterContext() {
+ assert(m_reg_context_up);
+ return *m_reg_context_up;
+}
+
+Status NativeThreadFreeBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags, bool hardware) {
+ assert(m_state == eStateStopped);
+ if (!hardware)
+ return Status("not implemented");
+ Status error = RemoveWatchpoint(addr);
+ if (error.Fail())
+ return error;
+ uint32_t wp_index =
+ GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags);
+ if (wp_index == LLDB_INVALID_INDEX32)
+ return Status("Setting hardware watchpoint failed.");
+ m_watchpoint_index_map.insert({addr, wp_index});
+ return Status();
+}
+
+Status NativeThreadFreeBSD::RemoveWatchpoint(lldb::addr_t addr) {
+ auto wp = m_watchpoint_index_map.find(addr);
+ if (wp == m_watchpoint_index_map.end())
+ return Status();
+ uint32_t wp_index = wp->second;
+ m_watchpoint_index_map.erase(wp);
+ if (GetRegisterContext().ClearHardwareWatchpoint(wp_index))
+ return Status();
+ return Status("Clearing hardware watchpoint failed.");
+}
+
+Status NativeThreadFreeBSD::SetHardwareBreakpoint(lldb::addr_t addr,
+ size_t size) {
+ assert(m_state == eStateStopped);
+ Status error = RemoveHardwareBreakpoint(addr);
+ if (error.Fail())
+ return error;
+
+ uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size);
+
+ if (bp_index == LLDB_INVALID_INDEX32)
+ return Status("Setting hardware breakpoint failed.");
+
+ m_hw_break_index_map.insert({addr, bp_index});
+ return Status();
+}
+
+Status NativeThreadFreeBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
+ auto bp = m_hw_break_index_map.find(addr);
+ if (bp == m_hw_break_index_map.end())
+ return Status();
+
+ uint32_t bp_index = bp->second;
+ if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) {
+ m_hw_break_index_map.erase(bp);
+ return Status();
+ }
+
+ return Status("Clearing hardware breakpoint failed.");
+}
+
+llvm::Error
+NativeThreadFreeBSD::CopyWatchpointsFrom(NativeThreadFreeBSD &source) {
+ llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom(
+ source.GetRegisterContext());
+ if (!s) {
+ m_watchpoint_index_map = source.m_watchpoint_index_map;
+ m_hw_break_index_map = source.m_hw_break_index_map;
+ }
+ return s;
+}
diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.h b/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.h
new file mode 100644
index 000000000000..4e997b3fb4bb
--- /dev/null
+++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.h
@@ -0,0 +1,83 @@
+//===-- NativeThreadFreeBSD.h --------------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_NativeThreadFreeBSD_H_
+#define liblldb_NativeThreadFreeBSD_H_
+
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+#include "Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h"
+
+#include <csignal>
+#include <map>
+#include <string>
+
+namespace lldb_private {
+namespace process_freebsd {
+
+class NativeProcessFreeBSD;
+
+class NativeThreadFreeBSD : public NativeThreadProtocol {
+ friend class NativeProcessFreeBSD;
+
+public:
+ NativeThreadFreeBSD(NativeProcessFreeBSD &process, lldb::tid_t tid);
+
+ // NativeThreadProtocol Interface
+ std::string GetName() override;
+
+ lldb::StateType GetState() override;
+
+ bool GetStopReason(ThreadStopInfo &stop_info,
+ std::string &description) override;
+
+ NativeRegisterContextFreeBSD &GetRegisterContext() override;
+
+ Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags,
+ bool hardware) override;
+
+ Status RemoveWatchpoint(lldb::addr_t addr) override;
+
+ Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
+
+ Status RemoveHardwareBreakpoint(lldb::addr_t addr) override;
+
+private:
+ // Interface for friend classes
+
+ Status Resume();
+ Status SingleStep();
+ Status Suspend();
+
+ void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
+ void SetStoppedByBreakpoint();
+ void SetStoppedByTrace();
+ void SetStoppedByExec();
+ void SetStoppedByWatchpoint(uint32_t wp_index);
+ void SetStoppedWithNoReason();
+ void SetStopped();
+ void SetRunning();
+ void SetStepping();
+
+ llvm::Error CopyWatchpointsFrom(NativeThreadFreeBSD &source);
+
+ // Member Variables
+ lldb::StateType m_state;
+ ThreadStopInfo m_stop_info;
+ std::unique_ptr<NativeRegisterContextFreeBSD> m_reg_context_up;
+ std::string m_stop_description;
+ using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
+ WatchpointIndexMap m_watchpoint_index_map;
+ WatchpointIndexMap m_hw_break_index_map;
+};
+
+typedef std::shared_ptr<NativeThreadFreeBSD> NativeThreadFreeBSDSP;
+} // namespace process_freebsd
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_NativeThreadFreeBSD_H_
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
index 5109022d80dd..57f0eb3cceb6 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
+++ b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp
@@ -98,18 +98,7 @@ NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info,
pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,
Info.GetArchitecture(), mainloop));
- // Enable event reporting
- ptrace_event_t events;
- status = PtraceWrapper(PT_GET_EVENT_MASK, pid, &events, sizeof(events));
- if (status.Fail())
- return status.ToError();
- // TODO: PTRACE_FORK | PTRACE_VFORK | PTRACE_POSIX_SPAWN?
- events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
- status = PtraceWrapper(PT_SET_EVENT_MASK, pid, &events, sizeof(events));
- if (status.Fail())
- return status.ToError();
-
- status = process_up->ReinitializeThreads();
+ status = process_up->SetupTrace();
if (status.Fail())
return status.ToError();
@@ -218,10 +207,14 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
// Get details on the signal raised.
if (siginfo_err.Fail()) {
+ LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err);
return;
}
- NativeThreadNetBSD* thread = nullptr;
+ LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, si_code = {2}", pid,
+ info.psi_lwpid, info.psi_siginfo.si_code);
+ NativeThreadNetBSD *thread = nullptr;
+
if (info.psi_lwpid > 0) {
for (const auto &t : m_threads) {
if (t->GetID() == static_cast<lldb::tid_t>(info.psi_lwpid)) {
@@ -231,8 +224,7 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
static_cast<NativeThreadNetBSD *>(t.get())->SetStoppedWithNoReason();
}
if (!thread)
- LLDB_LOG(log,
- "thread not found in m_threads, pid = {0}, LWP = {1}", pid,
+ LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid,
info.psi_lwpid);
}
@@ -243,12 +235,12 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
FixupBreakpointPCAsNeeded(*thread);
}
SetState(StateType::eStateStopped, true);
- break;
+ return;
case TRAP_TRACE:
if (thread)
thread->SetStoppedByTrace();
SetState(StateType::eStateStopped, true);
- break;
+ return;
case TRAP_EXEC: {
Status error = ReinitializeThreads();
if (error.Fail()) {
@@ -262,7 +254,8 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
for (const auto &thread : m_threads)
static_cast<NativeThreadNetBSD &>(*thread).SetStoppedByExec();
SetState(StateType::eStateStopped, true);
- } break;
+ return;
+ }
case TRAP_LWP: {
ptrace_state_t pst;
Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst));
@@ -272,35 +265,31 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
}
switch (pst.pe_report_event) {
- case PTRACE_LWP_CREATE: {
- LLDB_LOG(log,
- "monitoring new thread, pid = {0}, LWP = {1}", pid,
- pst.pe_lwp);
- NativeThreadNetBSD& t = AddThread(pst.pe_lwp);
- error = t.CopyWatchpointsFrom(
- static_cast<NativeThreadNetBSD &>(*GetCurrentThread()));
- if (error.Fail()) {
- LLDB_LOG(log,
- "failed to copy watchpoints to new thread {0}: {1}",
- pst.pe_lwp, error);
- SetState(StateType::eStateInvalid);
- return;
- }
- } break;
- case PTRACE_LWP_EXIT:
- LLDB_LOG(log,
- "removing exited thread, pid = {0}, LWP = {1}", pid,
- pst.pe_lwp);
- RemoveThread(pst.pe_lwp);
- break;
+ case PTRACE_LWP_CREATE: {
+ LLDB_LOG(log, "monitoring new thread, pid = {0}, LWP = {1}", pid,
+ pst.pe_lwp);
+ NativeThreadNetBSD &t = AddThread(pst.pe_lwp);
+ error = t.CopyWatchpointsFrom(
+ static_cast<NativeThreadNetBSD &>(*GetCurrentThread()));
+ if (error.Fail()) {
+ LLDB_LOG(log, "failed to copy watchpoints to new thread {0}: {1}",
+ pst.pe_lwp, error);
+ SetState(StateType::eStateInvalid);
+ return;
+ }
+ } break;
+ case PTRACE_LWP_EXIT:
+ LLDB_LOG(log, "removing exited thread, pid = {0}, LWP = {1}", pid,
+ pst.pe_lwp);
+ RemoveThread(pst.pe_lwp);
+ break;
}
- error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void*>(1), 0);
- if (error.Fail()) {
+ error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast<void *>(1), 0);
+ if (error.Fail())
SetState(StateType::eStateInvalid);
- return;
- }
- } break;
+ return;
+ }
case TRAP_DBREG: {
if (!thread)
break;
@@ -308,29 +297,42 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) {
auto &regctx = static_cast<NativeRegisterContextNetBSD &>(
thread->GetRegisterContext());
uint32_t wp_index = LLDB_INVALID_INDEX32;
- Status error = regctx.GetWatchpointHitIndex(wp_index,
- (uintptr_t)info.psi_siginfo.si_addr);
+ Status error = regctx.GetWatchpointHitIndex(
+ wp_index, (uintptr_t)info.psi_siginfo.si_addr);
if (error.Fail())
LLDB_LOG(log,
"received error while checking for watchpoint hits, pid = "
- "{0}, LWP = {1}, error = {2}", pid, info.psi_lwpid, error);
+ "{0}, LWP = {1}, error = {2}",
+ pid, info.psi_lwpid, error);
if (wp_index != LLDB_INVALID_INDEX32) {
thread->SetStoppedByWatchpoint(wp_index);
regctx.ClearWatchpointHit(wp_index);
SetState(StateType::eStateStopped, true);
- break;
+ return;
}
thread->SetStoppedByTrace();
SetState(StateType::eStateStopped, true);
- } break;
+ return;
}
+ }
+
+ // Either user-generated SIGTRAP or an unknown event that would
+ // otherwise leave the debugger hanging.
+ LLDB_LOG(log, "unknown SIGTRAP, passing to generic handler");
+ MonitorSignal(pid, SIGTRAP);
}
void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) {
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
ptrace_siginfo_t info;
+
const auto siginfo_err =
PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info));
+ if (siginfo_err.Fail()) {
+ LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err);
+ return;
+ }
for (const auto &abs_thread : m_threads) {
NativeThreadNetBSD &thread = static_cast<NativeThreadNetBSD &>(*abs_thread);
@@ -489,16 +491,14 @@ Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) {
signal = siginfo->psi_siginfo.si_signo;
}
- ret = PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1),
- signal);
+ ret =
+ PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast<void *>(1), signal);
if (ret.Success())
SetState(eStateRunning, true);
return ret;
}
-Status NativeProcessNetBSD::Halt() {
- return PtraceWrapper(PT_STOP, GetID());
-}
+Status NativeProcessNetBSD::Halt() { return PtraceWrapper(PT_STOP, GetID()); }
Status NativeProcessNetBSD::Detach() {
Status error;
@@ -662,8 +662,8 @@ Status NativeProcessNetBSD::PopulateMemoryRegionCache() {
if (vm[i].kve_path[0])
info.SetName(vm[i].kve_path);
- m_mem_region_cache.emplace_back(
- info, FileSpec(info.GetName().GetCString()));
+ m_mem_region_cache.emplace_back(info,
+ FileSpec(info.GetName().GetCString()));
}
free(vm);
@@ -684,15 +684,6 @@ Status NativeProcessNetBSD::PopulateMemoryRegionCache() {
return Status();
}
-Status NativeProcessNetBSD::AllocateMemory(size_t size, uint32_t permissions,
- lldb::addr_t &addr) {
- return Status("Unimplemented");
-}
-
-Status NativeProcessNetBSD::DeallocateMemory(lldb::addr_t addr) {
- return Status("Unimplemented");
-}
-
lldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() {
// punt on this for now
return LLDB_INVALID_ADDRESS;
@@ -710,21 +701,47 @@ Status NativeProcessNetBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size,
Status NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path,
FileSpec &file_spec) {
- return Status("Unimplemented");
+ Status error = PopulateMemoryRegionCache();
+ if (error.Fail())
+ return error;
+
+ FileSpec module_file_spec(module_path);
+ FileSystem::Instance().Resolve(module_file_spec);
+
+ file_spec.Clear();
+ for (const auto &it : m_mem_region_cache) {
+ if (it.second.GetFilename() == module_file_spec.GetFilename()) {
+ file_spec = it.second;
+ return Status();
+ }
+ }
+ return Status("Module file (%s) not found in process' memory map!",
+ module_file_spec.GetFilename().AsCString());
}
Status NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name,
lldb::addr_t &load_addr) {
load_addr = LLDB_INVALID_ADDRESS;
- return Status();
+ Status error = PopulateMemoryRegionCache();
+ if (error.Fail())
+ return error;
+
+ FileSpec file(file_name);
+ for (const auto &it : m_mem_region_cache) {
+ if (it.second == file) {
+ load_addr = it.first.GetRange().GetRangeBase();
+ return Status();
+ }
+ }
+ return Status("No load address found for file %s.", file_name.str().c_str());
}
void NativeProcessNetBSD::SigchldHandler() {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
// Process all pending waitpid notifications.
int status;
- ::pid_t wait_pid =
- llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WALLSIG | WNOHANG);
+ ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status,
+ WALLSIG | WNOHANG);
if (wait_pid == 0)
return; // We are done.
@@ -806,12 +823,13 @@ Status NativeProcessNetBSD::Attach() {
int wstatus;
// Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this
// point we should have a thread stopped if waitpid succeeds.
- if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid,
- m_pid, nullptr, WALLSIG)) < 0)
+ if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr,
+ WALLSIG)) < 0)
return Status(errno, eErrorTypePOSIX);
- /* Initialize threads */
- status = ReinitializeThreads();
+ // Initialize threads and tracing status
+ // NB: this needs to be called before we set thread state
+ status = SetupTrace();
if (status.Fail())
return status;
@@ -819,7 +837,8 @@ Status NativeProcessNetBSD::Attach() {
static_cast<NativeThreadNetBSD &>(*thread).SetStoppedBySignal(SIGSTOP);
// Let our process instance know the thread has stopped.
- SetState(StateType::eStateStopped);
+ SetCurrentThreadID(m_threads.front()->GetID());
+ SetState(StateType::eStateStopped, false);
return Status();
}
@@ -864,7 +883,8 @@ Status NativeProcessNetBSD::WriteMemory(lldb::addr_t addr, const void *buf,
io.piod_len = size;
do {
- io.piod_addr = const_cast<void *>(static_cast<const void *>(src + bytes_written));
+ io.piod_addr =
+ const_cast<void *>(static_cast<const void *>(src + bytes_written));
io.piod_offs = (void *)(addr + bytes_written);
Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io);
@@ -909,6 +929,22 @@ NativeProcessNetBSD::GetAuxvData() const {
return std::move(buf);
}
+Status NativeProcessNetBSD::SetupTrace() {
+ // Enable event reporting
+ ptrace_event_t events;
+ Status status =
+ PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events));
+ if (status.Fail())
+ return status;
+ // TODO: PTRACE_FORK | PTRACE_VFORK | PTRACE_POSIX_SPAWN?
+ events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
+ status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events));
+ if (status.Fail())
+ return status;
+
+ return ReinitializeThreads();
+}
+
Status NativeProcessNetBSD::ReinitializeThreads() {
// Clear old threads
m_threads.clear();
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
index 6a06773f40a8..3d59a4f72e94 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
+++ b/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h
@@ -60,11 +60,6 @@ public:
Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
size_t &bytes_written) override;
- Status AllocateMemory(size_t size, uint32_t permissions,
- lldb::addr_t &addr) override;
-
- Status DeallocateMemory(lldb::addr_t addr) override;
-
lldb::addr_t GetSharedLibraryInfoAddress() override;
size_t UpdateThreads() override;
@@ -74,9 +69,13 @@ public:
Status SetBreakpoint(lldb::addr_t addr, uint32_t size,
bool hardware) override;
+ // The two following methods are probably not necessary and probably
+ // will never be called. Nevertheless, we implement them right now
+ // to reduce the differences between different platforms and reduce
+ // the risk of the lack of implementation actually breaking something,
+ // at least for the time being.
Status GetLoadedModuleFileSpec(const char *module_path,
FileSpec &file_spec) override;
-
Status GetFileLoadAddress(const llvm::StringRef &file_name,
lldb::addr_t &load_addr) override;
@@ -112,6 +111,7 @@ private:
void SigchldHandler();
Status Attach();
+ Status SetupTrace();
Status ReinitializeThreads();
};
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
index 03b505c19890..4755dab0b073 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
+++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
@@ -20,12 +20,6 @@ using namespace lldb_private::process_netbsd;
#include <sys/ptrace.h>
// clang-format on
-NativeRegisterContextNetBSD::NativeRegisterContextNetBSD(
- NativeThreadProtocol &native_thread,
- RegisterInfoInterface *reg_info_interface_p)
- : NativeRegisterContextRegisterInfo(native_thread,
- reg_info_interface_p) {}
-
Status NativeRegisterContextNetBSD::DoRegisterSet(int ptrace_req, void *buf) {
return NativeProcessNetBSD::PtraceWrapper(ptrace_req, GetProcessPid(), buf,
m_thread.GetID());
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
index 13e023d856d2..08490aad9e0b 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
+++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
@@ -18,11 +18,9 @@ namespace process_netbsd {
class NativeProcessNetBSD;
-class NativeRegisterContextNetBSD : public NativeRegisterContextRegisterInfo {
+class NativeRegisterContextNetBSD
+ : public virtual NativeRegisterContextRegisterInfo {
public:
- NativeRegisterContextNetBSD(NativeThreadProtocol &native_thread,
- RegisterInfoInterface *reg_info_interface_p);
-
// This function is implemented in the NativeRegisterContextNetBSD_*
// subclasses to create a new instance of the host specific
// NativeRegisterContextNetBSD. The implementations can't collide as only one
@@ -31,11 +29,9 @@ public:
static NativeRegisterContextNetBSD *
CreateHostNativeRegisterContextNetBSD(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
- virtual Status
+ virtual llvm::Error
CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) = 0;
- virtual Status ClearWatchpointHit(uint32_t wp_index) = 0;
-
protected:
Status DoRegisterSet(int req, void *buf);
virtual NativeProcessNetBSD &GetProcess();
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
index ca4706a65657..ed1884c94a4b 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
+++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
@@ -36,9 +36,6 @@
using namespace lldb_private;
using namespace lldb_private::process_netbsd;
-// Private namespace.
-
-namespace {
// x86 64-bit general purpose registers.
static const uint32_t g_gpr_regnums_x86_64[] = {
lldb_rax_x86_64, lldb_rbx_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64,
@@ -87,20 +84,21 @@ static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) -
// x86 64-bit floating point registers.
static const uint32_t g_fpu_regnums_x86_64[] = {
- lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64,
- lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64,
- lldb_foseg_x86_64, lldb_fooff_x86_64, lldb_mxcsr_x86_64,
- lldb_mxcsrmask_x86_64, lldb_st0_x86_64, lldb_st1_x86_64,
- lldb_st2_x86_64, lldb_st3_x86_64, lldb_st4_x86_64,
- lldb_st5_x86_64, lldb_st6_x86_64, lldb_st7_x86_64,
- lldb_mm0_x86_64, lldb_mm1_x86_64, lldb_mm2_x86_64,
- lldb_mm3_x86_64, lldb_mm4_x86_64, lldb_mm5_x86_64,
- lldb_mm6_x86_64, lldb_mm7_x86_64, lldb_xmm0_x86_64,
- lldb_xmm1_x86_64, lldb_xmm2_x86_64, lldb_xmm3_x86_64,
- lldb_xmm4_x86_64, lldb_xmm5_x86_64, lldb_xmm6_x86_64,
- lldb_xmm7_x86_64, lldb_xmm8_x86_64, lldb_xmm9_x86_64,
- lldb_xmm10_x86_64, lldb_xmm11_x86_64, lldb_xmm12_x86_64,
- lldb_xmm13_x86_64, lldb_xmm14_x86_64, lldb_xmm15_x86_64,
+ lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64,
+ lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64,
+ lldb_fip_x86_64, lldb_foseg_x86_64, lldb_fooff_x86_64,
+ lldb_fdp_x86_64, lldb_mxcsr_x86_64, lldb_mxcsrmask_x86_64,
+ lldb_st0_x86_64, lldb_st1_x86_64, lldb_st2_x86_64,
+ lldb_st3_x86_64, lldb_st4_x86_64, lldb_st5_x86_64,
+ lldb_st6_x86_64, lldb_st7_x86_64, lldb_mm0_x86_64,
+ lldb_mm1_x86_64, lldb_mm2_x86_64, lldb_mm3_x86_64,
+ lldb_mm4_x86_64, lldb_mm5_x86_64, lldb_mm6_x86_64,
+ lldb_mm7_x86_64, lldb_xmm0_x86_64, lldb_xmm1_x86_64,
+ lldb_xmm2_x86_64, lldb_xmm3_x86_64, lldb_xmm4_x86_64,
+ lldb_xmm5_x86_64, lldb_xmm6_x86_64, lldb_xmm7_x86_64,
+ lldb_xmm8_x86_64, lldb_xmm9_x86_64, lldb_xmm10_x86_64,
+ lldb_xmm11_x86_64, lldb_xmm12_x86_64, lldb_xmm13_x86_64,
+ lldb_xmm14_x86_64, lldb_xmm15_x86_64,
LLDB_INVALID_REGNUM // register sets need to end with this flag
};
static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) -
@@ -108,27 +106,34 @@ static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) -
k_num_fpr_registers_x86_64,
"g_fpu_regnums_x86_64 has wrong number of register infos");
-// x86 64-bit registers available via XState.
-static const uint32_t g_xstate_regnums_x86_64[] = {
+static const uint32_t g_avx_regnums_x86_64[] = {
lldb_ymm0_x86_64, lldb_ymm1_x86_64, lldb_ymm2_x86_64, lldb_ymm3_x86_64,
lldb_ymm4_x86_64, lldb_ymm5_x86_64, lldb_ymm6_x86_64, lldb_ymm7_x86_64,
lldb_ymm8_x86_64, lldb_ymm9_x86_64, lldb_ymm10_x86_64, lldb_ymm11_x86_64,
lldb_ymm12_x86_64, lldb_ymm13_x86_64, lldb_ymm14_x86_64, lldb_ymm15_x86_64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) -
+ 1 ==
+ k_num_avx_registers_x86_64,
+ "g_avx_regnums_x86_64 has wrong number of register infos");
+
+static const uint32_t g_mpx_regnums_x86_64[] = {
// Note: we currently do not provide them but this is needed to avoid
// unnamed groups in SBFrame::GetRegisterContext().
- lldb_bnd0_x86_64, lldb_bnd1_x86_64, lldb_bnd2_x86_64,
- lldb_bnd3_x86_64, lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64,
+ lldb_bnd0_x86_64, lldb_bnd1_x86_64, lldb_bnd2_x86_64,
+ lldb_bnd3_x86_64, lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64,
LLDB_INVALID_REGNUM // register sets need to end with this flag
};
-static_assert((sizeof(g_xstate_regnums_x86_64) / sizeof(g_xstate_regnums_x86_64[0])) -
+static_assert((sizeof(g_mpx_regnums_x86_64) / sizeof(g_mpx_regnums_x86_64[0])) -
1 ==
- k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64,
- "g_xstate_regnums_x86_64 has wrong number of register infos");
+ k_num_mpx_registers_x86_64,
+ "g_mpx_regnums_x86_64 has wrong number of register infos");
// x86 debug registers.
static const uint32_t g_dbr_regnums_x86_64[] = {
- lldb_dr0_x86_64, lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64,
- lldb_dr4_x86_64, lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64,
+ lldb_dr0_x86_64, lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64,
+ lldb_dr4_x86_64, lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64,
LLDB_INVALID_REGNUM // register sets need to end with this flag
};
static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) -
@@ -137,7 +142,7 @@ static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) -
"g_dbr_regnums_x86_64 has wrong number of register infos");
// x86 32-bit general purpose registers.
-const uint32_t g_gpr_regnums_i386[] = {
+static const uint32_t g_gpr_regnums_i386[] = {
lldb_eax_i386, lldb_ebx_i386, lldb_ecx_i386, lldb_edx_i386,
lldb_edi_i386, lldb_esi_i386, lldb_ebp_i386, lldb_esp_i386,
lldb_eip_i386, lldb_eflags_i386, lldb_cs_i386, lldb_fs_i386,
@@ -154,7 +159,7 @@ static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) -
"g_gpr_regnums_i386 has wrong number of register infos");
// x86 32-bit floating point registers.
-const uint32_t g_fpu_regnums_i386[] = {
+static const uint32_t g_fpu_regnums_i386[] = {
lldb_fctrl_i386, lldb_fstat_i386, lldb_ftag_i386, lldb_fop_i386,
lldb_fiseg_i386, lldb_fioff_i386, lldb_foseg_i386, lldb_fooff_i386,
lldb_mxcsr_i386, lldb_mxcsrmask_i386, lldb_st0_i386, lldb_st1_i386,
@@ -171,25 +176,32 @@ static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) -
k_num_fpr_registers_i386,
"g_fpu_regnums_i386 has wrong number of register infos");
-// x86 64-bit registers available via XState.
-static const uint32_t g_xstate_regnums_i386[] = {
- lldb_ymm0_i386, lldb_ymm1_i386, lldb_ymm2_i386, lldb_ymm3_i386,
- lldb_ymm4_i386, lldb_ymm5_i386, lldb_ymm6_i386, lldb_ymm7_i386,
+static const uint32_t g_avx_regnums_i386[] = {
+ lldb_ymm0_i386, lldb_ymm1_i386, lldb_ymm2_i386, lldb_ymm3_i386,
+ lldb_ymm4_i386, lldb_ymm5_i386, lldb_ymm6_i386, lldb_ymm7_i386,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) -
+ 1 ==
+ k_num_avx_registers_i386,
+ "g_avx_regnums_i386 has wrong number of register infos");
+
+static const uint32_t g_mpx_regnums_i386[] = {
// Note: we currently do not provide them but this is needed to avoid
// unnamed groups in SBFrame::GetRegisterContext().
- lldb_bnd0_i386, lldb_bnd1_i386, lldb_bnd2_i386,
- lldb_bnd3_i386, lldb_bndcfgu_i386, lldb_bndstatus_i386,
+ lldb_bnd0_i386, lldb_bnd1_i386, lldb_bnd2_i386,
+ lldb_bnd3_i386, lldb_bndcfgu_i386, lldb_bndstatus_i386,
LLDB_INVALID_REGNUM // register sets need to end with this flag
};
-static_assert((sizeof(g_xstate_regnums_i386) / sizeof(g_xstate_regnums_i386[0])) -
+static_assert((sizeof(g_mpx_regnums_i386) / sizeof(g_mpx_regnums_i386[0])) -
1 ==
- k_num_avx_registers_i386 + k_num_mpx_registers_i386,
- "g_xstate_regnums_i386 has wrong number of register infos");
+ k_num_mpx_registers_i386,
+ "g_mpx_regnums_i386 has wrong number of register infos");
// x86 debug registers.
static const uint32_t g_dbr_regnums_i386[] = {
- lldb_dr0_i386, lldb_dr1_i386, lldb_dr2_i386, lldb_dr3_i386,
- lldb_dr4_i386, lldb_dr5_i386, lldb_dr6_i386, lldb_dr7_i386,
+ lldb_dr0_i386, lldb_dr1_i386, lldb_dr2_i386, lldb_dr3_i386,
+ lldb_dr4_i386, lldb_dr5_i386, lldb_dr6_i386, lldb_dr7_i386,
LLDB_INVALID_REGNUM // register sets need to end with this flag
};
static_assert((sizeof(g_dbr_regnums_i386) / sizeof(g_dbr_regnums_i386[0])) -
@@ -197,9 +209,8 @@ static_assert((sizeof(g_dbr_regnums_i386) / sizeof(g_dbr_regnums_i386[0])) -
k_num_dbr_registers_i386,
"g_dbr_regnums_i386 has wrong number of register infos");
-
// Number of register sets provided by this context.
-enum { k_num_register_sets = 4 };
+enum { k_num_register_sets = 5 };
// Register sets for x86 32-bit.
static const RegisterSet g_reg_sets_i386[k_num_register_sets] = {
@@ -207,11 +218,11 @@ static const RegisterSet g_reg_sets_i386[k_num_register_sets] = {
g_gpr_regnums_i386},
{"Floating Point Registers", "fpu", k_num_fpr_registers_i386,
g_fpu_regnums_i386},
- {"Extended State Registers", "xstate",
- k_num_avx_registers_i386 + k_num_mpx_registers_i386,
- g_xstate_regnums_i386},
- {"Debug Registers", "dbr", k_num_dbr_registers_i386,
- g_dbr_regnums_i386},
+ {"Debug Registers", "dbr", k_num_dbr_registers_i386, g_dbr_regnums_i386},
+ {"Advanced Vector Extensions", "avx", k_num_avx_registers_i386,
+ g_avx_regnums_i386},
+ {"Memory Protection Extensions", "mpx", k_num_mpx_registers_i386,
+ g_mpx_regnums_i386},
};
// Register sets for x86 64-bit.
@@ -220,15 +231,15 @@ static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = {
g_gpr_regnums_x86_64},
{"Floating Point Registers", "fpu", k_num_fpr_registers_x86_64,
g_fpu_regnums_x86_64},
- {"Extended State Registers", "xstate",
- k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64,
- g_xstate_regnums_x86_64},
{"Debug Registers", "dbr", k_num_dbr_registers_x86_64,
g_dbr_regnums_x86_64},
+ {"Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64,
+ g_avx_regnums_x86_64},
+ {"Memory Protection Extensions", "mpx", k_num_mpx_registers_x86_64,
+ g_mpx_regnums_x86_64},
};
#define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize())
-} // namespace
NativeRegisterContextNetBSD *
NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD(
@@ -246,28 +257,41 @@ CreateRegisterInfoInterface(const ArchSpec &target_arch) {
} else {
assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&
"Register setting path assumes this is a 64-bit host");
- // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64
- // register context.
+ // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the
+ // x86_64 register context.
return new RegisterContextNetBSD_x86_64(target_arch);
}
}
NativeRegisterContextNetBSD_x86_64::NativeRegisterContextNetBSD_x86_64(
const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
- : NativeRegisterContextNetBSD(native_thread,
- CreateRegisterInfoInterface(target_arch)),
- m_gpr(), m_fpr(), m_dbr() {}
+ : NativeRegisterContextRegisterInfo(
+ native_thread, CreateRegisterInfoInterface(target_arch)),
+ m_regset_offsets({0}) {
+ assert(m_gpr.size() == GetRegisterInfoInterface().GetGPRSize());
+ std::array<uint32_t, MaxRegularRegSet + 1> first_regnos;
-// CONSIDER after local and llgs debugging are merged, register set support can
-// be moved into a base x86-64 class with IsRegisterSetAvailable made virtual.
-uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetCount() const {
- uint32_t sets = 0;
- for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) {
- if (GetSetForNativeRegNum(set_index) != -1)
- ++sets;
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ first_regnos[FPRegSet] = lldb_fctrl_i386;
+ first_regnos[DBRegSet] = lldb_dr0_i386;
+ break;
+ case llvm::Triple::x86_64:
+ first_regnos[FPRegSet] = lldb_fctrl_x86_64;
+ first_regnos[DBRegSet] = lldb_dr0_x86_64;
+ break;
+ default:
+ llvm_unreachable("Unhandled target architecture.");
}
- return sets;
+ for (int i : {FPRegSet, DBRegSet})
+ m_regset_offsets[i] = GetRegisterInfoInterface()
+ .GetRegisterInfo()[first_regnos[i]]
+ .byte_offset;
+}
+
+uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetCount() const {
+ return k_num_register_sets;
}
const RegisterSet *
@@ -278,199 +302,79 @@ NativeRegisterContextNetBSD_x86_64::GetRegisterSet(uint32_t set_index) const {
case llvm::Triple::x86_64:
return &g_reg_sets_x86_64[set_index];
default:
- assert(false && "Unhandled target architecture.");
- return nullptr;
+ llvm_unreachable("Unhandled target architecture.");
}
-
- return nullptr;
}
-static constexpr int RegNumX86ToX86_64(int regnum) {
- switch (regnum) {
- case lldb_eax_i386:
- return lldb_rax_x86_64;
- case lldb_ebx_i386:
- return lldb_rbx_x86_64;
- case lldb_ecx_i386:
- return lldb_rcx_x86_64;
- case lldb_edx_i386:
- return lldb_rdx_x86_64;
- case lldb_edi_i386:
- return lldb_rdi_x86_64;
- case lldb_esi_i386:
- return lldb_rsi_x86_64;
- case lldb_ebp_i386:
- return lldb_rbp_x86_64;
- case lldb_esp_i386:
- return lldb_rsp_x86_64;
- case lldb_eip_i386:
- return lldb_rip_x86_64;
- case lldb_eflags_i386:
- return lldb_rflags_x86_64;
- case lldb_cs_i386:
- return lldb_cs_x86_64;
- case lldb_fs_i386:
- return lldb_fs_x86_64;
- case lldb_gs_i386:
- return lldb_gs_x86_64;
- case lldb_ss_i386:
- return lldb_ss_x86_64;
- case lldb_ds_i386:
- return lldb_ds_x86_64;
- case lldb_es_i386:
- return lldb_es_x86_64;
- case lldb_fctrl_i386:
- return lldb_fctrl_x86_64;
- case lldb_fstat_i386:
- return lldb_fstat_x86_64;
- case lldb_ftag_i386:
- return lldb_fstat_x86_64;
- case lldb_fop_i386:
- return lldb_fop_x86_64;
- case lldb_fiseg_i386:
- return lldb_fiseg_x86_64;
- case lldb_fioff_i386:
- return lldb_fioff_x86_64;
- case lldb_foseg_i386:
- return lldb_foseg_x86_64;
- case lldb_fooff_i386:
- return lldb_fooff_x86_64;
- case lldb_mxcsr_i386:
- return lldb_mxcsr_x86_64;
- case lldb_mxcsrmask_i386:
- return lldb_mxcsrmask_x86_64;
- case lldb_st0_i386:
- case lldb_st1_i386:
- case lldb_st2_i386:
- case lldb_st3_i386:
- case lldb_st4_i386:
- case lldb_st5_i386:
- case lldb_st6_i386:
- case lldb_st7_i386:
- return lldb_st0_x86_64 + regnum - lldb_st0_i386;
- case lldb_mm0_i386:
- case lldb_mm1_i386:
- case lldb_mm2_i386:
- case lldb_mm3_i386:
- case lldb_mm4_i386:
- case lldb_mm5_i386:
- case lldb_mm6_i386:
- case lldb_mm7_i386:
- return lldb_mm0_x86_64 + regnum - lldb_mm0_i386;
- case lldb_xmm0_i386:
- case lldb_xmm1_i386:
- case lldb_xmm2_i386:
- case lldb_xmm3_i386:
- case lldb_xmm4_i386:
- case lldb_xmm5_i386:
- case lldb_xmm6_i386:
- case lldb_xmm7_i386:
- return lldb_xmm0_x86_64 + regnum - lldb_xmm0_i386;
- case lldb_ymm0_i386:
- case lldb_ymm1_i386:
- case lldb_ymm2_i386:
- case lldb_ymm3_i386:
- case lldb_ymm4_i386:
- case lldb_ymm5_i386:
- case lldb_ymm6_i386:
- case lldb_ymm7_i386:
- return lldb_ymm0_x86_64 + regnum - lldb_ymm0_i386;
- case lldb_dr0_i386:
- case lldb_dr1_i386:
- case lldb_dr2_i386:
- case lldb_dr3_i386:
- case lldb_dr4_i386:
- case lldb_dr5_i386:
- case lldb_dr6_i386:
- case lldb_dr7_i386:
- return lldb_dr0_x86_64 + regnum - lldb_dr0_i386;
- default:
- assert(false && "Unhandled i386 register.");
- return 0;
- }
-}
-
-int NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum(
- int reg_num) const {
+llvm::Optional<NativeRegisterContextNetBSD_x86_64::RegSetKind>
+NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum(
+ uint32_t reg_num) const {
switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
case llvm::Triple::x86:
- if (reg_num <= k_last_gpr_i386)
+ if (reg_num >= k_first_gpr_i386 && reg_num <= k_last_gpr_i386)
return GPRegSet;
- else if (reg_num <= k_last_fpr_i386)
+ if (reg_num >= k_first_fpr_i386 && reg_num <= k_last_fpr_i386)
return FPRegSet;
- else if (reg_num <= k_last_avx_i386)
- return XStateRegSet; // AVX
- else if (reg_num <= lldb_dr7_i386)
+ if (reg_num >= k_first_avx_i386 && reg_num <= k_last_avx_i386)
+ return YMMRegSet;
+ if (reg_num >= k_first_mpxr_i386 && reg_num <= k_last_mpxr_i386)
+ return llvm::None; // MPXR
+ if (reg_num >= k_first_mpxc_i386 && reg_num <= k_last_mpxc_i386)
+ return llvm::None; // MPXC
+ if (reg_num >= k_first_dbr_i386 && reg_num <= k_last_dbr_i386)
return DBRegSet; // DBR
- else
- return -1;
+ break;
case llvm::Triple::x86_64:
- if (reg_num <= k_last_gpr_x86_64)
+ if (reg_num >= k_first_gpr_x86_64 && reg_num <= k_last_gpr_x86_64)
return GPRegSet;
- else if (reg_num <= k_last_fpr_x86_64)
+ if (reg_num >= k_first_fpr_x86_64 && reg_num <= k_last_fpr_x86_64)
return FPRegSet;
- else if (reg_num <= k_last_avx_x86_64)
- return XStateRegSet; // AVX
- else if (reg_num <= k_last_mpxr_x86_64)
- return -1; // MPXR
- else if (reg_num <= k_last_mpxc_x86_64)
- return -1; // MPXC
- else if (reg_num <= lldb_dr7_x86_64)
+ if (reg_num >= k_first_avx_x86_64 && reg_num <= k_last_avx_x86_64)
+ return YMMRegSet;
+ if (reg_num >= k_first_mpxr_x86_64 && reg_num <= k_last_mpxr_x86_64)
+ return llvm::None; // MPXR
+ if (reg_num >= k_first_mpxc_x86_64 && reg_num <= k_last_mpxc_x86_64)
+ return llvm::None; // MPXC
+ if (reg_num >= k_first_dbr_x86_64 && reg_num <= k_last_dbr_x86_64)
return DBRegSet; // DBR
- else
- return -1;
+ break;
default:
- assert(false && "Unhandled target architecture.");
- return -1;
+ llvm_unreachable("Unhandled target architecture.");
}
+
+ llvm_unreachable("Register does not belong to any register set");
}
-Status NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(uint32_t set) {
+Status NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(RegSetKind set) {
switch (set) {
case GPRegSet:
- return DoRegisterSet(PT_GETREGS, &m_gpr);
- case FPRegSet:
-#if defined(__x86_64__)
- return DoRegisterSet(PT_GETFPREGS, &m_fpr);
-#else
- return DoRegisterSet(PT_GETXMMREGS, &m_fpr);
-#endif
+ return DoRegisterSet(PT_GETREGS, m_gpr.data());
case DBRegSet:
- return DoRegisterSet(PT_GETDBREGS, &m_dbr);
- case XStateRegSet:
-#ifdef HAVE_XSTATE
- {
- struct iovec iov = {&m_xstate, sizeof(m_xstate)};
- return DoRegisterSet(PT_GETXSTATE, &iov);
- }
-#else
- return Status("XState is not supported by the kernel");
-#endif
+ return DoRegisterSet(PT_GETDBREGS, m_dbr.data());
+ case FPRegSet:
+ case YMMRegSet:
+ case MPXRegSet: {
+ struct iovec iov = {m_xstate.data(), m_xstate.size()};
+ Status ret = DoRegisterSet(PT_GETXSTATE, &iov);
+ assert(reinterpret_cast<xstate *>(m_xstate.data())->xs_rfbm & XCR0_X87);
+ return ret;
+ }
}
llvm_unreachable("NativeRegisterContextNetBSD_x86_64::ReadRegisterSet");
}
-Status NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(uint32_t set) {
+Status NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(RegSetKind set) {
switch (set) {
case GPRegSet:
- return DoRegisterSet(PT_SETREGS, &m_gpr);
- case FPRegSet:
-#if defined(__x86_64__)
- return DoRegisterSet(PT_SETFPREGS, &m_fpr);
-#else
- return DoRegisterSet(PT_SETXMMREGS, &m_fpr);
-#endif
+ return DoRegisterSet(PT_SETREGS, m_gpr.data());
case DBRegSet:
- return DoRegisterSet(PT_SETDBREGS, &m_dbr);
- case XStateRegSet:
-#ifdef HAVE_XSTATE
- {
- struct iovec iov = {&m_xstate, sizeof(m_xstate)};
- return DoRegisterSet(PT_SETXSTATE, &iov);
- }
-#else
- return Status("XState is not supported by the kernel");
-#endif
+ return DoRegisterSet(PT_SETDBREGS, m_dbr.data());
+ case FPRegSet:
+ case YMMRegSet:
+ case MPXRegSet: {
+ struct iovec iov = {&m_xstate, sizeof(m_xstate)};
+ return DoRegisterSet(PT_SETXSTATE, &iov);
+ }
}
llvm_unreachable("NativeRegisterContextNetBSD_x86_64::WriteRegisterSet");
}
@@ -495,8 +399,8 @@ NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info,
return error;
}
- int set = GetSetForNativeRegNum(reg);
- if (set == -1) {
+ llvm::Optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
+ if (!opt_set) {
// This is likely an internal register for lldb use only and should not be
// directly queried.
error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
@@ -504,261 +408,40 @@ NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info,
return error;
}
- switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
- case llvm::Triple::x86_64:
- break;
- case llvm::Triple::x86:
- reg = RegNumX86ToX86_64(reg);
- break;
- default:
- assert(false && "Unhandled target architecture.");
- error.SetErrorString("Unhandled target architecture.");
- return error;
- }
-
+ RegSetKind set = opt_set.getValue();
error = ReadRegisterSet(set);
if (error.Fail())
return error;
- switch (reg) {
-#if defined(__x86_64__)
- case lldb_rax_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_RAX];
- break;
- case lldb_rbx_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_RBX];
- break;
- case lldb_rcx_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_RCX];
- break;
- case lldb_rdx_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_RDX];
- break;
- case lldb_rdi_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_RDI];
- break;
- case lldb_rsi_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_RSI];
- break;
- case lldb_rbp_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_RBP];
- break;
- case lldb_rsp_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_RSP];
- break;
- case lldb_r8_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_R8];
- break;
- case lldb_r9_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_R9];
- break;
- case lldb_r10_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_R10];
- break;
- case lldb_r11_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_R11];
- break;
- case lldb_r12_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_R12];
- break;
- case lldb_r13_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_R13];
- break;
- case lldb_r14_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_R14];
- break;
- case lldb_r15_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_R15];
- break;
- case lldb_rip_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_RIP];
- break;
- case lldb_rflags_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_RFLAGS];
- break;
- case lldb_cs_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_CS];
- break;
- case lldb_fs_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_FS];
- break;
- case lldb_gs_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_GS];
- break;
- case lldb_ss_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_SS];
- break;
- case lldb_ds_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_DS];
- break;
- case lldb_es_x86_64:
- reg_value = (uint64_t)m_gpr.regs[_REG_ES];
- break;
-#else
- case lldb_rax_x86_64:
- reg_value = (uint32_t)m_gpr.r_eax;
- break;
- case lldb_rbx_x86_64:
- reg_value = (uint32_t)m_gpr.r_ebx;
- break;
- case lldb_rcx_x86_64:
- reg_value = (uint32_t)m_gpr.r_ecx;
- break;
- case lldb_rdx_x86_64:
- reg_value = (uint32_t)m_gpr.r_edx;
- break;
- case lldb_rdi_x86_64:
- reg_value = (uint32_t)m_gpr.r_edi;
- break;
- case lldb_rsi_x86_64:
- reg_value = (uint32_t)m_gpr.r_esi;
- break;
- case lldb_rsp_x86_64:
- reg_value = (uint32_t)m_gpr.r_esp;
- break;
- case lldb_rbp_x86_64:
- reg_value = (uint32_t)m_gpr.r_ebp;
- break;
- case lldb_rip_x86_64:
- reg_value = (uint32_t)m_gpr.r_eip;
- break;
- case lldb_rflags_x86_64:
- reg_value = (uint32_t)m_gpr.r_eflags;
- break;
- case lldb_cs_x86_64:
- reg_value = (uint32_t)m_gpr.r_cs;
- break;
- case lldb_fs_x86_64:
- reg_value = (uint32_t)m_gpr.r_fs;
- break;
- case lldb_gs_x86_64:
- reg_value = (uint32_t)m_gpr.r_gs;
- break;
- case lldb_ss_x86_64:
- reg_value = (uint32_t)m_gpr.r_ss;
- break;
- case lldb_ds_x86_64:
- reg_value = (uint32_t)m_gpr.r_ds;
- break;
- case lldb_es_x86_64:
- reg_value = (uint32_t)m_gpr.r_es;
- break;
-#endif
- case lldb_fctrl_x86_64:
- reg_value = (uint16_t)m_fpr.fxstate.fx_cw;
- break;
- case lldb_fstat_x86_64:
- reg_value = (uint16_t)m_fpr.fxstate.fx_sw;
- break;
- case lldb_ftag_x86_64:
- reg_value = (uint8_t)m_fpr.fxstate.fx_tw;
- break;
- case lldb_fop_x86_64:
- reg_value = (uint64_t)m_fpr.fxstate.fx_opcode;
- break;
- case lldb_fiseg_x86_64:
- reg_value = (uint64_t)m_fpr.fxstate.fx_ip.fa_64;
- break;
- case lldb_fioff_x86_64:
- reg_value = (uint32_t)m_fpr.fxstate.fx_ip.fa_32.fa_off;
- break;
- case lldb_foseg_x86_64:
- reg_value = (uint64_t)m_fpr.fxstate.fx_dp.fa_64;
- break;
- case lldb_fooff_x86_64:
- reg_value = (uint32_t)m_fpr.fxstate.fx_dp.fa_32.fa_off;
- break;
- case lldb_mxcsr_x86_64:
- reg_value = (uint32_t)m_fpr.fxstate.fx_mxcsr;
- break;
- case lldb_mxcsrmask_x86_64:
- reg_value = (uint32_t)m_fpr.fxstate.fx_mxcsr_mask;
- break;
- case lldb_st0_x86_64:
- case lldb_st1_x86_64:
- case lldb_st2_x86_64:
- case lldb_st3_x86_64:
- case lldb_st4_x86_64:
- case lldb_st5_x86_64:
- case lldb_st6_x86_64:
- case lldb_st7_x86_64:
- reg_value.SetBytes(&m_fpr.fxstate.fx_87_ac[reg - lldb_st0_x86_64],
- reg_info->byte_size, endian::InlHostByteOrder());
- break;
- case lldb_mm0_x86_64:
- case lldb_mm1_x86_64:
- case lldb_mm2_x86_64:
- case lldb_mm3_x86_64:
- case lldb_mm4_x86_64:
- case lldb_mm5_x86_64:
- case lldb_mm6_x86_64:
- case lldb_mm7_x86_64:
- reg_value.SetBytes(&m_fpr.fxstate.fx_87_ac[reg - lldb_mm0_x86_64],
- reg_info->byte_size, endian::InlHostByteOrder());
- break;
- case lldb_xmm0_x86_64:
- case lldb_xmm1_x86_64:
- case lldb_xmm2_x86_64:
- case lldb_xmm3_x86_64:
- case lldb_xmm4_x86_64:
- case lldb_xmm5_x86_64:
- case lldb_xmm6_x86_64:
- case lldb_xmm7_x86_64:
- case lldb_xmm8_x86_64:
- case lldb_xmm9_x86_64:
- case lldb_xmm10_x86_64:
- case lldb_xmm11_x86_64:
- case lldb_xmm12_x86_64:
- case lldb_xmm13_x86_64:
- case lldb_xmm14_x86_64:
- case lldb_xmm15_x86_64:
- reg_value.SetBytes(&m_fpr.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
- reg_info->byte_size, endian::InlHostByteOrder());
+ switch (set) {
+ case GPRegSet:
+ case FPRegSet:
+ case DBRegSet: {
+ void *data = GetOffsetRegSetData(set, reg_info->byte_offset);
+ FXSAVE *fpr = reinterpret_cast<FXSAVE *>(m_xstate.data() +
+ offsetof(xstate, xs_fxsave));
+ if (data == &fpr->ftag) // ftag
+ reg_value.SetUInt16(
+ AbridgedToFullTagWord(fpr->ftag, fpr->fstat, fpr->stmm));
+ else
+ reg_value.SetBytes(data, reg_info->byte_size, endian::InlHostByteOrder());
break;
- case lldb_ymm0_x86_64:
- case lldb_ymm1_x86_64:
- case lldb_ymm2_x86_64:
- case lldb_ymm3_x86_64:
- case lldb_ymm4_x86_64:
- case lldb_ymm5_x86_64:
- case lldb_ymm6_x86_64:
- case lldb_ymm7_x86_64:
- case lldb_ymm8_x86_64:
- case lldb_ymm9_x86_64:
- case lldb_ymm10_x86_64:
- case lldb_ymm11_x86_64:
- case lldb_ymm12_x86_64:
- case lldb_ymm13_x86_64:
- case lldb_ymm14_x86_64:
- case lldb_ymm15_x86_64:
-#ifdef HAVE_XSTATE
- if (!(m_xstate.xs_rfbm & XCR0_SSE) ||
- !(m_xstate.xs_rfbm & XCR0_YMM_Hi128)) {
- error.SetErrorStringWithFormat("register \"%s\" not supported by CPU/kernel",
- reg_info->name);
+ }
+ case YMMRegSet: {
+ llvm::Optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg);
+ if (!ymm_reg) {
+ error.SetErrorStringWithFormat(
+ "register \"%s\" not supported by CPU/kernel", reg_info->name);
} else {
- uint32_t reg_index = reg - lldb_ymm0_x86_64;
- YMMReg ymm = XStateToYMM(
- m_xstate.xs_fxsave.fx_xmm[reg_index].xmm_bytes,
- m_xstate.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes);
+ YMMReg ymm = XStateToYMM(ymm_reg->xmm, ymm_reg->ymm_hi);
reg_value.SetBytes(ymm.bytes, reg_info->byte_size,
endian::InlHostByteOrder());
}
-#else
- error.SetErrorString("XState queries not supported by the kernel");
-#endif
- break;
- case lldb_dr0_x86_64:
- case lldb_dr1_x86_64:
- case lldb_dr2_x86_64:
- case lldb_dr3_x86_64:
- case lldb_dr4_x86_64:
- case lldb_dr5_x86_64:
- case lldb_dr6_x86_64:
- case lldb_dr7_x86_64:
- reg_value = (uint64_t)m_dbr.dr[reg - lldb_dr0_x86_64];
break;
}
+ case MPXRegSet:
+ llvm_unreachable("MPX regset should have returned error");
+ }
return error;
}
@@ -783,8 +466,8 @@ Status NativeRegisterContextNetBSD_x86_64::WriteRegister(
return error;
}
- int set = GetSetForNativeRegNum(reg);
- if (set == -1) {
+ llvm::Optional<RegSetKind> opt_set = GetSetForNativeRegNum(reg);
+ if (!opt_set) {
// This is likely an internal register for lldb use only and should not be
// directly queried.
error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set",
@@ -792,262 +475,54 @@ Status NativeRegisterContextNetBSD_x86_64::WriteRegister(
return error;
}
- switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
- case llvm::Triple::x86_64:
- break;
- case llvm::Triple::x86:
- reg = RegNumX86ToX86_64(reg);
- break;
- default:
- assert(false && "Unhandled target architecture.");
- error.SetErrorString("Unhandled target architecture.");
- return error;
- }
+ RegSetKind set = opt_set.getValue();
+ uint64_t new_xstate_bv = 0;
error = ReadRegisterSet(set);
if (error.Fail())
return error;
- switch (reg) {
-#if defined(__x86_64__)
- case lldb_rax_x86_64:
- m_gpr.regs[_REG_RAX] = reg_value.GetAsUInt64();
- break;
- case lldb_rbx_x86_64:
- m_gpr.regs[_REG_RBX] = reg_value.GetAsUInt64();
- break;
- case lldb_rcx_x86_64:
- m_gpr.regs[_REG_RCX] = reg_value.GetAsUInt64();
- break;
- case lldb_rdx_x86_64:
- m_gpr.regs[_REG_RDX] = reg_value.GetAsUInt64();
- break;
- case lldb_rdi_x86_64:
- m_gpr.regs[_REG_RDI] = reg_value.GetAsUInt64();
- break;
- case lldb_rsi_x86_64:
- m_gpr.regs[_REG_RSI] = reg_value.GetAsUInt64();
- break;
- case lldb_rbp_x86_64:
- m_gpr.regs[_REG_RBP] = reg_value.GetAsUInt64();
- break;
- case lldb_rsp_x86_64:
- m_gpr.regs[_REG_RSP] = reg_value.GetAsUInt64();
- break;
- case lldb_r8_x86_64:
- m_gpr.regs[_REG_R8] = reg_value.GetAsUInt64();
- break;
- case lldb_r9_x86_64:
- m_gpr.regs[_REG_R9] = reg_value.GetAsUInt64();
- break;
- case lldb_r10_x86_64:
- m_gpr.regs[_REG_R10] = reg_value.GetAsUInt64();
- break;
- case lldb_r11_x86_64:
- m_gpr.regs[_REG_R11] = reg_value.GetAsUInt64();
- break;
- case lldb_r12_x86_64:
- m_gpr.regs[_REG_R12] = reg_value.GetAsUInt64();
- break;
- case lldb_r13_x86_64:
- m_gpr.regs[_REG_R13] = reg_value.GetAsUInt64();
- break;
- case lldb_r14_x86_64:
- m_gpr.regs[_REG_R14] = reg_value.GetAsUInt64();
- break;
- case lldb_r15_x86_64:
- m_gpr.regs[_REG_R15] = reg_value.GetAsUInt64();
- break;
- case lldb_rip_x86_64:
- m_gpr.regs[_REG_RIP] = reg_value.GetAsUInt64();
- break;
- case lldb_rflags_x86_64:
- m_gpr.regs[_REG_RFLAGS] = reg_value.GetAsUInt64();
- break;
- case lldb_cs_x86_64:
- m_gpr.regs[_REG_CS] = reg_value.GetAsUInt64();
- break;
- case lldb_fs_x86_64:
- m_gpr.regs[_REG_FS] = reg_value.GetAsUInt64();
- break;
- case lldb_gs_x86_64:
- m_gpr.regs[_REG_GS] = reg_value.GetAsUInt64();
- break;
- case lldb_ss_x86_64:
- m_gpr.regs[_REG_SS] = reg_value.GetAsUInt64();
- break;
- case lldb_ds_x86_64:
- m_gpr.regs[_REG_DS] = reg_value.GetAsUInt64();
- break;
- case lldb_es_x86_64:
- m_gpr.regs[_REG_ES] = reg_value.GetAsUInt64();
- break;
-#else
- case lldb_rax_x86_64:
- m_gpr.r_eax = reg_value.GetAsUInt32();
- break;
- case lldb_rbx_x86_64:
- m_gpr.r_ebx = reg_value.GetAsUInt32();
- break;
- case lldb_rcx_x86_64:
- m_gpr.r_ecx = reg_value.GetAsUInt32();
- break;
- case lldb_rdx_x86_64:
- m_gpr.r_edx = reg_value.GetAsUInt32();
- break;
- case lldb_rdi_x86_64:
- m_gpr.r_edi = reg_value.GetAsUInt32();
- break;
- case lldb_rsi_x86_64:
- m_gpr.r_esi = reg_value.GetAsUInt32();
- break;
- case lldb_rsp_x86_64:
- m_gpr.r_esp = reg_value.GetAsUInt32();
- break;
- case lldb_rbp_x86_64:
- m_gpr.r_ebp = reg_value.GetAsUInt32();
- break;
- case lldb_rip_x86_64:
- m_gpr.r_eip = reg_value.GetAsUInt32();
- break;
- case lldb_rflags_x86_64:
- m_gpr.r_eflags = reg_value.GetAsUInt32();
- break;
- case lldb_cs_x86_64:
- m_gpr.r_cs = reg_value.GetAsUInt32();
- break;
- case lldb_fs_x86_64:
- m_gpr.r_fs = reg_value.GetAsUInt32();
- break;
- case lldb_gs_x86_64:
- m_gpr.r_gs = reg_value.GetAsUInt32();
- break;
- case lldb_ss_x86_64:
- m_gpr.r_ss = reg_value.GetAsUInt32();
- break;
- case lldb_ds_x86_64:
- m_gpr.r_ds = reg_value.GetAsUInt32();
- break;
- case lldb_es_x86_64:
- m_gpr.r_es = reg_value.GetAsUInt32();
- break;
-#endif
- case lldb_fctrl_x86_64:
- m_fpr.fxstate.fx_cw = reg_value.GetAsUInt16();
- break;
- case lldb_fstat_x86_64:
- m_fpr.fxstate.fx_sw = reg_value.GetAsUInt16();
- break;
- case lldb_ftag_x86_64:
- m_fpr.fxstate.fx_tw = reg_value.GetAsUInt8();
- break;
- case lldb_fop_x86_64:
- m_fpr.fxstate.fx_opcode = reg_value.GetAsUInt16();
- break;
- case lldb_fiseg_x86_64:
- m_fpr.fxstate.fx_ip.fa_64 = reg_value.GetAsUInt64();
- break;
- case lldb_fioff_x86_64:
- m_fpr.fxstate.fx_ip.fa_32.fa_off = reg_value.GetAsUInt32();
- break;
- case lldb_foseg_x86_64:
- m_fpr.fxstate.fx_dp.fa_64 = reg_value.GetAsUInt64();
- break;
- case lldb_fooff_x86_64:
- m_fpr.fxstate.fx_dp.fa_32.fa_off = reg_value.GetAsUInt32();
- break;
- case lldb_mxcsr_x86_64:
- m_fpr.fxstate.fx_mxcsr = reg_value.GetAsUInt32();
- break;
- case lldb_mxcsrmask_x86_64:
- m_fpr.fxstate.fx_mxcsr_mask = reg_value.GetAsUInt32();
- break;
- case lldb_st0_x86_64:
- case lldb_st1_x86_64:
- case lldb_st2_x86_64:
- case lldb_st3_x86_64:
- case lldb_st4_x86_64:
- case lldb_st5_x86_64:
- case lldb_st6_x86_64:
- case lldb_st7_x86_64:
- ::memcpy(&m_fpr.fxstate.fx_87_ac[reg - lldb_st0_x86_64],
- reg_value.GetBytes(), reg_value.GetByteSize());
- break;
- case lldb_mm0_x86_64:
- case lldb_mm1_x86_64:
- case lldb_mm2_x86_64:
- case lldb_mm3_x86_64:
- case lldb_mm4_x86_64:
- case lldb_mm5_x86_64:
- case lldb_mm6_x86_64:
- case lldb_mm7_x86_64:
- ::memcpy(&m_fpr.fxstate.fx_87_ac[reg - lldb_mm0_x86_64],
+ switch (set) {
+ case GPRegSet:
+ case DBRegSet:
+ ::memcpy(GetOffsetRegSetData(set, reg_info->byte_offset),
reg_value.GetBytes(), reg_value.GetByteSize());
break;
- case lldb_xmm0_x86_64:
- case lldb_xmm1_x86_64:
- case lldb_xmm2_x86_64:
- case lldb_xmm3_x86_64:
- case lldb_xmm4_x86_64:
- case lldb_xmm5_x86_64:
- case lldb_xmm6_x86_64:
- case lldb_xmm7_x86_64:
- case lldb_xmm8_x86_64:
- case lldb_xmm9_x86_64:
- case lldb_xmm10_x86_64:
- case lldb_xmm11_x86_64:
- case lldb_xmm12_x86_64:
- case lldb_xmm13_x86_64:
- case lldb_xmm14_x86_64:
- case lldb_xmm15_x86_64:
- ::memcpy(&m_fpr.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
- reg_value.GetBytes(), reg_value.GetByteSize());
+ case FPRegSet: {
+ void *data = GetOffsetRegSetData(set, reg_info->byte_offset);
+ FXSAVE *fpr = reinterpret_cast<FXSAVE *>(m_xstate.data() +
+ offsetof(xstate, xs_fxsave));
+ if (data == &fpr->ftag) // ftag
+ fpr->ftag = FullToAbridgedTagWord(reg_value.GetAsUInt16());
+ else
+ ::memcpy(data, reg_value.GetBytes(), reg_value.GetByteSize());
+ if (data >= &fpr->xmm)
+ new_xstate_bv |= XCR0_SSE;
+ else if (data >= &fpr->mxcsr && data < &fpr->stmm)
+ new_xstate_bv |= XCR0_SSE;
+ else
+ new_xstate_bv |= XCR0_X87;
break;
- case lldb_ymm0_x86_64:
- case lldb_ymm1_x86_64:
- case lldb_ymm2_x86_64:
- case lldb_ymm3_x86_64:
- case lldb_ymm4_x86_64:
- case lldb_ymm5_x86_64:
- case lldb_ymm6_x86_64:
- case lldb_ymm7_x86_64:
- case lldb_ymm8_x86_64:
- case lldb_ymm9_x86_64:
- case lldb_ymm10_x86_64:
- case lldb_ymm11_x86_64:
- case lldb_ymm12_x86_64:
- case lldb_ymm13_x86_64:
- case lldb_ymm14_x86_64:
- case lldb_ymm15_x86_64:
-#ifdef HAVE_XSTATE
- if (!(m_xstate.xs_rfbm & XCR0_SSE) ||
- !(m_xstate.xs_rfbm & XCR0_YMM_Hi128)) {
- error.SetErrorStringWithFormat("register \"%s\" not supported by CPU/kernel",
- reg_info->name);
+ }
+ case YMMRegSet: {
+ llvm::Optional<YMMSplitPtr> ymm_reg = GetYMMSplitReg(reg);
+ if (!ymm_reg) {
+ error.SetErrorStringWithFormat(
+ "register \"%s\" not supported by CPU/kernel", reg_info->name);
} else {
- uint32_t reg_index = reg - lldb_ymm0_x86_64;
YMMReg ymm;
::memcpy(ymm.bytes, reg_value.GetBytes(), reg_value.GetByteSize());
- YMMToXState(ymm,
- m_xstate.xs_fxsave.fx_xmm[reg_index].xmm_bytes,
- m_xstate.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes);
+ YMMToXState(ymm, ymm_reg->xmm, ymm_reg->ymm_hi);
+ new_xstate_bv |= XCR0_SSE | XCR0_YMM_Hi128;
}
-#else
- error.SetErrorString("XState not supported by the kernel");
-#endif
- break;
- case lldb_dr0_x86_64:
- case lldb_dr1_x86_64:
- case lldb_dr2_x86_64:
- case lldb_dr3_x86_64:
- case lldb_dr4_x86_64:
- case lldb_dr5_x86_64:
- case lldb_dr6_x86_64:
- case lldb_dr7_x86_64:
- m_dbr.dr[reg - lldb_dr0_x86_64] = reg_value.GetAsUInt64();
break;
}
+ case MPXRegSet:
+ llvm_unreachable("MPX regset should have returned error");
+ }
+ if (new_xstate_bv != 0)
+ reinterpret_cast<xstate *>(m_xstate.data())->xs_xstate_bv |= new_xstate_bv;
return WriteRegisterSet(set);
}
@@ -1061,7 +536,7 @@ Status NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues(
return error;
uint8_t *dst = data_sp->GetBytes();
- ::memcpy(dst, &m_gpr, GetRegisterInfoInterface().GetGPRSize());
+ ::memcpy(dst, m_gpr.data(), GetRegisterInfoInterface().GetGPRSize());
dst += GetRegisterInfoInterface().GetGPRSize();
return error;
@@ -1094,7 +569,7 @@ Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues(
__FUNCTION__);
return error;
}
- ::memcpy(&m_gpr, src, GetRegisterInfoInterface().GetGPRSize());
+ ::memcpy(m_gpr.data(), src, GetRegisterInfoInterface().GetGPRSize());
error = WriteRegisterSet(GPRegSet);
if (error.Fail())
@@ -1104,260 +579,66 @@ Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues(
return error;
}
-int NativeRegisterContextNetBSD_x86_64::GetDR(int num) const {
- assert(num >= 0 && num <= 7);
- switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
- case llvm::Triple::x86:
- return lldb_dr0_i386 + num;
- case llvm::Triple::x86_64:
- return lldb_dr0_x86_64 + num;
- default:
- return -1;
- }
-}
-
-Status NativeRegisterContextNetBSD_x86_64::IsWatchpointHit(uint32_t wp_index,
- bool &is_hit) {
- if (wp_index >= NumSupportedHardwareWatchpoints())
- return Status("Watchpoint index out of range");
-
- RegisterValue reg_value;
- const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(GetDR(6));
- Status error = ReadRegister(reg_info, reg_value);
- if (error.Fail()) {
- is_hit = false;
- return error;
- }
-
- uint64_t status_bits = reg_value.GetAsUInt64();
-
- is_hit = status_bits & (1 << wp_index);
-
- return error;
-}
-
-Status NativeRegisterContextNetBSD_x86_64::GetWatchpointHitIndex(
- uint32_t &wp_index, lldb::addr_t trap_addr) {
- uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
- for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
- bool is_hit;
- Status error = IsWatchpointHit(wp_index, is_hit);
- if (error.Fail()) {
- wp_index = LLDB_INVALID_INDEX32;
- return error;
- } else if (is_hit) {
- return error;
- }
- }
- wp_index = LLDB_INVALID_INDEX32;
- return Status();
-}
-
-Status NativeRegisterContextNetBSD_x86_64::IsWatchpointVacant(uint32_t wp_index,
- bool &is_vacant) {
- if (wp_index >= NumSupportedHardwareWatchpoints())
- return Status("Watchpoint index out of range");
+llvm::Error NativeRegisterContextNetBSD_x86_64::CopyHardwareWatchpointsFrom(
+ NativeRegisterContextNetBSD &source) {
+ auto &r_source = static_cast<NativeRegisterContextNetBSD_x86_64 &>(source);
+ // NB: This implicitly reads the whole dbreg set.
+ RegisterValue dr7;
+ Status res = r_source.ReadRegister(GetDR(7), dr7);
+ if (!res.Fail()) {
+ // copy dbregs only if any watchpoints were set
+ if ((dr7.GetAsUInt64() & 0xFF) == 0)
+ return llvm::Error::success();
- RegisterValue reg_value;
- const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(GetDR(7));
- Status error = ReadRegister(reg_info, reg_value);
- if (error.Fail()) {
- is_vacant = false;
- return error;
+ m_dbr = r_source.m_dbr;
+ res = WriteRegisterSet(DBRegSet);
}
-
- uint64_t control_bits = reg_value.GetAsUInt64();
-
- is_vacant = !(control_bits & (1 << (2 * wp_index + 1)));
-
- return error;
+ return res.ToError();
}
-Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex(
- lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
-
- if (wp_index >= NumSupportedHardwareWatchpoints())
- return Status("Watchpoint index out of range");
-
- // Read only watchpoints aren't supported on x86_64. Fall back to read/write
- // waitchpoints instead.
- // TODO: Add logic to detect when a write happens and ignore that watchpoint
- // hit.
- if (watch_flags == 0x2)
- watch_flags = 0x3;
-
- if (watch_flags != 0x1 && watch_flags != 0x3)
- return Status("Invalid read/write bits for watchpoint");
-
- if (size != 1 && size != 2 && size != 4 && size != 8)
- return Status("Invalid size for watchpoint");
-
- bool is_vacant;
- Status error = IsWatchpointVacant(wp_index, is_vacant);
- if (error.Fail())
- return error;
- if (!is_vacant)
- return Status("Watchpoint index not vacant");
-
- const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(GetDR(7));
- RegisterValue dr7_value;
- error = ReadRegister(reg_info_dr7, dr7_value);
- if (error.Fail())
- return error;
-
- // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7
- uint64_t enable_bit = 1 << (2 * wp_index + 1);
-
- // set bits 16-17, 20-21, 24-25, or 28-29
- // with 0b01 for write, and 0b11 for read/write
- uint64_t rw_bits = watch_flags << (16 + 4 * wp_index);
-
- // set bits 18-19, 22-23, 26-27, or 30-31
- // with 0b00, 0b01, 0b10, or 0b11
- // for 1, 2, 8 (if supported), or 4 bytes, respectively
- uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
-
- uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index));
-
- uint64_t control_bits = dr7_value.GetAsUInt64() & ~bit_mask;
-
- control_bits |= enable_bit | rw_bits | size_bits;
-
- const RegisterInfo *const reg_info_drN =
- GetRegisterInfoAtIndex(GetDR(wp_index));
- RegisterValue drN_value;
- error = ReadRegister(reg_info_drN, drN_value);
- if (error.Fail())
- return error;
-
- // clear dr6 if address or bits changed (i.e. we're not reenabling the same
- // watchpoint)
- if (drN_value.GetAsUInt64() != addr ||
- (dr7_value.GetAsUInt64() & bit_mask) != (rw_bits | size_bits)) {
- ClearWatchpointHit(wp_index);
-
- error = WriteRegister(reg_info_drN, RegisterValue(addr));
- if (error.Fail())
- return error;
+uint8_t *
+NativeRegisterContextNetBSD_x86_64::GetOffsetRegSetData(RegSetKind set,
+ size_t reg_offset) {
+ uint8_t *base;
+ switch (set) {
+ case GPRegSet:
+ base = m_gpr.data();
+ break;
+ case FPRegSet:
+ base = m_xstate.data() + offsetof(xstate, xs_fxsave);
+ break;
+ case DBRegSet:
+ base = m_dbr.data();
+ break;
+ case YMMRegSet:
+ llvm_unreachable("GetRegSetData() is unsuitable for this regset.");
+ case MPXRegSet:
+ llvm_unreachable("MPX regset should have returned error");
}
-
- error = WriteRegister(reg_info_dr7, RegisterValue(control_bits));
- if (error.Fail())
- return error;
-
- error.Clear();
- return error;
-}
-
-bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint(
- uint32_t wp_index) {
- if (wp_index >= NumSupportedHardwareWatchpoints())
- return false;
-
- // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0-1, 2-3, 4-5
- // or 6-7 of the debug control register (DR7)
- const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(GetDR(7));
- RegisterValue reg_value;
- Status error = ReadRegister(reg_info_dr7, reg_value);
- if (error.Fail())
- return false;
- uint64_t bit_mask = 0x3 << (2 * wp_index);
- uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
-
- return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success();
+ assert(reg_offset >= m_regset_offsets[set]);
+ return base + (reg_offset - m_regset_offsets[set]);
}
-Status NativeRegisterContextNetBSD_x86_64::ClearWatchpointHit(uint32_t wp_index) {
- if (wp_index >= NumSupportedHardwareWatchpoints())
- return Status("Watchpoint index out of range");
+llvm::Optional<NativeRegisterContextNetBSD_x86_64::YMMSplitPtr>
+NativeRegisterContextNetBSD_x86_64::GetYMMSplitReg(uint32_t reg) {
+ auto xst = reinterpret_cast<xstate *>(m_xstate.data());
+ if (!(xst->xs_rfbm & XCR0_SSE) || !(xst->xs_rfbm & XCR0_YMM_Hi128))
+ return llvm::None;
- // for watchpoints 0, 1, 2, or 3, respectively, check bits 0, 1, 2, or 3 of
- // the debug status register (DR6)
- const RegisterInfo *const reg_info_dr6 = GetRegisterInfoAtIndex(GetDR(6));
- RegisterValue reg_value;
- Status error = ReadRegister(reg_info_dr6, reg_value);
- if (error.Fail())
- return error;
-
- uint64_t bit_mask = 1 << wp_index;
- uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
- return WriteRegister(reg_info_dr6, RegisterValue(status_bits));
-}
-
-Status NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() {
- RegisterValue reg_value;
-
- // clear bits {0-4} of the debug status register (DR6)
- const RegisterInfo *const reg_info_dr6 = GetRegisterInfoAtIndex(GetDR(6));
- Status error = ReadRegister(reg_info_dr6, reg_value);
- if (error.Fail())
- return error;
- uint64_t bit_mask = 0xF;
- uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask;
- error = WriteRegister(reg_info_dr6, RegisterValue(status_bits));
- if (error.Fail())
- return error;
-
- // clear bits {0-7,16-31} of the debug control register (DR7)
- const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(GetDR(7));
- error = ReadRegister(reg_info_dr7, reg_value);
- if (error.Fail())
- return error;
- bit_mask = 0xFF | (0xFFFF << 16);
- uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask;
- return WriteRegister(reg_info_dr7, RegisterValue(control_bits));
-}
-
-uint32_t NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpoint(
- lldb::addr_t addr, size_t size, uint32_t watch_flags) {
- Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
- const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
- for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) {
- bool is_vacant;
- Status error = IsWatchpointVacant(wp_index, is_vacant);
- if (is_vacant) {
- error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index);
- if (error.Success())
- return wp_index;
- }
- if (error.Fail() && log) {
- LLDB_LOGF(log, "NativeRegisterContextNetBSD_x86_64::%s Error: %s",
- __FUNCTION__, error.AsCString());
- }
+ uint32_t reg_index;
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ reg_index = reg - lldb_ymm0_i386;
+ break;
+ case llvm::Triple::x86_64:
+ reg_index = reg - lldb_ymm0_x86_64;
+ break;
+ default:
+ llvm_unreachable("Unhandled target architecture.");
}
- return LLDB_INVALID_INDEX32;
-}
-
-lldb::addr_t
-NativeRegisterContextNetBSD_x86_64::GetWatchpointAddress(uint32_t wp_index) {
- if (wp_index >= NumSupportedHardwareWatchpoints())
- return LLDB_INVALID_ADDRESS;
- RegisterValue reg_value;
- const RegisterInfo *const reg_info_drN =
- GetRegisterInfoAtIndex(GetDR(wp_index));
- if (ReadRegister(reg_info_drN, reg_value).Fail())
- return LLDB_INVALID_ADDRESS;
- return reg_value.GetAsUInt64();
-}
-uint32_t NativeRegisterContextNetBSD_x86_64::NumSupportedHardwareWatchpoints() {
- // Available debug address registers: dr0, dr1, dr2, dr3
- return 4;
-}
-
-Status NativeRegisterContextNetBSD_x86_64::CopyHardwareWatchpointsFrom(
- NativeRegisterContextNetBSD &source) {
- auto &r_source = static_cast<NativeRegisterContextNetBSD_x86_64&>(source);
- Status res = r_source.ReadRegisterSet(DBRegSet);
- if (!res.Fail()) {
- // copy dbregs only if any watchpoints were set
- if ((r_source.m_dbr.dr[7] & 0xFF) == 0)
- return res;
-
- m_dbr = r_source.m_dbr;
- res = WriteRegisterSet(DBRegSet);
- }
- return res;
+ return YMMSplitPtr{&xst->xs_fxsave.fx_xmm[reg_index],
+ &xst->xs_ymm_hi128.xs_ymm[reg_index]};
}
#endif // defined(__x86_64__)
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
index 6c0632f3bce8..d20fd67cdc5d 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
+++ b/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
@@ -18,20 +18,21 @@
#include <machine/reg.h>
// clang-format on
+#include <array>
+
#include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h"
#include "Plugins/Process/Utility/RegisterContext_x86.h"
+#include "Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.h"
#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
-#if defined(PT_GETXSTATE) && defined(PT_SETXSTATE)
-#define HAVE_XSTATE
-#endif
-
namespace lldb_private {
namespace process_netbsd {
class NativeProcessNetBSD;
-class NativeRegisterContextNetBSD_x86_64 : public NativeRegisterContextNetBSD {
+class NativeRegisterContextNetBSD_x86_64
+ : public NativeRegisterContextNetBSD,
+ public NativeRegisterContextWatchpoint_x86 {
public:
NativeRegisterContextNetBSD_x86_64(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);
@@ -49,54 +50,39 @@ public:
Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
- Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override;
-
- Status GetWatchpointHitIndex(uint32_t &wp_index,
- lldb::addr_t trap_addr) override;
-
- Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override;
-
- bool ClearHardwareWatchpoint(uint32_t wp_index) override;
-
- Status ClearWatchpointHit(uint32_t wp_index) override;
-
- Status ClearAllHardwareWatchpoints() override;
-
- Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size,
- uint32_t watch_flags,
- uint32_t wp_index);
-
- uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
- uint32_t watch_flags) override;
-
- lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
-
- uint32_t NumSupportedHardwareWatchpoints() override;
-
- Status
+ llvm::Error
CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) override;
private:
// Private member types.
- enum { GPRegSet, FPRegSet, XStateRegSet, DBRegSet };
+ enum RegSetKind {
+ GPRegSet,
+ FPRegSet,
+ DBRegSet,
+ MaxRegularRegSet = DBRegSet,
+ YMMRegSet,
+ MPXRegSet,
+ MaxRegSet = MPXRegSet,
+ };
// Private member variables.
- struct reg m_gpr;
-#if defined(__x86_64__)
- struct fpreg m_fpr;
-#else
- struct xmmregs m_fpr;
-#endif
- struct dbreg m_dbr;
-#ifdef HAVE_XSTATE
- struct xstate m_xstate;
-#endif
+ std::array<uint8_t, sizeof(struct reg)> m_gpr;
+ std::array<uint8_t, sizeof(struct xstate)> m_xstate;
+ std::array<uint8_t, sizeof(struct dbreg)> m_dbr;
+ std::array<size_t, MaxRegularRegSet + 1> m_regset_offsets;
+
+ llvm::Optional<RegSetKind> GetSetForNativeRegNum(uint32_t reg_num) const;
+
+ Status ReadRegisterSet(RegSetKind set);
+ Status WriteRegisterSet(RegSetKind set);
- int GetSetForNativeRegNum(int reg_num) const;
- int GetDR(int num) const;
+ uint8_t *GetOffsetRegSetData(RegSetKind set, size_t reg_offset);
- Status ReadRegisterSet(uint32_t set);
- Status WriteRegisterSet(uint32_t set);
+ struct YMMSplitPtr {
+ void *xmm;
+ void *ymm_hi;
+ };
+ llvm::Optional<YMMSplitPtr> GetYMMSplitReg(uint32_t reg);
};
} // namespace process_netbsd
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
index fe76fb40e0b3..1a3fd4d646ae 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
+++ b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp
@@ -116,8 +116,6 @@ void NativeThreadNetBSD::SetStoppedByExec() {
}
void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
- SetStopped();
-
lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid");
std::ostringstream ostr;
@@ -126,8 +124,8 @@ void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) {
ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index);
+ SetStopped();
m_stop_description = ostr.str();
-
m_stop_info.reason = StopReason::eStopReasonWatchpoint;
m_stop_info.details.signal.signo = SIGTRAP;
}
@@ -204,7 +202,6 @@ lldb::StateType NativeThreadNetBSD::GetState() { return m_state; }
bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info,
std::string &description) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD));
-
description.clear();
switch (m_state) {
@@ -239,14 +236,14 @@ NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() {
Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size,
uint32_t watch_flags, bool hardware) {
+ assert(m_state == eStateStopped);
if (!hardware)
return Status("not implemented");
- if (m_state == eStateLaunching)
- return Status();
Status error = RemoveWatchpoint(addr);
if (error.Fail())
return error;
- uint32_t wp_index = GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags);
+ uint32_t wp_index =
+ GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags);
if (wp_index == LLDB_INVALID_INDEX32)
return Status("Setting hardware watchpoint failed.");
m_watchpoint_index_map.insert({addr, wp_index});
@@ -266,9 +263,7 @@ Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) {
Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr,
size_t size) {
- if (m_state == eStateLaunching)
- return Status();
-
+ assert(m_state == eStateStopped);
Status error = RemoveHardwareBreakpoint(addr);
if (error.Fail())
return error;
@@ -296,10 +291,11 @@ Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) {
return Status("Clearing hardware breakpoint failed.");
}
-Status NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) {
- Status s = GetRegisterContext().CopyHardwareWatchpointsFrom(
+llvm::Error
+NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) {
+ llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom(
source.GetRegisterContext());
- if (!s.Fail()) {
+ if (!s) {
m_watchpoint_index_map = source.m_watchpoint_index_map;
m_hw_break_index_map = source.m_hw_break_index_map;
}
diff --git a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
index 89b61ef86722..d4e21bd2bdaa 100644
--- a/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
+++ b/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h
@@ -64,7 +64,7 @@ private:
void SetRunning();
void SetStepping();
- Status CopyWatchpointsFrom(NativeThreadNetBSD& source);
+ llvm::Error CopyWatchpointsFrom(NativeThreadNetBSD& source);
// Member Variables
lldb::StateType m_state;
diff --git a/lldb/source/Plugins/Process/POSIX/CrashReason.cpp b/lldb/source/Plugins/Process/POSIX/CrashReason.cpp
index 579077b45bf9..c6ede61cfe1b 100644
--- a/lldb/source/Plugins/Process/POSIX/CrashReason.cpp
+++ b/lldb/source/Plugins/Process/POSIX/CrashReason.cpp
@@ -58,6 +58,18 @@ CrashReason GetCrashReasonForSIGSEGV(const siginfo_t &info) {
#endif
case SEGV_BNDERR:
return CrashReason::eBoundViolation;
+#ifdef __linux__
+#ifndef SEGV_MTEAERR
+#define SEGV_MTEAERR 8
+#endif
+ case SEGV_MTEAERR:
+ return CrashReason::eAsyncTagCheckFault;
+#ifndef SEGV_MTESERR
+#define SEGV_MTESERR 9
+#endif
+ case SEGV_MTESERR:
+ return CrashReason::eSyncTagCheckFault;
+#endif // __linux__
}
return CrashReason::eInvalidCrashReason;
@@ -166,6 +178,13 @@ std::string GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr) {
case CrashReason::eBoundViolation:
str = "signal SIGSEGV: bound violation";
break;
+ case CrashReason::eAsyncTagCheckFault:
+ str = "signal SIGSEGV: async tag check fault";
+ break;
+ case CrashReason::eSyncTagCheckFault:
+ str = "signal SIGSEGV: sync tag check fault";
+ AppendFaultAddr(str, fault_addr);
+ break;
case CrashReason::eIllegalOpcode:
str = "signal SIGILL: illegal instruction";
break;
@@ -246,6 +265,12 @@ const char *CrashReasonAsString(CrashReason reason) {
case CrashReason::eBoundViolation:
str = "eBoundViolation";
break;
+ case CrashReason::eAsyncTagCheckFault:
+ str = "eAsyncTagCheckFault";
+ break;
+ case CrashReason::eSyncTagCheckFault:
+ str = "eSyncTagCheckFault";
+ break;
// SIGILL crash reasons.
case CrashReason::eIllegalOpcode:
diff --git a/lldb/source/Plugins/Process/POSIX/CrashReason.h b/lldb/source/Plugins/Process/POSIX/CrashReason.h
index 9b4784a1e68e..f5213891d976 100644
--- a/lldb/source/Plugins/Process/POSIX/CrashReason.h
+++ b/lldb/source/Plugins/Process/POSIX/CrashReason.h
@@ -22,6 +22,8 @@ enum class CrashReason {
eInvalidAddress,
ePrivilegedAddress,
eBoundViolation,
+ eAsyncTagCheckFault,
+ eSyncTagCheckFault,
// SIGILL crash reasons.
eIllegalOpcode,
diff --git a/lldb/source/Plugins/Process/Utility/AuxVector.cpp b/lldb/source/Plugins/Process/Utility/AuxVector.cpp
index 685d9d0824f6..c4f45f759a33 100644
--- a/lldb/source/Plugins/Process/Utility/AuxVector.cpp
+++ b/lldb/source/Plugins/Process/Utility/AuxVector.cpp
@@ -82,6 +82,7 @@ const char *AuxVector::GetEntryName(EntryType type) const {
case ENTRY_NAME(AUXV_AT_SECURE); break;
case ENTRY_NAME(AUXV_AT_BASE_PLATFORM); break;
case ENTRY_NAME(AUXV_AT_RANDOM); break;
+ case ENTRY_NAME(AUXV_AT_HWCAP2); break;
case ENTRY_NAME(AUXV_AT_EXECFN); break;
case ENTRY_NAME(AUXV_AT_SYSINFO); break;
case ENTRY_NAME(AUXV_AT_SYSINFO_EHDR); break;
diff --git a/lldb/source/Plugins/Process/Utility/AuxVector.h b/lldb/source/Plugins/Process/Utility/AuxVector.h
index c8c8b1249413..07a0010e198f 100644
--- a/lldb/source/Plugins/Process/Utility/AuxVector.h
+++ b/lldb/source/Plugins/Process/Utility/AuxVector.h
@@ -50,6 +50,7 @@ public:
AUXV_AT_SECURE = 23, ///< Boolean, was exec setuid-like?
AUXV_AT_BASE_PLATFORM = 24, ///< String identifying real platforms.
AUXV_AT_RANDOM = 25, ///< Address of 16 random bytes.
+ AUXV_AT_HWCAP2 = 26, ///< Extension of AT_HWCAP.
AUXV_AT_EXECFN = 31, ///< Filename of executable.
AUXV_AT_SYSINFO = 32, ///< Pointer to the global system page used for system
/// calls and other nice things.
diff --git a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
index 443638aa39f6..5463a071503c 100644
--- a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
+++ b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
@@ -151,10 +151,8 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict,
const uint32_t msbyte = msbit / 8;
const uint32_t lsbyte = lsbit / 8;
- ConstString containing_reg_name(reg_name_str);
-
const RegisterInfo *containing_reg_info =
- GetRegisterInfo(containing_reg_name);
+ GetRegisterInfo(reg_name_str);
if (containing_reg_info) {
const uint32_t max_bit = containing_reg_info->byte_size * 8;
if (msbit < max_bit && lsbit < max_bit) {
@@ -189,7 +187,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict,
}
} else {
printf("error: invalid concrete register \"%s\"\n",
- containing_reg_name.GetCString());
+ reg_name_str.c_str());
}
} else {
printf("error: msbit (%u) must be greater than lsbit (%u)\n",
@@ -217,7 +215,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict,
if (composite_reg_list->GetItemAtIndexAsString(
composite_idx, composite_reg_name, nullptr)) {
const RegisterInfo *composite_reg_info =
- GetRegisterInfo(composite_reg_name);
+ GetRegisterInfo(composite_reg_name.GetStringRef());
if (composite_reg_info) {
composite_offset = std::min(composite_offset,
composite_reg_info->byte_offset);
@@ -357,7 +355,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict,
if (invalidate_reg_list->GetItemAtIndexAsString(
idx, invalidate_reg_name)) {
const RegisterInfo *invalidate_reg_info =
- GetRegisterInfo(invalidate_reg_name);
+ GetRegisterInfo(invalidate_reg_name.GetStringRef());
if (invalidate_reg_info) {
m_invalidate_regs_map[i].push_back(
invalidate_reg_info->kinds[eRegisterKindLLDB]);
@@ -430,9 +428,6 @@ void DynamicRegisterInfo::AddRegister(RegisterInfo &reg_info,
assert(set < m_set_reg_nums.size());
assert(set < m_set_names.size());
m_set_reg_nums[set].push_back(reg_num);
- size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
- if (m_reg_data_byte_size < end_reg_offset)
- m_reg_data_byte_size = end_reg_offset;
}
void DynamicRegisterInfo::Finalize(const ArchSpec &arch) {
@@ -617,8 +612,70 @@ void DynamicRegisterInfo::Finalize(const ArchSpec &arch) {
break;
}
}
+
+ // At this stage call ConfigureOffsets to calculate register offsets for
+ // targets supporting dynamic offset calculation. It also calculates
+ // total byte size of register data.
+ ConfigureOffsets();
+
+ // Check if register info is reconfigurable
+ // AArch64 SVE register set has configurable register sizes
+ if (arch.GetTriple().isAArch64()) {
+ for (const auto &reg : m_regs) {
+ if (strcmp(reg.name, "vg") == 0) {
+ m_is_reconfigurable = true;
+ break;
+ }
+ }
+ }
}
+void DynamicRegisterInfo::ConfigureOffsets() {
+ // We are going to create a map between remote (eRegisterKindProcessPlugin)
+ // and local (eRegisterKindLLDB) register numbers. This map will give us
+ // remote register numbers in increasing order for offset calculation.
+ std::map<uint32_t, uint32_t> remote_to_local_regnum_map;
+ for (const auto &reg : m_regs)
+ remote_to_local_regnum_map[reg.kinds[eRegisterKindProcessPlugin]] =
+ reg.kinds[eRegisterKindLLDB];
+
+ // At this stage we manually calculate g/G packet offsets of all primary
+ // registers, only if target XML or qRegisterInfo packet did not send
+ // an offset explicitly.
+ uint32_t reg_offset = 0;
+ for (auto const &regnum_pair : remote_to_local_regnum_map) {
+ if (m_regs[regnum_pair.second].byte_offset == LLDB_INVALID_INDEX32 &&
+ m_regs[regnum_pair.second].value_regs == nullptr) {
+ m_regs[regnum_pair.second].byte_offset = reg_offset;
+
+ reg_offset = m_regs[regnum_pair.second].byte_offset +
+ m_regs[regnum_pair.second].byte_size;
+ }
+ }
+
+ // Now update all value_regs with each register info as needed
+ for (auto &reg : m_regs) {
+ if (reg.value_regs != nullptr) {
+ // Assign a valid offset to all pseudo registers if not assigned by stub.
+ // Pseudo registers with value_regs list populated will share same offset
+ // as that of their corresponding primary register in value_regs list.
+ if (reg.byte_offset == LLDB_INVALID_INDEX32) {
+ uint32_t value_regnum = reg.value_regs[0];
+ if (value_regnum != LLDB_INVALID_INDEX32)
+ reg.byte_offset =
+ GetRegisterInfoAtIndex(remote_to_local_regnum_map[value_regnum])
+ ->byte_offset;
+ }
+ }
+
+ reg_offset = reg.byte_offset + reg.byte_size;
+ if (m_reg_data_byte_size < reg_offset)
+ m_reg_data_byte_size = reg_offset;
+ }
+}
+
+bool DynamicRegisterInfo::IsReconfigurable() { return m_is_reconfigurable; }
+
size_t DynamicRegisterInfo::GetNumRegisters() const { return m_regs.size(); }
size_t DynamicRegisterInfo::GetNumRegisterSets() const { return m_sets.size(); }
@@ -737,16 +794,10 @@ void DynamicRegisterInfo::Dump() const {
}
}
-const lldb_private::RegisterInfo *DynamicRegisterInfo::GetRegisterInfo(
- lldb_private::ConstString reg_name) const {
- for (auto &reg_info : m_regs) {
- // We can use pointer comparison since we used a ConstString to set the
- // "name" member in AddRegister()
- assert(ConstString(reg_info.name).GetCString() == reg_info.name &&
- "reg_info.name not from a ConstString?");
- if (reg_info.name == reg_name.GetCString()) {
+const lldb_private::RegisterInfo *
+DynamicRegisterInfo::GetRegisterInfo(llvm::StringRef reg_name) const {
+ for (auto &reg_info : m_regs)
+ if (reg_info.name == reg_name)
return &reg_info;
- }
- }
return nullptr;
}
diff --git a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h
index 48939375a504..fbf9db685b71 100644
--- a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h
+++ b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h
@@ -17,6 +17,10 @@
#include "lldb/lldb-private.h"
class DynamicRegisterInfo {
+protected:
+ DynamicRegisterInfo(DynamicRegisterInfo &) = default;
+ DynamicRegisterInfo &operator=(DynamicRegisterInfo &) = default;
+
public:
DynamicRegisterInfo() = default;
@@ -25,9 +29,6 @@ public:
virtual ~DynamicRegisterInfo() = default;
- DynamicRegisterInfo(DynamicRegisterInfo &) = delete;
- void operator=(DynamicRegisterInfo &) = delete;
-
DynamicRegisterInfo(DynamicRegisterInfo &&info);
DynamicRegisterInfo &operator=(DynamicRegisterInfo &&info);
@@ -63,6 +64,11 @@ public:
void Clear();
+ bool IsReconfigurable();
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo(llvm::StringRef reg_name) const;
+
protected:
// Classes that inherit from DynamicRegisterInfo can see and modify these
typedef std::vector<lldb_private::RegisterInfo> reg_collection;
@@ -74,11 +80,10 @@ protected:
typedef std::vector<uint8_t> dwarf_opcode;
typedef std::map<uint32_t, dwarf_opcode> dynamic_reg_size_map;
- const lldb_private::RegisterInfo *
- GetRegisterInfo(lldb_private::ConstString reg_name) const;
-
void MoveFrom(DynamicRegisterInfo &&info);
+ void ConfigureOffsets();
+
reg_collection m_regs;
set_collection m_sets;
set_reg_num_collection m_set_reg_nums;
@@ -89,5 +94,6 @@ protected:
size_t m_reg_data_byte_size = 0u; // The number of bytes required to store
// all registers
bool m_finalized = false;
+ bool m_is_reconfigurable = false;
};
#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_DYNAMICREGISTERINFO_H
diff --git a/lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h b/lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h
new file mode 100644
index 000000000000..7f6f7cf5832d
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h
@@ -0,0 +1,291 @@
+//===-- LinuxPTraceDefines_arm64sve.h ------------------------- -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPTRACEDEFINES_ARM64SVE_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPTRACEDEFINES_ARM64SVE_H
+
+#include <stdint.h>
+
+namespace lldb_private {
+namespace sve {
+
+/*
+ * The SVE architecture leaves space for future expansion of the
+ * vector length beyond its initial architectural limit of 2048 bits
+ * (16 quadwords).
+ *
+ * See <Linux kernel source tree>/Documentation/arm64/sve.rst for a description
+ * of the vl/vq terminology.
+ */
+
+const uint16_t vq_bytes = 16; /* number of bytes per quadword */
+
+const uint16_t vq_min = 1;
+const uint16_t vq_max = 512;
+
+const uint16_t vl_min = vq_min * vq_bytes;
+const uint16_t vl_max = vq_max * vq_bytes;
+
+const uint16_t num_of_zregs = 32;
+const uint16_t num_of_pregs = 16;
+
+inline uint16_t vl_valid(uint16_t vl) {
+ return (vl % vq_bytes == 0 && vl >= vl_min && vl <= vl_max);
+}
+
+inline uint16_t vq_from_vl(uint16_t vl) { return vl / vq_bytes; }
+inline uint16_t vl_from_vq(uint16_t vq) { return vq * vq_bytes; }
+
+/* A new signal frame record sve_context encodes the SVE Registers on signal
+ * delivery. sve_context struct definition may be included in asm/sigcontext.h.
+ * We define sve_context_size which will be used by LLDB sve helper functions.
+ * More information on sve_context can be found in Linux kernel source tree at
+ * Documentation/arm64/sve.rst.
+ */
+
+const uint16_t sve_context_size = 16;
+
+/*
+ * If the SVE registers are currently live for the thread at signal delivery,
+ * sve_context.head.size >=
+ * SigContextSize(vq_from_vl(sve_context.vl))
+ * and the register data may be accessed using the Sig*() functions.
+ *
+ * If sve_context.head.size <
+ * SigContextSize(vq_from_vl(sve_context.vl)),
+ * the SVE registers were not live for the thread and no register data
+ * is included: in this case, the Sig*() functions should not be
+ * used except for this check.
+ *
+ * The same convention applies when returning from a signal: a caller
+ * will need to remove or resize the sve_context block if it wants to
+ * make the SVE registers live when they were previously non-live or
+ * vice-versa. This may require the the caller to allocate fresh
+ * memory and/or move other context blocks in the signal frame.
+ *
+ * Changing the vector length during signal return is not permitted:
+ * sve_context.vl must equal the thread's current vector length when
+ * doing a sigreturn.
+ *
+ *
+ * Note: for all these functions, the "vq" argument denotes the SVE
+ * vector length in quadwords (i.e., units of 128 bits).
+ *
+ * The correct way to obtain vq is to use vq_from_vl(vl). The
+ * result is valid if and only if vl_valid(vl) is true. This is
+ * guaranteed for a struct sve_context written by the kernel.
+ *
+ *
+ * Additional functions describe the contents and layout of the payload.
+ * For each, Sig*Offset(args) is the start offset relative to
+ * the start of struct sve_context, and Sig*Size(args) is the
+ * size in bytes:
+ *
+ * x type description
+ * - ---- -----------
+ * REGS the entire SVE context
+ *
+ * ZREGS __uint128_t[num_of_zregs][vq] all Z-registers
+ * ZREG __uint128_t[vq] individual Z-register Zn
+ *
+ * PREGS uint16_t[num_of_pregs][vq] all P-registers
+ * PREG uint16_t[vq] individual P-register Pn
+ *
+ * FFR uint16_t[vq] first-fault status register
+ *
+ * Additional data might be appended in the future.
+ */
+
+inline uint16_t SigZRegSize(uint16_t vq) { return vq * vq_bytes; }
+inline uint16_t SigPRegSize(uint16_t vq) { return vq * vq_bytes / 8; }
+inline uint16_t SigFFRSize(uint16_t vq) { return SigPRegSize(vq); }
+
+inline uint32_t SigRegsOffset() {
+ return (sve_context_size + vq_bytes - 1) / vq_bytes * vq_bytes;
+}
+
+inline uint32_t SigZRegsOffset() { return SigRegsOffset(); }
+
+inline uint32_t SigZRegOffset(uint16_t vq, uint16_t n) {
+ return SigRegsOffset() + SigZRegSize(vq) * n;
+}
+
+inline uint32_t SigZRegsSize(uint16_t vq) {
+ return SigZRegOffset(vq, num_of_zregs) - SigRegsOffset();
+}
+
+inline uint32_t SigPRegsOffset(uint16_t vq) {
+ return SigRegsOffset() + SigZRegsSize(vq);
+}
+
+inline uint32_t SigPRegOffset(uint16_t vq, uint16_t n) {
+ return SigPRegsOffset(vq) + SigPRegSize(vq) * n;
+}
+
+inline uint32_t SigpRegsSize(uint16_t vq) {
+ return SigPRegOffset(vq, num_of_pregs) - SigPRegsOffset(vq);
+}
+
+inline uint32_t SigFFROffset(uint16_t vq) {
+ return SigPRegsOffset(vq) + SigpRegsSize(vq);
+}
+
+inline uint32_t SigRegsSize(uint16_t vq) {
+ return SigFFROffset(vq) + SigFFRSize(vq) - SigRegsOffset();
+}
+
+inline uint32_t SVESigContextSize(uint16_t vq) {
+ return SigRegsOffset() + SigRegsSize(vq);
+}
+
+struct user_sve_header {
+ uint32_t size; /* total meaningful regset content in bytes */
+ uint32_t max_size; /* maxmium possible size for this thread */
+ uint16_t vl; /* current vector length */
+ uint16_t max_vl; /* maximum possible vector length */
+ uint16_t flags;
+ uint16_t reserved;
+};
+
+/* Definitions for user_sve_header.flags: */
+const uint16_t ptrace_regs_mask = 1 << 0;
+const uint16_t ptrace_regs_fpsimd = 0;
+const uint16_t ptrace_regs_sve = ptrace_regs_mask;
+
+/*
+ * The remainder of the SVE state follows struct user_sve_header. The
+ * total size of the SVE state (including header) depends on the
+ * metadata in the header: PTraceSize(vq, flags) gives the total size
+ * of the state in bytes, including the header.
+ *
+ * Refer to <asm/sigcontext.h> for details of how to pass the correct
+ * "vq" argument to these macros.
+ */
+
+/* Offset from the start of struct user_sve_header to the register data */
+inline uint16_t PTraceRegsOffset() {
+ return (sizeof(struct user_sve_header) + vq_bytes - 1) / vq_bytes * vq_bytes;
+}
+
+/*
+ * The register data content and layout depends on the value of the
+ * flags field.
+ */
+
+/*
+ * (flags & ptrace_regs_mask) == ptrace_regs_fpsimd case:
+ *
+ * The payload starts at offset PTraceFPSIMDOffset, and is of type
+ * struct user_fpsimd_state. Additional data might be appended in the
+ * future: use PTraceFPSIMDSize(vq, flags) to compute the total size.
+ * PTraceFPSIMDSize(vq, flags) will never be less than
+ * sizeof(struct user_fpsimd_state).
+ */
+
+const uint32_t ptrace_fpsimd_offset = PTraceRegsOffset();
+
+/* Return size of struct user_fpsimd_state from asm/ptrace.h */
+inline uint32_t PTraceFPSIMDSize(uint16_t vq, uint16_t flags) { return 528; }
+
+/*
+ * (flags & ptrace_regs_mask) == ptrace_regs_sve case:
+ *
+ * The payload starts at offset PTraceSVEOffset, and is of size
+ * PTraceSVESize(vq, flags).
+ *
+ * Additional functions describe the contents and layout of the payload.
+ * For each, PTrace*X*Offset(args) is the start offset relative to
+ * the start of struct user_sve_header, and PTrace*X*Size(args) is
+ * the size in bytes:
+ *
+ * x type description
+ * - ---- -----------
+ * ZREGS \
+ * ZREG |
+ * PREGS | refer to <asm/sigcontext.h>
+ * PREG |
+ * FFR /
+ *
+ * FPSR uint32_t FPSR
+ * FPCR uint32_t FPCR
+ *
+ * Additional data might be appended in the future.
+ */
+
+inline uint32_t PTraceZRegSize(uint16_t vq) { return SigZRegSize(vq); }
+
+inline uint32_t PTracePRegSize(uint16_t vq) { return SigPRegSize(vq); }
+
+inline uint32_t PTraceFFRSize(uint16_t vq) { return SigFFRSize(vq); }
+
+const uint32_t fpsr_size = sizeof(uint32_t);
+const uint32_t fpcr_size = sizeof(uint32_t);
+
+inline uint32_t SigToPTrace(uint32_t offset) {
+ return offset - SigRegsOffset() + PTraceRegsOffset();
+}
+
+const uint32_t ptrace_sve_offset = PTraceRegsOffset();
+
+inline uint32_t PTraceZRegsOffset(uint16_t vq) {
+ return SigToPTrace(SigZRegsOffset());
+}
+
+inline uint32_t PTraceZRegOffset(uint16_t vq, uint16_t n) {
+ return SigToPTrace(SigZRegOffset(vq, n));
+}
+
+inline uint32_t PTraceZRegsSize(uint16_t vq) {
+ return PTraceZRegOffset(vq, num_of_zregs) - SigToPTrace(SigRegsOffset());
+}
+
+inline uint32_t PTracePRegsOffset(uint16_t vq) {
+ return SigToPTrace(SigPRegsOffset(vq));
+}
+
+inline uint32_t PTracePRegOffset(uint16_t vq, uint16_t n) {
+ return SigToPTrace(SigPRegOffset(vq, n));
+}
+
+inline uint32_t PTracePRegsSize(uint16_t vq) {
+ return PTracePRegOffset(vq, num_of_pregs) - PTracePRegsOffset(vq);
+}
+
+inline uint32_t PTraceFFROffset(uint16_t vq) {
+ return SigToPTrace(SigFFROffset(vq));
+}
+
+inline uint32_t PTraceFPSROffset(uint16_t vq) {
+ return (PTraceFFROffset(vq) + PTraceFFRSize(vq) + (vq_bytes - 1)) / vq_bytes *
+ vq_bytes;
+}
+
+inline uint32_t PTraceFPCROffset(uint16_t vq) {
+ return PTraceFPSROffset(vq) + fpsr_size;
+}
+
+/*
+ * Any future extension appended after FPCR must be aligned to the next
+ * 128-bit boundary.
+ */
+
+inline uint32_t PTraceSVESize(uint16_t vq, uint16_t flags) {
+ return (PTraceFPCROffset(vq) + fpcr_size - ptrace_sve_offset + vq_bytes - 1) /
+ vq_bytes * vq_bytes;
+}
+
+inline uint32_t PTraceSize(uint16_t vq, uint16_t flags) {
+ return (flags & ptrace_regs_mask) == ptrace_regs_sve
+ ? ptrace_sve_offset + PTraceSVESize(vq, flags)
+ : ptrace_fpsimd_offset + PTraceFPSIMDSize(vq, flags);
+}
+
+} // namespace SVE
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPTRACEDEFINES_ARM64SVE_H
diff --git a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
index 0c7d9ddc5ac6..947b970edf6c 100644
--- a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
+++ b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
@@ -7,80 +7,93 @@
//===----------------------------------------------------------------------===//
#include "LinuxProcMaps.h"
-#include "llvm/ADT/StringRef.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StringExtractor.h"
+#include "llvm/ADT/StringRef.h"
using namespace lldb_private;
-static Status
+enum class MapsKind { Maps, SMaps };
+
+static llvm::Expected<MemoryRegionInfo> ProcMapError(const char *msg,
+ MapsKind kind) {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(), msg,
+ kind == MapsKind::Maps ? "maps" : "smaps");
+}
+
+static llvm::Expected<MemoryRegionInfo>
ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line,
- MemoryRegionInfo &memory_region_info) {
- memory_region_info.Clear();
-
+ MapsKind maps_kind) {
+ MemoryRegionInfo region;
StringExtractor line_extractor(maps_line);
-
+
// Format: {address_start_hex}-{address_end_hex} perms offset dev inode
// pathname perms: rwxp (letter is present if set, '-' if not, final
// character is p=private, s=shared).
-
+
// Parse out the starting address
lldb::addr_t start_address = line_extractor.GetHexMaxU64(false, 0);
-
+
// Parse out hyphen separating start and end address from range.
if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != '-'))
- return Status(
- "malformed /proc/{pid}/maps entry, missing dash between address range");
-
+ return ProcMapError(
+ "malformed /proc/{pid}/%s entry, missing dash between address range",
+ maps_kind);
+
// Parse out the ending address
lldb::addr_t end_address = line_extractor.GetHexMaxU64(false, start_address);
-
+
// Parse out the space after the address.
if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != ' '))
- return Status(
- "malformed /proc/{pid}/maps entry, missing space after range");
-
+ return ProcMapError(
+ "malformed /proc/{pid}/%s entry, missing space after range", maps_kind);
+
// Save the range.
- memory_region_info.GetRange().SetRangeBase(start_address);
- memory_region_info.GetRange().SetRangeEnd(end_address);
-
- // Any memory region in /proc/{pid}/maps is by definition mapped into the
- // process.
- memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
-
+ region.GetRange().SetRangeBase(start_address);
+ region.GetRange().SetRangeEnd(end_address);
+
+ // Any memory region in /proc/{pid}/(maps|smaps) is by definition mapped
+ // into the process.
+ region.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
+
// Parse out each permission entry.
if (line_extractor.GetBytesLeft() < 4)
- return Status("malformed /proc/{pid}/maps entry, missing some portion of "
- "permissions");
-
+ return ProcMapError(
+ "malformed /proc/{pid}/%s entry, missing some portion of "
+ "permissions",
+ maps_kind);
+
// Handle read permission.
const char read_perm_char = line_extractor.GetChar();
if (read_perm_char == 'r')
- memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
+ region.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
else if (read_perm_char == '-')
- memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+ region.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
else
- return Status("unexpected /proc/{pid}/maps read permission char");
-
+ return ProcMapError("unexpected /proc/{pid}/%s read permission char",
+ maps_kind);
+
// Handle write permission.
const char write_perm_char = line_extractor.GetChar();
if (write_perm_char == 'w')
- memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
+ region.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
else if (write_perm_char == '-')
- memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+ region.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
else
- return Status("unexpected /proc/{pid}/maps write permission char");
-
+ return ProcMapError("unexpected /proc/{pid}/%s write permission char",
+ maps_kind);
+
// Handle execute permission.
const char exec_perm_char = line_extractor.GetChar();
if (exec_perm_char == 'x')
- memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
+ region.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
else if (exec_perm_char == '-')
- memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+ region.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
else
- return Status("unexpected /proc/{pid}/maps exec permission char");
-
+ return ProcMapError("unexpected /proc/{pid}/%s exec permission char",
+ maps_kind);
+
line_extractor.GetChar(); // Read the private bit
line_extractor.SkipSpaces(); // Skip the separator
line_extractor.GetHexMaxU64(false, 0); // Read the offset
@@ -89,13 +102,13 @@ ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line,
line_extractor.GetHexMaxU64(false, 0); // Read the major device number
line_extractor.SkipSpaces(); // Skip the separator
line_extractor.GetU64(0, 10); // Read the inode number
-
+
line_extractor.SkipSpaces();
const char *name = line_extractor.Peek();
if (name)
- memory_region_info.SetName(name);
-
- return Status();
+ region.SetName(name);
+
+ return region;
}
void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map,
@@ -104,9 +117,80 @@ void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map,
llvm::StringRef line;
while (!lines.empty()) {
std::tie(line, lines) = lines.split('\n');
- MemoryRegionInfo region;
- Status error = ParseMemoryRegionInfoFromProcMapsLine(line, region);
- if (!callback(region, error))
+ if (!callback(ParseMemoryRegionInfoFromProcMapsLine(line, MapsKind::Maps)))
break;
}
}
+
+void lldb_private::ParseLinuxSMapRegions(llvm::StringRef linux_smap,
+ LinuxMapCallback const &callback) {
+ // Entries in /smaps look like:
+ // 00400000-0048a000 r-xp 00000000 fd:03 960637
+ // Size: 552 kB
+ // Rss: 460 kB
+ // <...>
+ // VmFlags: rd ex mr mw me dw
+ // 00500000-0058a000 rwxp 00000000 fd:03 960637
+ // <...>
+ //
+ // Where the first line is identical to the /maps format
+ // and VmFlags is only printed for kernels >= 3.8.
+
+ llvm::StringRef lines(linux_smap);
+ llvm::StringRef line;
+ llvm::Optional<MemoryRegionInfo> region;
+
+ while (lines.size()) {
+ std::tie(line, lines) = lines.split('\n');
+
+ // A property line looks like:
+ // <word>: <value>
+ // (no spaces on the left hand side)
+ // A header will have a ':' but the LHS will contain spaces
+ llvm::StringRef name;
+ llvm::StringRef value;
+ std::tie(name, value) = line.split(':');
+
+ // If this line is a property line
+ if (!name.contains(' ')) {
+ if (region) {
+ if (name == "VmFlags") {
+ if (value.contains("mt"))
+ region->SetMemoryTagged(MemoryRegionInfo::eYes);
+ else
+ region->SetMemoryTagged(MemoryRegionInfo::eNo);
+ }
+ // Ignore anything else
+ } else {
+ // Orphaned settings line
+ callback(ProcMapError(
+ "Found a property line without a corresponding mapping "
+ "in /proc/{pid}/%s",
+ MapsKind::SMaps));
+ return;
+ }
+ } else {
+ // Must be a new region header
+ if (region) {
+ // Save current region
+ callback(*region);
+ region.reset();
+ }
+
+ // Try to start a new region
+ llvm::Expected<MemoryRegionInfo> new_region =
+ ParseMemoryRegionInfoFromProcMapsLine(line, MapsKind::SMaps);
+ if (new_region) {
+ region = *new_region;
+ } else {
+ // Stop at first invalid region header
+ callback(new_region.takeError());
+ return;
+ }
+ }
+ }
+
+ // Catch last region
+ if (region)
+ callback(*region);
+}
diff --git a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h
index 363f248fd416..02f78d55c290 100644
--- a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h
+++ b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h
@@ -11,16 +11,16 @@
#include "lldb/lldb-forward.h"
#include "llvm/ADT/StringRef.h"
-#include <functional>
-
+#include "llvm/Support/Error.h"
namespace lldb_private {
-typedef std::function<bool(const lldb_private::MemoryRegionInfo &,
- const lldb_private::Status &)> LinuxMapCallback;
+typedef std::function<bool(llvm::Expected<MemoryRegionInfo>)> LinuxMapCallback;
void ParseLinuxMapRegions(llvm::StringRef linux_map,
LinuxMapCallback const &callback);
+void ParseLinuxSMapRegions(llvm::StringRef linux_smap,
+ LinuxMapCallback const &callback);
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp
index 4dd619e3bade..d4b0f4039da9 100644
--- a/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp
+++ b/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp
@@ -14,79 +14,72 @@ LinuxSignals::LinuxSignals() : UnixSignals() { Reset(); }
void LinuxSignals::Reset() {
m_signals.clear();
- // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION ALIAS
- // ===== =========== ======== ===== ======
- // ====================================== ======
- AddSignal(1, "SIGHUP", false, true, true, "hangup");
- AddSignal(2, "SIGINT", true, true, true, "interrupt");
- AddSignal(3, "SIGQUIT", false, true, true, "quit");
- AddSignal(4, "SIGILL", false, true, true, "illegal instruction");
- AddSignal(5, "SIGTRAP", true, true, true,
- "trace trap (not reset when caught)");
- AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT");
- AddSignal(7, "SIGBUS", false, true, true, "bus error");
- AddSignal(8, "SIGFPE", false, true, true, "floating point exception");
- AddSignal(9, "SIGKILL", false, true, true, "kill");
- AddSignal(10, "SIGUSR1", false, true, true, "user defined signal 1");
- AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation");
- AddSignal(12, "SIGUSR2", false, true, true, "user defined signal 2");
- AddSignal(13, "SIGPIPE", false, true, true,
- "write to pipe with reading end closed");
- AddSignal(14, "SIGALRM", false, false, false, "alarm");
- AddSignal(15, "SIGTERM", false, true, true, "termination requested");
- AddSignal(16, "SIGSTKFLT", false, true, true, "stack fault");
- AddSignal(17, "SIGCHLD", false, false, true, "child status has changed",
- "SIGCLD");
- AddSignal(18, "SIGCONT", false, true, true, "process continue");
- AddSignal(19, "SIGSTOP", true, true, true, "process stop");
- AddSignal(20, "SIGTSTP", false, true, true, "tty stop");
- AddSignal(21, "SIGTTIN", false, true, true, "background tty read");
- AddSignal(22, "SIGTTOU", false, true, true, "background tty write");
- AddSignal(23, "SIGURG", false, true, true, "urgent data on socket");
- AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded");
- 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(29, "SIGIO", false, true, true, "input/output ready/Pollable event",
- "SIGPOLL");
- AddSignal(30, "SIGPWR", false, true, true, "power failure");
- AddSignal(31, "SIGSYS", false, true, true, "invalid system call");
- AddSignal(32, "SIG32", false, false, false,
- "threading library internal signal 1");
- AddSignal(33, "SIG33", false, false, false,
- "threading library internal signal 2");
- AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0");
- AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1");
- AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2");
- AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3");
- AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4");
- AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5");
- AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6");
- AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7");
- AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8");
- AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9");
- AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10");
- AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11");
- AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12");
- AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13");
- AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14");
- AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15");
- AddSignal(50, "SIGRTMAX-14", false, false, false,
- "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill
- // -l" output
- AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17");
- AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18");
- AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19");
- AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20");
- AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21");
- AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22");
- AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23");
- AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24");
- AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25");
- AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26");
- AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27");
- AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28");
- AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29");
- AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30");
+ // clang-format off
+ // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION
+ // ====== ============== ======== ====== ====== ===================================================
+ AddSignal(1, "SIGHUP", false, true, true, "hangup");
+ AddSignal(2, "SIGINT", true, true, true, "interrupt");
+ AddSignal(3, "SIGQUIT", false, true, true, "quit");
+ AddSignal(4, "SIGILL", false, true, true, "illegal instruction");
+ AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)");
+ AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT");
+ AddSignal(7, "SIGBUS", false, true, true, "bus error");
+ AddSignal(8, "SIGFPE", false, true, true, "floating point exception");
+ AddSignal(9, "SIGKILL", false, true, true, "kill");
+ AddSignal(10, "SIGUSR1", false, true, true, "user defined signal 1");
+ AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation");
+ AddSignal(12, "SIGUSR2", false, true, true, "user defined signal 2");
+ AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed");
+ AddSignal(14, "SIGALRM", false, false, false, "alarm");
+ AddSignal(15, "SIGTERM", false, true, true, "termination requested");
+ AddSignal(16, "SIGSTKFLT", false, true, true, "stack fault");
+ AddSignal(17, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD");
+ AddSignal(18, "SIGCONT", false, false, true, "process continue");
+ AddSignal(19, "SIGSTOP", true, true, true, "process stop");
+ AddSignal(20, "SIGTSTP", false, true, true, "tty stop");
+ AddSignal(21, "SIGTTIN", false, true, true, "background tty read");
+ AddSignal(22, "SIGTTOU", false, true, true, "background tty write");
+ AddSignal(23, "SIGURG", false, true, true, "urgent data on socket");
+ AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded");
+ 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(29, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL");
+ AddSignal(30, "SIGPWR", false, true, true, "power failure");
+ AddSignal(31, "SIGSYS", false, true, true, "invalid system call");
+ AddSignal(32, "SIG32", false, false, false, "threading library internal signal 1");
+ AddSignal(33, "SIG33", false, false, false, "threading library internal signal 2");
+ AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0");
+ AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1");
+ AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2");
+ AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3");
+ AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4");
+ AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5");
+ AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6");
+ AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7");
+ AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8");
+ AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9");
+ AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10");
+ AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11");
+ AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12");
+ AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13");
+ AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14");
+ AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15");
+ AddSignal(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output
+ AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17");
+ AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18");
+ AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19");
+ AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20");
+ AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21");
+ AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22");
+ AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23");
+ AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24");
+ AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25");
+ AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26");
+ AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27");
+ AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28");
+ AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29");
+ AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30");
+ // clang-format on
}
diff --git a/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp b/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp
index 8f75844277c0..fb51c56953f8 100644
--- a/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp
+++ b/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp
@@ -14,79 +14,72 @@ MipsLinuxSignals::MipsLinuxSignals() : UnixSignals() { Reset(); }
void MipsLinuxSignals::Reset() {
m_signals.clear();
- // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION ALIAS
- // ===== =========== ======== ===== ======
- // ====================================== ========
- AddSignal(1, "SIGHUP", false, true, true, "hangup");
- AddSignal(2, "SIGINT", true, true, true, "interrupt");
- AddSignal(3, "SIGQUIT", false, true, true, "quit");
- AddSignal(4, "SIGILL", false, true, true, "illegal instruction");
- AddSignal(5, "SIGTRAP", true, true, true,
- "trace trap (not reset when caught)");
- AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT");
- AddSignal(7, "SIGEMT", false, true, true, "terminate process with core dump");
- AddSignal(8, "SIGFPE", false, true, true, "floating point exception");
- AddSignal(9, "SIGKILL", false, true, true, "kill");
- AddSignal(10, "SIGBUS", false, true, true, "bus error");
- AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation");
- AddSignal(12, "SIGSYS", false, true, true, "invalid system call");
- AddSignal(13, "SIGPIPE", false, true, true,
- "write to pipe with reading end closed");
- AddSignal(14, "SIGALRM", false, false, false, "alarm");
- AddSignal(15, "SIGTERM", false, true, true, "termination requested");
- AddSignal(16, "SIGUSR1", false, true, true, "user defined signal 1");
- AddSignal(17, "SIGUSR2", false, true, true, "user defined signal 2");
- AddSignal(18, "SIGCHLD", false, false, true, "child status has changed",
- "SIGCLD");
- AddSignal(19, "SIGPWR", false, true, true, "power failure");
- AddSignal(20, "SIGWINCH", false, true, true, "window size changes");
- AddSignal(21, "SIGURG", false, true, true, "urgent data on socket");
- AddSignal(22, "SIGIO", false, true, true, "input/output ready/Pollable event",
- "SIGPOLL");
- AddSignal(23, "SIGSTOP", true, true, true, "process stop");
- AddSignal(24, "SIGTSTP", false, true, true, "tty stop");
- AddSignal(25, "SIGCONT", false, true, true, "process continue");
- AddSignal(26, "SIGTTIN", false, true, true, "background tty read");
- AddSignal(27, "SIGTTOU", false, true, true, "background tty write");
- AddSignal(28, "SIGVTALRM", false, true, true, "virtual time alarm");
- AddSignal(29, "SIGPROF", false, false, false, "profiling time alarm");
- AddSignal(30, "SIGXCPU", false, true, true, "CPU resource exceeded");
- AddSignal(31, "SIGXFSZ", false, true, true, "file size limit exceeded");
- AddSignal(32, "SIG32", false, false, false,
- "threading library internal signal 1");
- AddSignal(33, "SIG33", false, false, false,
- "threading library internal signal 2");
- AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0");
- AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1");
- AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2");
- AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3");
- AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4");
- AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5");
- AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6");
- AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7");
- AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8");
- AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9");
- AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10");
- AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11");
- AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12");
- AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13");
- AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14");
- AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15");
- AddSignal(50, "SIGRTMAX-14", false, false, false,
- "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill
- // -l" output
- AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17");
- AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18");
- AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19");
- AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20");
- AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21");
- AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22");
- AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23");
- AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24");
- AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25");
- AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26");
- AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27");
- AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28");
- AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29");
- AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30");
+ // clang-format off
+ // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION
+ // ====== ============== ======== ====== ====== ===================================================
+ AddSignal(1, "SIGHUP", false, true, true, "hangup");
+ AddSignal(2, "SIGINT", true, true, true, "interrupt");
+ AddSignal(3, "SIGQUIT", false, true, true, "quit");
+ AddSignal(4, "SIGILL", false, true, true, "illegal instruction");
+ AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)");
+ AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT");
+ AddSignal(7, "SIGEMT", false, true, true, "terminate process with core dump");
+ AddSignal(8, "SIGFPE", false, true, true, "floating point exception");
+ AddSignal(9, "SIGKILL", false, true, true, "kill");
+ AddSignal(10, "SIGBUS", false, true, true, "bus error");
+ AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation");
+ AddSignal(12, "SIGSYS", false, true, true, "invalid system call");
+ AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed");
+ AddSignal(14, "SIGALRM", false, false, false, "alarm");
+ AddSignal(15, "SIGTERM", false, true, true, "termination requested");
+ AddSignal(16, "SIGUSR1", false, true, true, "user defined signal 1");
+ AddSignal(17, "SIGUSR2", false, true, true, "user defined signal 2");
+ AddSignal(18, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD");
+ AddSignal(19, "SIGPWR", false, true, true, "power failure");
+ AddSignal(20, "SIGWINCH", false, true, true, "window size changes");
+ AddSignal(21, "SIGURG", false, true, true, "urgent data on socket");
+ AddSignal(22, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL");
+ AddSignal(23, "SIGSTOP", true, true, true, "process stop");
+ AddSignal(24, "SIGTSTP", false, true, true, "tty stop");
+ AddSignal(25, "SIGCONT", false, false, true, "process continue");
+ AddSignal(26, "SIGTTIN", false, true, true, "background tty read");
+ AddSignal(27, "SIGTTOU", false, true, true, "background tty write");
+ AddSignal(28, "SIGVTALRM", false, true, true, "virtual time alarm");
+ AddSignal(29, "SIGPROF", false, false, false, "profiling time alarm");
+ AddSignal(30, "SIGXCPU", false, true, true, "CPU resource exceeded");
+ AddSignal(31, "SIGXFSZ", false, true, true, "file size limit exceeded");
+ AddSignal(32, "SIG32", false, false, false, "threading library internal signal 1");
+ AddSignal(33, "SIG33", false, false, false, "threading library internal signal 2");
+ AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0");
+ AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1");
+ AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2");
+ AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3");
+ AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4");
+ AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5");
+ AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6");
+ AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7");
+ AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8");
+ AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9");
+ AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10");
+ AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11");
+ AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12");
+ AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13");
+ AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14");
+ AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15");
+ AddSignal(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output
+ AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17");
+ AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18");
+ AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19");
+ AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20");
+ AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21");
+ AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22");
+ AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23");
+ AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24");
+ AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25");
+ AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26");
+ AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27");
+ AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28");
+ AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29");
+ AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30");
+ // clang-format on
}
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.cpp b/lldb/source/Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.cpp
new file mode 100644
index 000000000000..0f57f2ed3f35
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.cpp
@@ -0,0 +1,278 @@
+//===-- NativeRegisterContextWatchpoint_x86.cpp ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NativeRegisterContextWatchpoint_x86.h"
+
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+using namespace lldb_private;
+
+// Returns mask/value for status bit of wp_index in DR6
+static inline uint64_t GetStatusBit(uint32_t wp_index) {
+ // DR6: ...BBBB
+ // 3210 <- status bits for bp./wp. i; 1 if hit
+ return 1 << wp_index;
+}
+
+// Returns mask/value for global enable bit of wp_index in DR7
+static inline uint64_t GetEnableBit(uint32_t wp_index) {
+ // DR7: ...GLGLGLGL
+ // 33221100 <- global/local enable for bp./wp.; 1 if enabled
+ // we use global bits because NetBSD kernel does not preserve local
+ // bits reliably; Linux seems fine with either
+ return 1 << (2 * wp_index + 1);
+}
+
+// Returns mask for both enable bits of wp_index in DR7
+static inline uint64_t GetBothEnableBitMask(uint32_t wp_index) {
+ // DR7: ...GLGLGLGL
+ // 33221100 <- global/local enable for bp./wp.; 1 if enabled
+ return 3 << (2 * wp_index + 1);
+}
+
+// Returns value for type bits of wp_index in DR7
+static inline uint64_t GetWatchTypeBits(uint32_t watch_flags,
+ uint32_t wp_index) {
+ // DR7:
+ // bit: 3322222222221111...
+ // 1098765432109876...
+ // val: SSTTSSTTSSTTSSTT...
+ // wp.: 3333222211110000...
+ //
+ // where T - type is 01 for write, 11 for r/w
+ return watch_flags << (16 + 4 * wp_index);
+}
+
+// Returns value for size bits of wp_index in DR7
+static inline uint64_t GetWatchSizeBits(uint32_t size, uint32_t wp_index) {
+ // DR7:
+ // bit: 3322222222221111...
+ // 1098765432109876...
+ // val: SSTTSSTTSSTTSSTT...
+ // wp.: 3333222211110000...
+ //
+ // where S - size is:
+ // 00 for 1 byte
+ // 01 for 2 bytes
+ // 10 for 8 bytes
+ // 11 for 4 bytes
+ return (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index);
+}
+
+// Returns bitmask for all bits controlling wp_index in DR7
+static inline uint64_t GetWatchControlBitmask(uint32_t wp_index) {
+ // DR7:
+ // bit: 33222222222211111111110000000000
+ // 10987654321098765432109876543210
+ // val: SSTTSSTTSSTTSSTTxxxxxxGLGLGLGLGL
+ // wp.: 3333222211110000xxxxxxEE33221100
+ return GetBothEnableBitMask(wp_index) | (0xF << (16 + 4 * wp_index));
+}
+
+// Bit mask for control bits regarding all watchpoints.
+static constexpr uint64_t watchpoint_all_control_bit_mask = 0xFFFF00FF;
+
+const RegisterInfo *NativeRegisterContextWatchpoint_x86::GetDR(int num) const {
+ assert(num >= 0 && num <= 7);
+ switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {
+ case llvm::Triple::x86:
+ return GetRegisterInfoAtIndex(lldb_dr0_i386 + num);
+ case llvm::Triple::x86_64:
+ return GetRegisterInfoAtIndex(lldb_dr0_x86_64 + num);
+ default:
+ llvm_unreachable("Unhandled target architecture.");
+ }
+}
+
+Status NativeRegisterContextWatchpoint_x86::IsWatchpointHit(uint32_t wp_index,
+ bool &is_hit) {
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Status("Watchpoint index out of range");
+
+ RegisterValue dr6;
+ Status error = ReadRegister(GetDR(6), dr6);
+ if (error.Fail())
+ is_hit = false;
+ else
+ is_hit = dr6.GetAsUInt64() & GetStatusBit(wp_index);
+
+ return error;
+}
+
+Status NativeRegisterContextWatchpoint_x86::GetWatchpointHitIndex(
+ uint32_t &wp_index, lldb::addr_t trap_addr) {
+ uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
+ for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {
+ bool is_hit;
+ Status error = IsWatchpointHit(wp_index, is_hit);
+ if (error.Fail()) {
+ wp_index = LLDB_INVALID_INDEX32;
+ return error;
+ } else if (is_hit) {
+ return error;
+ }
+ }
+ wp_index = LLDB_INVALID_INDEX32;
+ return Status();
+}
+
+Status
+NativeRegisterContextWatchpoint_x86::IsWatchpointVacant(uint32_t wp_index,
+ bool &is_vacant) {
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Status("Watchpoint index out of range");
+
+ RegisterValue dr7;
+ Status error = ReadRegister(GetDR(7), dr7);
+ if (error.Fail())
+ is_vacant = false;
+ else
+ is_vacant = !(dr7.GetAsUInt64() & GetEnableBit(wp_index));
+
+ return error;
+}
+
+Status NativeRegisterContextWatchpoint_x86::SetHardwareWatchpointWithIndex(
+ lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {
+
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Status("Watchpoint index out of range");
+
+ // Read only watchpoints aren't supported on x86_64. Fall back to read/write
+ // waitchpoints instead.
+ // TODO: Add logic to detect when a write happens and ignore that watchpoint
+ // hit.
+ if (watch_flags == 2)
+ watch_flags = 3;
+
+ if (watch_flags != 1 && watch_flags != 3)
+ return Status("Invalid read/write bits for watchpoint");
+ if (size != 1 && size != 2 && size != 4 && size != 8)
+ return Status("Invalid size for watchpoint");
+
+ bool is_vacant;
+ Status error = IsWatchpointVacant(wp_index, is_vacant);
+ if (error.Fail())
+ return error;
+ if (!is_vacant)
+ return Status("Watchpoint index not vacant");
+
+ RegisterValue dr7, drN;
+ error = ReadRegister(GetDR(7), dr7);
+ if (error.Fail())
+ return error;
+ error = ReadRegister(GetDR(wp_index), drN);
+ if (error.Fail())
+ return error;
+
+ uint64_t control_bits = dr7.GetAsUInt64() & ~GetWatchControlBitmask(wp_index);
+ control_bits |= GetEnableBit(wp_index) |
+ GetWatchTypeBits(watch_flags, wp_index) |
+ GetWatchSizeBits(size, wp_index);
+
+ // Clear dr6 if address or bits changed (i.e. we're not reenabling the same
+ // watchpoint). This can not be done when clearing watchpoints since
+ // the gdb-remote protocol repeatedly clears and readds watchpoints on all
+ // program threads, effectively clearing pending events on NetBSD.
+ // NB: enable bits in dr7 are always 0 here since we're (re)adding it
+ if (drN.GetAsUInt64() != addr ||
+ (dr7.GetAsUInt64() & GetWatchControlBitmask(wp_index)) !=
+ (GetWatchTypeBits(watch_flags, wp_index) |
+ GetWatchSizeBits(size, wp_index))) {
+ ClearWatchpointHit(wp_index);
+
+ // We skip update to drN if neither address nor mode changed.
+ error = WriteRegister(GetDR(wp_index), RegisterValue(addr));
+ if (error.Fail())
+ return error;
+ }
+
+ error = WriteRegister(GetDR(7), RegisterValue(control_bits));
+ if (error.Fail())
+ return error;
+
+ return error;
+}
+
+bool NativeRegisterContextWatchpoint_x86::ClearHardwareWatchpoint(
+ uint32_t wp_index) {
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return false;
+
+ RegisterValue dr7;
+ Status error = ReadRegister(GetDR(7), dr7);
+ if (error.Fail())
+ return false;
+
+ return WriteRegister(GetDR(7), RegisterValue(dr7.GetAsUInt64() &
+ ~GetBothEnableBitMask(wp_index)))
+ .Success();
+}
+
+Status
+NativeRegisterContextWatchpoint_x86::ClearWatchpointHit(uint32_t wp_index) {
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return Status("Watchpoint index out of range");
+
+ RegisterValue dr6;
+ Status error = ReadRegister(GetDR(6), dr6);
+ if (error.Fail())
+ return error;
+
+ return WriteRegister(
+ GetDR(6), RegisterValue(dr6.GetAsUInt64() & ~GetStatusBit(wp_index)));
+}
+
+Status NativeRegisterContextWatchpoint_x86::ClearAllHardwareWatchpoints() {
+ RegisterValue dr7;
+ Status error = ReadRegister(GetDR(7), dr7);
+ if (error.Fail())
+ return error;
+ return WriteRegister(
+ GetDR(7),
+ RegisterValue(dr7.GetAsUInt64() & ~watchpoint_all_control_bit_mask));
+}
+
+uint32_t NativeRegisterContextWatchpoint_x86::SetHardwareWatchpoint(
+ lldb::addr_t addr, size_t size, uint32_t watch_flags) {
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+ for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) {
+ bool is_vacant;
+ Status error = IsWatchpointVacant(wp_index, is_vacant);
+ if (is_vacant) {
+ error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index);
+ if (error.Success())
+ return wp_index;
+ }
+ if (error.Fail() && log) {
+ LLDB_LOGF(log, "NativeRegisterContextWatchpoint_x86::%s Error: %s",
+ __FUNCTION__, error.AsCString());
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+lldb::addr_t
+NativeRegisterContextWatchpoint_x86::GetWatchpointAddress(uint32_t wp_index) {
+ if (wp_index >= NumSupportedHardwareWatchpoints())
+ return LLDB_INVALID_ADDRESS;
+ RegisterValue drN;
+ if (ReadRegister(GetDR(wp_index), drN).Fail())
+ return LLDB_INVALID_ADDRESS;
+ return drN.GetAsUInt64();
+}
+
+uint32_t
+NativeRegisterContextWatchpoint_x86::NumSupportedHardwareWatchpoints() {
+ // Available debug address registers: dr0, dr1, dr2, dr3
+ return 4;
+}
diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.h
new file mode 100644
index 000000000000..cfb8900a4fd2
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextWatchpoint_x86.h
@@ -0,0 +1,48 @@
+//===-- NativeRegisterContextWatchpoint_x86.h -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_NativeRegisterContextWatchpoint_x86_h
+#define lldb_NativeRegisterContextWatchpoint_x86_h
+
+#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
+
+namespace lldb_private {
+
+class NativeRegisterContextWatchpoint_x86
+ : public virtual NativeRegisterContextRegisterInfo {
+public:
+ Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override;
+
+ Status GetWatchpointHitIndex(uint32_t &wp_index,
+ lldb::addr_t trap_addr) override;
+
+ Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override;
+
+ bool ClearHardwareWatchpoint(uint32_t wp_index) override;
+
+ Status ClearWatchpointHit(uint32_t wp_index) override;
+
+ Status ClearAllHardwareWatchpoints() override;
+
+ Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags,
+ uint32_t wp_index);
+
+ uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
+ uint32_t watch_flags) override;
+
+ lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;
+
+ uint32_t NumSupportedHardwareWatchpoints() override;
+
+ const RegisterInfo *GetDR(int num) const;
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef lldb_NativeRegisterContextWatchpoint_x86_h
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
index 10d346a3cb7e..acebe9d53568 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
@@ -35,7 +35,7 @@ struct GPR {
uint32_t gs;
};
-struct dbreg {
+struct DBG {
uint32_t dr[8]; /* debug registers */
/* Index 0-3: debug address registers */
/* Index 4-5: reserved */
@@ -48,10 +48,13 @@ using FPR_i386 = FXSAVE;
struct UserArea {
GPR gpr;
FPR_i386 i387;
+ DBG dbg;
};
#define DR_SIZE sizeof(uint32_t)
-#define DR_OFFSET(reg_index) (LLVM_EXTENSION offsetof(dbreg, dr[reg_index]))
+#define DR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, dbg) + \
+ LLVM_EXTENSION offsetof(DBG, dr[reg_index]))
// Include RegisterInfos_i386 to declare our g_register_infos_i386 structure.
#define DECLARE_REGISTER_INFOS_I386_STRUCT
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
index c1f390ade9b9..e0f3971c6e27 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
@@ -59,7 +59,9 @@ struct UserArea {
DBG dbg;
};
-#define DR_OFFSET(reg_index) (LLVM_EXTENSION offsetof(DBG, dr[reg_index]))
+#define DR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, dbg) + \
+ LLVM_EXTENSION offsetof(DBG, dr[reg_index]))
// Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64
// structure.
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h b/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h
index e7c180dbdd27..1ceca65c97c3 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h
@@ -19,21 +19,21 @@ public:
virtual ~RegisterContextMach_arm();
protected:
- virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr);
+ int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override;
- int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu);
+ int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override;
- int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc);
+ int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override;
- int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg);
+ int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override;
- int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr);
+ int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override;
- int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu);
+ int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override;
- int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc);
+ int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override;
- int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg);
+ int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override;
};
#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_ARM_H
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h b/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h
index 09966be60c92..da5411eb2de2 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h
@@ -19,17 +19,17 @@ public:
virtual ~RegisterContextMach_i386();
protected:
- virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr);
+ int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override;
- int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu);
+ int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override;
- int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc);
+ int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override;
- int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr);
+ int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override;
- int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu);
+ int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override;
- int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc);
+ int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override;
};
#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_I386_H
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h b/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h
index 2a8a2cca2f8a..c131c8282bd2 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h
@@ -20,17 +20,17 @@ public:
virtual ~RegisterContextMach_x86_64();
protected:
- virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr);
+ int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override;
- int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu);
+ int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override;
- int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc);
+ int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override;
- int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr);
+ int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override;
- int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu);
+ int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override;
- int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc);
+ int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override;
};
#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_X86_64_H
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp
index 617893b6b3b0..97a760396ba9 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp
@@ -25,88 +25,25 @@
using namespace lldb;
using namespace lldb_private;
-// arm general purpose registers.
-const uint32_t g_gpr_regnums_arm[] = {
- gpr_r0_arm, gpr_r1_arm, gpr_r2_arm, gpr_r3_arm, gpr_r4_arm,
- gpr_r5_arm, gpr_r6_arm, gpr_r7_arm, gpr_r8_arm, gpr_r9_arm,
- gpr_r10_arm, gpr_r11_arm, gpr_r12_arm, gpr_sp_arm, gpr_lr_arm,
- gpr_pc_arm, gpr_cpsr_arm,
- LLDB_INVALID_REGNUM // register sets need to end with this flag
-
-};
-static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) ==
- k_num_gpr_registers_arm,
- "g_gpr_regnums_arm has wrong number of register infos");
-
-// arm floating point registers.
-static const uint32_t g_fpu_regnums_arm[] = {
- fpu_s0_arm, fpu_s1_arm, fpu_s2_arm, fpu_s3_arm, fpu_s4_arm,
- fpu_s5_arm, fpu_s6_arm, fpu_s7_arm, fpu_s8_arm, fpu_s9_arm,
- fpu_s10_arm, fpu_s11_arm, fpu_s12_arm, fpu_s13_arm, fpu_s14_arm,
- fpu_s15_arm, fpu_s16_arm, fpu_s17_arm, fpu_s18_arm, fpu_s19_arm,
- fpu_s20_arm, fpu_s21_arm, fpu_s22_arm, fpu_s23_arm, fpu_s24_arm,
- fpu_s25_arm, fpu_s26_arm, fpu_s27_arm, fpu_s28_arm, fpu_s29_arm,
- fpu_s30_arm, fpu_s31_arm, fpu_fpscr_arm, fpu_d0_arm, fpu_d1_arm,
- fpu_d2_arm, fpu_d3_arm, fpu_d4_arm, fpu_d5_arm, fpu_d6_arm,
- fpu_d7_arm, fpu_d8_arm, fpu_d9_arm, fpu_d10_arm, fpu_d11_arm,
- fpu_d12_arm, fpu_d13_arm, fpu_d14_arm, fpu_d15_arm, fpu_d16_arm,
- fpu_d17_arm, fpu_d18_arm, fpu_d19_arm, fpu_d20_arm, fpu_d21_arm,
- fpu_d22_arm, fpu_d23_arm, fpu_d24_arm, fpu_d25_arm, fpu_d26_arm,
- fpu_d27_arm, fpu_d28_arm, fpu_d29_arm, fpu_d30_arm, fpu_d31_arm,
- fpu_q0_arm, fpu_q1_arm, fpu_q2_arm, fpu_q3_arm, fpu_q4_arm,
- fpu_q5_arm, fpu_q6_arm, fpu_q7_arm, fpu_q8_arm, fpu_q9_arm,
- fpu_q10_arm, fpu_q11_arm, fpu_q12_arm, fpu_q13_arm, fpu_q14_arm,
- fpu_q15_arm,
- LLDB_INVALID_REGNUM // register sets need to end with this flag
-
-};
-static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) ==
- k_num_fpr_registers_arm,
- "g_fpu_regnums_arm has wrong number of register infos");
-
-// Number of register sets provided by this context.
-enum { k_num_register_sets = 2 };
-
-// Register sets for arm.
-static const lldb_private::RegisterSet g_reg_sets_arm[k_num_register_sets] = {
- {"General Purpose Registers", "gpr", k_num_gpr_registers_arm,
- g_gpr_regnums_arm},
- {"Floating Point Registers", "fpu", k_num_fpr_registers_arm,
- g_fpu_regnums_arm}};
-
bool RegisterContextPOSIX_arm::IsGPR(unsigned reg) {
- return reg <= m_reg_info.last_gpr; // GPR's come first.
+ if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) ==
+ RegisterInfoPOSIX_arm::GPRegSet)
+ return true;
+ return false;
}
bool RegisterContextPOSIX_arm::IsFPR(unsigned reg) {
- return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
+ if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) ==
+ RegisterInfoPOSIX_arm::FPRegSet)
+ return true;
+ return false;
}
RegisterContextPOSIX_arm::RegisterContextPOSIX_arm(
- lldb_private::Thread &thread, uint32_t concrete_frame_idx,
- lldb_private::RegisterInfoInterface *register_info)
- : lldb_private::RegisterContext(thread, concrete_frame_idx) {
- m_register_info_up.reset(register_info);
-
- switch (register_info->m_target_arch.GetMachine()) {
- case llvm::Triple::arm:
- m_reg_info.num_registers = k_num_registers_arm;
- m_reg_info.num_gpr_registers = k_num_gpr_registers_arm;
- m_reg_info.num_fpr_registers = k_num_fpr_registers_arm;
- m_reg_info.last_gpr = k_last_gpr_arm;
- m_reg_info.first_fpr = k_first_fpr_arm;
- m_reg_info.last_fpr = k_last_fpr_arm;
- m_reg_info.first_fpr_v = fpu_s0_arm;
- m_reg_info.last_fpr_v = fpu_s31_arm;
- m_reg_info.gpr_flags = gpr_cpsr_arm;
- break;
- default:
- assert(false && "Unhandled target architecture.");
- break;
- }
-
- ::memset(&m_fpr, 0, sizeof m_fpr);
-}
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_arm> register_info)
+ : lldb_private::RegisterContext(thread, 0),
+ m_register_info_up(std::move(register_info)) {}
RegisterContextPOSIX_arm::~RegisterContextPOSIX_arm() {}
@@ -115,19 +52,15 @@ void RegisterContextPOSIX_arm::Invalidate() {}
void RegisterContextPOSIX_arm::InvalidateAllRegisters() {}
unsigned RegisterContextPOSIX_arm::GetRegisterOffset(unsigned reg) {
- assert(reg < m_reg_info.num_registers && "Invalid register number.");
- return GetRegisterInfo()[reg].byte_offset;
+ return m_register_info_up->GetRegisterInfo()[reg].byte_offset;
}
unsigned RegisterContextPOSIX_arm::GetRegisterSize(unsigned reg) {
- assert(reg < m_reg_info.num_registers && "Invalid register number.");
- return GetRegisterInfo()[reg].byte_size;
+ return m_register_info_up->GetRegisterInfo()[reg].byte_size;
}
size_t RegisterContextPOSIX_arm::GetRegisterCount() {
- size_t num_registers =
- m_reg_info.num_gpr_registers + m_reg_info.num_fpr_registers;
- return num_registers;
+ return m_register_info_up->GetRegisterCount();
}
size_t RegisterContextPOSIX_arm::GetGPRSize() {
@@ -143,41 +76,23 @@ const lldb_private::RegisterInfo *RegisterContextPOSIX_arm::GetRegisterInfo() {
const lldb_private::RegisterInfo *
RegisterContextPOSIX_arm::GetRegisterInfoAtIndex(size_t reg) {
- if (reg < m_reg_info.num_registers)
+ if (reg < GetRegisterCount())
return &GetRegisterInfo()[reg];
- else
- return nullptr;
+
+ return nullptr;
}
size_t RegisterContextPOSIX_arm::GetRegisterSetCount() {
- size_t sets = 0;
- for (size_t set = 0; set < k_num_register_sets; ++set) {
- if (IsRegisterSetAvailable(set))
- ++sets;
- }
-
- return sets;
+ return m_register_info_up->GetRegisterSetCount();
}
const lldb_private::RegisterSet *
RegisterContextPOSIX_arm::GetRegisterSet(size_t set) {
- if (IsRegisterSetAvailable(set)) {
- switch (m_register_info_up->m_target_arch.GetMachine()) {
- case llvm::Triple::arm:
- return &g_reg_sets_arm[set];
- default:
- assert(false && "Unhandled target architecture.");
- return nullptr;
- }
- }
- return nullptr;
+ return m_register_info_up->GetRegisterSet(set);
}
const char *RegisterContextPOSIX_arm::GetRegisterName(unsigned reg) {
- assert(reg < m_reg_info.num_registers && "Invalid register offset.");
- return GetRegisterInfo()[reg].name;
-}
-
-bool RegisterContextPOSIX_arm::IsRegisterSetAvailable(size_t set_index) {
- return set_index < k_num_register_sets;
+ if (reg < GetRegisterCount())
+ return GetRegisterInfo()[reg].name;
+ return nullptr;
}
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h
index d6967f05ed48..099c37d46f49 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h
@@ -10,17 +10,15 @@
#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_ARM_H
#include "RegisterInfoInterface.h"
-#include "lldb-arm-register-enums.h"
+#include "RegisterInfoPOSIX_arm.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Utility/Log.h"
-class ProcessMonitor;
-
class RegisterContextPOSIX_arm : public lldb_private::RegisterContext {
public:
- RegisterContextPOSIX_arm(lldb_private::Thread &thread,
- uint32_t concrete_frame_idx,
- lldb_private::RegisterInfoInterface *register_info);
+ RegisterContextPOSIX_arm(
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_arm> register_info);
~RegisterContextPOSIX_arm() override;
@@ -45,46 +43,7 @@ public:
const char *GetRegisterName(unsigned reg);
protected:
- struct RegInfo {
- uint32_t num_registers;
- uint32_t num_gpr_registers;
- uint32_t num_fpr_registers;
-
- uint32_t last_gpr;
- uint32_t first_fpr;
- uint32_t last_fpr;
-
- uint32_t first_fpr_v;
- uint32_t last_fpr_v;
-
- uint32_t gpr_flags;
- };
-
- struct QReg {
- uint8_t bytes[16];
- };
-
- struct FPU {
- union {
- uint32_t s[32];
- uint64_t d[32];
- QReg q[16]; // the 128-bit NEON registers
- } floats;
- uint32_t fpscr;
- };
-
- uint32_t m_gpr_arm[lldb_private::k_num_gpr_registers_arm]; // 32-bit general
- // purpose
- // registers.
- RegInfo m_reg_info;
- struct RegisterContextPOSIX_arm::FPU
- m_fpr; // floating-point registers including extended register sets.
- std::unique_ptr<lldb_private::RegisterInfoInterface>
- m_register_info_up; // Register Info Interface (FreeBSD or Linux)
-
- // Determines if an extended register set is supported on the processor
- // running the inferior process.
- virtual bool IsRegisterSetAvailable(size_t set_index);
+ std::unique_ptr<RegisterInfoPOSIX_arm> m_register_info_up;
virtual const lldb_private::RegisterInfo *GetRegisterInfo();
@@ -92,6 +51,8 @@ protected:
bool IsFPR(unsigned reg);
+ size_t GetFPUSize() { return sizeof(RegisterInfoPOSIX_arm::FPU); }
+
virtual bool ReadGPR() = 0;
virtual bool ReadFPR() = 0;
virtual bool WriteGPR() = 0;
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
index 8ef587f13e3a..3f52501c35f3 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
@@ -39,14 +39,18 @@ bool RegisterContextPOSIX_arm64::IsFPR(unsigned reg) {
return false;
}
+bool RegisterContextPOSIX_arm64::IsSVE(unsigned reg) const {
+ if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) ==
+ RegisterInfoPOSIX_arm64::SVERegSet)
+ return true;
+ return false;
+}
+
RegisterContextPOSIX_arm64::RegisterContextPOSIX_arm64(
lldb_private::Thread &thread,
std::unique_ptr<RegisterInfoPOSIX_arm64> register_info)
: lldb_private::RegisterContext(thread, 0),
- m_register_info_up(std::move(register_info)) {
-
- ::memset(&m_fpr, 0, sizeof m_fpr);
-}
+ m_register_info_up(std::move(register_info)) {}
RegisterContextPOSIX_arm64::~RegisterContextPOSIX_arm64() {}
@@ -82,8 +86,8 @@ const lldb_private::RegisterInfo *
RegisterContextPOSIX_arm64::GetRegisterInfoAtIndex(size_t reg) {
if (reg < GetRegisterCount())
return &GetRegisterInfo()[reg];
- else
- return nullptr;
+
+ return nullptr;
}
size_t RegisterContextPOSIX_arm64::GetRegisterSetCount() {
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
index c2d5aee7f73c..a3f07bb2823b 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
@@ -11,12 +11,9 @@
#include "RegisterInfoInterface.h"
#include "RegisterInfoPOSIX_arm64.h"
-#include "lldb-arm64-register-enums.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Utility/Log.h"
-class ProcessMonitor;
-
class RegisterContextPOSIX_arm64 : public lldb_private::RegisterContext {
public:
RegisterContextPOSIX_arm64(
@@ -46,13 +43,6 @@ public:
const char *GetRegisterName(unsigned reg);
protected:
- uint64_t m_gpr_arm64[lldb_private::k_num_gpr_registers_arm64]; // 64-bit
- // general
- // purpose
- // registers.
-
- struct RegisterInfoPOSIX_arm64::FPU
- m_fpr; // floating-point registers including extended register sets.
std::unique_ptr<RegisterInfoPOSIX_arm64> m_register_info_up;
virtual const lldb_private::RegisterInfo *GetRegisterInfo();
@@ -63,6 +53,23 @@ protected:
size_t GetFPUSize() { return sizeof(RegisterInfoPOSIX_arm64::FPU); }
+ bool IsSVE(unsigned reg) const;
+
+ bool IsSVEZ(unsigned reg) const { return m_register_info_up->IsSVEZReg(reg); }
+ bool IsSVEP(unsigned reg) const { return m_register_info_up->IsSVEPReg(reg); }
+ bool IsSVEVG(unsigned reg) const {
+ return m_register_info_up->IsSVERegVG(reg);
+ }
+
+ uint32_t GetRegNumSVEZ0() const {
+ return m_register_info_up->GetRegNumSVEZ0();
+ }
+ uint32_t GetRegNumSVEFFR() const {
+ return m_register_info_up->GetRegNumSVEFFR();
+ }
+ uint32_t GetRegNumFPCR() const { return m_register_info_up->GetRegNumFPCR(); }
+ uint32_t GetRegNumFPSR() const { return m_register_info_up->GetRegNumFPSR(); }
+
virtual bool ReadGPR() = 0;
virtual bool ReadFPR() = 0;
virtual bool WriteGPR() = 0;
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h
index 1843a2a6aff3..b66dc3f44524 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h
@@ -14,10 +14,6 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Utility/Log.h"
-using namespace lldb_private;
-
-class ProcessMonitor;
-
class RegisterContextPOSIX_mips64 : public lldb_private::RegisterContext {
public:
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h
index e2c33461c8f1..5dd8c890da6e 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h
@@ -14,8 +14,6 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Utility/Log.h"
-class ProcessMonitor;
-
// Internal codes for all powerpc registers.
enum {
k_first_gpr_powerpc,
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h
index 7df732d13ffa..7027af04f0bb 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h
@@ -15,8 +15,6 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Utility/Log.h"
-class ProcessMonitor;
-
class RegisterContextPOSIX_s390x : public lldb_private::RegisterContext {
public:
RegisterContextPOSIX_s390x(
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp
index ac271a90d6a1..2c7f63503d7c 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp
@@ -119,20 +119,21 @@ static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) -
"g_gpr_regnums_x86_64 has wrong number of register infos");
static const uint32_t g_lldb_regnums_x86_64[] = {
- lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64,
- lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64,
- lldb_foseg_x86_64, lldb_fooff_x86_64, lldb_mxcsr_x86_64,
- lldb_mxcsrmask_x86_64, lldb_st0_x86_64, lldb_st1_x86_64,
- lldb_st2_x86_64, lldb_st3_x86_64, lldb_st4_x86_64,
- lldb_st5_x86_64, lldb_st6_x86_64, lldb_st7_x86_64,
- lldb_mm0_x86_64, lldb_mm1_x86_64, lldb_mm2_x86_64,
- lldb_mm3_x86_64, lldb_mm4_x86_64, lldb_mm5_x86_64,
- lldb_mm6_x86_64, lldb_mm7_x86_64, lldb_xmm0_x86_64,
- lldb_xmm1_x86_64, lldb_xmm2_x86_64, lldb_xmm3_x86_64,
- lldb_xmm4_x86_64, lldb_xmm5_x86_64, lldb_xmm6_x86_64,
- lldb_xmm7_x86_64, lldb_xmm8_x86_64, lldb_xmm9_x86_64,
- lldb_xmm10_x86_64, lldb_xmm11_x86_64, lldb_xmm12_x86_64,
- lldb_xmm13_x86_64, lldb_xmm14_x86_64, lldb_xmm15_x86_64,
+ lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64,
+ lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64,
+ lldb_fip_x86_64, lldb_foseg_x86_64, lldb_fooff_x86_64,
+ lldb_fdp_x86_64, lldb_mxcsr_x86_64, lldb_mxcsrmask_x86_64,
+ lldb_st0_x86_64, lldb_st1_x86_64, lldb_st2_x86_64,
+ lldb_st3_x86_64, lldb_st4_x86_64, lldb_st5_x86_64,
+ lldb_st6_x86_64, lldb_st7_x86_64, lldb_mm0_x86_64,
+ lldb_mm1_x86_64, lldb_mm2_x86_64, lldb_mm3_x86_64,
+ lldb_mm4_x86_64, lldb_mm5_x86_64, lldb_mm6_x86_64,
+ lldb_mm7_x86_64, lldb_xmm0_x86_64, lldb_xmm1_x86_64,
+ lldb_xmm2_x86_64, lldb_xmm3_x86_64, lldb_xmm4_x86_64,
+ lldb_xmm5_x86_64, lldb_xmm6_x86_64, lldb_xmm7_x86_64,
+ lldb_xmm8_x86_64, lldb_xmm9_x86_64, lldb_xmm10_x86_64,
+ lldb_xmm11_x86_64, lldb_xmm12_x86_64, lldb_xmm13_x86_64,
+ lldb_xmm14_x86_64, lldb_xmm15_x86_64,
LLDB_INVALID_REGNUM // Register sets must be terminated with
// LLDB_INVALID_REGNUM.
};
@@ -275,6 +276,84 @@ uint32_t RegisterContextPOSIX_x86::g_invalidate_r15[] = {
lldb_r15_x86_64, lldb_r15d_x86_64, lldb_r15w_x86_64, lldb_r15l_x86_64,
LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_fip[] = {lldb_fip_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_fdp[] = {lldb_fdp_x86_64,
+ LLDB_INVALID_REGNUM};
+
+uint32_t RegisterContextPOSIX_x86::g_invalidate_fip[] = {
+ lldb_fip_x86_64, lldb_fioff_x86_64, lldb_fiseg_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_fdp[] = {
+ lldb_fdp_x86_64, lldb_fooff_x86_64, lldb_foseg_x86_64, LLDB_INVALID_REGNUM};
+
+uint32_t RegisterContextPOSIX_x86::g_contained_st0_32[] = {lldb_st0_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st1_32[] = {lldb_st1_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st2_32[] = {lldb_st2_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st3_32[] = {lldb_st3_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st4_32[] = {lldb_st4_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st5_32[] = {lldb_st5_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st6_32[] = {lldb_st6_i386,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st7_32[] = {lldb_st7_i386,
+ LLDB_INVALID_REGNUM};
+
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st0_32[] = {
+ lldb_st0_i386, lldb_mm0_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st1_32[] = {
+ lldb_st1_i386, lldb_mm1_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st2_32[] = {
+ lldb_st2_i386, lldb_mm2_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st3_32[] = {
+ lldb_st3_i386, lldb_mm3_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st4_32[] = {
+ lldb_st4_i386, lldb_mm4_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st5_32[] = {
+ lldb_st5_i386, lldb_mm5_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st6_32[] = {
+ lldb_st6_i386, lldb_mm6_i386, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st7_32[] = {
+ lldb_st7_i386, lldb_mm7_i386, LLDB_INVALID_REGNUM};
+
+uint32_t RegisterContextPOSIX_x86::g_contained_st0_64[] = {lldb_st0_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st1_64[] = {lldb_st1_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st2_64[] = {lldb_st2_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st3_64[] = {lldb_st3_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st4_64[] = {lldb_st4_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st5_64[] = {lldb_st5_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st6_64[] = {lldb_st6_x86_64,
+ LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_contained_st7_64[] = {lldb_st7_x86_64,
+ LLDB_INVALID_REGNUM};
+
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st0_64[] = {
+ lldb_st0_x86_64, lldb_mm0_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st1_64[] = {
+ lldb_st1_x86_64, lldb_mm1_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st2_64[] = {
+ lldb_st2_x86_64, lldb_mm2_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st3_64[] = {
+ lldb_st3_x86_64, lldb_mm3_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st4_64[] = {
+ lldb_st4_x86_64, lldb_mm4_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st5_64[] = {
+ lldb_st5_x86_64, lldb_mm5_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st6_64[] = {
+ lldb_st6_x86_64, lldb_mm6_x86_64, LLDB_INVALID_REGNUM};
+uint32_t RegisterContextPOSIX_x86::g_invalidate_st7_64[] = {
+ lldb_st7_x86_64, lldb_mm7_x86_64, LLDB_INVALID_REGNUM};
+
// Number of register sets provided by this context.
enum { k_num_extended_register_sets = 1, k_num_register_sets = 3 };
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h
index c4886ae618a2..d6672835b4a8 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h
@@ -15,8 +15,6 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Utility/Log.h"
-class ProcessMonitor;
-
class RegisterContextPOSIX_x86 : public lldb_private::RegisterContext {
public:
RegisterContextPOSIX_x86(lldb_private::Thread &thread,
@@ -108,6 +106,48 @@ public:
static uint32_t g_invalidate_r14[];
static uint32_t g_invalidate_r15[];
+ static uint32_t g_contained_fip[];
+ static uint32_t g_contained_fdp[];
+
+ static uint32_t g_invalidate_fip[];
+ static uint32_t g_invalidate_fdp[];
+
+ static uint32_t g_contained_st0_32[];
+ static uint32_t g_contained_st1_32[];
+ static uint32_t g_contained_st2_32[];
+ static uint32_t g_contained_st3_32[];
+ static uint32_t g_contained_st4_32[];
+ static uint32_t g_contained_st5_32[];
+ static uint32_t g_contained_st6_32[];
+ static uint32_t g_contained_st7_32[];
+
+ static uint32_t g_invalidate_st0_32[];
+ static uint32_t g_invalidate_st1_32[];
+ static uint32_t g_invalidate_st2_32[];
+ static uint32_t g_invalidate_st3_32[];
+ static uint32_t g_invalidate_st4_32[];
+ static uint32_t g_invalidate_st5_32[];
+ static uint32_t g_invalidate_st6_32[];
+ static uint32_t g_invalidate_st7_32[];
+
+ static uint32_t g_contained_st0_64[];
+ static uint32_t g_contained_st1_64[];
+ static uint32_t g_contained_st2_64[];
+ static uint32_t g_contained_st3_64[];
+ static uint32_t g_contained_st4_64[];
+ static uint32_t g_contained_st5_64[];
+ static uint32_t g_contained_st6_64[];
+ static uint32_t g_contained_st7_64[];
+
+ static uint32_t g_invalidate_st0_64[];
+ static uint32_t g_invalidate_st1_64[];
+ static uint32_t g_invalidate_st2_64[];
+ static uint32_t g_invalidate_st3_64[];
+ static uint32_t g_invalidate_st4_64[];
+ static uint32_t g_invalidate_st5_64[];
+ static uint32_t g_invalidate_st6_64[];
+ static uint32_t g_invalidate_st7_64[];
+
protected:
struct RegInfo {
uint32_t num_registers;
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContext_x86.cpp b/lldb/source/Plugins/Process/Utility/RegisterContext_x86.cpp
new file mode 100644
index 000000000000..b21c72bd9621
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/RegisterContext_x86.cpp
@@ -0,0 +1,58 @@
+//===-- RegisterContext_x86.cpp ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContext_x86.h"
+
+using namespace lldb_private;
+
+// Convert the 8-bit abridged FPU Tag Word (as found in FXSAVE) to the full
+// 16-bit FPU Tag Word (as found in FSAVE, and used by gdb protocol). This
+// requires knowing the values of the ST(i) registers and the FPU Status Word.
+uint16_t lldb_private::AbridgedToFullTagWord(uint8_t abridged_tw, uint16_t sw,
+ llvm::ArrayRef<MMSReg> st_regs) {
+ // Tag word is using internal FPU register numbering rather than ST(i).
+ // Mapping to ST(i): i = FPU regno - TOP (Status Word, bits 11:13).
+ // Here we start with FPU reg 7 and go down.
+ int st = 7 - ((sw >> 11) & 7);
+ uint16_t tw = 0;
+ for (uint8_t mask = 0x80; mask != 0; mask >>= 1) {
+ tw <<= 2;
+ if (abridged_tw & mask) {
+ // The register is non-empty, so we need to check the value of ST(i).
+ uint16_t exp =
+ st_regs[st].comp.sign_exp & 0x7fff; // Discard the sign bit.
+ if (exp == 0) {
+ if (st_regs[st].comp.mantissa == 0)
+ tw |= 1; // Zero
+ else
+ tw |= 2; // Denormal
+ } else if (exp == 0x7fff)
+ tw |= 2; // Infinity or NaN
+ // 0 if normal number
+ } else
+ tw |= 3; // Empty register
+
+ // Rotate ST down.
+ st = (st - 1) & 7;
+ }
+
+ return tw;
+}
+
+// Convert the 16-bit FPU Tag Word to the abridged 8-bit value, to be written
+// into FXSAVE.
+uint8_t lldb_private::FullToAbridgedTagWord(uint16_t tw) {
+ uint8_t abridged_tw = 0;
+ for (uint16_t mask = 0xc000; mask != 0; mask >>= 2) {
+ abridged_tw <<= 1;
+ // full TW uses 11 for empty registers, aTW uses 0
+ if ((tw & mask) != mask)
+ abridged_tw |= 1;
+ }
+ return abridged_tw;
+}
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h b/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h
index 27a1bad4d53f..76e004ce0ceb 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h
@@ -12,6 +12,7 @@
#include <cstddef>
#include <cstdint>
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitmaskEnum.h"
#include "llvm/Support/Compiler.h"
@@ -239,10 +240,23 @@ enum {
// Generic floating-point registers
+LLVM_PACKED_START
+struct MMSRegComp {
+ uint64_t mantissa;
+ uint16_t sign_exp;
+};
+
struct MMSReg {
- uint8_t bytes[10];
+ union {
+ uint8_t bytes[10];
+ MMSRegComp comp;
+ };
uint8_t pad[6];
};
+LLVM_PACKED_END
+
+static_assert(sizeof(MMSRegComp) == 10, "MMSRegComp is not 10 bytes of size");
+static_assert(sizeof(MMSReg) == 16, "MMSReg is not 16 bytes of size");
struct XMMReg {
uint8_t bytes[16]; // 128-bits for each XMM register
@@ -369,6 +383,10 @@ inline void YMMToXState(const YMMReg& input, void* xmm_bytes, void* ymmh_bytes)
::memcpy(ymmh_bytes, input.bytes + sizeof(XMMReg), sizeof(YMMHReg));
}
+uint16_t AbridgedToFullTagWord(uint8_t abridged_tw, uint16_t sw,
+ llvm::ArrayRef<MMSReg> st_regs);
+uint8_t FullToAbridgedTagWord(uint16_t tw);
+
} // namespace lldb_private
#endif
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp
index 8fc4d5282b06..17b96f944cda 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp
@@ -71,9 +71,87 @@ GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) {
}
}
+// Number of register sets provided by this context.
+enum {
+ k_num_gpr_registers = gpr_cpsr - gpr_r0 + 1,
+ k_num_fpr_registers = fpu_q15 - fpu_s0 + 1,
+ k_num_register_sets = 2
+};
+
+// arm general purpose registers.
+static const uint32_t g_gpr_regnums_arm[] = {
+ gpr_r0, gpr_r1,
+ gpr_r2, gpr_r3,
+ gpr_r4, gpr_r5,
+ gpr_r6, gpr_r7,
+ gpr_r8, gpr_r9,
+ gpr_r10, gpr_r11,
+ gpr_r12, gpr_sp,
+ gpr_lr, gpr_pc,
+ gpr_cpsr, LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) ==
+ k_num_gpr_registers,
+ "g_gpr_regnums_arm has wrong number of register infos");
+
+// arm floating point registers.
+static const uint32_t g_fpu_regnums_arm[] = {
+ fpu_s0, fpu_s1,
+ fpu_s2, fpu_s3,
+ fpu_s4, fpu_s5,
+ fpu_s6, fpu_s7,
+ fpu_s8, fpu_s9,
+ fpu_s10, fpu_s11,
+ fpu_s12, fpu_s13,
+ fpu_s14, fpu_s15,
+ fpu_s16, fpu_s17,
+ fpu_s18, fpu_s19,
+ fpu_s20, fpu_s21,
+ fpu_s22, fpu_s23,
+ fpu_s24, fpu_s25,
+ fpu_s26, fpu_s27,
+ fpu_s28, fpu_s29,
+ fpu_s30, fpu_s31,
+ fpu_fpscr, fpu_d0,
+ fpu_d1, fpu_d2,
+ fpu_d3, fpu_d4,
+ fpu_d5, fpu_d6,
+ fpu_d7, fpu_d8,
+ fpu_d9, fpu_d10,
+ fpu_d11, fpu_d12,
+ fpu_d13, fpu_d14,
+ fpu_d15, fpu_d16,
+ fpu_d17, fpu_d18,
+ fpu_d19, fpu_d20,
+ fpu_d21, fpu_d22,
+ fpu_d23, fpu_d24,
+ fpu_d25, fpu_d26,
+ fpu_d27, fpu_d28,
+ fpu_d29, fpu_d30,
+ fpu_d31, fpu_q0,
+ fpu_q1, fpu_q2,
+ fpu_q3, fpu_q4,
+ fpu_q5, fpu_q6,
+ fpu_q7, fpu_q8,
+ fpu_q9, fpu_q10,
+ fpu_q11, fpu_q12,
+ fpu_q13, fpu_q14,
+ fpu_q15, LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) ==
+ k_num_fpr_registers,
+ "g_fpu_regnums_arm has wrong number of register infos");
+
+// Register sets for arm.
+static const RegisterSet g_reg_sets_arm[k_num_register_sets] = {
+ {"General Purpose Registers", "gpr", k_num_gpr_registers,
+ g_gpr_regnums_arm},
+ {"Floating Point Registers", "fpu", k_num_fpr_registers,
+ g_fpu_regnums_arm}};
+
RegisterInfoPOSIX_arm::RegisterInfoPOSIX_arm(
const lldb_private::ArchSpec &target_arch)
- : lldb_private::RegisterInfoInterface(target_arch),
+ : lldb_private::RegisterInfoAndSetInterface(target_arch),
m_register_info_p(GetRegisterInfoPtr(target_arch)),
m_register_info_count(GetRegisterInfoCount(target_arch)) {}
@@ -81,11 +159,35 @@ size_t RegisterInfoPOSIX_arm::GetGPRSize() const {
return sizeof(struct RegisterInfoPOSIX_arm::GPR);
}
+size_t RegisterInfoPOSIX_arm::GetFPRSize() const {
+ return sizeof(struct RegisterInfoPOSIX_arm::FPU);
+}
+
const lldb_private::RegisterInfo *
RegisterInfoPOSIX_arm::GetRegisterInfo() const {
return m_register_info_p;
}
+size_t RegisterInfoPOSIX_arm::GetRegisterSetCount() const {
+ return k_num_register_sets;
+}
+
+size_t RegisterInfoPOSIX_arm::GetRegisterSetFromRegisterIndex(
+ uint32_t reg_index) const {
+ if (reg_index <= gpr_cpsr)
+ return GPRegSet;
+ if (reg_index <= fpu_q15)
+ return FPRegSet;
+ return LLDB_INVALID_REGNUM;
+}
+
+const lldb_private::RegisterSet *
+RegisterInfoPOSIX_arm::GetRegisterSet(size_t set_index) const {
+ if (set_index < GetRegisterSetCount())
+ return &g_reg_sets_arm[set_index];
+ return nullptr;
+}
+
uint32_t RegisterInfoPOSIX_arm::GetRegisterCount() const {
return m_register_info_count;
}
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h
index 1cf896e3decf..db155d757ca8 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h
@@ -9,12 +9,14 @@
#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM_H
#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM_H
-#include "RegisterInfoInterface.h"
+#include "RegisterInfoAndSetInterface.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/lldb-private.h"
-class RegisterInfoPOSIX_arm : public lldb_private::RegisterInfoInterface {
+class RegisterInfoPOSIX_arm : public lldb_private::RegisterInfoAndSetInterface {
public:
+ enum { GPRegSet = 0, FPRegSet};
+
struct GPR {
uint32_t r[16]; // R0-R15
uint32_t cpsr; // CPSR
@@ -49,10 +51,19 @@ public:
size_t GetGPRSize() const override;
+ size_t GetFPRSize() const override;
+
const lldb_private::RegisterInfo *GetRegisterInfo() const override;
uint32_t GetRegisterCount() const override;
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t reg_set) const override;
+
+ size_t GetRegisterSetCount() const override;
+
+ size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override;
+
private:
const lldb_private::RegisterInfo *m_register_info_p;
uint32_t m_register_info_count;
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
index 4537cee42ad9..515c9f44e1e2 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
@@ -25,6 +25,24 @@
(LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::FPU, reg) + \
sizeof(RegisterInfoPOSIX_arm64::GPR))
+// This information is based on AArch64 with SVE architecture reference manual.
+// AArch64 with SVE has 32 Z and 16 P vector registers. There is also an FFR
+// (First Fault) register and a VG (Vector Granule) pseudo register.
+
+// SVE 16-byte quad word is the basic unit of expansion in vector length.
+#define SVE_QUAD_WORD_BYTES 16
+
+// Vector length is the multiplier which decides the no of quad words,
+// (multiples of 128-bits or 16-bytes) present in a Z register. Vector length
+// is decided during execution and can change at runtime. SVE AArch64 register
+// infos have modes one for each valid value of vector length. A change in
+// vector length requires register context to update sizes of SVE Z, P and FFR.
+// Also register context needs to update byte offsets of all registers affected
+// by the change in vector length.
+#define SVE_REGS_DEFAULT_OFFSET_LINUX sizeof(RegisterInfoPOSIX_arm64::GPR)
+
+#define SVE_OFFSET_VG SVE_REGS_DEFAULT_OFFSET_LINUX
+
#define EXC_OFFSET_NAME(reg) \
(LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::EXC, reg) + \
sizeof(RegisterInfoPOSIX_arm64::GPR) + \
@@ -51,6 +69,7 @@
// Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure.
#define DECLARE_REGISTER_INFOS_ARM64_STRUCT
#include "RegisterInfos_arm64.h"
+#include "RegisterInfos_arm64_sve.h"
#undef DECLARE_REGISTER_INFOS_ARM64_STRUCT
static const lldb_private::RegisterInfo *
@@ -69,7 +88,8 @@ GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
enum {
k_num_gpr_registers = gpr_w28 - gpr_x0 + 1,
k_num_fpr_registers = fpu_fpcr - fpu_v0 + 1,
- k_num_register_sets = 2
+ k_num_sve_registers = sve_ffr - sve_vg + 1,
+ k_num_register_sets = 3
};
// ARM64 general purpose registers.
@@ -133,13 +153,38 @@ static const uint32_t g_fpu_regnums_arm64[] = {
static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) -
1) == k_num_fpr_registers,
"g_fpu_regnums_arm64 has wrong number of register infos");
-// clang-format on
+
+// ARM64 SVE registers.
+static const uint32_t g_sve_regnums_arm64[] = {
+ sve_vg, sve_z0, sve_z1,
+ sve_z2, sve_z3, sve_z4,
+ sve_z5, sve_z6, sve_z7,
+ sve_z8, sve_z9, sve_z10,
+ sve_z11, sve_z12, sve_z13,
+ sve_z14, sve_z15, sve_z16,
+ sve_z17, sve_z18, sve_z19,
+ sve_z20, sve_z21, sve_z22,
+ sve_z23, sve_z24, sve_z25,
+ sve_z26, sve_z27, sve_z28,
+ sve_z29, sve_z30, sve_z31,
+ sve_p0, sve_p1, sve_p2,
+ sve_p3, sve_p4, sve_p5,
+ sve_p6, sve_p7, sve_p8,
+ sve_p9, sve_p10, sve_p11,
+ sve_p12, sve_p13, sve_p14,
+ sve_p15, sve_ffr, LLDB_INVALID_REGNUM};
+static_assert(((sizeof g_sve_regnums_arm64 / sizeof g_sve_regnums_arm64[0]) -
+ 1) == k_num_sve_registers,
+ "g_sve_regnums_arm64 has wrong number of register infos");
+
// Register sets for ARM64.
static const lldb_private::RegisterSet g_reg_sets_arm64[k_num_register_sets] = {
{"General Purpose Registers", "gpr", k_num_gpr_registers,
g_gpr_regnums_arm64},
{"Floating Point Registers", "fpu", k_num_fpr_registers,
- g_fpu_regnums_arm64}};
+ g_fpu_regnums_arm64},
+ {"Scalable Vector Extension Registers", "sve", k_num_sve_registers,
+ g_sve_regnums_arm64}};
static uint32_t
GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) {
@@ -159,25 +204,13 @@ RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64(
: lldb_private::RegisterInfoAndSetInterface(target_arch),
m_register_info_p(GetRegisterInfoPtr(target_arch)),
m_register_info_count(GetRegisterInfoCount(target_arch)) {
-
- switch (target_arch.GetMachine()) {
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_32:
- num_registers = k_num_gpr_registers + k_num_fpr_registers;
- num_gpr_registers = k_num_gpr_registers;
- num_fpr_registers = k_num_fpr_registers;
- last_gpr = gpr_w28;
- first_fpr = fpu_v0;
- last_fpr = fpu_fpcr;
- break;
- default:
- assert(false && "Unhandled target architecture.");
- break;
- }
}
uint32_t RegisterInfoPOSIX_arm64::GetRegisterCount() const {
- return num_gpr_registers + num_fpr_registers;
+ if (IsSVEEnabled())
+ return k_num_gpr_registers + k_num_fpr_registers + k_num_sve_registers;
+
+ return k_num_gpr_registers + k_num_fpr_registers;
}
size_t RegisterInfoPOSIX_arm64::GetGPRSize() const {
@@ -194,22 +227,120 @@ RegisterInfoPOSIX_arm64::GetRegisterInfo() const {
}
size_t RegisterInfoPOSIX_arm64::GetRegisterSetCount() const {
- return k_num_register_sets;
+ if (IsSVEEnabled())
+ return k_num_register_sets;
+ return k_num_register_sets - 1;
}
size_t RegisterInfoPOSIX_arm64::GetRegisterSetFromRegisterIndex(
uint32_t reg_index) const {
- if (reg_index <= last_gpr)
+ if (reg_index <= gpr_w28)
return GPRegSet;
- else if (reg_index <= last_fpr)
+ if (reg_index <= fpu_fpcr)
return FPRegSet;
+ if (reg_index <= sve_ffr)
+ return SVERegSet;
return LLDB_INVALID_REGNUM;
}
const lldb_private::RegisterSet *
RegisterInfoPOSIX_arm64::GetRegisterSet(size_t set_index) const {
- if (set_index < k_num_register_sets)
+ if (set_index < GetRegisterSetCount())
return &g_reg_sets_arm64[set_index];
-
return nullptr;
}
+
+uint32_t
+RegisterInfoPOSIX_arm64::ConfigureVectorRegisterInfos(uint32_t sve_vq) {
+ // sve_vq contains SVE Quad vector length in context of AArch64 SVE.
+ // SVE register infos if enabled cannot be disabled by selecting sve_vq = 0.
+ // Also if an invalid or previously set vector length is passed to this
+ // function then it will exit immediately with previously set vector length.
+ if (!VectorSizeIsValid(sve_vq) || m_vector_reg_vq == sve_vq)
+ return m_vector_reg_vq;
+
+ // We cannot enable AArch64 only mode if SVE was enabled.
+ if (sve_vq == eVectorQuadwordAArch64 &&
+ m_vector_reg_vq > eVectorQuadwordAArch64)
+ sve_vq = eVectorQuadwordAArch64SVE;
+
+ m_vector_reg_vq = sve_vq;
+
+ if (sve_vq == eVectorQuadwordAArch64) {
+ m_register_info_count =
+ static_cast<uint32_t>(sizeof(g_register_infos_arm64_le) /
+ sizeof(g_register_infos_arm64_le[0]));
+ m_register_info_p = g_register_infos_arm64_le;
+
+ return m_vector_reg_vq;
+ }
+
+ m_register_info_count =
+ static_cast<uint32_t>(sizeof(g_register_infos_arm64_sve_le) /
+ sizeof(g_register_infos_arm64_sve_le[0]));
+
+ std::vector<lldb_private::RegisterInfo> &reg_info_ref =
+ m_per_vq_reg_infos[sve_vq];
+
+ if (reg_info_ref.empty()) {
+ reg_info_ref = llvm::makeArrayRef(g_register_infos_arm64_sve_le,
+ m_register_info_count);
+
+ uint32_t offset = SVE_REGS_DEFAULT_OFFSET_LINUX;
+
+ reg_info_ref[fpu_fpsr].byte_offset = offset;
+ reg_info_ref[fpu_fpcr].byte_offset = offset + 4;
+ reg_info_ref[sve_vg].byte_offset = offset + 8;
+ offset += 16;
+
+ // Update Z registers size and offset
+ uint32_t s_reg_base = fpu_s0;
+ uint32_t d_reg_base = fpu_d0;
+ uint32_t v_reg_base = fpu_v0;
+ uint32_t z_reg_base = sve_z0;
+
+ for (uint32_t index = 0; index < 32; index++) {
+ reg_info_ref[s_reg_base + index].byte_offset = offset;
+ reg_info_ref[d_reg_base + index].byte_offset = offset;
+ reg_info_ref[v_reg_base + index].byte_offset = offset;
+ reg_info_ref[z_reg_base + index].byte_offset = offset;
+
+ reg_info_ref[z_reg_base + index].byte_size = sve_vq * SVE_QUAD_WORD_BYTES;
+ offset += reg_info_ref[z_reg_base + index].byte_size;
+ }
+
+ // Update P registers and FFR size and offset
+ for (uint32_t it = sve_p0; it <= sve_ffr; it++) {
+ reg_info_ref[it].byte_offset = offset;
+ reg_info_ref[it].byte_size = sve_vq * SVE_QUAD_WORD_BYTES / 8;
+ offset += reg_info_ref[it].byte_size;
+ }
+
+ m_per_vq_reg_infos[sve_vq] = reg_info_ref;
+ }
+
+ m_register_info_p = reg_info_ref.data();
+ return m_vector_reg_vq;
+}
+
+bool RegisterInfoPOSIX_arm64::IsSVEZReg(unsigned reg) const {
+ return (sve_z0 <= reg && reg <= sve_z31);
+}
+
+bool RegisterInfoPOSIX_arm64::IsSVEPReg(unsigned reg) const {
+ return (sve_p0 <= reg && reg <= sve_p15);
+}
+
+bool RegisterInfoPOSIX_arm64::IsSVERegVG(unsigned reg) const {
+ return sve_vg == reg;
+}
+
+uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEZ0() const { return sve_z0; }
+
+uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEFFR() const { return sve_ffr; }
+
+uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPCR() const { return fpu_fpcr; }
+
+uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPSR() const { return fpu_fpsr; }
+
+uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEVG() const { return sve_vg; }
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h
index 2da6a531a6b6..2929f2009dd9 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h
@@ -12,13 +12,24 @@
#include "RegisterInfoAndSetInterface.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/lldb-private.h"
+#include <map>
+
+enum class SVEState { Unknown, Disabled, FPSIMD, Full };
class RegisterInfoPOSIX_arm64
: public lldb_private::RegisterInfoAndSetInterface {
public:
- enum { GPRegSet = 0, FPRegSet };
+ enum { GPRegSet = 0, FPRegSet, SVERegSet };
+
+ // AArch64 Register set FP/SIMD feature configuration
+ enum {
+ eVectorQuadwordAArch64,
+ eVectorQuadwordAArch64SVE,
+ eVectorQuadwordAArch64SVEMax = 256
+ };
// based on RegisterContextDarwin_arm64.h
+ LLVM_PACKED_START
struct GPR {
uint64_t x[29]; // x0-x28
uint64_t fp; // x29
@@ -27,6 +38,7 @@ public:
uint64_t pc; // pc
uint32_t cpsr; // cpsr
};
+ LLVM_PACKED_END
// based on RegisterContextDarwin_arm64.h
struct VReg {
@@ -73,14 +85,33 @@ public:
size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override;
+ uint32_t ConfigureVectorRegisterInfos(uint32_t sve_vq);
+
+ bool VectorSizeIsValid(uint32_t vq) {
+ if (vq >= eVectorQuadwordAArch64 && vq <= eVectorQuadwordAArch64SVEMax)
+ return true;
+ return false;
+ }
+
+ bool IsSVEEnabled() const { return m_vector_reg_vq > eVectorQuadwordAArch64; }
+
+ bool IsSVEZReg(unsigned reg) const;
+ bool IsSVEPReg(unsigned reg) const;
+ bool IsSVERegVG(unsigned reg) const;
+
+ uint32_t GetRegNumSVEZ0() const;
+ uint32_t GetRegNumSVEFFR() const;
+ uint32_t GetRegNumFPCR() const;
+ uint32_t GetRegNumFPSR() const;
+ uint32_t GetRegNumSVEVG() const;
+
private:
- uint32_t num_registers;
- uint32_t num_gpr_registers;
- uint32_t num_fpr_registers;
+ typedef std::map<uint32_t, std::vector<lldb_private::RegisterInfo>>
+ per_vq_register_infos;
+
+ per_vq_register_infos m_per_vq_reg_infos;
- uint32_t last_gpr;
- uint32_t first_fpr;
- uint32_t last_fpr;
+ uint32_t m_vector_reg_vq = eVectorQuadwordAArch64;
const lldb_private::RegisterInfo *m_register_info_p;
uint32_t m_register_info_count;
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h
new file mode 100644
index 000000000000..9551db7e8ebf
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h
@@ -0,0 +1,572 @@
+//===-- RegisterInfos_arm64_sve.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef DECLARE_REGISTER_INFOS_ARM64_STRUCT
+
+enum {
+ sve_vg = exc_far,
+
+ sve_z0,
+ sve_z1,
+ sve_z2,
+ sve_z3,
+ sve_z4,
+ sve_z5,
+ sve_z6,
+ sve_z7,
+ sve_z8,
+ sve_z9,
+ sve_z10,
+ sve_z11,
+ sve_z12,
+ sve_z13,
+ sve_z14,
+ sve_z15,
+ sve_z16,
+ sve_z17,
+ sve_z18,
+ sve_z19,
+ sve_z20,
+ sve_z21,
+ sve_z22,
+ sve_z23,
+ sve_z24,
+ sve_z25,
+ sve_z26,
+ sve_z27,
+ sve_z28,
+ sve_z29,
+ sve_z30,
+ sve_z31,
+
+ sve_p0,
+ sve_p1,
+ sve_p2,
+ sve_p3,
+ sve_p4,
+ sve_p5,
+ sve_p6,
+ sve_p7,
+ sve_p8,
+ sve_p9,
+ sve_p10,
+ sve_p11,
+ sve_p12,
+ sve_p13,
+ sve_p14,
+ sve_p15,
+
+ sve_ffr,
+};
+
+#ifndef SVE_OFFSET_VG
+#error SVE_OFFSET_VG must be defined before including this header file
+#endif
+
+static uint32_t g_sve_s0_invalidates[] = {sve_z0, fpu_v0, fpu_d0,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s1_invalidates[] = {sve_z1, fpu_v1, fpu_d1,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s2_invalidates[] = {sve_z2, fpu_v2, fpu_d2,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s3_invalidates[] = {sve_z3, fpu_v3, fpu_d3,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s4_invalidates[] = {sve_z4, fpu_v4, fpu_d4,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s5_invalidates[] = {sve_z5, fpu_v5, fpu_d5,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s6_invalidates[] = {sve_z6, fpu_v6, fpu_d6,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s7_invalidates[] = {sve_z7, fpu_v7, fpu_d7,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s8_invalidates[] = {sve_z8, fpu_v8, fpu_d8,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s9_invalidates[] = {sve_z9, fpu_v9, fpu_d9,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s10_invalidates[] = {sve_z10, fpu_v10, fpu_d10,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s11_invalidates[] = {sve_z11, fpu_v11, fpu_d11,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s12_invalidates[] = {sve_z12, fpu_v12, fpu_d12,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s13_invalidates[] = {sve_z13, fpu_v13, fpu_d13,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s14_invalidates[] = {sve_z14, fpu_v14, fpu_d14,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s15_invalidates[] = {sve_z15, fpu_v15, fpu_d15,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s16_invalidates[] = {sve_z16, fpu_v16, fpu_d16,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s17_invalidates[] = {sve_z17, fpu_v17, fpu_d17,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s18_invalidates[] = {sve_z18, fpu_v18, fpu_d18,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s19_invalidates[] = {sve_z19, fpu_v19, fpu_d19,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s20_invalidates[] = {sve_z20, fpu_v20, fpu_d20,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s21_invalidates[] = {sve_z21, fpu_v21, fpu_d21,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s22_invalidates[] = {sve_z22, fpu_v22, fpu_d22,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s23_invalidates[] = {sve_z23, fpu_v23, fpu_d23,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s24_invalidates[] = {sve_z24, fpu_v24, fpu_d24,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s25_invalidates[] = {sve_z25, fpu_v25, fpu_d25,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s26_invalidates[] = {sve_z26, fpu_v26, fpu_d26,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s27_invalidates[] = {sve_z27, fpu_v27, fpu_d27,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s28_invalidates[] = {sve_z28, fpu_v28, fpu_d28,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s29_invalidates[] = {sve_z29, fpu_v29, fpu_d29,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s30_invalidates[] = {sve_z30, fpu_v30, fpu_d30,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_s31_invalidates[] = {sve_z31, fpu_v31, fpu_d31,
+ LLDB_INVALID_REGNUM};
+
+static uint32_t g_sve_d0_invalidates[] = {sve_z0, fpu_v0, fpu_s0,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d1_invalidates[] = {sve_z1, fpu_v1, fpu_s1,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d2_invalidates[] = {sve_z2, fpu_v2, fpu_s2,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d3_invalidates[] = {sve_z3, fpu_v3, fpu_s3,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d4_invalidates[] = {sve_z4, fpu_v4, fpu_s4,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d5_invalidates[] = {sve_z5, fpu_v5, fpu_s5,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d6_invalidates[] = {sve_z6, fpu_v6, fpu_s6,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d7_invalidates[] = {sve_z7, fpu_v7, fpu_s7,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d8_invalidates[] = {sve_z8, fpu_v8, fpu_s8,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d9_invalidates[] = {sve_z9, fpu_v9, fpu_s9,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d10_invalidates[] = {sve_z10, fpu_v10, fpu_s10,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d11_invalidates[] = {sve_z11, fpu_v11, fpu_s11,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d12_invalidates[] = {sve_z12, fpu_v12, fpu_s12,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d13_invalidates[] = {sve_z13, fpu_v13, fpu_s13,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d14_invalidates[] = {sve_z14, fpu_v14, fpu_s14,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d15_invalidates[] = {sve_z15, fpu_v15, fpu_s15,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d16_invalidates[] = {sve_z16, fpu_v16, fpu_s16,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d17_invalidates[] = {sve_z17, fpu_v17, fpu_s17,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d18_invalidates[] = {sve_z18, fpu_v18, fpu_s18,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d19_invalidates[] = {sve_z19, fpu_v19, fpu_s19,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d20_invalidates[] = {sve_z20, fpu_v20, fpu_s20,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d21_invalidates[] = {sve_z21, fpu_v21, fpu_s21,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d22_invalidates[] = {sve_z22, fpu_v22, fpu_s22,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d23_invalidates[] = {sve_z23, fpu_v23, fpu_s23,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d24_invalidates[] = {sve_z24, fpu_v24, fpu_s24,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d25_invalidates[] = {sve_z25, fpu_v25, fpu_s25,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d26_invalidates[] = {sve_z26, fpu_v26, fpu_s26,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d27_invalidates[] = {sve_z27, fpu_v27, fpu_s27,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d28_invalidates[] = {sve_z28, fpu_v28, fpu_s28,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d29_invalidates[] = {sve_z29, fpu_v29, fpu_s29,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d30_invalidates[] = {sve_z30, fpu_v30, fpu_s30,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_d31_invalidates[] = {sve_z31, fpu_v31, fpu_s31,
+ LLDB_INVALID_REGNUM};
+
+static uint32_t g_sve_v0_invalidates[] = {sve_z0, fpu_d0, fpu_s0,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v1_invalidates[] = {sve_z1, fpu_d1, fpu_s1,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v2_invalidates[] = {sve_z2, fpu_d2, fpu_s2,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v3_invalidates[] = {sve_z3, fpu_d3, fpu_s3,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v4_invalidates[] = {sve_z4, fpu_d4, fpu_s4,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v5_invalidates[] = {sve_z5, fpu_d5, fpu_s5,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v6_invalidates[] = {sve_z6, fpu_d6, fpu_s6,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v7_invalidates[] = {sve_z7, fpu_d7, fpu_s7,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v8_invalidates[] = {sve_z8, fpu_d8, fpu_s8,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v9_invalidates[] = {sve_z9, fpu_d9, fpu_s9,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v10_invalidates[] = {sve_z10, fpu_d10, fpu_s10,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v11_invalidates[] = {sve_z11, fpu_d11, fpu_s11,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v12_invalidates[] = {sve_z12, fpu_d12, fpu_s12,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v13_invalidates[] = {sve_z13, fpu_d13, fpu_s13,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v14_invalidates[] = {sve_z14, fpu_d14, fpu_s14,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v15_invalidates[] = {sve_z15, fpu_d15, fpu_s15,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v16_invalidates[] = {sve_z16, fpu_d16, fpu_s16,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v17_invalidates[] = {sve_z17, fpu_d17, fpu_s17,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v18_invalidates[] = {sve_z18, fpu_d18, fpu_s18,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v19_invalidates[] = {sve_z19, fpu_d19, fpu_s19,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v20_invalidates[] = {sve_z20, fpu_d20, fpu_s20,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v21_invalidates[] = {sve_z21, fpu_d21, fpu_s21,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v22_invalidates[] = {sve_z22, fpu_d22, fpu_s22,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v23_invalidates[] = {sve_z23, fpu_d23, fpu_s23,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v24_invalidates[] = {sve_z24, fpu_d24, fpu_s24,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v25_invalidates[] = {sve_z25, fpu_d25, fpu_s25,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v26_invalidates[] = {sve_z26, fpu_d26, fpu_s26,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v27_invalidates[] = {sve_z27, fpu_d27, fpu_s27,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v28_invalidates[] = {sve_z28, fpu_d28, fpu_s28,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v29_invalidates[] = {sve_z29, fpu_d29, fpu_s29,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v30_invalidates[] = {sve_z30, fpu_d30, fpu_s30,
+ LLDB_INVALID_REGNUM};
+static uint32_t g_sve_v31_invalidates[] = {sve_z31, fpu_d31, fpu_s31,
+ LLDB_INVALID_REGNUM};
+
+static uint32_t g_contained_z0[] = {sve_z0, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z1[] = {sve_z1, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z2[] = {sve_z2, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z3[] = {sve_z3, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z4[] = {sve_z4, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z5[] = {sve_z5, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z6[] = {sve_z6, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z7[] = {sve_z7, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z8[] = {sve_z8, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z9[] = {sve_z9, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z10[] = {sve_z10, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z11[] = {sve_z11, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z12[] = {sve_z12, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z13[] = {sve_z13, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z14[] = {sve_z14, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z15[] = {sve_z15, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z16[] = {sve_z16, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z17[] = {sve_z17, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z18[] = {sve_z18, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z19[] = {sve_z19, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z20[] = {sve_z20, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z21[] = {sve_z21, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z22[] = {sve_z22, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z23[] = {sve_z23, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z24[] = {sve_z24, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z25[] = {sve_z25, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z26[] = {sve_z26, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z27[] = {sve_z27, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z28[] = {sve_z28, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z29[] = {sve_z29, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z30[] = {sve_z30, LLDB_INVALID_REGNUM};
+static uint32_t g_contained_z31[] = {sve_z31, LLDB_INVALID_REGNUM};
+
+#define VG_OFFSET_NAME(reg) SVE_OFFSET_VG
+
+#define SVE_REG_KIND(reg) MISC_KIND(reg, sve, LLDB_INVALID_REGNUM)
+#define MISC_VG_KIND(lldb_kind) MISC_KIND(vg, sve, LLDB_INVALID_REGNUM)
+
+// Default offset SVE Z registers and all corresponding pseudo registers
+// ( S, D and V registers) is zero and will be configured during execution.
+
+// Defines sve pseudo vector (V) register with 16-byte size
+#define DEFINE_VREG_SVE(vreg, zreg) \
+ { \
+ #vreg, nullptr, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \
+ VREG_KIND(vreg), g_contained_##zreg, g_sve_##vreg##_invalidates, \
+ nullptr, 0 \
+ }
+
+// Defines S and D pseudo registers mapping over corresponding vector register
+#define DEFINE_FPU_PSEUDO_SVE(reg, size, zreg) \
+ { \
+ #reg, nullptr, size, 0, lldb::eEncodingIEEE754, lldb::eFormatFloat, \
+ LLDB_KIND(fpu_##reg), g_contained_##zreg, g_sve_##reg##_invalidates, \
+ nullptr, 0 \
+ }
+
+// Defines a Z vector register with 16-byte default size
+#define DEFINE_ZREG(reg) \
+ { \
+ #reg, nullptr, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \
+ SVE_REG_KIND(reg), nullptr, nullptr, nullptr, 0 \
+ }
+
+// Defines a P vector register with 2-byte default size
+#define DEFINE_PREG(reg) \
+ { \
+ #reg, nullptr, 2, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \
+ SVE_REG_KIND(reg), nullptr, nullptr, nullptr, 0 \
+ }
+
+static lldb_private::RegisterInfo g_register_infos_arm64_sve_le[] = {
+ // clang-format off
+ // DEFINE_GPR64(name, GENERIC KIND)
+ DEFINE_GPR64(x0, LLDB_REGNUM_GENERIC_ARG1),
+ DEFINE_GPR64(x1, LLDB_REGNUM_GENERIC_ARG2),
+ DEFINE_GPR64(x2, LLDB_REGNUM_GENERIC_ARG3),
+ DEFINE_GPR64(x3, LLDB_REGNUM_GENERIC_ARG4),
+ DEFINE_GPR64(x4, LLDB_REGNUM_GENERIC_ARG5),
+ DEFINE_GPR64(x5, LLDB_REGNUM_GENERIC_ARG6),
+ DEFINE_GPR64(x6, LLDB_REGNUM_GENERIC_ARG7),
+ DEFINE_GPR64(x7, LLDB_REGNUM_GENERIC_ARG8),
+ DEFINE_GPR64(x8, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x9, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x10, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x11, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x12, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x13, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x14, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x15, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x16, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x17, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x18, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x19, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x20, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x21, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x22, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x23, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x24, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x25, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x26, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x27, LLDB_INVALID_REGNUM),
+ DEFINE_GPR64(x28, LLDB_INVALID_REGNUM),
+ // DEFINE_GPR64(name, GENERIC KIND)
+ DEFINE_GPR64_ALT(fp, x29, LLDB_REGNUM_GENERIC_FP),
+ DEFINE_GPR64_ALT(lr, x30, LLDB_REGNUM_GENERIC_RA),
+ DEFINE_GPR64_ALT(sp, x31, LLDB_REGNUM_GENERIC_SP),
+ DEFINE_GPR64(pc, LLDB_REGNUM_GENERIC_PC),
+
+ // DEFINE_MISC_REGS(name, size, TYPE, lldb kind)
+ DEFINE_MISC_REGS(cpsr, 4, GPR, gpr_cpsr),
+
+ // DEFINE_GPR32(name, parent name)
+ DEFINE_GPR32(w0, x0),
+ DEFINE_GPR32(w1, x1),
+ DEFINE_GPR32(w2, x2),
+ DEFINE_GPR32(w3, x3),
+ DEFINE_GPR32(w4, x4),
+ DEFINE_GPR32(w5, x5),
+ DEFINE_GPR32(w6, x6),
+ DEFINE_GPR32(w7, x7),
+ DEFINE_GPR32(w8, x8),
+ DEFINE_GPR32(w9, x9),
+ DEFINE_GPR32(w10, x10),
+ DEFINE_GPR32(w11, x11),
+ DEFINE_GPR32(w12, x12),
+ DEFINE_GPR32(w13, x13),
+ DEFINE_GPR32(w14, x14),
+ DEFINE_GPR32(w15, x15),
+ DEFINE_GPR32(w16, x16),
+ DEFINE_GPR32(w17, x17),
+ DEFINE_GPR32(w18, x18),
+ DEFINE_GPR32(w19, x19),
+ DEFINE_GPR32(w20, x20),
+ DEFINE_GPR32(w21, x21),
+ DEFINE_GPR32(w22, x22),
+ DEFINE_GPR32(w23, x23),
+ DEFINE_GPR32(w24, x24),
+ DEFINE_GPR32(w25, x25),
+ DEFINE_GPR32(w26, x26),
+ DEFINE_GPR32(w27, x27),
+ DEFINE_GPR32(w28, x28),
+
+ // DEFINE_VREG_SVE(v register, z register)
+ DEFINE_VREG_SVE(v0, z0),
+ DEFINE_VREG_SVE(v1, z1),
+ DEFINE_VREG_SVE(v2, z2),
+ DEFINE_VREG_SVE(v3, z3),
+ DEFINE_VREG_SVE(v4, z4),
+ DEFINE_VREG_SVE(v5, z5),
+ DEFINE_VREG_SVE(v6, z6),
+ DEFINE_VREG_SVE(v7, z7),
+ DEFINE_VREG_SVE(v8, z8),
+ DEFINE_VREG_SVE(v9, z9),
+ DEFINE_VREG_SVE(v10, z10),
+ DEFINE_VREG_SVE(v11, z11),
+ DEFINE_VREG_SVE(v12, z12),
+ DEFINE_VREG_SVE(v13, z13),
+ DEFINE_VREG_SVE(v14, z14),
+ DEFINE_VREG_SVE(v15, z15),
+ DEFINE_VREG_SVE(v16, z16),
+ DEFINE_VREG_SVE(v17, z17),
+ DEFINE_VREG_SVE(v18, z18),
+ DEFINE_VREG_SVE(v19, z19),
+ DEFINE_VREG_SVE(v20, z20),
+ DEFINE_VREG_SVE(v21, z21),
+ DEFINE_VREG_SVE(v22, z22),
+ DEFINE_VREG_SVE(v23, z23),
+ DEFINE_VREG_SVE(v24, z24),
+ DEFINE_VREG_SVE(v25, z25),
+ DEFINE_VREG_SVE(v26, z26),
+ DEFINE_VREG_SVE(v27, z27),
+ DEFINE_VREG_SVE(v28, z28),
+ DEFINE_VREG_SVE(v29, z29),
+ DEFINE_VREG_SVE(v30, z30),
+ DEFINE_VREG_SVE(v31, z31),
+
+ // DEFINE_FPU_PSEUDO(name, size, ENDIAN OFFSET, parent register)
+ DEFINE_FPU_PSEUDO_SVE(s0, 4, z0),
+ DEFINE_FPU_PSEUDO_SVE(s1, 4, z1),
+ DEFINE_FPU_PSEUDO_SVE(s2, 4, z2),
+ DEFINE_FPU_PSEUDO_SVE(s3, 4, z3),
+ DEFINE_FPU_PSEUDO_SVE(s4, 4, z4),
+ DEFINE_FPU_PSEUDO_SVE(s5, 4, z5),
+ DEFINE_FPU_PSEUDO_SVE(s6, 4, z6),
+ DEFINE_FPU_PSEUDO_SVE(s7, 4, z7),
+ DEFINE_FPU_PSEUDO_SVE(s8, 4, z8),
+ DEFINE_FPU_PSEUDO_SVE(s9, 4, z9),
+ DEFINE_FPU_PSEUDO_SVE(s10, 4, z10),
+ DEFINE_FPU_PSEUDO_SVE(s11, 4, z11),
+ DEFINE_FPU_PSEUDO_SVE(s12, 4, z12),
+ DEFINE_FPU_PSEUDO_SVE(s13, 4, z13),
+ DEFINE_FPU_PSEUDO_SVE(s14, 4, z14),
+ DEFINE_FPU_PSEUDO_SVE(s15, 4, z15),
+ DEFINE_FPU_PSEUDO_SVE(s16, 4, z16),
+ DEFINE_FPU_PSEUDO_SVE(s17, 4, z17),
+ DEFINE_FPU_PSEUDO_SVE(s18, 4, z18),
+ DEFINE_FPU_PSEUDO_SVE(s19, 4, z19),
+ DEFINE_FPU_PSEUDO_SVE(s20, 4, z20),
+ DEFINE_FPU_PSEUDO_SVE(s21, 4, z21),
+ DEFINE_FPU_PSEUDO_SVE(s22, 4, z22),
+ DEFINE_FPU_PSEUDO_SVE(s23, 4, z23),
+ DEFINE_FPU_PSEUDO_SVE(s24, 4, z24),
+ DEFINE_FPU_PSEUDO_SVE(s25, 4, z25),
+ DEFINE_FPU_PSEUDO_SVE(s26, 4, z26),
+ DEFINE_FPU_PSEUDO_SVE(s27, 4, z27),
+ DEFINE_FPU_PSEUDO_SVE(s28, 4, z28),
+ DEFINE_FPU_PSEUDO_SVE(s29, 4, z29),
+ DEFINE_FPU_PSEUDO_SVE(s30, 4, z30),
+ DEFINE_FPU_PSEUDO_SVE(s31, 4, z31),
+
+ DEFINE_FPU_PSEUDO_SVE(d0, 8, z0),
+ DEFINE_FPU_PSEUDO_SVE(d1, 8, z1),
+ DEFINE_FPU_PSEUDO_SVE(d2, 8, z2),
+ DEFINE_FPU_PSEUDO_SVE(d3, 8, z3),
+ DEFINE_FPU_PSEUDO_SVE(d4, 8, z4),
+ DEFINE_FPU_PSEUDO_SVE(d5, 8, z5),
+ DEFINE_FPU_PSEUDO_SVE(d6, 8, z6),
+ DEFINE_FPU_PSEUDO_SVE(d7, 8, z7),
+ DEFINE_FPU_PSEUDO_SVE(d8, 8, z8),
+ DEFINE_FPU_PSEUDO_SVE(d9, 8, z9),
+ DEFINE_FPU_PSEUDO_SVE(d10, 8, z10),
+ DEFINE_FPU_PSEUDO_SVE(d11, 8, z11),
+ DEFINE_FPU_PSEUDO_SVE(d12, 8, z12),
+ DEFINE_FPU_PSEUDO_SVE(d13, 8, z13),
+ DEFINE_FPU_PSEUDO_SVE(d14, 8, z14),
+ DEFINE_FPU_PSEUDO_SVE(d15, 8, z15),
+ DEFINE_FPU_PSEUDO_SVE(d16, 8, z16),
+ DEFINE_FPU_PSEUDO_SVE(d17, 8, z17),
+ DEFINE_FPU_PSEUDO_SVE(d18, 8, z18),
+ DEFINE_FPU_PSEUDO_SVE(d19, 8, z19),
+ DEFINE_FPU_PSEUDO_SVE(d20, 8, z20),
+ DEFINE_FPU_PSEUDO_SVE(d21, 8, z21),
+ DEFINE_FPU_PSEUDO_SVE(d22, 8, z22),
+ DEFINE_FPU_PSEUDO_SVE(d23, 8, z23),
+ DEFINE_FPU_PSEUDO_SVE(d24, 8, z24),
+ DEFINE_FPU_PSEUDO_SVE(d25, 8, z25),
+ DEFINE_FPU_PSEUDO_SVE(d26, 8, z26),
+ DEFINE_FPU_PSEUDO_SVE(d27, 8, z27),
+ DEFINE_FPU_PSEUDO_SVE(d28, 8, z28),
+ DEFINE_FPU_PSEUDO_SVE(d29, 8, z29),
+ DEFINE_FPU_PSEUDO_SVE(d30, 8, z30),
+ DEFINE_FPU_PSEUDO_SVE(d31, 8, z31),
+
+ // DEFINE_MISC_REGS(name, size, TYPE, lldb kind)
+ DEFINE_MISC_REGS(fpsr, 4, FPU, fpu_fpsr),
+ DEFINE_MISC_REGS(fpcr, 4, FPU, fpu_fpcr),
+
+ DEFINE_MISC_REGS(vg, 8, VG, sve_vg),
+ // DEFINE_ZREG(name)
+ DEFINE_ZREG(z0),
+ DEFINE_ZREG(z1),
+ DEFINE_ZREG(z2),
+ DEFINE_ZREG(z3),
+ DEFINE_ZREG(z4),
+ DEFINE_ZREG(z5),
+ DEFINE_ZREG(z6),
+ DEFINE_ZREG(z7),
+ DEFINE_ZREG(z8),
+ DEFINE_ZREG(z9),
+ DEFINE_ZREG(z10),
+ DEFINE_ZREG(z11),
+ DEFINE_ZREG(z12),
+ DEFINE_ZREG(z13),
+ DEFINE_ZREG(z14),
+ DEFINE_ZREG(z15),
+ DEFINE_ZREG(z16),
+ DEFINE_ZREG(z17),
+ DEFINE_ZREG(z18),
+ DEFINE_ZREG(z19),
+ DEFINE_ZREG(z20),
+ DEFINE_ZREG(z21),
+ DEFINE_ZREG(z22),
+ DEFINE_ZREG(z23),
+ DEFINE_ZREG(z24),
+ DEFINE_ZREG(z25),
+ DEFINE_ZREG(z26),
+ DEFINE_ZREG(z27),
+ DEFINE_ZREG(z28),
+ DEFINE_ZREG(z29),
+ DEFINE_ZREG(z30),
+ DEFINE_ZREG(z31),
+
+ // DEFINE_PREG(name)
+ DEFINE_PREG(p0),
+ DEFINE_PREG(p1),
+ DEFINE_PREG(p2),
+ DEFINE_PREG(p3),
+ DEFINE_PREG(p4),
+ DEFINE_PREG(p5),
+ DEFINE_PREG(p6),
+ DEFINE_PREG(p7),
+ DEFINE_PREG(p8),
+ DEFINE_PREG(p9),
+ DEFINE_PREG(p10),
+ DEFINE_PREG(p11),
+ DEFINE_PREG(p12),
+ DEFINE_PREG(p13),
+ DEFINE_PREG(p14),
+ DEFINE_PREG(p15),
+
+ // DEFINE FFR
+ DEFINE_PREG(ffr)
+ // clang-format on
+};
+
+#endif // DECLARE_REGISTER_INFOS_ARM64_SVE_STRUCT
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h
index 343579cd2657..15c7cac544a1 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h
@@ -87,15 +87,14 @@
nullptr, nullptr, nullptr, 0 \
}
-#define DEFINE_FP_MM(reg, i) \
+#define DEFINE_FP_MM(reg, i, streg) \
{ \
- #reg #i, nullptr, sizeof(uint64_t), \
- LLVM_EXTENSION FPR_OFFSET( \
- stmm[i]), eEncodingUint, eFormatHex, \
- {ehframe_mm##i##_i386, dwarf_mm##i##_i386, \
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- lldb_mm##i##_i386 }, \
- nullptr, nullptr, nullptr, 0 \
+ #reg #i, nullptr, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \
+ eEncodingUint, eFormatHex, \
+ {dwarf_mm##i##_i386, dwarf_mm##i##_i386, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, lldb_mm##i##_i386 }, \
+ RegisterContextPOSIX_x86::g_contained_##streg##_32, \
+ RegisterContextPOSIX_x86::g_invalidate_##streg##_32, nullptr, 0 \
}
#define DEFINE_XMM(reg, i) \
@@ -251,10 +250,12 @@ static RegisterInfo g_register_infos_i386[] = {
// FP registers.
DEFINE_FP_ST(st, 0), DEFINE_FP_ST(st, 1), DEFINE_FP_ST(st, 2),
DEFINE_FP_ST(st, 3), DEFINE_FP_ST(st, 4), DEFINE_FP_ST(st, 5),
- DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7), DEFINE_FP_MM(mm, 0),
- DEFINE_FP_MM(mm, 1), DEFINE_FP_MM(mm, 2), DEFINE_FP_MM(mm, 3),
- DEFINE_FP_MM(mm, 4), DEFINE_FP_MM(mm, 5), DEFINE_FP_MM(mm, 6),
- DEFINE_FP_MM(mm, 7),
+ DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7),
+
+ DEFINE_FP_MM(mm, 0, st0), DEFINE_FP_MM(mm, 1, st1),
+ DEFINE_FP_MM(mm, 2, st2), DEFINE_FP_MM(mm, 3, st3),
+ DEFINE_FP_MM(mm, 4, st4), DEFINE_FP_MM(mm, 5, st5),
+ DEFINE_FP_MM(mm, 6, st6), DEFINE_FP_MM(mm, 7, st7),
// XMM registers
DEFINE_XMM(xmm, 0), DEFINE_XMM(xmm, 1), DEFINE_XMM(xmm, 2),
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
index af3027afa73c..41c04b20f391 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
@@ -88,15 +88,14 @@
nullptr, nullptr, nullptr, 0 \
}
-#define DEFINE_FP_MM(reg, i) \
+#define DEFINE_FP_MM(reg, i, streg) \
{ \
- #reg #i, nullptr, sizeof(uint64_t), \
- LLVM_EXTENSION FPR_OFFSET( \
- stmm[i]), eEncodingUint, eFormatHex, \
- {dwarf_mm##i##_x86_64, dwarf_mm##i##_x86_64, \
- LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
- lldb_mm##i##_x86_64 }, \
- nullptr, nullptr, nullptr, 0 \
+ #reg #i, nullptr, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \
+ eEncodingUint, eFormatHex, \
+ {dwarf_mm##i##_x86_64, dwarf_mm##i##_x86_64, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, lldb_mm##i##_x86_64 }, \
+ RegisterContextPOSIX_x86::g_contained_##streg##_64, \
+ RegisterContextPOSIX_x86::g_invalidate_##streg##_64, nullptr, 0 \
}
#define DEFINE_XMM(reg, i) \
@@ -195,6 +194,14 @@
RegisterContextPOSIX_x86::g_invalidate_##reg64, nullptr, 0 \
}
+#define DEFINE_FPR_32(name, reg, kind1, kind2, kind3, kind4, reg64) \
+ { \
+ #name, nullptr, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, eFormatHex, \
+ {kind1, kind2, kind3, kind4, lldb_##name##_x86_64 }, \
+ RegisterContextPOSIX_x86::g_contained_##reg64, \
+ RegisterContextPOSIX_x86::g_invalidate_##reg64, nullptr, 0 \
+ }
+
// clang-format off
static RegisterInfo g_register_infos_x86_64[] = {
// General purpose registers EH_Frame DWARF Generic Process Plugin
@@ -251,26 +258,30 @@ static RegisterInfo g_register_infos_x86_64[] = {
DEFINE_GPR_PSEUDO_8L(r12l, r12), DEFINE_GPR_PSEUDO_8L(r13l, r13),
DEFINE_GPR_PSEUDO_8L(r14l, r14), DEFINE_GPR_PSEUDO_8L(r15l, r15),
-// i387 Floating point registers. EH_frame DWARF Generic Process Plugin
-// ====================================== =============== ================== =================== ====================
+// i387 Floating point registers. EH_frame DWARF Generic Process Plugin reg64
+// ====================================== =============== ================== =================== ==================== =====
DEFINE_FPR(fctrl, fctrl, dwarf_fctrl_x86_64, dwarf_fctrl_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
DEFINE_FPR(fstat, fstat, dwarf_fstat_x86_64, dwarf_fstat_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_FPR(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_FPR(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_FPR(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
- DEFINE_FPR(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR_32(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fip),
+ DEFINE_FPR_32(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fip),
+ DEFINE_FPR(fip, ptr.x86_64.fip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR_32(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fdp),
+ DEFINE_FPR_32(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fdp),
+ DEFINE_FPR(fdp, ptr.x86_64.fdp, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
DEFINE_FPR(mxcsr, mxcsr, dwarf_mxcsr_x86_64, dwarf_mxcsr_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
// FP registers.
DEFINE_FP_ST(st, 0), DEFINE_FP_ST(st, 1), DEFINE_FP_ST(st, 2),
DEFINE_FP_ST(st, 3), DEFINE_FP_ST(st, 4), DEFINE_FP_ST(st, 5),
- DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7), DEFINE_FP_MM(mm, 0),
- DEFINE_FP_MM(mm, 1), DEFINE_FP_MM(mm, 2), DEFINE_FP_MM(mm, 3),
- DEFINE_FP_MM(mm, 4), DEFINE_FP_MM(mm, 5), DEFINE_FP_MM(mm, 6),
- DEFINE_FP_MM(mm, 7),
+ DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7),
+
+ DEFINE_FP_MM(mm, 0, st0), DEFINE_FP_MM(mm, 1, st1),
+ DEFINE_FP_MM(mm, 2, st2), DEFINE_FP_MM(mm, 3, st3),
+ DEFINE_FP_MM(mm, 4, st4), DEFINE_FP_MM(mm, 5, st5),
+ DEFINE_FP_MM(mm, 6, st6), DEFINE_FP_MM(mm, 7, st7),
// XMM registers
DEFINE_XMM(xmm, 0), DEFINE_XMM(xmm, 1), DEFINE_XMM(xmm, 2),
diff --git a/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h b/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h
index 35f1a4075d09..4d10600f4771 100644
--- a/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h
+++ b/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h
@@ -106,7 +106,7 @@ enum {
lldb_bnd1_i386,
lldb_bnd2_i386,
lldb_bnd3_i386,
- k_last_mpxr = lldb_bnd3_i386,
+ k_last_mpxr_i386 = lldb_bnd3_i386,
k_first_mpxc_i386,
lldb_bndcfgu_i386 = k_first_mpxc_i386,
@@ -228,8 +228,10 @@ enum {
lldb_fop_x86_64,
lldb_fiseg_x86_64,
lldb_fioff_x86_64,
+ lldb_fip_x86_64,
lldb_foseg_x86_64,
lldb_fooff_x86_64,
+ lldb_fdp_x86_64,
lldb_mxcsr_x86_64,
lldb_mxcsrmask_x86_64,
lldb_st0_x86_64,
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index aa95e92607ad..ae19367ca3ae 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -52,9 +52,10 @@ void ProcessElfCore::Terminate() {
lldb::ProcessSP ProcessElfCore::CreateInstance(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
- const FileSpec *crash_file) {
+ const FileSpec *crash_file,
+ bool can_connect) {
lldb::ProcessSP process_sp;
- if (crash_file) {
+ if (crash_file && !can_connect) {
// Read enough data for a ELF32 header or ELF64 header Note: Here we care
// about e_type field only, so it is safe to ignore possible presence of
// the header extension.
@@ -97,7 +98,7 @@ bool ProcessElfCore::CanDebug(lldb::TargetSP target_sp,
ProcessElfCore::ProcessElfCore(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
const FileSpec &core_file)
- : Process(target_sp, listener_sp), m_core_file(core_file) {}
+ : PostMortemProcess(target_sp, listener_sp), m_core_file(core_file) {}
// Destructor
ProcessElfCore::~ProcessElfCore() {
@@ -260,8 +261,8 @@ lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() {
return m_dyld_up.get();
}
-bool ProcessElfCore::UpdateThreadList(ThreadList &old_thread_list,
- ThreadList &new_thread_list) {
+bool ProcessElfCore::DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) {
const uint32_t num_threads = GetNumThreadContexts();
if (!m_thread_data_valid)
return false;
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
index 6f6309799f43..d8e3cc9ae3e1 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -19,7 +19,7 @@
#include <list>
#include <vector>
-#include "lldb/Target/Process.h"
+#include "lldb/Target/PostMortemProcess.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Status.h"
@@ -28,12 +28,13 @@
struct ThreadData;
-class ProcessElfCore : public lldb_private::Process {
+class ProcessElfCore : public lldb_private::PostMortemProcess {
public:
// Constructors and Destructors
static lldb::ProcessSP
CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
- const lldb_private::FileSpec *crash_file_path);
+ const lldb_private::FileSpec *crash_file_path,
+ bool can_connect);
static void Initialize();
@@ -104,8 +105,8 @@ public:
protected:
void Clear();
- bool UpdateThreadList(lldb_private::ThreadList &old_thread_list,
- lldb_private::ThreadList &new_thread_list) override;
+ bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list) override;
private:
struct NT_FILE_Entry {
@@ -125,8 +126,6 @@ private:
lldb::ModuleSP m_core_module_sp;
lldb_private::FileSpec m_core_file;
std::string m_dyld_plugin_name;
- ProcessElfCore(const ProcessElfCore &) = delete;
- const ProcessElfCore &operator=(const ProcessElfCore &) = delete;
// True if m_thread_contexts contains valid entries
bool m_thread_data_valid = false;
diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp
index b76f26a584c0..2f71f175a00d 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp
+++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp
@@ -16,9 +16,9 @@
using namespace lldb_private;
RegisterContextCorePOSIX_arm::RegisterContextCorePOSIX_arm(
- Thread &thread, RegisterInfoInterface *register_info,
+ Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm> register_info,
const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
- : RegisterContextPOSIX_arm(thread, 0, register_info) {
+ : RegisterContextPOSIX_arm(thread, std::move(register_info)) {
m_gpr_buffer = std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
gpregset.GetByteSize());
m_gpr.SetData(m_gpr_buffer);
diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
index f9ec08ed35fc..de343f9001e0 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
+++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
@@ -18,7 +18,7 @@ class RegisterContextCorePOSIX_arm : public RegisterContextPOSIX_arm {
public:
RegisterContextCorePOSIX_arm(
lldb_private::Thread &thread,
- lldb_private::RegisterInfoInterface *register_info,
+ std::unique_ptr<RegisterInfoPOSIX_arm> register_info,
const lldb_private::DataExtractor &gpregset,
llvm::ArrayRef<lldb_private::CoreNote> notes);
diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
index 685567416983..129a887a550c 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
+++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "RegisterContextPOSIXCore_arm64.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
#include "Plugins/Process/elf-core/RegisterUtilities.h"
#include "lldb/Target/Thread.h"
@@ -27,6 +28,12 @@ RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(
m_fpregset = getRegset(
notes, m_register_info_up->GetTargetArchitecture().GetTriple(), FPR_Desc);
+
+ m_sveregset =
+ getRegset(notes, m_register_info_up->GetTargetArchitecture().GetTriple(),
+ AARCH64_SVE_Desc);
+
+ ConfigureRegisterContext();
}
RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() {}
@@ -45,9 +52,57 @@ bool RegisterContextCorePOSIX_arm64::WriteFPR() {
return false;
}
+const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) {
+ return m_sveregset.GetDataStart() + offset;
+}
+
+void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() {
+ if (m_sveregset.GetByteSize() > sizeof(sve::user_sve_header)) {
+ uint64_t sve_header_field_offset = 8;
+ m_sve_vector_length = m_sveregset.GetU16(&sve_header_field_offset);
+ sve_header_field_offset = 12;
+ uint16_t sve_header_flags_field =
+ m_sveregset.GetU16(&sve_header_field_offset);
+ if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
+ sve::ptrace_regs_fpsimd)
+ m_sve_state = SVEState::FPSIMD;
+ else if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
+ sve::ptrace_regs_sve)
+ m_sve_state = SVEState::Full;
+
+ if (sve::vl_valid(m_sve_vector_length))
+ m_register_info_up->ConfigureVectorRegisterInfos(
+ sve::vq_from_vl(m_sve_vector_length));
+ else {
+ m_sve_state = SVEState::Disabled;
+ m_sve_vector_length = 0;
+ }
+ } else
+ m_sve_state = SVEState::Disabled;
+}
+
+uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset(
+ const RegisterInfo *reg_info) {
+ // Start of Z0 data is after GPRs plus 8 bytes of vg register
+ uint32_t sve_reg_offset = LLDB_INVALID_INDEX32;
+ if (m_sve_state == SVEState::FPSIMD) {
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+ sve_reg_offset = sve::ptrace_fpsimd_offset + (reg - GetRegNumSVEZ0()) * 16;
+ } else if (m_sve_state == SVEState::Full) {
+ uint32_t sve_z0_offset = GetGPRSize() + 16;
+ sve_reg_offset =
+ sve::SigRegsOffset() + reg_info->byte_offset - sve_z0_offset;
+ }
+
+ return sve_reg_offset;
+}
+
bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info,
RegisterValue &value) {
- lldb::offset_t offset = reg_info->byte_offset;
+ Status error;
+ lldb::offset_t offset;
+
+ offset = reg_info->byte_offset;
if (offset + reg_info->byte_size <= GetGPRSize()) {
uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
if (offset == reg_info->byte_offset + reg_info->byte_size) {
@@ -60,15 +115,86 @@ bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info,
if (reg == LLDB_INVALID_REGNUM)
return false;
- offset -= GetGPRSize();
- if (IsFPR(reg) && offset + reg_info->byte_size <= GetFPUSize()) {
- Status error;
- value.SetFromMemoryData(reg_info, m_fpregset.GetDataStart() + offset,
- reg_info->byte_size, lldb::eByteOrderLittle, error);
- return error.Success();
- }
+ if (IsFPR(reg)) {
+ if (m_sve_state == SVEState::Disabled) {
+ // SVE is disabled take legacy route for FPU register access
+ offset -= GetGPRSize();
+ if (offset < m_fpregset.GetByteSize()) {
+ value.SetFromMemoryData(reg_info, m_fpregset.GetDataStart() + offset,
+ reg_info->byte_size, lldb::eByteOrderLittle,
+ error);
+ return error.Success();
+ }
+ } else {
+ // FPSR and FPCR will be located right after Z registers in
+ // SVEState::FPSIMD while in SVEState::Full they will be located at the
+ // end of register data after an alignment correction based on currently
+ // selected vector length.
+ uint32_t sve_reg_num = LLDB_INVALID_REGNUM;
+ if (reg == GetRegNumFPSR()) {
+ sve_reg_num = reg;
+ if (m_sve_state == SVEState::Full)
+ offset = sve::PTraceFPSROffset(sve::vq_from_vl(m_sve_vector_length));
+ else if (m_sve_state == SVEState::FPSIMD)
+ offset = sve::ptrace_fpsimd_offset + (32 * 16);
+ } else if (reg == GetRegNumFPCR()) {
+ sve_reg_num = reg;
+ if (m_sve_state == SVEState::Full)
+ offset = sve::PTraceFPCROffset(sve::vq_from_vl(m_sve_vector_length));
+ else if (m_sve_state == SVEState::FPSIMD)
+ offset = sve::ptrace_fpsimd_offset + (32 * 16) + 4;
+ } else {
+ // Extract SVE Z register value register number for this reg_info
+ if (reg_info->value_regs &&
+ reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
+ sve_reg_num = reg_info->value_regs[0];
+ offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num));
+ }
- return false;
+ assert(sve_reg_num != LLDB_INVALID_REGNUM);
+ assert(offset < m_sveregset.GetByteSize());
+ value.SetFromMemoryData(reg_info, GetSVEBuffer(offset),
+ reg_info->byte_size, lldb::eByteOrderLittle,
+ error);
+ }
+ } else if (IsSVE(reg)) {
+ if (IsSVEVG(reg)) {
+ value = GetSVERegVG();
+ return true;
+ }
+
+ switch (m_sve_state) {
+ case SVEState::FPSIMD: {
+ // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so just
+ // copy 16 bytes of v register to the start of z register. All other
+ // SVE register will be set to zero.
+ uint64_t byte_size = 1;
+ uint8_t zeros = 0;
+ const uint8_t *src = &zeros;
+ if (IsSVEZ(reg)) {
+ byte_size = 16;
+ offset = CalculateSVEOffset(reg_info);
+ assert(offset < m_sveregset.GetByteSize());
+ src = GetSVEBuffer(offset);
+ }
+ value.SetFromMemoryData(reg_info, src, byte_size, lldb::eByteOrderLittle,
+ error);
+ } break;
+ case SVEState::Full:
+ offset = CalculateSVEOffset(reg_info);
+ assert(offset < m_sveregset.GetByteSize());
+ value.SetFromMemoryData(reg_info, GetSVEBuffer(offset),
+ reg_info->byte_size, lldb::eByteOrderLittle,
+ error);
+ break;
+ case SVEState::Disabled:
+ default:
+ return false;
+ }
+ } else
+ return false;
+
+ return error.Success();
}
bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues(
diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
index 830e0ff91e4c..a4fdc4f14328 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
+++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
@@ -9,7 +9,9 @@
#ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H
#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H
+#include "Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h"
#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
+
#include "Plugins/Process/elf-core/RegisterUtilities.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/DataExtractor.h"
@@ -49,6 +51,18 @@ private:
lldb::DataBufferSP m_gpr_buffer;
lldb_private::DataExtractor m_gpr;
lldb_private::DataExtractor m_fpregset;
+ lldb_private::DataExtractor m_sveregset;
+
+ SVEState m_sve_state;
+ uint16_t m_sve_vector_length = 0;
+
+ const uint8_t *GetSVEBuffer(uint64_t offset = 0);
+
+ void ConfigureRegisterContext();
+
+ uint32_t CalculateSVEOffset(const lldb_private::RegisterInfo *reg_info);
+
+ uint64_t GetSVERegVG() { return m_sve_vector_length / 8; }
};
#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H
diff --git a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
index 4e08aa280817..25abd7ed54b7 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
+++ b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h
@@ -107,6 +107,10 @@ constexpr RegsetDesc FPR_Desc[] = {
{llvm::Triple::OpenBSD, llvm::Triple::UnknownArch, OPENBSD::NT_FPREGS},
};
+constexpr RegsetDesc AARCH64_SVE_Desc[] = {
+ {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_SVE},
+};
+
constexpr RegsetDesc PPC_VMX_Desc[] = {
{llvm::Triple::FreeBSD, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX},
{llvm::Triple::Linux, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX},
diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp
index 6b5acfa4bc1b..76c0c2843e6d 100644
--- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp
@@ -82,9 +82,7 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {
case llvm::Triple::FreeBSD: {
switch (arch.GetMachine()) {
case llvm::Triple::aarch64:
- break;
case llvm::Triple::arm:
- reg_interface = new RegisterInfoPOSIX_arm(arch);
break;
case llvm::Triple::ppc:
reg_interface = new RegisterContextFreeBSD_powerpc32(arch);
@@ -122,9 +120,6 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {
case llvm::Triple::Linux: {
switch (arch.GetMachine()) {
- case llvm::Triple::arm:
- reg_interface = new RegisterInfoPOSIX_arm(arch);
- break;
case llvm::Triple::aarch64:
break;
case llvm::Triple::mipsel:
@@ -157,9 +152,6 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {
switch (arch.GetMachine()) {
case llvm::Triple::aarch64:
break;
- case llvm::Triple::arm:
- reg_interface = new RegisterInfoPOSIX_arm(arch);
- break;
case llvm::Triple::x86:
reg_interface = new RegisterContextOpenBSD_i386(arch);
break;
@@ -176,7 +168,8 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {
break;
}
- if (!reg_interface && arch.GetMachine() != llvm::Triple::aarch64) {
+ if (!reg_interface && arch.GetMachine() != llvm::Triple::aarch64 &&
+ arch.GetMachine() != llvm::Triple::arm) {
LLDB_LOGF(log, "elf-core::%s:: Architecture(%d) or OS(%d) not supported",
__FUNCTION__, arch.GetMachine(), arch.GetTriple().getOS());
assert(false && "Architecture or OS not supported");
@@ -190,7 +183,8 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) {
break;
case llvm::Triple::arm:
m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_arm>(
- *this, reg_interface, m_gpregset_data, m_notes);
+ *this, std::make_unique<RegisterInfoPOSIX_arm>(arch), m_gpregset_data,
+ m_notes);
break;
case llvm::Triple::mipsel:
case llvm::Triple::mips:
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index bfacd41dc1a3..4981345d6a18 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -50,7 +50,7 @@
#include <compression.h>
#endif
-#if defined(HAVE_LIBZ)
+#if LLVM_ENABLE_ZLIB
#include <zlib.h>
#endif
@@ -284,7 +284,7 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet,
LLDB_LOGV(log,
"Read(buffer, sizeof(buffer), timeout = {0}, "
"status = {1}, error = {2}) => bytes_read = {3}",
- timeout, Communication::ConnectionStatusAsCString(status), error,
+ timeout, Communication::ConnectionStatusAsString(status), error,
bytes_read);
if (bytes_read > 0) {
@@ -582,7 +582,7 @@ bool GDBRemoteCommunication::DecompressPacket() {
}
#endif
-#if defined(HAVE_LIBZ)
+#if LLVM_ENABLE_ZLIB
if (decompressed_bytes == 0 && decompressed_bufsize != ULONG_MAX &&
decompressed_buffer != nullptr &&
m_compression_type == CompressionType::ZlibDeflate) {
@@ -1234,7 +1234,7 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client,
const int backlog = 5;
TCPSocket listen_socket(true, child_processes_inherit);
if (llvm::Error error =
- listen_socket.Listen("127.0.0.1:0", backlog).ToError())
+ listen_socket.Listen("localhost:0", backlog).ToError())
return error;
Socket *accept_socket;
@@ -1243,7 +1243,7 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client,
llvm::SmallString<32> remote_addr;
llvm::raw_svector_ostream(remote_addr)
- << "connect://127.0.0.1:" << listen_socket.GetLocalPortNumber();
+ << "connect://localhost:" << listen_socket.GetLocalPortNumber();
std::unique_ptr<ConnectionFileDescriptor> conn_up(
new ConnectionFileDescriptor());
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index c75d5e106cd0..d375a312ae2c 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -1053,7 +1053,7 @@ void GDBRemoteCommunicationClient::MaybeEnableCompression(
}
#endif
-#if defined(HAVE_LIBZ)
+#if LLVM_ENABLE_ZLIB
if (avail_type == CompressionType::None) {
for (auto compression : supported_compressions) {
if (compression == "zlib-deflate") {
@@ -1529,6 +1529,22 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo(
std::string name;
name_extractor.GetHexByteString(name);
region_info.SetName(name.c_str());
+ } else if (name.equals("flags")) {
+ region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
+
+ llvm::StringRef flags = value;
+ llvm::StringRef flag;
+ while (flags.size()) {
+ flags = flags.ltrim();
+ std::tie(flag, flags) = flags.split(' ');
+ // To account for trailing whitespace
+ if (flag.size()) {
+ if (flag == "mt") {
+ region_info.SetMemoryTagged(MemoryRegionInfo::eYes);
+ break;
+ }
+ }
+ }
} else if (name.equals("error")) {
StringExtractorGDBRemote error_extractor(value);
std::string error_string;
@@ -1701,14 +1717,9 @@ Status GDBRemoteCommunicationClient::GetWatchpointSupportInfo(uint32_t &num) {
// Set num to 0 first.
num = 0;
if (m_supports_watchpoint_support_info != eLazyBoolNo) {
- char packet[64];
- const int packet_len =
- ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:");
- assert(packet_len < (int)sizeof(packet));
- UNUSED_IF_ASSERT_DISABLED(packet_len);
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse(packet, response, false) ==
- PacketResult::Success) {
+ if (SendPacketAndWaitForResponse("qWatchpointSupportInfo:", response,
+ false) == PacketResult::Success) {
m_supports_watchpoint_support_info = eLazyBoolYes;
llvm::StringRef name;
llvm::StringRef value;
@@ -2120,6 +2131,7 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) {
case llvm::Triple::COFF:
m_process_arch.SetArchitecture(eArchTypeCOFF, cpu, sub);
break;
+ case llvm::Triple::GOFF:
case llvm::Triple::Wasm:
case llvm::Triple::XCOFF:
LLDB_LOGF(log, "error: not supported target architecture");
@@ -2816,7 +2828,7 @@ lldb::addr_t GDBRemoteCommunicationClient::GetShlibInfoAddr() {
}
lldb_private::Status GDBRemoteCommunicationClient::RunShellCommand(
- const char *command, // Shouldn't be NULL
+ llvm::StringRef command,
const FileSpec &
working_dir, // Pass empty FileSpec to use the current working directory
int *status_ptr, // Pass NULL if you don't want the process exit status
@@ -2827,7 +2839,7 @@ lldb_private::Status GDBRemoteCommunicationClient::RunShellCommand(
const Timeout<std::micro> &timeout) {
lldb_private::StreamString stream;
stream.PutCString("qPlatform_shell:");
- stream.PutBytesAsRawHex8(command, strlen(command));
+ stream.PutBytesAsRawHex8(command.data(), command.size());
stream.PutChar(',');
uint32_t timeout_sec = UINT32_MAX;
if (timeout) {
@@ -2981,6 +2993,31 @@ lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize(
return UINT64_MAX;
}
+void GDBRemoteCommunicationClient::AutoCompleteDiskFileOrDirectory(
+ CompletionRequest &request, bool only_dir) {
+ lldb_private::StreamString stream;
+ stream.PutCString("qPathComplete:");
+ stream.PutHex32(only_dir ? 1 : 0);
+ stream.PutChar(',');
+ stream.PutStringAsRawHex8(request.GetCursorArgumentPrefix());
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response, false) ==
+ PacketResult::Success) {
+ StreamString strm;
+ char ch = response.GetChar();
+ if (ch != 'M')
+ return;
+ while (response.Peek()) {
+ strm.Clear();
+ while ((ch = response.GetHexU8(0, false)) != '\0')
+ strm.PutChar(ch);
+ request.AddCompletion(strm.GetString());
+ if (response.GetChar() != ',')
+ break;
+ }
+ }
+}
+
Status
GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec,
uint32_t &file_permissions) {
@@ -3433,6 +3470,35 @@ Status GDBRemoteCommunicationClient::SendGetMetaDataPacket(
return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset);
}
+llvm::Expected<TraceTypeInfo>
+GDBRemoteCommunicationClient::SendGetSupportedTraceType() {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jLLDBTraceSupportedType");
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+ true) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsErrorResponse())
+ return response.GetStatus().ToError();
+ if (response.IsUnsupportedResponse())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "jLLDBTraceSupportedType is unsupported");
+
+ if (llvm::Expected<TraceTypeInfo> type =
+ llvm::json::parse<TraceTypeInfo>(response.Peek()))
+ return *type;
+ else
+ return type.takeError();
+ }
+ LLDB_LOG(log, "failed to send packet: jLLDBTraceSupportedType");
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "failed to send packet: jLLDBTraceSupportedType");
+}
+
Status
GDBRemoteCommunicationClient::SendGetTraceConfigPacket(lldb::user_id_t uid,
TraceOptions &options) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 8df08cbde735..af3755fce774 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -22,6 +22,7 @@
#include "lldb/Utility/GDBRemote.h"
#include "lldb/Utility/ProcessInfo.h"
#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/TraceOptions.h"
#if defined(_WIN32)
#include "lldb/Host/windows/PosixApi.h"
#endif
@@ -375,6 +376,9 @@ public:
lldb::user_id_t GetFileSize(const FileSpec &file_spec);
+ void AutoCompleteDiskFileOrDirectory(CompletionRequest &request,
+ bool only_dir);
+
Status GetFilePermissions(const FileSpec &file_spec,
uint32_t &file_permissions);
@@ -396,7 +400,7 @@ public:
bool GetFileExists(const FileSpec &file_spec);
Status RunShellCommand(
- const char *command, // Shouldn't be nullptr
+ llvm::StringRef command,
const FileSpec &working_dir, // Pass empty FileSpec to use the current
// working directory
int *status_ptr, // Pass nullptr if you don't want the process exit status
@@ -516,6 +520,8 @@ public:
Status SendGetTraceConfigPacket(lldb::user_id_t uid, TraceOptions &options);
+ llvm::Expected<TraceTypeInfo> SendGetSupportedTraceType();
+
protected:
LazyBool m_supports_not_sending_acks;
LazyBool m_supports_thread_suffix;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index b78f0916b9b9..60548efc0f33 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -12,11 +12,11 @@
#include "GDBRemoteCommunicationServer.h"
-#include <cstring>
-
#include "ProcessGDBRemoteLog.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StringExtractorGDBRemote.h"
+#include "lldb/Utility/UnimplementedError.h"
+#include <cstring>
using namespace lldb;
using namespace lldb_private;
@@ -113,18 +113,17 @@ GDBRemoteCommunicationServer::SendErrorResponse(const Status &error) {
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::SendErrorResponse(llvm::Error error) {
+ assert(error);
std::unique_ptr<llvm::ErrorInfoBase> EIB;
- std::unique_ptr<PacketUnimplementedError> PUE;
+ std::unique_ptr<UnimplementedError> UE;
llvm::handleAllErrors(
std::move(error),
- [&](std::unique_ptr<PacketUnimplementedError> E) { PUE = std::move(E); },
+ [&](std::unique_ptr<UnimplementedError> E) { UE = std::move(E); },
[&](std::unique_ptr<llvm::ErrorInfoBase> E) { EIB = std::move(E); });
if (EIB)
return SendErrorResponse(Status(llvm::Error(std::move(EIB))));
- if (PUE)
- return SendUnimplementedResponse(PUE->message().c_str());
- return SendErrorResponse(Status("Unknown Error"));
+ return SendUnimplementedResponse("");
}
GDBRemoteCommunication::PacketResult
@@ -152,5 +151,3 @@ GDBRemoteCommunicationServer::SendOKResponse() {
bool GDBRemoteCommunicationServer::HandshakeWithClient() {
return GetAck() == PacketResult::Success;
}
-
-char PacketUnimplementedError::ID;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
index a7c2ea47e3ba..a1cf70f9cd1a 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
@@ -27,7 +27,6 @@ class ProcessGDBRemote;
class GDBRemoteCommunicationServer : public GDBRemoteCommunication {
public:
- using PortMap = std::map<uint16_t, lldb::pid_t>;
using PacketHandler =
std::function<PacketResult(StringExtractorGDBRemote &packet,
Status &error, bool &interrupt, bool &quit)>;
@@ -79,18 +78,6 @@ private:
operator=(const GDBRemoteCommunicationServer &) = delete;
};
-class PacketUnimplementedError
- : public llvm::ErrorInfo<PacketUnimplementedError, llvm::StringError> {
-public:
- static char ID;
- using llvm::ErrorInfo<PacketUnimplementedError,
- llvm::StringError>::ErrorInfo; // inherit constructors
- PacketUnimplementedError(const llvm::Twine &S)
- : ErrorInfo(S, llvm::errc::not_supported) {}
-
- PacketUnimplementedError() : ErrorInfo(llvm::errc::not_supported) {}
-};
-
} // namespace process_gdb_remote
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
index 08d489851799..1ca0290eda13 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -843,7 +843,7 @@ GDBRemoteCommunicationServerCommon::Handle_qSupported(
response.PutCString(";QListThreadsInStopReply+");
response.PutCString(";qEcho+");
response.PutCString(";qXfer:features:read+");
-#if defined(__linux__) || defined(__NetBSD__)
+#if defined(__linux__) || defined(__NetBSD__) || defined(__FreeBSD__)
response.PutCString(";QPassSignals+");
response.PutCString(";qXfer:auxv:read+");
response.PutCString(";qXfer:libraries-svr4:read+");
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index ae2f4bd041c9..62a09a2a432c 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -10,13 +10,12 @@
#include "lldb/Host/Config.h"
-#include "GDBRemoteCommunicationServerLLGS.h"
-#include "lldb/Utility/GDBRemote.h"
#include <chrono>
#include <cstring>
#include <thread>
+#include "GDBRemoteCommunicationServerLLGS.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/Debug.h"
#include "lldb/Host/File.h"
@@ -32,11 +31,13 @@
#include "lldb/Utility/Args.h"
#include "lldb/Utility/DataBuffer.h"
#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/GDBRemote.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/UnimplementedError.h"
#include "lldb/Utility/UriParser.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/JSON.h"
@@ -92,6 +93,10 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
&GDBRemoteCommunicationServerLLGS::Handle_memory_read);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M,
&GDBRemoteCommunicationServerLLGS::Handle_M);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType__M,
+ &GDBRemoteCommunicationServerLLGS::Handle__M);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType__m,
+ &GDBRemoteCommunicationServerLLGS::Handle__m);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_p,
&GDBRemoteCommunicationServerLLGS::Handle_p);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_P,
@@ -155,6 +160,15 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
StringExtractorGDBRemote::eServerPacketType_vAttach,
&GDBRemoteCommunicationServerLLGS::Handle_vAttach);
RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vAttachWait,
+ &GDBRemoteCommunicationServerLLGS::Handle_vAttachWait);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qVAttachOrWaitSupported,
+ &GDBRemoteCommunicationServerLLGS::Handle_qVAttachOrWaitSupported);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vAttachOrWait,
+ &GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait);
+ RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_vCont,
&GDBRemoteCommunicationServerLLGS::Handle_vCont);
RegisterMemberFunctionHandler(
@@ -186,6 +200,9 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead,
&GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jLLDBTraceSupportedType,
+ &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupportedType);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g,
&GDBRemoteCommunicationServerLLGS::Handle_g);
@@ -326,6 +343,75 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) {
return Status();
}
+Status GDBRemoteCommunicationServerLLGS::AttachWaitProcess(
+ llvm::StringRef process_name, bool include_existing) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ std::chrono::milliseconds polling_interval = std::chrono::milliseconds(1);
+
+ // Create the matcher used to search the process list.
+ ProcessInstanceInfoList exclusion_list;
+ ProcessInstanceInfoMatch match_info;
+ match_info.GetProcessInfo().GetExecutableFile().SetFile(
+ process_name, llvm::sys::path::Style::native);
+ match_info.SetNameMatchType(NameMatch::Equals);
+
+ if (include_existing) {
+ LLDB_LOG(log, "including existing processes in search");
+ } else {
+ // Create the excluded process list before polling begins.
+ Host::FindProcesses(match_info, exclusion_list);
+ LLDB_LOG(log, "placed '{0}' processes in the exclusion list.",
+ exclusion_list.size());
+ }
+
+ LLDB_LOG(log, "waiting for '{0}' to appear", process_name);
+
+ auto is_in_exclusion_list =
+ [&exclusion_list](const ProcessInstanceInfo &info) {
+ for (auto &excluded : exclusion_list) {
+ if (excluded.GetProcessID() == info.GetProcessID())
+ return true;
+ }
+ return false;
+ };
+
+ ProcessInstanceInfoList loop_process_list;
+ while (true) {
+ loop_process_list.clear();
+ if (Host::FindProcesses(match_info, loop_process_list)) {
+ // Remove all the elements that are in the exclusion list.
+ llvm::erase_if(loop_process_list, is_in_exclusion_list);
+
+ // One match! We found the desired process.
+ if (loop_process_list.size() == 1) {
+ auto matching_process_pid = loop_process_list[0].GetProcessID();
+ LLDB_LOG(log, "found pid {0}", matching_process_pid);
+ return AttachToProcess(matching_process_pid);
+ }
+
+ // Multiple matches! Return an error reporting the PIDs we found.
+ if (loop_process_list.size() > 1) {
+ StreamString error_stream;
+ error_stream.Format(
+ "Multiple executables with name: '{0}' found. Pids: ",
+ process_name);
+ for (size_t i = 0; i < loop_process_list.size() - 1; ++i) {
+ error_stream.Format("{0}, ", loop_process_list[i].GetProcessID());
+ }
+ error_stream.Format("{0}.", loop_process_list.back().GetProcessID());
+
+ Status error;
+ error.SetErrorString(error_stream.GetString());
+ return error;
+ }
+ }
+ // No matches, we have not found the process. Sleep until next poll.
+ LLDB_LOG(log, "sleep {0} seconds", polling_interval);
+ std::this_thread::sleep_for(polling_interval);
+ }
+}
+
void GDBRemoteCommunicationServerLLGS::InitializeDelegate(
NativeProcessProtocol *process) {
assert(process && "process cannot be NULL");
@@ -495,7 +581,7 @@ static void WriteRegisterValueInHexFixedWidth(
}
}
-static llvm::Expected<json::Object>
+static llvm::Optional<json::Object>
GetRegistersAsJSON(NativeThreadProtocol &thread) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
@@ -504,30 +590,16 @@ GetRegistersAsJSON(NativeThreadProtocol &thread) {
json::Object register_object;
#ifdef LLDB_JTHREADSINFO_FULL_REGISTER_SET
- // Expedite all registers in the first register set (i.e. should be GPRs)
- // that are not contained in other registers.
- const RegisterSet *reg_set_p = reg_ctx_sp->GetRegisterSet(0);
- if (!reg_set_p)
- return llvm::make_error<llvm::StringError>("failed to get registers",
- llvm::inconvertibleErrorCode());
- for (const uint32_t *reg_num_p = reg_set_p->registers;
- *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) {
- uint32_t reg_num = *reg_num_p;
+ const auto expedited_regs =
+ reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Full);
#else
- // Expedite only a couple of registers until we figure out why sending
- // registers is expensive.
- static const uint32_t k_expedited_registers[] = {
- LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP,
- LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM};
-
- for (const uint32_t *generic_reg_p = k_expedited_registers;
- *generic_reg_p != LLDB_INVALID_REGNUM; ++generic_reg_p) {
- uint32_t reg_num = reg_ctx.ConvertRegisterKindToRegisterNumber(
- eRegisterKindGeneric, *generic_reg_p);
- if (reg_num == LLDB_INVALID_REGNUM)
- continue; // Target does not support the given register.
+ const auto expedited_regs =
+ reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Minimal);
#endif
+ if (expedited_regs.empty())
+ return llvm::None;
+ for (auto &reg_num : expedited_regs) {
const RegisterInfo *const reg_info_p =
reg_ctx.GetRegisterInfoAtIndex(reg_num);
if (reg_info_p == nullptr) {
@@ -620,12 +692,8 @@ GetJSONThreadsInfo(NativeProcessProtocol &process, bool abridged) {
json::Object thread_obj;
if (!abridged) {
- if (llvm::Expected<json::Object> registers =
- GetRegistersAsJSON(*thread)) {
+ if (llvm::Optional<json::Object> registers = GetRegistersAsJSON(*thread))
thread_obj.try_emplace("registers", std::move(*registers));
- } else {
- return registers.takeError();
- }
}
thread_obj.try_emplace("tid", static_cast<int64_t>(tid));
@@ -806,46 +874,27 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread(
// Grab the register context.
NativeRegisterContext& reg_ctx = thread->GetRegisterContext();
- // Expedite all registers in the first register set (i.e. should be GPRs)
- // that are not contained in other registers.
- const RegisterSet *reg_set_p;
- if (reg_ctx.GetRegisterSetCount() > 0 &&
- ((reg_set_p = reg_ctx.GetRegisterSet(0)) != nullptr)) {
- LLDB_LOGF(log,
- "GDBRemoteCommunicationServerLLGS::%s expediting registers "
- "from set '%s' (registers set count: %zu)",
- __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>",
- reg_set_p->num_registers);
+ const auto expedited_regs =
+ reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Full);
- for (const uint32_t *reg_num_p = reg_set_p->registers;
- *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) {
- const RegisterInfo *const reg_info_p =
- reg_ctx.GetRegisterInfoAtIndex(*reg_num_p);
- if (reg_info_p == nullptr) {
- LLDB_LOGF(log,
- "GDBRemoteCommunicationServerLLGS::%s failed to get "
- "register info for register set '%s', register index "
- "%" PRIu32,
+ for (auto &reg_num : expedited_regs) {
+ const RegisterInfo *const reg_info_p =
+ reg_ctx.GetRegisterInfoAtIndex(reg_num);
+ // Only expediate registers that are not contained in other registers.
+ if (reg_info_p != nullptr && reg_info_p->value_regs == nullptr) {
+ RegisterValue reg_value;
+ Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
+ if (error.Success()) {
+ response.Printf("%.02x:", reg_num);
+ WriteRegisterValueInHexFixedWidth(response, reg_ctx, *reg_info_p,
+ &reg_value, lldb::eByteOrderBig);
+ response.PutChar(';');
+ } else {
+ LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s failed to read "
+ "register '%s' index %" PRIu32 ": %s",
__FUNCTION__,
- reg_set_p->name ? reg_set_p->name : "<unnamed-set>",
- *reg_num_p);
- } else if (reg_info_p->value_regs == nullptr) {
- // Only expediate registers that are not contained in other registers.
- RegisterValue reg_value;
- Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
- if (error.Success()) {
- response.Printf("%.02x:", *reg_num_p);
- WriteRegisterValueInHexFixedWidth(response, reg_ctx, *reg_info_p,
- &reg_value, lldb::eByteOrderBig);
- response.PutChar(';');
- } else {
- LLDB_LOGF(log,
- "GDBRemoteCommunicationServerLLGS::%s failed to read "
- "register '%s' index %" PRIu32 ": %s",
- __FUNCTION__,
- reg_info_p->name ? reg_info_p->name : "<unnamed-register>",
- *reg_num_p, error.AsCString());
- }
+ reg_info_p->name ? reg_info_p->name : "<unnamed-register>",
+ reg_num, error.AsCString());
}
}
}
@@ -1222,6 +1271,33 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceStop(
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupportedType(
+ StringExtractorGDBRemote &packet) {
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(Status("Process not running."));
+
+ llvm::Expected<TraceTypeInfo> supported_trace_type =
+ m_debugged_process_up->GetSupportedTraceType();
+ if (!supported_trace_type)
+ return SendErrorResponse(supported_trace_type.takeError());
+
+ StreamGDBRemote escaped_response;
+ StructuredData::Dictionary json_packet;
+
+ json_packet.AddStringItem("name", supported_trace_type->name);
+ json_packet.AddStringItem("description", supported_trace_type->description);
+
+ StreamString json_string;
+ json_packet.Dump(json_string, false);
+ escaped_response.PutEscapedBytes(json_string.GetData(),
+ json_string.GetSize());
+ return SendPacketNoLock(escaped_response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead(
StringExtractorGDBRemote &packet) {
@@ -1723,6 +1799,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState(
case eStateSuspended:
case eStateStopped:
case eStateCrashed: {
+ assert(m_debugged_process_up != nullptr);
lldb::tid_t tid = m_debugged_process_up->GetCurrentThreadID();
// Make sure we set the current thread so g and p packets return the data
// the gdb will expect.
@@ -1789,8 +1866,10 @@ GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo(
response.PutChar(';');
}
- response.Printf("bitsize:%" PRIu32 ";offset:%" PRIu32 ";",
- reg_info->byte_size * 8, reg_info->byte_offset);
+ response.Printf("bitsize:%" PRIu32 ";", reg_info->byte_size * 8);
+
+ if (!reg_context.RegisterOffsetIsDynamic())
+ response.Printf("offset:%" PRIu32 ";", reg_info->byte_offset);
llvm::StringRef encoding = GetEncodingNameOrEmpty(*reg_info);
if (!encoding.empty())
@@ -2085,7 +2164,7 @@ GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) {
StreamGDBRemote response;
RegisterValue reg_value(
- reg_bytes, reg_size,
+ makeArrayRef(reg_bytes, reg_size),
m_debugged_process_up->GetArchitecture().GetByteOrder());
Status error = reg_context.WriteRegister(reg_info, reg_value);
if (error.Fail()) {
@@ -2321,6 +2400,84 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read(
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle__M(StringExtractorGDBRemote &packet) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos(strlen("_M"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short _M packet");
+
+ const lldb::addr_t size = packet.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ if (size == LLDB_INVALID_ADDRESS)
+ return SendIllFormedResponse(packet, "Address not valid");
+ if (packet.GetChar() != ',')
+ return SendIllFormedResponse(packet, "Bad packet");
+ Permissions perms = {};
+ while (packet.GetBytesLeft() > 0) {
+ switch (packet.GetChar()) {
+ case 'r':
+ perms |= ePermissionsReadable;
+ break;
+ case 'w':
+ perms |= ePermissionsWritable;
+ break;
+ case 'x':
+ perms |= ePermissionsExecutable;
+ break;
+ default:
+ return SendIllFormedResponse(packet, "Bad permissions");
+ }
+ }
+
+ llvm::Expected<addr_t> addr =
+ m_debugged_process_up->AllocateMemory(size, perms);
+ if (!addr)
+ return SendErrorResponse(addr.takeError());
+
+ StreamGDBRemote response;
+ response.PutHex64(*addr);
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle__m(StringExtractorGDBRemote &packet) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos(strlen("_m"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short m packet");
+
+ const lldb::addr_t addr = packet.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ if (addr == LLDB_INVALID_ADDRESS)
+ return SendIllFormedResponse(packet, "Address not valid");
+
+ if (llvm::Error Err = m_debugged_process_up->DeallocateMemory(addr))
+ return SendErrorResponse(std::move(Err));
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
@@ -2491,6 +2648,17 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo(
response.PutChar(';');
}
+ // Flags
+ MemoryRegionInfo::OptionalBool memory_tagged =
+ region_info.GetMemoryTagged();
+ if (memory_tagged != MemoryRegionInfo::eDontKnow) {
+ response.PutCString("flags:");
+ if (memory_tagged == MemoryRegionInfo::eYes) {
+ response.PutCString("mt");
+ }
+ response.PutChar(';');
+ }
+
// Name
ConstString name = region_info.GetName();
if (name) {
@@ -2773,10 +2941,11 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() {
continue;
}
- response.Printf("<reg name=\"%s\" bitsize=\"%" PRIu32 "\" offset=\"%" PRIu32
- "\" regnum=\"%d\" ",
- reg_info->name, reg_info->byte_size * 8,
- reg_info->byte_offset, reg_index);
+ response.Printf("<reg name=\"%s\" bitsize=\"%" PRIu32 "\" regnum=\"%d\" ",
+ reg_info->name, reg_info->byte_size * 8, reg_index);
+
+ if (!reg_context.RegisterOffsetIsDynamic())
+ response.Printf("offset=\"%" PRIu32 "\" ", reg_info->byte_offset);
if (reg_info->alt_name && reg_info->alt_name[0])
response.Printf("altname=\"%s\" ", reg_info->alt_name);
@@ -2876,8 +3045,7 @@ GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object,
if (object == "features" && annex == "target.xml")
return BuildTargetXml();
- return llvm::make_error<PacketUnimplementedError>(
- "Xfer object not supported");
+ return llvm::make_error<UnimplementedError>();
}
GDBRemoteCommunication::PacketResult
@@ -3099,6 +3267,72 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttach(
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vAttachWait(
+ StringExtractorGDBRemote &packet) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Consume the ';' after the identifier.
+ packet.SetFilePos(strlen("vAttachWait"));
+
+ if (!packet.GetBytesLeft() || packet.GetChar() != ';')
+ return SendIllFormedResponse(packet, "vAttachWait missing expected ';'");
+
+ // Allocate the buffer for the process name from vAttachWait.
+ std::string process_name;
+ if (!packet.GetHexByteString(process_name))
+ return SendIllFormedResponse(packet,
+ "vAttachWait failed to parse process name");
+
+ LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name);
+
+ Status error = AttachWaitProcess(process_name, false);
+ if (error.Fail()) {
+ LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name,
+ error);
+ return SendErrorResponse(error);
+ }
+
+ // Notify we attached by sending a stop packet.
+ return SendStopReasonForState(m_debugged_process_up->GetState());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qVAttachOrWaitSupported(
+ StringExtractorGDBRemote &packet) {
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait(
+ StringExtractorGDBRemote &packet) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Consume the ';' after the identifier.
+ packet.SetFilePos(strlen("vAttachOrWait"));
+
+ if (!packet.GetBytesLeft() || packet.GetChar() != ';')
+ return SendIllFormedResponse(packet, "vAttachOrWait missing expected ';'");
+
+ // Allocate the buffer for the process name from vAttachWait.
+ std::string process_name;
+ if (!packet.GetHexByteString(process_name))
+ return SendIllFormedResponse(packet,
+ "vAttachOrWait failed to parse process name");
+
+ LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name);
+
+ Status error = AttachWaitProcess(process_name, true);
+ if (error.Fail()) {
+ LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name,
+ error);
+ return SendErrorResponse(error);
+ }
+
+ // Notify we attached by sending a stop packet.
+ return SendStopReasonForState(m_debugged_process_up->GetState());
+}
+
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
index 3ce285910c25..c51139924559 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -59,6 +59,17 @@ public:
/// attach operation.
Status AttachToProcess(lldb::pid_t pid);
+ /// Wait to attach to a process with a given name.
+ ///
+ /// This method supports waiting for the next instance of a process
+ /// with a given name and attaching llgs to that via the configured
+ /// Platform.
+ ///
+ /// \return
+ /// An Status object indicating the success or failure of the
+ /// attach operation.
+ Status AttachWaitProcess(llvm::StringRef process_name, bool include_existing);
+
// NativeProcessProtocol::NativeDelegate overrides
void InitializeDelegate(NativeProcessProtocol *process) override;
@@ -138,6 +149,8 @@ protected:
PacketResult Handle_memory_read(StringExtractorGDBRemote &packet);
PacketResult Handle_M(StringExtractorGDBRemote &packet);
+ PacketResult Handle__M(StringExtractorGDBRemote &packet);
+ PacketResult Handle__m(StringExtractorGDBRemote &packet);
PacketResult
Handle_qMemoryRegionInfoSupported(StringExtractorGDBRemote &packet);
@@ -162,10 +175,18 @@ protected:
PacketResult Handle_jTraceConfigRead(StringExtractorGDBRemote &packet);
+ PacketResult Handle_jLLDBTraceSupportedType(StringExtractorGDBRemote &packet);
+
PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet);
PacketResult Handle_vAttach(StringExtractorGDBRemote &packet);
+ PacketResult Handle_vAttachWait(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qVAttachOrWaitSupported(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vAttachOrWait(StringExtractorGDBRemote &packet);
+
PacketResult Handle_D(StringExtractorGDBRemote &packet);
PacketResult Handle_qThreadStopInfo(StringExtractorGDBRemote &packet);
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
index d14b79a03d17..3462fb7ec8b9 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
@@ -26,12 +26,14 @@
#include "lldb/Host/FileAction.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
+#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/GDBRemote.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/TildeExpressionResolver.h"
#include "lldb/Utility/UriParser.h"
#include "lldb/Utility/StringExtractorGDBRemote.h"
@@ -40,6 +42,69 @@ using namespace lldb;
using namespace lldb_private::process_gdb_remote;
using namespace lldb_private;
+GDBRemoteCommunicationServerPlatform::PortMap::PortMap(uint16_t min_port,
+ uint16_t max_port) {
+ for (; min_port < max_port; ++min_port)
+ m_port_map[min_port] = LLDB_INVALID_PROCESS_ID;
+}
+
+void GDBRemoteCommunicationServerPlatform::PortMap::AllowPort(uint16_t port) {
+ // Do not modify existing mappings
+ m_port_map.insert({port, LLDB_INVALID_PROCESS_ID});
+}
+
+llvm::Expected<uint16_t>
+GDBRemoteCommunicationServerPlatform::PortMap::GetNextAvailablePort() {
+ if (m_port_map.empty())
+ return 0; // Bind to port zero and get a port, we didn't have any
+ // limitations
+
+ for (auto &pair : m_port_map) {
+ if (pair.second == LLDB_INVALID_PROCESS_ID) {
+ pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID;
+ return pair.first;
+ }
+ }
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No free port found in port map");
+}
+
+bool GDBRemoteCommunicationServerPlatform::PortMap::AssociatePortWithProcess(
+ uint16_t port, lldb::pid_t pid) {
+ auto pos = m_port_map.find(port);
+ if (pos != m_port_map.end()) {
+ pos->second = pid;
+ return true;
+ }
+ return false;
+}
+
+bool GDBRemoteCommunicationServerPlatform::PortMap::FreePort(uint16_t port) {
+ std::map<uint16_t, lldb::pid_t>::iterator pos = m_port_map.find(port);
+ if (pos != m_port_map.end()) {
+ pos->second = LLDB_INVALID_PROCESS_ID;
+ return true;
+ }
+ return false;
+}
+
+bool GDBRemoteCommunicationServerPlatform::PortMap::FreePortForProcess(
+ lldb::pid_t pid) {
+ if (!m_port_map.empty()) {
+ for (auto &pair : m_port_map) {
+ if (pair.second == pid) {
+ pair.second = LLDB_INVALID_PROCESS_ID;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool GDBRemoteCommunicationServerPlatform::PortMap::empty() const {
+ return m_port_map.empty();
+}
+
// GDBRemoteCommunicationServerPlatform constructor
GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(
const Socket::SocketProtocol socket_protocol, const char *socket_scheme)
@@ -69,6 +134,9 @@ GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(
StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
&GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo);
RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qPathComplete,
+ &GDBRemoteCommunicationServerPlatform::Handle_qPathComplete);
+ RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
&GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir);
RegisterMemberFunctionHandler(
@@ -89,9 +157,14 @@ GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() {}
Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
const lldb_private::Args &args, std::string hostname, lldb::pid_t &pid,
- uint16_t &port, std::string &socket_name) {
- if (port == UINT16_MAX)
- port = GetNextAvailablePort();
+ llvm::Optional<uint16_t> &port, std::string &socket_name) {
+ if (!port) {
+ llvm::Expected<uint16_t> available_port = m_port_map.GetNextAvailablePort();
+ if (available_port)
+ port = *available_port;
+ else
+ return Status(available_port.takeError());
+ }
// Spawn a new thread to accept the port that gets bound after binding to
// port 0 (zero).
@@ -106,7 +179,7 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
LLDB_LOGF(log, "Launching debugserver with: %s:%u...", hostname.c_str(),
- port);
+ *port);
// Do not run in a new session so that it can not linger after the platform
// closes.
@@ -121,7 +194,7 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
#if !defined(__APPLE__)
url << m_socket_scheme << "://";
#endif
- uint16_t *port_ptr = &port;
+ uint16_t *port_ptr = port.getPointer();
if (m_socket_protocol == Socket::ProtocolTcp) {
llvm::StringRef platform_scheme;
llvm::StringRef platform_ip;
@@ -132,7 +205,7 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
platform_port, platform_path);
UNUSED_IF_ASSERT_DISABLED(ok);
assert(ok);
- url << platform_ip.str() << ":" << port;
+ url << '[' << platform_ip.str() << "]:" << *port;
} else {
socket_name = GetDomainSocketPath("gdbserver").GetPath();
url << socket_name;
@@ -146,11 +219,11 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
if (pid != LLDB_INVALID_PROCESS_ID) {
std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
m_spawned_pids.insert(pid);
- if (port > 0)
- AssociatePortWithProcess(port, pid);
+ if (*port > 0)
+ m_port_map.AssociatePortWithProcess(*port, pid);
} else {
- if (port > 0)
- FreePort(port);
+ if (*port > 0)
+ m_port_map.FreePort(*port);
}
return error;
}
@@ -170,12 +243,15 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer(
packet.SetFilePos(::strlen("qLaunchGDBServer;"));
llvm::StringRef name;
llvm::StringRef value;
- uint16_t port = UINT16_MAX;
+ llvm::Optional<uint16_t> port;
while (packet.GetNameColonValue(name, value)) {
if (name.equals("host"))
hostname = std::string(value);
- else if (name.equals("port"))
- value.getAsInteger(0, port);
+ else if (name.equals("port")) {
+ // Make the Optional valid so we can use its value
+ port = 0;
+ value.getAsInteger(0, port.getValue());
+ }
}
lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
@@ -196,8 +272,9 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer(
__FUNCTION__, debugserver_pid);
StreamGDBRemote response;
+ assert(port);
response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid,
- port + m_port_offset);
+ *port + m_port_offset);
if (!socket_name.empty()) {
response.PutCString("socket_name:");
response.PutStringAsRawHex8(socket_name);
@@ -334,6 +411,38 @@ GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo(
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qPathComplete(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("qPathComplete:"));
+ const bool only_dir = (packet.GetHexMaxU32(false, 0) == 1);
+ if (packet.GetChar() != ',')
+ return SendErrorResponse(85);
+ std::string path;
+ packet.GetHexByteString(path);
+
+ StringList matches;
+ StandardTildeExpressionResolver resolver;
+ if (only_dir)
+ CommandCompletions::DiskDirectories(path, matches, resolver);
+ else
+ CommandCompletions::DiskFiles(path, matches, resolver);
+
+ StreamString response;
+ response.PutChar('M');
+ llvm::StringRef separator;
+ std::sort(matches.begin(), matches.end());
+ for (const auto &match : matches) {
+ response << separator;
+ separator = ",";
+ // encode result strings into hex bytes to avoid unexpected error caused by
+ // special characters like '$'.
+ response.PutStringAsRawHex8(match.c_str());
+ }
+
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir(
StringExtractorGDBRemote &packet) {
@@ -416,7 +525,7 @@ GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo(
bool GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped(
lldb::pid_t pid) {
std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
- FreePortForProcess(pid);
+ m_port_map.FreePortForProcess(pid);
m_spawned_pids.erase(pid);
return true;
}
@@ -462,51 +571,6 @@ void GDBRemoteCommunicationServerPlatform::SetPortMap(PortMap &&port_map) {
m_port_map = port_map;
}
-uint16_t GDBRemoteCommunicationServerPlatform::GetNextAvailablePort() {
- if (m_port_map.empty())
- return 0; // Bind to port zero and get a port, we didn't have any
- // limitations
-
- for (auto &pair : m_port_map) {
- if (pair.second == LLDB_INVALID_PROCESS_ID) {
- pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID;
- return pair.first;
- }
- }
- return UINT16_MAX;
-}
-
-bool GDBRemoteCommunicationServerPlatform::AssociatePortWithProcess(
- uint16_t port, lldb::pid_t pid) {
- PortMap::iterator pos = m_port_map.find(port);
- if (pos != m_port_map.end()) {
- pos->second = pid;
- return true;
- }
- return false;
-}
-
-bool GDBRemoteCommunicationServerPlatform::FreePort(uint16_t port) {
- PortMap::iterator pos = m_port_map.find(port);
- if (pos != m_port_map.end()) {
- pos->second = LLDB_INVALID_PROCESS_ID;
- return true;
- }
- return false;
-}
-
-bool GDBRemoteCommunicationServerPlatform::FreePortForProcess(lldb::pid_t pid) {
- if (!m_port_map.empty()) {
- for (auto &pair : m_port_map) {
- if (pair.second == pid) {
- pair.second = LLDB_INVALID_PROCESS_ID;
- return true;
- }
- }
- }
- return false;
-}
-
const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() {
static FileSpec g_domainsocket_dir;
static llvm::once_flag g_once_flag;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
index a8cacea78835..6b964da4a279 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
@@ -16,13 +16,61 @@
#include "GDBRemoteCommunicationServerCommon.h"
#include "lldb/Host/Socket.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/Error.h"
+
namespace lldb_private {
namespace process_gdb_remote {
class GDBRemoteCommunicationServerPlatform
: public GDBRemoteCommunicationServerCommon {
public:
- typedef std::map<uint16_t, lldb::pid_t> PortMap;
+ class PortMap {
+ public:
+ // This class is used to restrict the range of ports that
+ // platform created debugserver/gdbserver processes will
+ // communicate on.
+
+ // Construct an empty map, where empty means any port is allowed.
+ PortMap() = default;
+
+ // Make a port map with a range of free ports
+ // from min_port to max_port-1.
+ PortMap(uint16_t min_port, uint16_t max_port);
+
+ // Add a port to the map. If it is already in the map do not modify
+ // its mapping. (used ports remain used, new ports start as free)
+ void AllowPort(uint16_t port);
+
+ // If we are using a port map where we can only use certain ports,
+ // get the next available port.
+ //
+ // If we are using a port map and we are out of ports, return an error.
+ //
+ // If we aren't using a port map, return 0 to indicate we should bind to
+ // port 0 and then figure out which port we used.
+ llvm::Expected<uint16_t> GetNextAvailablePort();
+
+ // Tie a port to a process ID. Returns false if the port is not in the port
+ // map. If the port is already in use it will be moved to the given pid.
+ // FIXME: This is and GetNextAvailablePort make create a race condition if
+ // the portmap is shared between processes.
+ bool AssociatePortWithProcess(uint16_t port, lldb::pid_t pid);
+
+ // Free the given port. Returns false if the port is not in the map.
+ bool FreePort(uint16_t port);
+
+ // Free the port associated with the given pid. Returns false if there is
+ // no port associated with the pid.
+ bool FreePortForProcess(lldb::pid_t pid);
+
+ // Returns true if there are no ports in the map, regardless of the state
+ // of those ports. Meaning a map with 1 used port is not empty.
+ bool empty() const;
+
+ private:
+ std::map<uint16_t, lldb::pid_t> m_port_map;
+ };
GDBRemoteCommunicationServerPlatform(
const Socket::SocketProtocol socket_protocol, const char *socket_scheme);
@@ -35,27 +83,14 @@ public:
// a port chosen by the OS.
void SetPortMap(PortMap &&port_map);
- // If we are using a port map where we can only use certain ports,
- // get the next available port.
- //
- // If we are using a port map and we are out of ports, return UINT16_MAX
- //
- // If we aren't using a port map, return 0 to indicate we should bind to
- // port 0 and then figure out which port we used.
- uint16_t GetNextAvailablePort();
-
- bool AssociatePortWithProcess(uint16_t port, lldb::pid_t pid);
-
- bool FreePort(uint16_t port);
-
- bool FreePortForProcess(lldb::pid_t pid);
-
void SetPortOffset(uint16_t port_offset);
void SetInferiorArguments(const lldb_private::Args &args);
+ // Set port if you want to use a specific port number.
+ // Otherwise port will be set to the port that was chosen for you.
Status LaunchGDBServer(const lldb_private::Args &args, std::string hostname,
- lldb::pid_t &pid, uint16_t &port,
+ lldb::pid_t &pid, llvm::Optional<uint16_t> &port,
std::string &socket_name);
void SetPendingGdbServer(lldb::pid_t pid, uint16_t port,
@@ -81,6 +116,8 @@ protected:
PacketResult Handle_qKillSpawnedProcess(StringExtractorGDBRemote &packet);
+ PacketResult Handle_qPathComplete(StringExtractorGDBRemote &packet);
+
PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet);
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
index 1f31b45d0fa9..10006616b0c6 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -31,19 +31,20 @@ using namespace lldb_private::process_gdb_remote;
// GDBRemoteRegisterContext constructor
GDBRemoteRegisterContext::GDBRemoteRegisterContext(
ThreadGDBRemote &thread, uint32_t concrete_frame_idx,
- GDBRemoteDynamicRegisterInfo &reg_info, bool read_all_at_once,
+ GDBRemoteDynamicRegisterInfoSP reg_info_sp, bool read_all_at_once,
bool write_all_at_once)
- : RegisterContext(thread, concrete_frame_idx), m_reg_info(reg_info),
- m_reg_valid(), m_reg_data(), m_read_all_at_once(read_all_at_once),
+ : RegisterContext(thread, concrete_frame_idx),
+ m_reg_info_sp(std::move(reg_info_sp)), m_reg_valid(), m_reg_data(),
+ m_read_all_at_once(read_all_at_once),
m_write_all_at_once(write_all_at_once) {
// Resize our vector of bools to contain one bool for every register. We will
// use these boolean values to know when a register value is valid in
// m_reg_data.
- m_reg_valid.resize(reg_info.GetNumRegisters());
+ m_reg_valid.resize(m_reg_info_sp->GetNumRegisters());
// Make a heap based buffer that is big enough to store all registers
DataBufferSP reg_data_sp(
- new DataBufferHeap(reg_info.GetRegisterDataByteSize(), 0));
+ new DataBufferHeap(m_reg_info_sp->GetRegisterDataByteSize(), 0));
m_reg_data.SetData(reg_data_sp);
m_reg_data.SetByteOrder(thread.GetProcess()->GetByteOrder());
}
@@ -62,12 +63,12 @@ void GDBRemoteRegisterContext::SetAllRegisterValid(bool b) {
}
size_t GDBRemoteRegisterContext::GetRegisterCount() {
- return m_reg_info.GetNumRegisters();
+ return m_reg_info_sp->GetNumRegisters();
}
const RegisterInfo *
GDBRemoteRegisterContext::GetRegisterInfoAtIndex(size_t reg) {
- RegisterInfo *reg_info = m_reg_info.GetRegisterInfoAtIndex(reg);
+ RegisterInfo *reg_info = m_reg_info_sp->GetRegisterInfoAtIndex(reg);
if (reg_info && reg_info->dynamic_size_dwarf_expr_bytes) {
const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture();
@@ -78,11 +79,11 @@ GDBRemoteRegisterContext::GetRegisterInfoAtIndex(size_t reg) {
}
size_t GDBRemoteRegisterContext::GetRegisterSetCount() {
- return m_reg_info.GetNumRegisterSets();
+ return m_reg_info_sp->GetNumRegisterSets();
}
const RegisterSet *GDBRemoteRegisterContext::GetRegisterSet(size_t reg_set) {
- return m_reg_info.GetRegisterSet(reg_set);
+ return m_reg_info_sp->GetRegisterSet(reg_set);
}
bool GDBRemoteRegisterContext::ReadRegister(const RegisterInfo *reg_info,
@@ -209,11 +210,12 @@ bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info,
SetAllRegisterValid(true);
return true;
} else if (buffer_sp->GetByteSize() > 0) {
- const int regcount = m_reg_info.GetNumRegisters();
+ const int regcount = m_reg_info_sp->GetNumRegisters();
for (int i = 0; i < regcount; i++) {
- struct RegisterInfo *reginfo = m_reg_info.GetRegisterInfoAtIndex(i);
- if (reginfo->byte_offset + reginfo->byte_size
- <= buffer_sp->GetByteSize()) {
+ struct RegisterInfo *reginfo =
+ m_reg_info_sp->GetRegisterInfoAtIndex(i);
+ if (reginfo->byte_offset + reginfo->byte_size <=
+ buffer_sp->GetByteSize()) {
m_reg_valid[i] = true;
} else {
m_reg_valid[i] = false;
@@ -342,6 +344,15 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info,
if (dst == nullptr)
return false;
+ // Code below is specific to AArch64 target in SVE state
+ // If vector granule (vg) register is being written then thread's
+ // register context reconfiguration is triggered on success.
+ bool do_reconfigure_arm64_sve = false;
+ const ArchSpec &arch = process->GetTarget().GetArchitecture();
+ if (arch.IsValid() && arch.GetTriple().isAArch64())
+ if (strcmp(reg_info->name, "vg") == 0)
+ do_reconfigure_arm64_sve = true;
+
if (data.CopyByteOrderedData(data_offset, // src offset
reg_info->byte_size, // src length
dst, // dst
@@ -361,6 +372,10 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info,
{
SetAllRegisterValid(false);
+
+ if (do_reconfigure_arm64_sve)
+ AArch64SVEReconfigure();
+
return true;
}
} else {
@@ -389,6 +404,9 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info,
} else {
// This is an actual register, write it
success = SetPrimordialRegister(reg_info, gdb_comm);
+
+ if (success && do_reconfigure_arm64_sve)
+ AArch64SVEReconfigure();
}
// Check if writing this register will invalidate any other register
@@ -506,7 +524,7 @@ bool GDBRemoteRegisterContext::ReadAllRegisterValues(
// m_reg_data buffer
}
data_sp = std::make_shared<DataBufferHeap>(
- m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize());
+ m_reg_data.GetDataStart(), m_reg_info_sp->GetRegisterDataByteSize());
return true;
} else {
@@ -654,9 +672,8 @@ bool GDBRemoteRegisterContext::WriteAllRegisterValues(
if (m_thread.GetProcess().get()) {
const ArchSpec &arch =
m_thread.GetProcess()->GetTarget().GetArchitecture();
- if (arch.IsValid() &&
- (arch.GetMachine() == llvm::Triple::aarch64 ||
- arch.GetMachine() == llvm::Triple::aarch64_32) &&
+ if (arch.IsValid() && (arch.GetMachine() == llvm::Triple::aarch64 ||
+ arch.GetMachine() == llvm::Triple::aarch64_32) &&
arch.GetTriple().getVendor() == llvm::Triple::Apple &&
arch.GetTriple().getOS() == llvm::Triple::IOS) {
arm64_debugserver = true;
@@ -708,7 +725,63 @@ bool GDBRemoteRegisterContext::WriteAllRegisterValues(
uint32_t GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber(
lldb::RegisterKind kind, uint32_t num) {
- return m_reg_info.ConvertRegisterKindToRegisterNumber(kind, num);
+ return m_reg_info_sp->ConvertRegisterKindToRegisterNumber(kind, num);
+}
+
+bool GDBRemoteRegisterContext::AArch64SVEReconfigure() {
+ if (!m_reg_info_sp)
+ return false;
+
+ const RegisterInfo *reg_info = m_reg_info_sp->GetRegisterInfo("vg");
+ if (!reg_info)
+ return false;
+
+ uint64_t fail_value = LLDB_INVALID_ADDRESS;
+ uint32_t vg_reg_num = reg_info->kinds[eRegisterKindLLDB];
+ uint64_t vg_reg_value = ReadRegisterAsUnsigned(vg_reg_num, fail_value);
+
+ if (vg_reg_value != fail_value && vg_reg_value <= 32) {
+ const RegisterInfo *reg_info = m_reg_info_sp->GetRegisterInfo("p0");
+ if (!reg_info || vg_reg_value == reg_info->byte_size)
+ return false;
+
+ if (m_reg_info_sp->UpdateARM64SVERegistersInfos(vg_reg_value)) {
+ // Make a heap based buffer that is big enough to store all registers
+ m_reg_data.SetData(std::make_shared<DataBufferHeap>(
+ m_reg_info_sp->GetRegisterDataByteSize(), 0));
+ m_reg_data.SetByteOrder(GetByteOrder());
+
+ InvalidateAllRegisters();
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool GDBRemoteDynamicRegisterInfo::UpdateARM64SVERegistersInfos(uint64_t vg) {
+ // SVE Z register size is vg x 8 bytes.
+ uint32_t z_reg_byte_size = vg * 8;
+
+ // SVE vector length has changed, accordingly set size of Z, P and FFR
+ // registers. Also invalidate register offsets it will be recalculated
+ // after SVE register size update.
+ for (auto &reg : m_regs) {
+ if (reg.value_regs == nullptr) {
+ if (reg.name[0] == 'z' && isdigit(reg.name[1]))
+ reg.byte_size = z_reg_byte_size;
+ else if (reg.name[0] == 'p' && isdigit(reg.name[1]))
+ reg.byte_size = vg;
+ else if (strcmp(reg.name, "ffr") == 0)
+ reg.byte_size = vg;
+ }
+ reg.byte_offset = LLDB_INVALID_INDEX32;
+ }
+
+ // Re-calculate register offsets
+ ConfigureOffsets();
+ return true;
}
void GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
index 015862587103..252d7b359ee8 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -27,20 +27,25 @@ namespace process_gdb_remote {
class ThreadGDBRemote;
class ProcessGDBRemote;
+class GDBRemoteDynamicRegisterInfo;
-class GDBRemoteDynamicRegisterInfo : public DynamicRegisterInfo {
+typedef std::shared_ptr<GDBRemoteDynamicRegisterInfo>
+ GDBRemoteDynamicRegisterInfoSP;
+
+class GDBRemoteDynamicRegisterInfo final : public DynamicRegisterInfo {
public:
GDBRemoteDynamicRegisterInfo() : DynamicRegisterInfo() {}
~GDBRemoteDynamicRegisterInfo() override = default;
void HardcodeARMRegisters(bool from_scratch);
+ bool UpdateARM64SVERegistersInfos(uint64_t vg);
};
class GDBRemoteRegisterContext : public RegisterContext {
public:
GDBRemoteRegisterContext(ThreadGDBRemote &thread, uint32_t concrete_frame_idx,
- GDBRemoteDynamicRegisterInfo &reg_info,
+ GDBRemoteDynamicRegisterInfoSP reg_info_sp,
bool read_all_at_once, bool write_all_at_once);
~GDBRemoteRegisterContext() override;
@@ -73,6 +78,8 @@ public:
uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
uint32_t num) override;
+ bool AArch64SVEReconfigure();
+
protected:
friend class ThreadGDBRemote;
@@ -106,7 +113,7 @@ protected:
m_reg_valid[reg] = valid;
}
- GDBRemoteDynamicRegisterInfo &m_reg_info;
+ GDBRemoteDynamicRegisterInfoSP m_reg_info_sp;
std::vector<bool> m_reg_valid;
DataExtractor m_reg_data;
bool m_read_all_at_once;
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 1fed8e064267..aba870c42e55 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -205,7 +205,8 @@ void ProcessGDBRemote::Terminate() {
lldb::ProcessSP
ProcessGDBRemote::CreateInstance(lldb::TargetSP target_sp,
ListenerSP listener_sp,
- const FileSpec *crash_file_path) {
+ const FileSpec *crash_file_path,
+ bool can_connect) {
lldb::ProcessSP process_sp;
if (crash_file_path == nullptr)
process_sp = std::make_shared<ProcessGDBRemote>(target_sp, listener_sp);
@@ -248,7 +249,7 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp,
ListenerSP listener_sp)
: Process(target_sp, listener_sp),
m_debugserver_pid(LLDB_INVALID_PROCESS_ID), m_last_stop_packet_mutex(),
- m_register_info(),
+ m_register_info_sp(nullptr),
m_async_broadcaster(nullptr, "lldb.process.gdb-remote.async-broadcaster"),
m_async_listener_sp(
Listener::MakeListener("lldb.process.gdb-remote.async-listener")),
@@ -367,8 +368,8 @@ bool ProcessGDBRemote::ParsePythonTargetDefinition(
m_breakpoint_pc_offset = breakpoint_pc_int_value->GetValue();
}
- if (m_register_info.SetRegisterInfo(*target_definition_sp,
- GetTarget().GetArchitecture()) > 0) {
+ if (m_register_info_sp->SetRegisterInfo(
+ *target_definition_sp, GetTarget().GetArchitecture()) > 0) {
return true;
}
}
@@ -395,10 +396,10 @@ static size_t SplitCommaSeparatedRegisterNumberString(
}
void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
- if (!force && m_register_info.GetNumRegisters() > 0)
+ if (!force && m_register_info_sp)
return;
- m_register_info.Clear();
+ m_register_info_sp = std::make_shared<GDBRemoteDynamicRegisterInfo>();
// Check if qHostInfo specified a specific packet timeout for this
// connection. If so then lets update our setting so the user knows what the
@@ -450,7 +451,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
return;
char packet[128];
- uint32_t reg_offset = 0;
+ uint32_t reg_offset = LLDB_INVALID_INDEX32;
uint32_t reg_num = 0;
for (StringExtractorGDBRemote::ResponseType response_type =
StringExtractorGDBRemote::eResponse;
@@ -563,7 +564,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
reg_info.byte_offset = reg_offset;
assert(reg_info.byte_size != 0);
- reg_offset += reg_info.byte_size;
+ reg_offset = LLDB_INVALID_INDEX32;
if (!value_regs.empty()) {
value_regs.push_back(LLDB_INVALID_REGNUM);
reg_info.value_regs = value_regs.data();
@@ -580,7 +581,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
if (ABISP abi_sp = ABI::FindPlugin(shared_from_this(), arch_to_use))
abi_sp->AugmentRegisterInfo(reg_info);
- m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name);
+ m_register_info_sp->AddRegister(reg_info, reg_name, alt_name, set_name);
} else {
break; // ensure exit before reg_num is incremented
}
@@ -589,8 +590,8 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
}
}
- if (m_register_info.GetNumRegisters() > 0) {
- m_register_info.Finalize(GetTarget().GetArchitecture());
+ if (m_register_info_sp->GetNumRegisters() > 0) {
+ m_register_info_sp->Finalize(GetTarget().GetArchitecture());
return;
}
@@ -599,21 +600,21 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
// updated debugserver down on the devices. On the other hand, if the
// accumulated reg_num is positive, see if we can add composite registers to
// the existing primordial ones.
- bool from_scratch = (m_register_info.GetNumRegisters() == 0);
+ bool from_scratch = (m_register_info_sp->GetNumRegisters() == 0);
if (!target_arch.IsValid()) {
if (arch_to_use.IsValid() &&
(arch_to_use.GetMachine() == llvm::Triple::arm ||
arch_to_use.GetMachine() == llvm::Triple::thumb) &&
arch_to_use.GetTriple().getVendor() == llvm::Triple::Apple)
- m_register_info.HardcodeARMRegisters(from_scratch);
+ m_register_info_sp->HardcodeARMRegisters(from_scratch);
} else if (target_arch.GetMachine() == llvm::Triple::arm ||
target_arch.GetMachine() == llvm::Triple::thumb) {
- m_register_info.HardcodeARMRegisters(from_scratch);
+ m_register_info_sp->HardcodeARMRegisters(from_scratch);
}
// At this point, we can finalize our register info.
- m_register_info.Finalize(GetTarget().GetArchitecture());
+ m_register_info_sp->Finalize(GetTarget().GetArchitecture());
}
Status ProcessGDBRemote::WillLaunch(lldb_private::Module *module) {
@@ -817,8 +818,8 @@ Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module,
// since 'O' packets can really slow down debugging if the inferior
// does a lot of output.
if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) &&
- pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY, nullptr, 0)) {
- FileSpec secondary_name{pty.GetSecondaryName(nullptr, 0)};
+ !errorToBool(pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY))) {
+ FileSpec secondary_name(pty.GetSecondaryName());
if (!stdin_file_spec)
stdin_file_spec = secondary_name;
@@ -1224,6 +1225,10 @@ Status ProcessGDBRemote::GetTraceConfig(lldb::user_id_t uid,
return m_gdb_comm.SendGetTraceConfigPacket(uid, options);
}
+llvm::Expected<TraceTypeInfo> ProcessGDBRemote::GetSupportedTraceType() {
+ return m_gdb_comm.SendGetSupportedTraceType();
+}
+
void ProcessGDBRemote::DidExit() {
// When we exit, disconnect from the GDB server communications
m_gdb_comm.Disconnect();
@@ -1597,8 +1602,8 @@ bool ProcessGDBRemote::UpdateThreadIDList() {
return true;
}
-bool ProcessGDBRemote::UpdateThreadList(ThreadList &old_thread_list,
- ThreadList &new_thread_list) {
+bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) {
// locker will keep a mutex locked until it goes out of scope
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_THREAD));
LLDB_LOGV(log, "pid = {0}", GetID());
@@ -1758,6 +1763,19 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
gdb_thread->PrivateSetRegisterValue(pair.first, buffer_sp->GetData());
}
+ // AArch64 SVE specific code below calls AArch64SVEReconfigure to update
+ // SVE register sizes and offsets if value of VG register has changed
+ // since last stop.
+ const ArchSpec &arch = GetTarget().GetArchitecture();
+ if (arch.IsValid() && arch.GetTriple().isAArch64()) {
+ GDBRemoteRegisterContext *reg_ctx_sp =
+ static_cast<GDBRemoteRegisterContext *>(
+ gdb_thread->GetRegisterContext().get());
+
+ if (reg_ctx_sp)
+ reg_ctx_sp->AArch64SVEReconfigure();
+ }
+
thread_sp->SetName(thread_name.empty() ? nullptr : thread_name.c_str());
gdb_thread->SetThreadDispatchQAddr(thread_dispatch_qaddr);
@@ -2647,7 +2665,7 @@ addr_t ProcessGDBRemote::GetImageInfoAddress() {
llvm::Expected<LoadedModuleInfoList> list = GetLoadedModuleList();
if (!list) {
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
- LLDB_LOG_ERROR(log, list.takeError(), "Failed to read module list: {0}");
+ LLDB_LOG_ERROR(log, list.takeError(), "Failed to read module list: {0}.");
} else {
addr = list->m_link_map;
}
@@ -3204,14 +3222,8 @@ Status ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) {
break;
case BreakpointSite::eExternal: {
- GDBStoppointType stoppoint_type;
- if (bp_site->IsHardware())
- stoppoint_type = eBreakpointHardware;
- else
- stoppoint_type = eBreakpointSoftware;
-
- if (m_gdb_comm.SendGDBStoppointTypePacket(stoppoint_type, false, addr,
- bp_op_size))
+ if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false,
+ addr, bp_op_size))
error.SetErrorToGenericError();
} break;
}
@@ -4277,14 +4289,14 @@ struct GdbServerTargetInfo {
bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
GDBRemoteDynamicRegisterInfo &dyn_reg_info, ABISP abi_sp,
- uint32_t &cur_reg_num, uint32_t &reg_offset) {
+ uint32_t &reg_num_remote, uint32_t &reg_num_local) {
if (!feature_node)
return false;
+ uint32_t reg_offset = LLDB_INVALID_INDEX32;
feature_node.ForEachChildElementWithName(
- "reg",
- [&target_info, &dyn_reg_info, &cur_reg_num, &reg_offset,
- &abi_sp](const XMLNode &reg_node) -> bool {
+ "reg", [&target_info, &dyn_reg_info, &reg_num_remote, &reg_num_local,
+ &reg_offset, &abi_sp](const XMLNode &reg_node) -> bool {
std::string gdb_group;
std::string gdb_type;
ConstString reg_name;
@@ -4306,8 +4318,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
LLDB_INVALID_REGNUM, // eh_frame reg num
LLDB_INVALID_REGNUM, // DWARF reg num
LLDB_INVALID_REGNUM, // generic reg num
- cur_reg_num, // process plugin reg num
- cur_reg_num // native register number
+ reg_num_remote, // process plugin reg num
+ reg_num_local // native register number
},
nullptr,
nullptr,
@@ -4434,7 +4446,7 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
reg_info.byte_offset = reg_offset;
assert(reg_info.byte_size != 0);
- reg_offset += reg_info.byte_size;
+ reg_offset = LLDB_INVALID_INDEX32;
if (!value_regs.empty()) {
value_regs.push_back(LLDB_INVALID_REGNUM);
reg_info.value_regs = value_regs.data();
@@ -4444,7 +4456,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
reg_info.invalidate_regs = invalidate_regs.data();
}
- ++cur_reg_num;
+ reg_num_remote = reg_info.kinds[eRegisterKindProcessPlugin] + 1;
+ ++reg_num_local;
reg_info.name = reg_name.AsCString();
if (abi_sp)
abi_sp->AugmentRegisterInfo(reg_info);
@@ -4463,8 +4476,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
// for nested register definition files. It returns true if it was able
// to fetch and parse an xml file.
bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess(
- ArchSpec &arch_to_use, std::string xml_filename, uint32_t &cur_reg_num,
- uint32_t &reg_offset) {
+ ArchSpec &arch_to_use, std::string xml_filename, uint32_t &reg_num_remote,
+ uint32_t &reg_num_local) {
// request the target xml file
std::string raw;
lldb_private::Status lldberr;
@@ -4567,13 +4580,13 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess(
// ABI is also potentially incorrect.
ABISP abi_to_use_sp = ABI::FindPlugin(shared_from_this(), arch_to_use);
for (auto &feature_node : feature_nodes) {
- ParseRegisters(feature_node, target_info, this->m_register_info,
- abi_to_use_sp, cur_reg_num, reg_offset);
+ ParseRegisters(feature_node, target_info, *this->m_register_info_sp,
+ abi_to_use_sp, reg_num_remote, reg_num_local);
}
for (const auto &include : target_info.includes) {
- GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, include, cur_reg_num,
- reg_offset);
+ GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, include,
+ reg_num_remote, reg_num_local);
}
}
} else {
@@ -4593,12 +4606,13 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
if (!m_gdb_comm.GetQXferFeaturesReadSupported())
return false;
- uint32_t cur_reg_num = 0;
- uint32_t reg_offset = 0;
- if (GetGDBServerRegisterInfoXMLAndProcess (arch_to_use, "target.xml", cur_reg_num, reg_offset))
- this->m_register_info.Finalize(arch_to_use);
+ uint32_t reg_num_remote = 0;
+ uint32_t reg_num_local = 0;
+ if (GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, "target.xml",
+ reg_num_remote, reg_num_local))
+ this->m_register_info_sp->Finalize(arch_to_use);
- return m_register_info.GetNumRegisters() > 0;
+ return m_register_info_sp->GetNumRegisters() > 0;
}
llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() {
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index ba967727ae3b..0921bf17c4e4 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -55,7 +55,8 @@ public:
static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
- const FileSpec *crash_file_path);
+ const FileSpec *crash_file_path,
+ bool can_connect);
static void Initialize();
@@ -175,6 +176,8 @@ public:
llvm::MutableArrayRef<uint8_t> &buffer,
size_t offset = 0) override;
+ llvm::Expected<TraceTypeInfo> GetSupportedTraceType() override;
+
Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) override;
Status GetWatchpointSupportInfo(uint32_t &num, bool &after) override;
@@ -251,7 +254,7 @@ protected:
// the last stop
// packet variable
std::recursive_mutex m_last_stop_packet_mutex;
- GDBRemoteDynamicRegisterInfo m_register_info;
+ GDBRemoteDynamicRegisterInfoSP m_register_info_sp;
Broadcaster m_async_broadcaster;
lldb::ListenerSP m_async_listener_sp;
HostThread m_async_thread;
@@ -309,8 +312,8 @@ protected:
void Clear();
- bool UpdateThreadList(ThreadList &old_thread_list,
- ThreadList &new_thread_list) override;
+ bool DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) override;
Status ConnectToReplayServer();
@@ -388,8 +391,8 @@ protected:
bool GetGDBServerRegisterInfoXMLAndProcess(ArchSpec &arch_to_use,
std::string xml_filename,
- uint32_t &cur_reg_num,
- uint32_t &reg_offset);
+ uint32_t &cur_reg_remote,
+ uint32_t &cur_reg_local);
// Query remote GDBServer for register information
bool GetGDBServerRegisterInfo(ArchSpec &arch);
diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
index 6deabf8d5d71..2a9896e41085 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
@@ -42,6 +42,14 @@ ThreadGDBRemote::ThreadGDBRemote(Process &process, lldb::tid_t tid)
Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_THREAD));
LLDB_LOG(log, "this = {0}, pid = {1}, tid = {2}", this, process.GetID(),
GetID());
+ // At this point we can clone reg_info for architectures supporting
+ // run-time update to register sizes and offsets..
+ auto &gdb_process = static_cast<ProcessGDBRemote &>(process);
+ if (!gdb_process.m_register_info_sp->IsReconfigurable())
+ m_reg_info_sp = gdb_process.m_register_info_sp;
+ else
+ m_reg_info_sp = std::make_shared<GDBRemoteDynamicRegisterInfo>(
+ *gdb_process.m_register_info_sp);
}
ThreadGDBRemote::~ThreadGDBRemote() {
@@ -307,8 +315,8 @@ ThreadGDBRemote::CreateRegisterContextForFrame(StackFrame *frame) {
!pSupported || gdb_process->m_use_g_packet_for_reading;
bool write_all_registers_at_once = !pSupported;
reg_ctx_sp = std::make_shared<GDBRemoteRegisterContext>(
- *this, concrete_frame_idx, gdb_process->m_register_info,
- read_all_registers_at_once, write_all_registers_at_once);
+ *this, concrete_frame_idx, m_reg_info_sp, read_all_registers_at_once,
+ write_all_registers_at_once);
}
} else {
reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);
diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
index 5ad11170fec4..b7d75021c062 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
@@ -14,6 +14,8 @@
#include "lldb/Target/Thread.h"
#include "lldb/Utility/StructuredData.h"
+#include "GDBRemoteRegisterContext.h"
+
class StringExtractor;
namespace lldb_private {
@@ -101,6 +103,8 @@ protected:
m_queue_serial_number; // Queue info from stop reply/stop info for thread
lldb_private::LazyBool m_associated_with_libdispatch_queue;
+ GDBRemoteDynamicRegisterInfoSP m_reg_info_sp;
+
bool PrivateSetRegisterValue(uint32_t reg, llvm::ArrayRef<uint8_t> data);
bool PrivateSetRegisterValue(uint32_t reg, uint64_t regval);
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
index 0c7f4cbbb859..61106ebcc430 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
+++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -62,27 +62,17 @@ UUID MinidumpParser::GetModuleUUID(const minidump::Module *module) {
static_cast<CvSignature>(static_cast<uint32_t>(*signature));
if (cv_signature == CvSignature::Pdb70) {
- const CvRecordPdb70 *pdb70_uuid = nullptr;
+ const UUID::CvRecordPdb70 *pdb70_uuid = nullptr;
Status error = consumeObject(cv_record, pdb70_uuid);
if (error.Fail())
return UUID();
-
- CvRecordPdb70 swapped;
- if (!GetArchitecture().GetTriple().isOSBinFormatELF()) {
- // LLDB's UUID class treats the data as a sequence of bytes, but breakpad
- // interprets it as a sequence of little-endian fields, which it converts
- // to big-endian when converting to text. Swap the bytes to big endian so
- // that the string representation comes out right.
- swapped = *pdb70_uuid;
- llvm::sys::swapByteOrder(swapped.Uuid.Data1);
- llvm::sys::swapByteOrder(swapped.Uuid.Data2);
- llvm::sys::swapByteOrder(swapped.Uuid.Data3);
- llvm::sys::swapByteOrder(swapped.Age);
- pdb70_uuid = &swapped;
+ if (GetArchitecture().GetTriple().isOSBinFormatELF()) {
+ if (pdb70_uuid->Age != 0)
+ return UUID::fromOptionalData(pdb70_uuid, sizeof(*pdb70_uuid));
+ return UUID::fromOptionalData(&pdb70_uuid->Uuid,
+ sizeof(pdb70_uuid->Uuid));
}
- if (pdb70_uuid->Age != 0)
- return UUID::fromOptionalData(pdb70_uuid, sizeof(*pdb70_uuid));
- return UUID::fromOptionalData(&pdb70_uuid->Uuid, sizeof(pdb70_uuid->Uuid));
+ return UUID::fromCvRecord(*pdb70_uuid);
} else if (cv_signature == CvSignature::ElfBuildId)
return UUID::fromOptionalData(cv_record);
@@ -267,6 +257,93 @@ llvm::ArrayRef<minidump::Module> MinidumpParser::GetModuleList() {
return {};
}
+static bool
+CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser,
+ std::vector<MemoryRegionInfo> &regions) {
+ auto data = parser.GetStream(StreamType::LinuxMaps);
+ if (data.empty())
+ return false;
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
+ ParseLinuxMapRegions(
+ llvm::toStringRef(data),
+ [&regions, &log](llvm::Expected<MemoryRegionInfo> region) -> bool {
+ if (region)
+ regions.push_back(*region);
+ else
+ LLDB_LOG_ERROR(log, region.takeError(),
+ "Reading memory region from minidump failed: {0}");
+ return true;
+ });
+ return !regions.empty();
+}
+
+/// Check for the memory regions starting at \a load_addr for a contiguous
+/// section that has execute permissions that matches the module path.
+///
+/// When we load a breakpad generated minidump file, we might have the
+/// /proc/<pid>/maps text for a process that details the memory map of the
+/// process that the minidump is describing. This checks the sorted memory
+/// regions for a section that has execute permissions. A sample maps files
+/// might look like:
+///
+/// 00400000-00401000 r--p 00000000 fd:01 2838574 /tmp/a.out
+/// 00401000-00402000 r-xp 00001000 fd:01 2838574 /tmp/a.out
+/// 00402000-00403000 r--p 00002000 fd:01 2838574 /tmp/a.out
+/// 00403000-00404000 r--p 00002000 fd:01 2838574 /tmp/a.out
+/// 00404000-00405000 rw-p 00003000 fd:01 2838574 /tmp/a.out
+/// ...
+///
+/// This function should return true when given 0x00400000 and "/tmp/a.out"
+/// is passed in as the path since it has a consecutive memory region for
+/// "/tmp/a.out" that has execute permissions at 0x00401000. This will help us
+/// differentiate if a file has been memory mapped into a process for reading
+/// and breakpad ends up saving a minidump file that has two module entries for
+/// a given file: one that is read only for the entire file, and then one that
+/// is the real executable that is loaded into memory for execution. For memory
+/// mapped files they will typically show up and r--p permissions and a range
+/// matcning the entire range of the file on disk:
+///
+/// 00800000-00805000 r--p 00000000 fd:01 2838574 /tmp/a.out
+/// 00805000-00806000 r-xp 00001000 fd:01 1234567 /usr/lib/libc.so
+///
+/// This function should return false when asked about 0x00800000 with
+/// "/tmp/a.out" as the path.
+///
+/// \param[in] path
+/// The path to the module to check for in the memory regions. Only sequential
+/// memory regions whose paths match this path will be considered when looking
+/// for execute permissions.
+///
+/// \param[in] regions
+/// A sorted list of memory regions obtained from a call to
+/// CreateRegionsCacheFromLinuxMaps.
+///
+/// \param[in] base_of_image
+/// The load address of this module from BaseOfImage in the modules list.
+///
+/// \return
+/// True if a contiguous region of memory belonging to the module with a
+/// matching path exists that has executable permissions. Returns false if
+/// \a regions is empty or if there are no regions with execute permissions
+/// that match \a path.
+
+static bool CheckForLinuxExecutable(ConstString path,
+ const MemoryRegionInfos &regions,
+ lldb::addr_t base_of_image) {
+ if (regions.empty())
+ return false;
+ lldb::addr_t addr = base_of_image;
+ MemoryRegionInfo region = MinidumpParser::GetMemoryRegionInfo(regions, addr);
+ while (region.GetName() == path) {
+ if (region.GetExecutable() == MemoryRegionInfo::eYes)
+ return true;
+ addr += region.GetRange().GetByteSize();
+ region = MinidumpParser::GetMemoryRegionInfo(regions, addr);
+ }
+ return false;
+}
+
std::vector<const minidump::Module *> MinidumpParser::GetFilteredModuleList() {
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_MODULES);
auto ExpectedModules = GetMinidumpFile().getModuleList();
@@ -276,6 +353,15 @@ std::vector<const minidump::Module *> MinidumpParser::GetFilteredModuleList() {
return {};
}
+ // Create memory regions from the linux maps only. We do this to avoid issues
+ // with breakpad generated minidumps where if someone has mmap'ed a shared
+ // library into memory to accesss its data in the object file, we can get a
+ // minidump with two mappings for a binary: one whose base image points to a
+ // memory region that is read + execute and one that is read only.
+ MemoryRegionInfos linux_regions;
+ if (CreateRegionsCacheFromLinuxMaps(*this, linux_regions))
+ llvm::sort(linux_regions);
+
// map module_name -> filtered_modules index
typedef llvm::StringMap<size_t> MapType;
MapType module_name_to_filtered_index;
@@ -304,10 +390,29 @@ std::vector<const minidump::Module *> MinidumpParser::GetFilteredModuleList() {
// "filtered_modules.size()" above.
filtered_modules.push_back(&module);
} else {
+ // We have a duplicate module entry. Check the linux regions to see if
+ // either module is not really a mapped executable. If one but not the
+ // other is a real mapped executable, prefer the executable one. This
+ // can happen when a process mmap's in the file for an executable in
+ // order to read bytes from the executable file. A memory region mapping
+ // will exist for the mmap'ed version and for the loaded executable, but
+ // only one will have a consecutive region that is executable in the
+ // memory regions.
+ auto dup_module = filtered_modules[iter->second];
+ ConstString name(*ExpectedName);
+ bool is_executable =
+ CheckForLinuxExecutable(name, linux_regions, module.BaseOfImage);
+ bool dup_is_executable =
+ CheckForLinuxExecutable(name, linux_regions, dup_module->BaseOfImage);
+
+ if (is_executable != dup_is_executable) {
+ if (is_executable)
+ filtered_modules[iter->second] = &module;
+ continue;
+ }
// This module has been seen. Modules are sometimes mentioned multiple
// times when they are mapped discontiguously, so find the module with
// the lowest "base_of_image" and use that as the filtered module.
- auto dup_module = filtered_modules[iter->second];
if (module.BaseOfImage < dup_module->BaseOfImage)
filtered_modules[iter->second] = &module;
}
@@ -412,22 +517,6 @@ llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
}
static bool
-CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser,
- std::vector<MemoryRegionInfo> &regions) {
- auto data = parser.GetStream(StreamType::LinuxMaps);
- if (data.empty())
- return false;
- ParseLinuxMapRegions(llvm::toStringRef(data),
- [&](const lldb_private::MemoryRegionInfo &region,
- const lldb_private::Status &status) -> bool {
- if (status.Success())
- regions.push_back(region);
- return true;
- });
- return !regions.empty();
-}
-
-static bool
CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser,
std::vector<MemoryRegionInfo> &regions) {
Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_MODULES);
@@ -500,10 +589,10 @@ CreateRegionsCacheFromMemory64List(MinidumpParser &parser,
uint64_t base_rva;
std::tie(memory64_list, base_rva) =
MinidumpMemoryDescriptor64::ParseMemory64List(data);
-
+
if (memory64_list.empty())
return false;
-
+
regions.reserve(memory64_list.size());
for (const auto &memory_desc : memory64_list) {
if (memory_desc.data_size == 0)
@@ -597,3 +686,30 @@ MinidumpParser::GetStreamTypeAsString(StreamType stream_type) {
}
return "unknown stream type";
}
+
+MemoryRegionInfo
+MinidumpParser::GetMemoryRegionInfo(const MemoryRegionInfos &regions,
+ lldb::addr_t load_addr) {
+ MemoryRegionInfo region;
+ auto pos = llvm::upper_bound(regions, load_addr);
+ if (pos != regions.begin() &&
+ std::prev(pos)->GetRange().Contains(load_addr)) {
+ return *std::prev(pos);
+ }
+
+ if (pos == regions.begin())
+ region.GetRange().SetRangeBase(0);
+ else
+ region.GetRange().SetRangeBase(std::prev(pos)->GetRange().GetRangeEnd());
+
+ if (pos == regions.end())
+ region.GetRange().SetRangeEnd(UINT64_MAX);
+ else
+ region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase());
+
+ region.SetReadable(MemoryRegionInfo::eNo);
+ region.SetWritable(MemoryRegionInfo::eNo);
+ region.SetExecutable(MemoryRegionInfo::eNo);
+ region.SetMapped(MemoryRegionInfo::eNo);
+ return region;
+}
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.h b/lldb/source/Plugins/Process/minidump/MinidumpParser.h
index c4d7612b5f8d..ff7134ff1815 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpParser.h
+++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.h
@@ -96,6 +96,9 @@ public:
llvm::object::MinidumpFile &GetMinidumpFile() { return *m_file; }
+ static MemoryRegionInfo GetMemoryRegionInfo(const MemoryRegionInfos &regions,
+ lldb::addr_t load_addr);
+
private:
MinidumpParser(lldb::DataBufferSP data_sp,
std::unique_ptr<llvm::object::MinidumpFile> file);
diff --git a/lldb/source/Plugins/Process/minidump/MinidumpTypes.h b/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
index a7ac65120e2b..c05fcfef05a6 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
+++ b/lldb/source/Plugins/Process/minidump/MinidumpTypes.h
@@ -40,21 +40,6 @@ enum class CvSignature : uint32_t {
ElfBuildId = 0x4270454c, // BpEL (Breakpad/Crashpad minidumps)
};
-// Reference:
-// https://crashpad.chromium.org/doxygen/structcrashpad_1_1CodeViewRecordPDB70.html
-struct CvRecordPdb70 {
- struct {
- llvm::support::ulittle32_t Data1;
- llvm::support::ulittle16_t Data2;
- llvm::support::ulittle16_t Data3;
- uint8_t Data4[8];
- } Uuid;
- llvm::support::ulittle32_t Age;
- // char PDBFileName[];
-};
-static_assert(sizeof(CvRecordPdb70) == 20,
- "sizeof CvRecordPdb70 is not correct!");
-
enum class MinidumpMiscInfoFlags : uint32_t {
ProcessID = (1 << 0),
ProcessTimes = (1 << 1),
diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
index fc8ee346f449..05a48acc2f7a 100644
--- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
+++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
@@ -121,6 +121,72 @@ private:
lldb::addr_t m_base;
lldb::addr_t m_size;
};
+
+/// Duplicate the HashElfTextSection() from the breakpad sources.
+///
+/// Breakpad, a Google crash log reporting tool suite, creates minidump files
+/// for many different architectures. When using Breakpad to create ELF
+/// minidumps, it will check for a GNU build ID when creating a minidump file
+/// and if one doesn't exist in the file, it will say the UUID of the file is a
+/// checksum of up to the first 4096 bytes of the .text section. Facebook also
+/// uses breakpad and modified this hash to avoid collisions so we can
+/// calculate and check for this as well.
+///
+/// The breakpad code might end up hashing up to 15 bytes that immediately
+/// follow the .text section in the file, so this code must do exactly what it
+/// does so we can get an exact match for the UUID.
+///
+/// \param[in] module_sp The module to grab the .text section from.
+///
+/// \param[in/out] breakpad_uuid A vector that will receive the calculated
+/// breakpad .text hash.
+///
+/// \param[in/out] facebook_uuid A vector that will receive the calculated
+/// facebook .text hash.
+///
+void HashElfTextSection(ModuleSP module_sp, std::vector<uint8_t> &breakpad_uuid,
+ std::vector<uint8_t> &facebook_uuid) {
+ SectionList *sect_list = module_sp->GetSectionList();
+ if (sect_list == nullptr)
+ return;
+ SectionSP sect_sp = sect_list->FindSectionByName(ConstString(".text"));
+ if (!sect_sp)
+ return;
+ constexpr size_t kMDGUIDSize = 16;
+ constexpr size_t kBreakpadPageSize = 4096;
+ // The breakpad code has a bug where it might access beyond the end of a
+ // .text section by up to 15 bytes, so we must ensure we round up to the
+ // next kMDGUIDSize byte boundary.
+ DataExtractor data;
+ const size_t text_size = sect_sp->GetFileSize();
+ const size_t read_size = std::min<size_t>(
+ llvm::alignTo(text_size, kMDGUIDSize), kBreakpadPageSize);
+ sect_sp->GetObjectFile()->GetData(sect_sp->GetFileOffset(), read_size, data);
+
+ breakpad_uuid.assign(kMDGUIDSize, 0);
+ facebook_uuid.assign(kMDGUIDSize, 0);
+
+ // The only difference between the breakpad hash and the facebook hash is the
+ // hashing of the text section size into the hash prior to hashing the .text
+ // contents.
+ for (size_t i = 0; i < kMDGUIDSize; i++)
+ facebook_uuid[i] ^= text_size % 255;
+
+ // This code carefully duplicates how the hash was created in Breakpad
+ // sources, including the error where it might has an extra 15 bytes past the
+ // end of the .text section if the .text section is less than a page size in
+ // length.
+ const uint8_t *ptr = data.GetDataStart();
+ const uint8_t *ptr_end = data.GetDataEnd();
+ while (ptr < ptr_end) {
+ for (unsigned i = 0; i < kMDGUIDSize; i++) {
+ breakpad_uuid[i] ^= ptr[i];
+ facebook_uuid[i] ^= ptr[i];
+ }
+ ptr += kMDGUIDSize;
+ }
+}
+
} // namespace
ConstString ProcessMinidump::GetPluginNameStatic() {
@@ -134,8 +200,9 @@ const char *ProcessMinidump::GetPluginDescriptionStatic() {
lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
- const FileSpec *crash_file) {
- if (!crash_file)
+ const FileSpec *crash_file,
+ bool can_connect) {
+ if (!crash_file || can_connect)
return nullptr;
lldb::ProcessSP process_sp;
@@ -168,7 +235,7 @@ ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
const FileSpec &core_file,
DataBufferSP core_data)
- : Process(target_sp, listener_sp), m_core_file(core_file),
+ : PostMortemProcess(target_sp, listener_sp), m_core_file(core_file),
m_core_data(std::move(core_data)), m_is_wow64(false) {}
ProcessMinidump::~ProcessMinidump() {
@@ -338,32 +405,6 @@ ArchSpec ProcessMinidump::GetArchitecture() {
return ArchSpec(triple);
}
-static MemoryRegionInfo GetMemoryRegionInfo(const MemoryRegionInfos &regions,
- lldb::addr_t load_addr) {
- MemoryRegionInfo region;
- auto pos = llvm::upper_bound(regions, load_addr);
- if (pos != regions.begin() &&
- std::prev(pos)->GetRange().Contains(load_addr)) {
- return *std::prev(pos);
- }
-
- if (pos == regions.begin())
- region.GetRange().SetRangeBase(0);
- else
- region.GetRange().SetRangeBase(std::prev(pos)->GetRange().GetRangeEnd());
-
- if (pos == regions.end())
- region.GetRange().SetRangeEnd(UINT64_MAX);
- else
- region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase());
-
- region.SetReadable(MemoryRegionInfo::eNo);
- region.SetWritable(MemoryRegionInfo::eNo);
- region.SetExecutable(MemoryRegionInfo::eNo);
- region.SetMapped(MemoryRegionInfo::eNo);
- return region;
-}
-
void ProcessMinidump::BuildMemoryRegions() {
if (m_memory_regions)
return;
@@ -388,7 +429,7 @@ void ProcessMinidump::BuildMemoryRegions() {
MemoryRegionInfo::RangeType section_range(load_addr,
section_sp->GetByteSize());
MemoryRegionInfo region =
- ::GetMemoryRegionInfo(*m_memory_regions, load_addr);
+ MinidumpParser::GetMemoryRegionInfo(*m_memory_regions, load_addr);
if (region.GetMapped() != MemoryRegionInfo::eYes &&
region.GetRange().GetRangeBase() <= section_range.GetRangeBase() &&
section_range.GetRangeEnd() <= region.GetRange().GetRangeEnd()) {
@@ -409,7 +450,7 @@ void ProcessMinidump::BuildMemoryRegions() {
Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr,
MemoryRegionInfo &region) {
BuildMemoryRegions();
- region = ::GetMemoryRegionInfo(*m_memory_regions, load_addr);
+ region = MinidumpParser::GetMemoryRegionInfo(*m_memory_regions, load_addr);
return Status();
}
@@ -421,8 +462,8 @@ Status ProcessMinidump::GetMemoryRegions(MemoryRegionInfos &region_list) {
void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); }
-bool ProcessMinidump::UpdateThreadList(ThreadList &old_thread_list,
- ThreadList &new_thread_list) {
+bool ProcessMinidump::DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) {
for (const minidump::Thread &thread : m_thread_list) {
LocationDescriptor context_location = thread.Context;
@@ -444,6 +485,53 @@ bool ProcessMinidump::UpdateThreadList(ThreadList &old_thread_list,
return new_thread_list.GetSize(false) > 0;
}
+ModuleSP ProcessMinidump::GetOrCreateModule(UUID minidump_uuid,
+ llvm::StringRef name,
+ ModuleSpec module_spec) {
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+ Status error;
+
+ ModuleSP module_sp =
+ GetTarget().GetOrCreateModule(module_spec, true /* notify */, &error);
+ if (!module_sp)
+ return module_sp;
+ // We consider the module to be a match if the minidump UUID is a
+ // prefix of the actual UUID, or if either of the UUIDs are empty.
+ const auto dmp_bytes = minidump_uuid.GetBytes();
+ const auto mod_bytes = module_sp->GetUUID().GetBytes();
+ const bool match = dmp_bytes.empty() || mod_bytes.empty() ||
+ mod_bytes.take_front(dmp_bytes.size()) == dmp_bytes;
+ if (match) {
+ LLDB_LOG(log, "Partial uuid match for {0}.", name);
+ return module_sp;
+ }
+
+ // Breakpad generates minindump files, and if there is no GNU build
+ // ID in the binary, it will calculate a UUID by hashing first 4096
+ // bytes of the .text section and using that as the UUID for a module
+ // in the minidump. Facebook uses a modified breakpad client that
+ // uses a slightly modified this hash to avoid collisions. Check for
+ // UUIDs from the minindump that match these cases and accept the
+ // module we find if they do match.
+ std::vector<uint8_t> breakpad_uuid;
+ std::vector<uint8_t> facebook_uuid;
+ HashElfTextSection(module_sp, breakpad_uuid, facebook_uuid);
+ if (dmp_bytes == llvm::ArrayRef<uint8_t>(breakpad_uuid)) {
+ LLDB_LOG(log, "Breakpad .text hash match for {0}.", name);
+ return module_sp;
+ }
+ if (dmp_bytes == llvm::ArrayRef<uint8_t>(facebook_uuid)) {
+ LLDB_LOG(log, "Facebook .text hash match for {0}.", name);
+ return module_sp;
+ }
+ // The UUID wasn't a partial match and didn't match the .text hash
+ // so remove the module from the target, we will need to create a
+ // placeholder object file.
+ GetTarget().GetImages().Remove(module_sp);
+ module_sp.reset();
+ return module_sp;
+}
+
void ProcessMinidump::ReadModuleList() {
std::vector<const minidump::Module *> filtered_modules =
m_minidump_parser->GetFilteredModuleList();
@@ -473,30 +561,21 @@ void ProcessMinidump::ReadModuleList() {
// add the module to the target if it finds one.
lldb::ModuleSP module_sp = GetTarget().GetOrCreateModule(module_spec,
true /* notify */, &error);
- if (!module_sp) {
- // Try and find a module without specifying the UUID and only looking for
- // the file given a basename. We then will look for a partial UUID match
- // if we find any matches. This function will add the module to the
- // target if it finds one, so we need to remove the module from the target
- // if the UUID doesn't match during our manual UUID verification. This
- // allows the "target.exec-search-paths" setting to specify one or more
- // directories that contain executables that can be searched for matches.
- ModuleSpec basename_module_spec(module_spec);
- basename_module_spec.GetUUID().Clear();
- basename_module_spec.GetFileSpec().GetDirectory().Clear();
- module_sp = GetTarget().GetOrCreateModule(basename_module_spec,
- true /* notify */, &error);
- if (module_sp) {
- // We consider the module to be a match if the minidump UUID is a
- // prefix of the actual UUID, or if either of the UUIDs are empty.
- const auto dmp_bytes = uuid.GetBytes();
- const auto mod_bytes = module_sp->GetUUID().GetBytes();
- const bool match = dmp_bytes.empty() || mod_bytes.empty() ||
- mod_bytes.take_front(dmp_bytes.size()) == dmp_bytes;
- if (!match) {
- GetTarget().GetImages().Remove(module_sp);
- module_sp.reset();
- }
+ if (module_sp) {
+ LLDB_LOG(log, "Full uuid match for {0}.", name);
+ } else {
+ // We couldn't find a module with an exactly-matching UUID. Sometimes
+ // a minidump UUID is only a partial match or is a hash. So try again
+ // without specifying the UUID, then again without specifying the
+ // directory if that fails. This will allow us to find modules with
+ // partial matches or hash UUIDs in user-provided sysroots or search
+ // directories (target.exec-search-paths).
+ ModuleSpec partial_module_spec = module_spec;
+ partial_module_spec.GetUUID().Clear();
+ module_sp = GetOrCreateModule(uuid, name, partial_module_spec);
+ if (!module_sp) {
+ partial_module_spec.GetFileSpec().GetDirectory().Clear();
+ module_sp = GetOrCreateModule(uuid, name, partial_module_spec);
}
}
if (module_sp) {
diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
index 839b0e7563f7..27b0da0047a5 100644
--- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
+++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
@@ -12,7 +12,7 @@
#include "MinidumpParser.h"
#include "MinidumpTypes.h"
-#include "lldb/Target/Process.h"
+#include "lldb/Target/PostMortemProcess.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/ConstString.h"
@@ -26,11 +26,12 @@ namespace lldb_private {
namespace minidump {
-class ProcessMinidump : public Process {
+class ProcessMinidump : public PostMortemProcess {
public:
static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
- const FileSpec *crash_file_path);
+ const FileSpec *crash_file_path,
+ bool can_connect);
static void Initialize();
@@ -97,11 +98,15 @@ public:
protected:
void Clear();
- bool UpdateThreadList(ThreadList &old_thread_list,
- ThreadList &new_thread_list) override;
+ bool DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) override;
void ReadModuleList();
+ lldb::ModuleSP GetOrCreateModule(lldb_private::UUID minidump_uuid,
+ llvm::StringRef name,
+ lldb_private::ModuleSpec module_spec);
+
JITLoaderList &GetJITLoaders() override;
private: