summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/lldb/source/Plugins/Process
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Plugins/Process')
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp70
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.h39
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp92
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h110
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXThread.cpp665
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXThread.h132
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp276
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h104
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp1626
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h328
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessPOSIX.cpp939
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessPOSIX.h205
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp322
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h95
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp318
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h95
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp318
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h95
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp337
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h104
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp650
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h95
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/CrashReason.cpp315
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/CrashReason.h62
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessMessage.cpp78
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessMessage.h182
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp210
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h117
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMDefines.h142
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMUtils.h394
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp766
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h98
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/FreeBSDSignals.cpp95
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/FreeBSDSignals.h31
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp32
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.h36
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp101
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h136
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp81
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryUnwind.h50
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp280
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h38
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InstructionUtils.h138
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp95
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/LinuxSignals.h34
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp95
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.h34
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp1228
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h333
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp944
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h296
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp981
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h269
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp1068
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h274
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp137
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h77
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp88
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.h75
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.cpp86
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h78
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp95
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h31
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp93
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h31
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp269
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h66
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp164
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h35
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp138
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h79
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp2084
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h272
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp87
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm.h76
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp89
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm64.h81
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp133
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.h34
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp67
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.h35
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp126
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h44
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp198
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h39
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp207
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h77
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp87
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h56
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp72
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h49
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp72
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h49
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp174
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h102
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX.h79
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp287
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h121
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp302
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h119
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp237
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h90
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp319
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h218
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp667
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h189
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp261
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h114
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_mips.h611
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h232
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h487
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h60
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h303
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h347
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h215
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_mips.h175
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h237
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h184
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h418
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp529
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.h77
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp140
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.h152
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp451
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h154
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp275
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h74
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-arm-register-enums.h153
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-arm64-register-enums.h172
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h70
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-mips-linux-register-enums.h285
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h295
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp596
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h160
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp94
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h60
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp94
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h60
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp94
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h60
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp134
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h71
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp100
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h58
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp252
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h180
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp1456
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h384
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp4455
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h684
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp138
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h85
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp1341
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h216
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp2841
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h317
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp409
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h105
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp1170
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h178
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp5038
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h467
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp215
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h66
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp324
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h138
166 files changed, 53039 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp
new file mode 100644
index 0000000..5e46c83
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.cpp
@@ -0,0 +1,70 @@
+//===-- FreeBSDThread.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/State.h"
+#include "lldb/Target/UnixSignals.h"
+
+// Project includes
+#include "FreeBSDThread.h"
+#include "ProcessFreeBSD.h"
+#include "ProcessPOSIXLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------------------
+// Constructors and destructors.
+
+FreeBSDThread::FreeBSDThread(Process &process, lldb::tid_t tid)
+ : POSIXThread(process, tid)
+{
+}
+
+FreeBSDThread::~FreeBSDThread()
+{
+}
+
+//------------------------------------------------------------------------------
+// ProcessInterface protocol.
+
+void
+FreeBSDThread::WillResume(lldb::StateType resume_state)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf("tid %lu resume_state = %s", GetID(),
+ lldb_private::StateAsCString(resume_state));
+ ProcessSP process_sp(GetProcess());
+ ProcessFreeBSD *process = static_cast<ProcessFreeBSD *>(process_sp.get());
+ int signo = GetResumeSignal();
+ bool signo_valid = process->GetUnixSignals()->SignalIsValid(signo);
+
+ switch (resume_state)
+ {
+ case eStateSuspended:
+ case eStateStopped:
+ process->m_suspend_tids.push_back(GetID());
+ break;
+ case eStateRunning:
+ process->m_run_tids.push_back(GetID());
+ if (signo_valid)
+ process->m_resume_signo = signo;
+ break;
+ case eStateStepping:
+ process->m_step_tids.push_back(GetID());
+ if (signo_valid)
+ process->m_resume_signo = signo;
+ break;
+ default:
+ break;
+ }
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.h
new file mode 100644
index 0000000..8741075
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/FreeBSDThread.h
@@ -0,0 +1,39 @@
+//===-- FreeBSDThread.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_FreeBSDThread_H_
+#define liblldb_FreeBSDThread_H_
+
+// Other libraries and framework includes
+#include "POSIXThread.h"
+
+//------------------------------------------------------------------------------
+// @class FreeBSDThread
+// @brief Abstraction of a FreeBSD thread.
+class FreeBSDThread
+ : public POSIXThread
+{
+public:
+
+ //------------------------------------------------------------------
+ // Constructors and destructors
+ //------------------------------------------------------------------
+ FreeBSDThread(lldb_private::Process &process, lldb::tid_t tid);
+
+ virtual ~FreeBSDThread();
+
+ //--------------------------------------------------------------------------
+ // FreeBSDThread internal API.
+
+ // POSIXThread override
+ virtual void
+ WillResume(lldb::StateType resume_state);
+};
+
+#endif // #ifndef liblldb_FreeBSDThread_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp
new file mode 100644
index 0000000..3b8cea7
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.cpp
@@ -0,0 +1,92 @@
+//===-- POSIXStopInfo.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "POSIXStopInfo.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//===----------------------------------------------------------------------===//
+// POSIXLimboStopInfo
+
+POSIXLimboStopInfo::~POSIXLimboStopInfo() { }
+
+lldb::StopReason
+POSIXLimboStopInfo::GetStopReason() const
+{
+ return lldb::eStopReasonThreadExiting;
+}
+
+const char *
+POSIXLimboStopInfo::GetDescription()
+{
+ return "thread exiting";
+}
+
+bool
+POSIXLimboStopInfo::ShouldStop(Event *event_ptr)
+{
+ return false;
+}
+
+bool
+POSIXLimboStopInfo::ShouldNotify(Event *event_ptr)
+{
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// POSIXCrashStopInfo
+
+POSIXCrashStopInfo::POSIXCrashStopInfo(POSIXThread &thread,
+ uint32_t status,
+ CrashReason reason,
+ lldb::addr_t fault_addr)
+ : POSIXStopInfo(thread, status)
+{
+ m_description = ::GetCrashReasonString(reason, fault_addr);
+}
+
+POSIXCrashStopInfo::~POSIXCrashStopInfo() { }
+
+lldb::StopReason
+POSIXCrashStopInfo::GetStopReason() const
+{
+ return lldb::eStopReasonException;
+}
+
+//===----------------------------------------------------------------------===//
+// POSIXNewThreadStopInfo
+
+POSIXNewThreadStopInfo::~POSIXNewThreadStopInfo() { }
+
+lldb::StopReason
+POSIXNewThreadStopInfo::GetStopReason() const
+{
+ return lldb::eStopReasonNone;
+}
+
+const char *
+POSIXNewThreadStopInfo::GetDescription()
+{
+ return "thread spawned";
+}
+
+bool
+POSIXNewThreadStopInfo::ShouldStop(Event *event_ptr)
+{
+ return false;
+}
+
+bool
+POSIXNewThreadStopInfo::ShouldNotify(Event *event_ptr)
+{
+ return false;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h
new file mode 100644
index 0000000..a1ee2ea
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXStopInfo.h
@@ -0,0 +1,110 @@
+//===-- POSIXStopInfo.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_POSIXStopInfo_H_
+#define liblldb_POSIXStopInfo_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/StopInfo.h"
+
+#include "CrashReason.h"
+#include "POSIXThread.h"
+
+#include <string>
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXStopInfo
+/// @brief Simple base class for all POSIX-specific StopInfo objects.
+///
+class POSIXStopInfo
+ : public lldb_private::StopInfo
+{
+public:
+ POSIXStopInfo(lldb_private::Thread &thread, uint32_t status)
+ : StopInfo(thread, status)
+ { }
+};
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXLimboStopInfo
+/// @brief Represents the stop state of a process ready to exit.
+///
+class POSIXLimboStopInfo
+ : public POSIXStopInfo
+{
+public:
+ POSIXLimboStopInfo(POSIXThread &thread)
+ : POSIXStopInfo(thread, 0)
+ { }
+
+ ~POSIXLimboStopInfo();
+
+ lldb::StopReason
+ GetStopReason() const;
+
+ const char *
+ GetDescription();
+
+ bool
+ ShouldStop(lldb_private::Event *event_ptr);
+
+ bool
+ ShouldNotify(lldb_private::Event *event_ptr);
+};
+
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXCrashStopInfo
+/// @brief Represents the stop state of process that is ready to crash.
+///
+class POSIXCrashStopInfo
+ : public POSIXStopInfo
+{
+public:
+ POSIXCrashStopInfo(POSIXThread &thread, uint32_t status,
+ CrashReason reason,
+ lldb::addr_t fault_addr);
+ ~POSIXCrashStopInfo();
+
+ lldb::StopReason
+ GetStopReason() const;
+};
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXNewThreadStopInfo
+/// @brief Represents the stop state of process when a new thread is spawned.
+///
+
+class POSIXNewThreadStopInfo
+ : public POSIXStopInfo
+{
+public:
+ POSIXNewThreadStopInfo (POSIXThread &thread)
+ : POSIXStopInfo (thread, 0)
+ { }
+
+ ~POSIXNewThreadStopInfo();
+
+ lldb::StopReason
+ GetStopReason() const;
+
+ const char *
+ GetDescription();
+
+ bool
+ ShouldStop(lldb_private::Event *event_ptr);
+
+ bool
+ ShouldNotify(lldb_private::Event *event_ptr);
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXThread.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXThread.cpp
new file mode 100644
index 0000000..7d95e96
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXThread.cpp
@@ -0,0 +1,665 @@
+//===-- POSIXThread.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostNativeThread.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "llvm/ADT/SmallString.h"
+#include "POSIXStopInfo.h"
+#include "POSIXThread.h"
+#include "ProcessPOSIX.h"
+#include "ProcessPOSIXLog.h"
+#include "ProcessMonitor.h"
+#include "RegisterContextPOSIXProcessMonitor_arm.h"
+#include "RegisterContextPOSIXProcessMonitor_arm64.h"
+#include "RegisterContextPOSIXProcessMonitor_mips64.h"
+#include "RegisterContextPOSIXProcessMonitor_powerpc.h"
+#include "RegisterContextPOSIXProcessMonitor_x86.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
+#include "Plugins/Process/Utility/UnwindLLDB.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+POSIXThread::POSIXThread(Process &process, lldb::tid_t tid)
+ : Thread(process, tid),
+ m_frame_ap (),
+ m_breakpoint (),
+ m_thread_name_valid (false),
+ m_thread_name (),
+ m_posix_thread(NULL)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("POSIXThread::%s (tid = %" PRIi64 ")", __FUNCTION__, tid);
+
+ // Set the current watchpoints for this thread.
+ Target &target = GetProcess()->GetTarget();
+ const WatchpointList &wp_list = target.GetWatchpointList();
+ size_t wp_size = wp_list.GetSize();
+
+ for (uint32_t wp_idx = 0; wp_idx < wp_size; wp_idx++)
+ {
+ lldb::WatchpointSP wp = wp_list.GetByIndex(wp_idx);
+ if (wp.get() && wp->IsEnabled())
+ {
+ // This watchpoint as been enabled; obviously this "new" thread
+ // has been created since that watchpoint was enabled. Since
+ // the POSIXBreakpointProtocol has yet to be initialized, its
+ // m_watchpoints_initialized member will be FALSE. Attempting to
+ // read the debug status register to determine if a watchpoint
+ // has been hit would result in the zeroing of that register.
+ // Since the active debug registers would have been cloned when
+ // this thread was created, simply force the m_watchpoints_initized
+ // member to TRUE and avoid resetting dr6 and dr7.
+ GetPOSIXBreakpointProtocol()->ForceWatchpointsInitialized();
+ }
+ }
+}
+
+POSIXThread::~POSIXThread()
+{
+ DestroyThread();
+}
+
+ProcessMonitor &
+POSIXThread::GetMonitor()
+{
+ ProcessSP base = GetProcess();
+ ProcessPOSIX &process = static_cast<ProcessPOSIX&>(*base);
+ return process.GetMonitor();
+}
+
+void
+POSIXThread::RefreshStateAfterStop()
+{
+ // Invalidate all registers in our register context. We don't set "force" to
+ // true because the stop reply packet might have had some register values
+ // that were expedited and these will already be copied into the register
+ // context by the time this function gets called. The KDPRegisterContext
+ // class has been made smart enough to detect when it needs to invalidate
+ // which registers are valid by putting hooks in the register read and
+ // register supply functions where they check the process stop ID and do
+ // the right thing.
+ //if (StateIsStoppedState(GetState())
+ {
+ const bool force = false;
+ GetRegisterContext()->InvalidateIfNeeded (force);
+ }
+}
+
+const char *
+POSIXThread::GetInfo()
+{
+ return NULL;
+}
+
+void
+POSIXThread::SetName (const char *name)
+{
+ m_thread_name_valid = (name && name[0]);
+ if (m_thread_name_valid)
+ m_thread_name.assign (name);
+ else
+ m_thread_name.clear();
+}
+
+const char *
+POSIXThread::GetName ()
+{
+ if (!m_thread_name_valid)
+ {
+ llvm::SmallString<32> thread_name;
+ HostNativeThread::GetName(GetID(), thread_name);
+ m_thread_name = thread_name.c_str();
+ m_thread_name_valid = true;
+ }
+
+ if (m_thread_name.empty())
+ return NULL;
+ return m_thread_name.c_str();
+}
+
+lldb::RegisterContextSP
+POSIXThread::GetRegisterContext()
+{
+ if (!m_reg_context_sp)
+ {
+ m_posix_thread = NULL;
+
+ RegisterInfoInterface *reg_interface = NULL;
+ const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture();
+
+ switch (target_arch.GetTriple().getOS())
+ {
+ case llvm::Triple::FreeBSD:
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ reg_interface = new RegisterContextFreeBSD_arm64(target_arch);
+ break;
+ case llvm::Triple::arm:
+ reg_interface = new RegisterContextFreeBSD_arm(target_arch);
+ break;
+ case llvm::Triple::ppc:
+#ifndef __powerpc64__
+ reg_interface = new RegisterContextFreeBSD_powerpc32(target_arch);
+ break;
+#endif
+ case llvm::Triple::ppc64:
+ reg_interface = new RegisterContextFreeBSD_powerpc64(target_arch);
+ break;
+ case llvm::Triple::mips64:
+ reg_interface = new RegisterContextFreeBSD_mips64(target_arch);
+ break;
+ case llvm::Triple::x86:
+ reg_interface = new RegisterContextFreeBSD_i386(target_arch);
+ break;
+ case llvm::Triple::x86_64:
+ reg_interface = new RegisterContextFreeBSD_x86_64(target_arch);
+ break;
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ assert(reg_interface && "OS or CPU not supported!");
+
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ {
+ RegisterContextPOSIXProcessMonitor_arm64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm64(*this, 0, reg_interface);
+ m_posix_thread = reg_ctx;
+ m_reg_context_sp.reset(reg_ctx);
+ break;
+ }
+ case llvm::Triple::arm:
+ {
+ RegisterContextPOSIXProcessMonitor_arm *reg_ctx = new RegisterContextPOSIXProcessMonitor_arm(*this, 0, reg_interface);
+ m_posix_thread = reg_ctx;
+ m_reg_context_sp.reset(reg_ctx);
+ break;
+ }
+ case llvm::Triple::mips64:
+ {
+ RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface);
+ m_posix_thread = reg_ctx;
+ m_reg_context_sp.reset(reg_ctx);
+ break;
+ }
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ {
+ RegisterContextPOSIXProcessMonitor_powerpc *reg_ctx = new RegisterContextPOSIXProcessMonitor_powerpc(*this, 0, reg_interface);
+ m_posix_thread = reg_ctx;
+ m_reg_context_sp.reset(reg_ctx);
+ break;
+ }
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ {
+ RegisterContextPOSIXProcessMonitor_x86_64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_x86_64(*this, 0, reg_interface);
+ m_posix_thread = reg_ctx;
+ m_reg_context_sp.reset(reg_ctx);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return m_reg_context_sp;
+}
+
+lldb::RegisterContextSP
+POSIXThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("POSIXThread::%s ()", __FUNCTION__);
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex();
+
+ if (concrete_frame_idx == 0)
+ reg_ctx_sp = GetRegisterContext();
+ else
+ {
+ assert(GetUnwinder());
+ reg_ctx_sp = GetUnwinder()->CreateRegisterContextForFrame(frame);
+ }
+
+ return reg_ctx_sp;
+}
+
+lldb::addr_t
+POSIXThread::GetThreadPointer ()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ addr_t addr;
+ if (monitor.ReadThreadPointer (GetID(), addr))
+ return addr;
+ else
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+POSIXThread::CalculateStopInfo()
+{
+ SetStopInfo (m_stop_info_sp);
+ return true;
+}
+
+Unwind *
+POSIXThread::GetUnwinder()
+{
+ if (m_unwinder_ap.get() == NULL)
+ m_unwinder_ap.reset(new UnwindLLDB(*this));
+
+ return m_unwinder_ap.get();
+}
+
+void
+POSIXThread::DidStop()
+{
+ // Don't set the thread state to stopped unless we really stopped.
+}
+
+bool
+POSIXThread::Resume()
+{
+ lldb::StateType resume_state = GetResumeState();
+ ProcessMonitor &monitor = GetMonitor();
+ bool status;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s (), resume_state = %s", __FUNCTION__,
+ StateAsCString(resume_state));
+
+ switch (resume_state)
+ {
+ default:
+ assert(false && "Unexpected state for resume!");
+ status = false;
+ break;
+
+ case lldb::eStateRunning:
+ SetState(resume_state);
+ status = monitor.Resume(GetID(), GetResumeSignal());
+ break;
+
+ case lldb::eStateStepping:
+ SetState(resume_state);
+ status = monitor.SingleStep(GetID(), GetResumeSignal());
+ break;
+ case lldb::eStateStopped:
+ case lldb::eStateSuspended:
+ status = true;
+ break;
+ }
+
+ return status;
+}
+
+void
+POSIXThread::Notify(const ProcessMessage &message)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s () message kind = '%s' for tid %" PRIu64,
+ __FUNCTION__, message.PrintKind(), GetID());
+
+ switch (message.GetKind())
+ {
+ default:
+ assert(false && "Unexpected message kind!");
+ break;
+
+ case ProcessMessage::eExitMessage:
+ // Nothing to be done.
+ break;
+
+ case ProcessMessage::eLimboMessage:
+ LimboNotify(message);
+ break;
+
+ case ProcessMessage::eSignalMessage:
+ SignalNotify(message);
+ break;
+
+ case ProcessMessage::eSignalDeliveredMessage:
+ SignalDeliveredNotify(message);
+ break;
+
+ case ProcessMessage::eTraceMessage:
+ TraceNotify(message);
+ break;
+
+ case ProcessMessage::eBreakpointMessage:
+ BreakNotify(message);
+ break;
+
+ case ProcessMessage::eWatchpointMessage:
+ WatchNotify(message);
+ break;
+
+ case ProcessMessage::eCrashMessage:
+ CrashNotify(message);
+ break;
+
+ case ProcessMessage::eNewThreadMessage:
+ ThreadNotify(message);
+ break;
+
+ case ProcessMessage::eExecMessage:
+ ExecNotify(message);
+ break;
+ }
+}
+
+bool
+POSIXThread::EnableHardwareWatchpoint(Watchpoint *wp)
+{
+ bool wp_set = false;
+ if (wp)
+ {
+ addr_t wp_addr = wp->GetLoadAddress();
+ size_t wp_size = wp->GetByteSize();
+ bool wp_read = wp->WatchpointRead();
+ bool wp_write = wp->WatchpointWrite();
+ uint32_t wp_hw_index = wp->GetHardwareIndex();
+ POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol();
+ if (reg_ctx)
+ wp_set = reg_ctx->SetHardwareWatchpointWithIndex(wp_addr, wp_size,
+ wp_read, wp_write,
+ wp_hw_index);
+ }
+ return wp_set;
+}
+
+bool
+POSIXThread::DisableHardwareWatchpoint(Watchpoint *wp)
+{
+ bool result = false;
+ if (wp)
+ {
+ lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
+ if (reg_ctx_sp.get())
+ result = reg_ctx_sp->ClearHardwareWatchpoint(wp->GetHardwareIndex());
+ }
+ return result;
+}
+
+uint32_t
+POSIXThread::NumSupportedHardwareWatchpoints()
+{
+ lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
+ if (reg_ctx_sp.get())
+ return reg_ctx_sp->NumSupportedHardwareWatchpoints();
+ return 0;
+}
+
+uint32_t
+POSIXThread::FindVacantWatchpointIndex()
+{
+ uint32_t hw_index = LLDB_INVALID_INDEX32;
+ uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
+ uint32_t wp_idx;
+ POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol();
+ if (reg_ctx)
+ {
+ for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++)
+ {
+ if (reg_ctx->IsWatchpointVacant(wp_idx))
+ {
+ hw_index = wp_idx;
+ break;
+ }
+ }
+ }
+ return hw_index;
+}
+
+void
+POSIXThread::BreakNotify(const ProcessMessage &message)
+{
+ bool status;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+
+ assert(GetRegisterContext());
+ status = GetPOSIXBreakpointProtocol()->UpdateAfterBreakpoint();
+ assert(status && "Breakpoint update failed!");
+
+ // With our register state restored, resolve the breakpoint object
+ // corresponding to our current PC.
+ assert(GetRegisterContext());
+ lldb::addr_t pc = GetRegisterContext()->GetPC();
+ if (log)
+ log->Printf ("POSIXThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc);
+ lldb::BreakpointSiteSP bp_site(GetProcess()->GetBreakpointSiteList().FindByAddress(pc));
+
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we create a stop reason with should_stop=false. If there is no breakpoint location, then report
+ // an invalid stop reason. We don't need to worry about stepping over the breakpoint here, that will
+ // be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ if (bp_site)
+ {
+ lldb::break_id_t bp_id = bp_site->GetID();
+ // If we have an operating system plug-in, we might have set a thread specific breakpoint using the
+ // operating system thread ID, so we can't make any assumptions about the thread ID so we must always
+ // report the breakpoint regardless of the thread.
+ if (bp_site->ValidForThisThread(this) || GetProcess()->GetOperatingSystem () != NULL)
+ SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id));
+ else
+ {
+ const bool should_stop = false;
+ SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id, should_stop));
+ }
+ }
+ else
+ SetStopInfo(StopInfoSP());
+}
+
+void
+POSIXThread::WatchNotify(const ProcessMessage &message)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+
+ lldb::addr_t halt_addr = message.GetHWAddress();
+ if (log)
+ log->Printf ("POSIXThread::%s () Hardware Watchpoint Address = 0x%8.8"
+ PRIx64, __FUNCTION__, halt_addr);
+
+ POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol();
+ if (reg_ctx)
+ {
+ uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints();
+ uint32_t wp_idx;
+ for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++)
+ {
+ if (reg_ctx->IsWatchpointHit(wp_idx))
+ {
+ // Clear the watchpoint hit here
+ reg_ctx->ClearWatchpointHits();
+ break;
+ }
+ }
+
+ if (wp_idx == num_hw_wps)
+ return;
+
+ Target &target = GetProcess()->GetTarget();
+ lldb::addr_t wp_monitor_addr = reg_ctx->GetWatchpointAddress(wp_idx);
+ const WatchpointList &wp_list = target.GetWatchpointList();
+ lldb::WatchpointSP wp_sp = wp_list.FindByAddress(wp_monitor_addr);
+
+ assert(wp_sp.get() && "No watchpoint found");
+ SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID(*this,
+ wp_sp->GetID()));
+ }
+}
+
+void
+POSIXThread::TraceNotify(const ProcessMessage &message)
+{
+ POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol();
+ if (reg_ctx)
+ {
+ uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints();
+ uint32_t wp_idx;
+ for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++)
+ {
+ if (reg_ctx->IsWatchpointHit(wp_idx))
+ {
+ WatchNotify(message);
+ return;
+ }
+ }
+ }
+
+ SetStopInfo (StopInfo::CreateStopReasonToTrace(*this));
+}
+
+void
+POSIXThread::LimboNotify(const ProcessMessage &message)
+{
+ SetStopInfo (lldb::StopInfoSP(new POSIXLimboStopInfo(*this)));
+}
+
+void
+POSIXThread::SignalNotify(const ProcessMessage &message)
+{
+ int signo = message.GetSignal();
+ SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo));
+}
+
+void
+POSIXThread::SignalDeliveredNotify(const ProcessMessage &message)
+{
+ int signo = message.GetSignal();
+ SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo));
+}
+
+void
+POSIXThread::CrashNotify(const ProcessMessage &message)
+{
+ // FIXME: Update stop reason as per bugzilla 14598
+ int signo = message.GetSignal();
+
+ assert(message.GetKind() == ProcessMessage::eCrashMessage);
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s () signo = %i, reason = '%s'",
+ __FUNCTION__, signo, message.PrintCrashReason());
+
+ SetStopInfo (lldb::StopInfoSP(new POSIXCrashStopInfo(*this, signo,
+ message.GetCrashReason(),
+ message.GetFaultAddress())));
+}
+
+void
+POSIXThread::ThreadNotify(const ProcessMessage &message)
+{
+ SetStopInfo (lldb::StopInfoSP(new POSIXNewThreadStopInfo(*this)));
+}
+
+unsigned
+POSIXThread::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg = LLDB_INVALID_REGNUM;
+ ArchSpec arch = HostInfo::GetArchitecture();
+
+ switch (arch.GetMachine())
+ {
+ default:
+ llvm_unreachable("CPU type not supported!");
+ break;
+
+ case llvm::Triple::aarch64:
+ case llvm::Triple::arm:
+ case llvm::Triple::mips64:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ {
+ POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol();
+ reg = reg_ctx->GetRegisterIndexFromOffset(offset);
+ }
+ break;
+ }
+ return reg;
+}
+
+void
+POSIXThread::ExecNotify(const ProcessMessage &message)
+{
+ SetStopInfo (StopInfo::CreateStopReasonWithExec(*this));
+}
+
+const char *
+POSIXThread::GetRegisterName(unsigned reg)
+{
+ const char * name = nullptr;
+ ArchSpec arch = HostInfo::GetArchitecture();
+
+ switch (arch.GetMachine())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case llvm::Triple::aarch64:
+ case llvm::Triple::arm:
+ case llvm::Triple::mips64:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ name = GetRegisterContext()->GetRegisterName(reg);
+ break;
+ }
+ return name;
+}
+
+const char *
+POSIXThread::GetRegisterNameFromOffset(unsigned offset)
+{
+ return GetRegisterName(GetRegisterIndexFromOffset(offset));
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXThread.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXThread.h
new file mode 100644
index 0000000..c38d194
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/POSIXThread.h
@@ -0,0 +1,132 @@
+//===-- POSIXThread.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_POSIXThread_H_
+#define liblldb_POSIXThread_H_
+
+// C Includes
+// C++ Includes
+#include <memory>
+#include <string>
+
+// Other libraries and framework includes
+#include "lldb/Target/Thread.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX.h"
+
+class ProcessMessage;
+class ProcessMonitor;
+class POSIXBreakpointProtocol;
+
+//------------------------------------------------------------------------------
+// @class POSIXThread
+// @brief Abstraction of a POSIX thread.
+class POSIXThread
+ : public lldb_private::Thread
+{
+public:
+ POSIXThread(lldb_private::Process &process, lldb::tid_t tid);
+
+ virtual ~POSIXThread();
+
+ void
+ RefreshStateAfterStop() override;
+
+ // This notifies the thread when a private stop occurs.
+ void
+ DidStop () override;
+
+ const char *
+ GetInfo() override;
+
+ void
+ SetName (const char *name) override;
+
+ const char *
+ GetName () override;
+
+ lldb::RegisterContextSP
+ GetRegisterContext() override;
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame) override;
+
+ lldb::addr_t
+ GetThreadPointer () override;
+
+ //--------------------------------------------------------------------------
+ // These functions provide a mapping from the register offset
+ // back to the register index or name for use in debugging or log
+ // output.
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ const char *
+ GetRegisterNameFromOffset(unsigned offset);
+
+ //--------------------------------------------------------------------------
+ // These methods form a specialized interface to POSIX threads.
+ //
+ bool Resume();
+
+ void Notify(const ProcessMessage &message);
+
+ //--------------------------------------------------------------------------
+ // These methods provide an interface to watchpoints
+ //
+ bool EnableHardwareWatchpoint(lldb_private::Watchpoint *wp);
+
+ bool DisableHardwareWatchpoint(lldb_private::Watchpoint *wp);
+
+ uint32_t NumSupportedHardwareWatchpoints();
+
+ uint32_t FindVacantWatchpointIndex();
+
+protected:
+ POSIXBreakpointProtocol *
+ GetPOSIXBreakpointProtocol ()
+ {
+ if (!m_reg_context_sp)
+ m_reg_context_sp = GetRegisterContext();
+ return m_posix_thread;
+ }
+
+ std::unique_ptr<lldb_private::StackFrame> m_frame_ap;
+
+ lldb::BreakpointSiteSP m_breakpoint;
+
+ bool m_thread_name_valid;
+ std::string m_thread_name;
+ POSIXBreakpointProtocol *m_posix_thread;
+
+ ProcessMonitor &
+ GetMonitor();
+
+ bool
+ CalculateStopInfo() override;
+
+ void BreakNotify(const ProcessMessage &message);
+ void WatchNotify(const ProcessMessage &message);
+ virtual void TraceNotify(const ProcessMessage &message);
+ void LimboNotify(const ProcessMessage &message);
+ void SignalNotify(const ProcessMessage &message);
+ void SignalDeliveredNotify(const ProcessMessage &message);
+ void CrashNotify(const ProcessMessage &message);
+ void ThreadNotify(const ProcessMessage &message);
+ void ExitNotify(const ProcessMessage &message);
+ void ExecNotify(const ProcessMessage &message);
+
+ lldb_private::Unwind *
+ GetUnwinder() override;
+};
+
+#endif // #ifndef liblldb_POSIXThread_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
new file mode 100644
index 0000000..a0458f1
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
@@ -0,0 +1,276 @@
+//===-- ProcessFreeBSD.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+#include <mutex>
+
+// Other libraries and framework includes
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Target.h"
+
+#include "ProcessFreeBSD.h"
+#include "ProcessPOSIXLog.h"
+#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "Plugins/Process/Utility/FreeBSDSignals.h"
+#include "ProcessMonitor.h"
+#include "FreeBSDThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace
+{
+ UnixSignalsSP&
+ GetFreeBSDSignals ()
+ {
+ static UnixSignalsSP s_freebsd_signals_sp (new FreeBSDSignals ());
+ return s_freebsd_signals_sp;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Static functions.
+
+lldb::ProcessSP
+ProcessFreeBSD::CreateInstance(Target& target,
+ Listener &listener,
+ const FileSpec *crash_file_path)
+{
+ lldb::ProcessSP process_sp;
+ if (crash_file_path == NULL)
+ process_sp.reset(new ProcessFreeBSD (target, listener));
+ return process_sp;
+}
+
+void
+ProcessFreeBSD::Initialize()
+{
+ static std::once_flag g_once_flag;
+
+ std::call_once(g_once_flag, []() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+ ProcessPOSIXLog::Initialize(GetPluginNameStatic());
+ });
+}
+
+lldb_private::ConstString
+ProcessFreeBSD::GetPluginNameStatic()
+{
+ static ConstString g_name("freebsd");
+ return g_name;
+}
+
+const char *
+ProcessFreeBSD::GetPluginDescriptionStatic()
+{
+ return "Process plugin for FreeBSD";
+}
+
+//------------------------------------------------------------------------------
+// ProcessInterface protocol.
+
+lldb_private::ConstString
+ProcessFreeBSD::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessFreeBSD::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ProcessFreeBSD::GetPluginCommandHelp(const char *command, Stream *strm)
+{
+}
+
+Error
+ProcessFreeBSD::ExecutePluginCommand(Args &command, Stream *strm)
+{
+ return Error(1, eErrorTypeGeneric);
+}
+
+Log *
+ProcessFreeBSD::EnablePluginLogging(Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+//------------------------------------------------------------------------------
+// Constructors and destructors.
+
+ProcessFreeBSD::ProcessFreeBSD(Target& target, Listener &listener)
+ : ProcessPOSIX(target, listener, GetFreeBSDSignals ()),
+ m_resume_signo(0)
+{
+}
+
+void
+ProcessFreeBSD::Terminate()
+{
+}
+
+Error
+ProcessFreeBSD::DoDetach(bool keep_stopped)
+{
+ Error error;
+ if (keep_stopped)
+ {
+ error.SetErrorString("Detaching with keep_stopped true is not currently supported on FreeBSD.");
+ return error;
+ }
+
+ error = m_monitor->Detach(GetID());
+
+ if (error.Success())
+ SetPrivateState(eStateDetached);
+
+ return error;
+}
+
+Error
+ProcessFreeBSD::DoResume()
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ SetPrivateState(eStateRunning);
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ bool do_step = false;
+
+ for (tid_collection::const_iterator t_pos = m_run_tids.begin(), t_end = m_run_tids.end(); t_pos != t_end; ++t_pos)
+ {
+ m_monitor->ThreadSuspend(*t_pos, false);
+ }
+ for (tid_collection::const_iterator t_pos = m_step_tids.begin(), t_end = m_step_tids.end(); t_pos != t_end; ++t_pos)
+ {
+ m_monitor->ThreadSuspend(*t_pos, false);
+ do_step = true;
+ }
+ for (tid_collection::const_iterator t_pos = m_suspend_tids.begin(), t_end = m_suspend_tids.end(); t_pos != t_end; ++t_pos)
+ {
+ m_monitor->ThreadSuspend(*t_pos, true);
+ // XXX Cannot PT_CONTINUE properly with suspended threads.
+ do_step = true;
+ }
+
+ if (log)
+ log->Printf("process %" PRIu64 " resuming (%s)", GetID(), do_step ? "step" : "continue");
+ if (do_step)
+ m_monitor->SingleStep(GetID(), m_resume_signo);
+ else
+ m_monitor->Resume(GetID(), m_resume_signo);
+
+ return Error();
+}
+
+bool
+ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+ if (log)
+ log->Printf("ProcessFreeBSD::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID());
+
+ std::vector<lldb::pid_t> tds;
+ if (!GetMonitor().GetCurrentThreadIDs(tds))
+ {
+ return false;
+ }
+
+ ThreadList old_thread_list_copy(old_thread_list);
+ for (size_t i = 0; i < tds.size(); ++i)
+ {
+ tid_t tid = tds[i];
+ ThreadSP thread_sp (old_thread_list_copy.RemoveThreadByID(tid, false));
+ if (!thread_sp)
+ {
+ thread_sp.reset(new FreeBSDThread(*this, tid));
+ if (log)
+ log->Printf("ProcessFreeBSD::%s new tid = %" PRIu64, __FUNCTION__, tid);
+ }
+ else
+ {
+ if (log)
+ log->Printf("ProcessFreeBSD::%s existing tid = %" PRIu64, __FUNCTION__, tid);
+ }
+ new_thread_list.AddThread(thread_sp);
+ }
+ for (size_t i = 0; i < old_thread_list_copy.GetSize(false); ++i)
+ {
+ ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex(i, false));
+ if (old_thread_sp)
+ {
+ if (log)
+ log->Printf("ProcessFreeBSD::%s remove tid", __FUNCTION__);
+ }
+ }
+
+ return true;
+}
+
+Error
+ProcessFreeBSD::WillResume()
+{
+ m_resume_signo = 0;
+ m_suspend_tids.clear();
+ m_run_tids.clear();
+ m_step_tids.clear();
+ return ProcessPOSIX::WillResume();
+}
+
+void
+ProcessFreeBSD::SendMessage(const ProcessMessage &message)
+{
+ Mutex::Locker lock(m_message_mutex);
+
+ switch (message.GetKind())
+ {
+ case ProcessMessage::eInvalidMessage:
+ return;
+
+ case ProcessMessage::eAttachMessage:
+ SetPrivateState(eStateStopped);
+ return;
+
+ case ProcessMessage::eLimboMessage:
+ case ProcessMessage::eExitMessage:
+ SetExitStatus(message.GetExitStatus(), NULL);
+ break;
+
+ case ProcessMessage::eSignalMessage:
+ case ProcessMessage::eSignalDeliveredMessage:
+ case ProcessMessage::eBreakpointMessage:
+ case ProcessMessage::eTraceMessage:
+ case ProcessMessage::eWatchpointMessage:
+ case ProcessMessage::eCrashMessage:
+ SetPrivateState(eStateStopped);
+ break;
+
+ case ProcessMessage::eNewThreadMessage:
+ assert(0 && "eNewThreadMessage unexpected on FreeBSD");
+ break;
+
+ case ProcessMessage::eExecMessage:
+ SetPrivateState(eStateStopped);
+ break;
+ }
+
+ m_message_queue.push(message);
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
new file mode 100644
index 0000000..2a5e245
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
@@ -0,0 +1,104 @@
+//===-- ProcessFreeBSD.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessFreeBSD_H_
+#define liblldb_ProcessFreeBSD_H_
+
+// C Includes
+
+// C++ Includes
+#include <queue>
+
+// Other libraries and framework includes
+#include "lldb/Target/Process.h"
+#include "lldb/Target/ThreadList.h"
+#include "Plugins/Process/POSIX/ProcessMessage.h"
+#include "ProcessPOSIX.h"
+
+class ProcessMonitor;
+
+class ProcessFreeBSD :
+ public ProcessPOSIX
+{
+
+public:
+ //------------------------------------------------------------------
+ // Static functions.
+ //------------------------------------------------------------------
+ static lldb::ProcessSP
+ CreateInstance(lldb_private::Target& target,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec *crash_file_path);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and destructors
+ //------------------------------------------------------------------
+ ProcessFreeBSD(lldb_private::Target& target,
+ lldb_private::Listener &listener);
+
+ virtual lldb_private::Error
+ DoDetach(bool keep_stopped);
+
+ virtual bool
+ UpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list);
+
+ virtual lldb_private::Error
+ DoResume();
+
+ virtual lldb_private::Error
+ WillResume();
+
+ virtual void
+ SendMessage(const ProcessMessage &message);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp(const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand(lldb_private::Args &command,
+ lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging(lldb_private::Stream *strm,
+ lldb_private::Args &command);
+
+protected:
+ friend class FreeBSDThread;
+
+ typedef std::vector<lldb::tid_t> tid_collection;
+ tid_collection m_suspend_tids;
+ tid_collection m_run_tids;
+ tid_collection m_step_tids;
+
+ int m_resume_signo;
+
+};
+
+#endif // liblldb_ProcessFreeBSD_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
new file mode 100644
index 0000000..427c66c
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
@@ -0,0 +1,1626 @@
+//===-- ProcessMonitor.cpp ------------------------------------ -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <errno.h>
+#include <poll.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+#include "Plugins/Process/POSIX/CrashReason.h"
+#include "POSIXThread.h"
+#include "ProcessFreeBSD.h"
+#include "ProcessPOSIXLog.h"
+#include "ProcessMonitor.h"
+
+extern "C" {
+ extern char ** environ;
+ }
+
+using namespace lldb;
+using namespace lldb_private;
+
+// We disable the tracing of ptrace calls for integration builds to
+// avoid the additional indirection and checks.
+#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+// Wrapper for ptrace to catch errors and log calls.
+
+const char *
+Get_PT_IO_OP(int op)
+{
+ switch (op) {
+ case PIOD_READ_D: return "READ_D";
+ case PIOD_WRITE_D: return "WRITE_D";
+ case PIOD_READ_I: return "READ_I";
+ case PIOD_WRITE_I: return "WRITE_I";
+ default: return "Unknown op";
+ }
+}
+
+// Wrapper for ptrace to catch errors and log calls.
+// Note that ptrace sets errno on error because -1 is reserved as a valid result.
+extern long
+PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data,
+ const char* reqName, const char* file, int line)
+{
+ long int result;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+
+ if (log) {
+ log->Printf("ptrace(%s, %" PRIu64 ", %p, %x) called from file %s line %d",
+ reqName, pid, addr, data, file, line);
+ if (req == PT_IO) {
+ struct ptrace_io_desc *pi = (struct ptrace_io_desc *) addr;
+
+ log->Printf("PT_IO: op=%s offs=%zx size=%zu",
+ Get_PT_IO_OP(pi->piod_op), (size_t)pi->piod_offs, pi->piod_len);
+ }
+ }
+
+ //PtraceDisplayBytes(req, data);
+
+ errno = 0;
+ result = ptrace(req, pid, (caddr_t) addr, data);
+
+ //PtraceDisplayBytes(req, data);
+
+ if (log && errno != 0)
+ {
+ const char* str;
+ switch (errno)
+ {
+ case ESRCH: str = "ESRCH"; break;
+ case EINVAL: str = "EINVAL"; break;
+ case EBUSY: str = "EBUSY"; break;
+ case EPERM: str = "EPERM"; break;
+ default: str = "<unknown>";
+ }
+ log->Printf("ptrace() failed; errno=%d (%s)", errno, str);
+ }
+
+ if (log) {
+#ifdef __amd64__
+ if (req == PT_GETREGS) {
+ struct reg *r = (struct reg *) addr;
+
+ log->Printf("PT_GETREGS: rip=0x%lx rsp=0x%lx rbp=0x%lx rax=0x%lx",
+ r->r_rip, r->r_rsp, r->r_rbp, r->r_rax);
+ }
+ if (req == PT_GETDBREGS || req == PT_SETDBREGS) {
+ struct dbreg *r = (struct dbreg *) addr;
+ char setget = (req == PT_GETDBREGS) ? 'G' : 'S';
+
+ for (int i = 0; i <= 7; i++)
+ log->Printf("PT_%cETDBREGS: dr[%d]=0x%lx", setget, i, r->dr[i]);
+ }
+#endif
+ }
+
+ return result;
+}
+
+// Wrapper for ptrace when logging is not required.
+// Sets errno to 0 prior to calling ptrace.
+extern long
+PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data)
+{
+ long result = 0;
+ errno = 0;
+ result = ptrace(req, pid, (caddr_t)addr, data);
+ return result;
+}
+
+#define PTRACE(req, pid, addr, data) \
+ PtraceWrapper((req), (pid), (addr), (data), #req, __FILE__, __LINE__)
+#else
+ PtraceWrapper((req), (pid), (addr), (data))
+#endif
+
+//------------------------------------------------------------------------------
+// Static implementations of ProcessMonitor::ReadMemory and
+// ProcessMonitor::WriteMemory. This enables mutual recursion between these
+// functions without needed to go thru the thread funnel.
+
+static size_t
+DoReadMemory(lldb::pid_t pid, lldb::addr_t vm_addr, void *buf, size_t size,
+ Error &error)
+{
+ struct ptrace_io_desc pi_desc;
+
+ pi_desc.piod_op = PIOD_READ_D;
+ pi_desc.piod_offs = (void *)vm_addr;
+ pi_desc.piod_addr = buf;
+ pi_desc.piod_len = size;
+
+ if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0)
+ error.SetErrorToErrno();
+ return pi_desc.piod_len;
+}
+
+static size_t
+DoWriteMemory(lldb::pid_t pid, lldb::addr_t vm_addr, const void *buf,
+ size_t size, Error &error)
+{
+ struct ptrace_io_desc pi_desc;
+
+ pi_desc.piod_op = PIOD_WRITE_D;
+ pi_desc.piod_offs = (void *)vm_addr;
+ pi_desc.piod_addr = (void *)buf;
+ pi_desc.piod_len = size;
+
+ if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0)
+ error.SetErrorToErrno();
+ return pi_desc.piod_len;
+}
+
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static bool
+EnsureFDFlags(int fd, int flags, Error &error)
+{
+ int status;
+
+ if ((status = fcntl(fd, F_GETFL)) == -1)
+ {
+ error.SetErrorToErrno();
+ return false;
+ }
+
+ if (fcntl(fd, F_SETFL, status | flags) == -1)
+ {
+ error.SetErrorToErrno();
+ return false;
+ }
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+/// @class Operation
+/// @brief Represents a ProcessMonitor operation.
+///
+/// Under FreeBSD, it is not possible to ptrace() from any other thread but the
+/// one that spawned or attached to the process from the start. Therefore, when
+/// a ProcessMonitor is asked to deliver or change the state of an inferior
+/// process the operation must be "funneled" to a specific thread to perform the
+/// task. The Operation class provides an abstract base for all services the
+/// ProcessMonitor must perform via the single virtual function Execute, thus
+/// encapsulating the code that needs to run in the privileged context.
+class Operation
+{
+public:
+ virtual ~Operation() {}
+ virtual void Execute(ProcessMonitor *monitor) = 0;
+};
+
+//------------------------------------------------------------------------------
+/// @class ReadOperation
+/// @brief Implements ProcessMonitor::ReadMemory.
+class ReadOperation : public Operation
+{
+public:
+ ReadOperation(lldb::addr_t addr, void *buff, size_t size,
+ Error &error, size_t &result)
+ : m_addr(addr), m_buff(buff), m_size(size),
+ m_error(error), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::addr_t m_addr;
+ void *m_buff;
+ size_t m_size;
+ Error &m_error;
+ size_t &m_result;
+};
+
+void
+ReadOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ m_result = DoReadMemory(pid, m_addr, m_buff, m_size, m_error);
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteOperation
+/// @brief Implements ProcessMonitor::WriteMemory.
+class WriteOperation : public Operation
+{
+public:
+ WriteOperation(lldb::addr_t addr, const void *buff, size_t size,
+ Error &error, size_t &result)
+ : m_addr(addr), m_buff(buff), m_size(size),
+ m_error(error), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::addr_t m_addr;
+ const void *m_buff;
+ size_t m_size;
+ Error &m_error;
+ size_t &m_result;
+};
+
+void
+WriteOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ m_result = DoWriteMemory(pid, m_addr, m_buff, m_size, m_error);
+}
+
+//------------------------------------------------------------------------------
+/// @class ReadRegOperation
+/// @brief Implements ProcessMonitor::ReadRegisterValue.
+class ReadRegOperation : public Operation
+{
+public:
+ ReadRegOperation(lldb::tid_t tid, unsigned offset, unsigned size,
+ RegisterValue &value, bool &result)
+ : m_tid(tid), m_offset(offset), m_size(size),
+ m_value(value), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ unsigned m_offset;
+ unsigned m_size;
+ RegisterValue &m_value;
+ bool &m_result;
+};
+
+void
+ReadRegOperation::Execute(ProcessMonitor *monitor)
+{
+ struct reg regs;
+ int rc;
+
+ if ((rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)&regs, 0)) < 0) {
+ m_result = false;
+ } else {
+ // 'struct reg' contains only 32- or 64-bit register values. Punt on
+ // others. Also, not all entries may be uintptr_t sized, such as 32-bit
+ // processes on powerpc64 (probably the same for i386 on amd64)
+ if (m_size == sizeof(uint32_t))
+ m_value = *(uint32_t *)(((caddr_t)&regs) + m_offset);
+ else if (m_size == sizeof(uint64_t))
+ m_value = *(uint64_t *)(((caddr_t)&regs) + m_offset);
+ else
+ memcpy(&m_value, (((caddr_t)&regs) + m_offset), m_size);
+ m_result = true;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteRegOperation
+/// @brief Implements ProcessMonitor::WriteRegisterValue.
+class WriteRegOperation : public Operation
+{
+public:
+ WriteRegOperation(lldb::tid_t tid, unsigned offset,
+ const RegisterValue &value, bool &result)
+ : m_tid(tid), m_offset(offset),
+ m_value(value), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ unsigned m_offset;
+ const RegisterValue &m_value;
+ bool &m_result;
+};
+
+void
+WriteRegOperation::Execute(ProcessMonitor *monitor)
+{
+ struct reg regs;
+
+ if (PTRACE(PT_GETREGS, m_tid, (caddr_t)&regs, 0) < 0) {
+ m_result = false;
+ return;
+ }
+ *(uintptr_t *)(((caddr_t)&regs) + m_offset) = (uintptr_t)m_value.GetAsUInt64();
+ if (PTRACE(PT_SETREGS, m_tid, (caddr_t)&regs, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class ReadDebugRegOperation
+/// @brief Implements ProcessMonitor::ReadDebugRegisterValue.
+class ReadDebugRegOperation : public Operation
+{
+public:
+ ReadDebugRegOperation(lldb::tid_t tid, unsigned offset, unsigned size,
+ RegisterValue &value, bool &result)
+ : m_tid(tid), m_offset(offset), m_size(size),
+ m_value(value), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ unsigned m_offset;
+ unsigned m_size;
+ RegisterValue &m_value;
+ bool &m_result;
+};
+
+void
+ReadDebugRegOperation::Execute(ProcessMonitor *monitor)
+{
+ struct dbreg regs;
+ int rc;
+
+ if ((rc = PTRACE(PT_GETDBREGS, m_tid, (caddr_t)&regs, 0)) < 0) {
+ m_result = false;
+ } else {
+ if (m_size == sizeof(uintptr_t))
+ m_value = *(uintptr_t *)(((caddr_t)&regs) + m_offset);
+ else
+ memcpy(&m_value, (((caddr_t)&regs) + m_offset), m_size);
+ m_result = true;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteDebugRegOperation
+/// @brief Implements ProcessMonitor::WriteDebugRegisterValue.
+class WriteDebugRegOperation : public Operation
+{
+public:
+ WriteDebugRegOperation(lldb::tid_t tid, unsigned offset,
+ const RegisterValue &value, bool &result)
+ : m_tid(tid), m_offset(offset),
+ m_value(value), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ unsigned m_offset;
+ const RegisterValue &m_value;
+ bool &m_result;
+};
+
+void
+WriteDebugRegOperation::Execute(ProcessMonitor *monitor)
+{
+ struct dbreg regs;
+
+ if (PTRACE(PT_GETDBREGS, m_tid, (caddr_t)&regs, 0) < 0) {
+ m_result = false;
+ return;
+ }
+ *(uintptr_t *)(((caddr_t)&regs) + m_offset) = (uintptr_t)m_value.GetAsUInt64();
+ if (PTRACE(PT_SETDBREGS, m_tid, (caddr_t)&regs, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class ReadGPROperation
+/// @brief Implements ProcessMonitor::ReadGPR.
+class ReadGPROperation : public Operation
+{
+public:
+ ReadGPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+ReadGPROperation::Execute(ProcessMonitor *monitor)
+{
+ int rc;
+
+ errno = 0;
+ rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)m_buf, 0);
+ if (errno != 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class ReadFPROperation
+/// @brief Implements ProcessMonitor::ReadFPR.
+class ReadFPROperation : public Operation
+{
+public:
+ ReadFPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+ReadFPROperation::Execute(ProcessMonitor *monitor)
+{
+ if (PTRACE(PT_GETFPREGS, m_tid, (caddr_t)m_buf, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteGPROperation
+/// @brief Implements ProcessMonitor::WriteGPR.
+class WriteGPROperation : public Operation
+{
+public:
+ WriteGPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+WriteGPROperation::Execute(ProcessMonitor *monitor)
+{
+ if (PTRACE(PT_SETREGS, m_tid, (caddr_t)m_buf, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteFPROperation
+/// @brief Implements ProcessMonitor::WriteFPR.
+class WriteFPROperation : public Operation
+{
+public:
+ WriteFPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+WriteFPROperation::Execute(ProcessMonitor *monitor)
+{
+ if (PTRACE(PT_SETFPREGS, m_tid, (caddr_t)m_buf, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class ResumeOperation
+/// @brief Implements ProcessMonitor::Resume.
+class ResumeOperation : public Operation
+{
+public:
+ ResumeOperation(uint32_t signo, bool &result) :
+ m_signo(signo), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ uint32_t m_signo;
+ bool &m_result;
+};
+
+void
+ResumeOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+ int data = 0;
+
+ if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
+ data = m_signo;
+
+ if (PTRACE(PT_CONTINUE, pid, (caddr_t)1, data))
+ {
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ResumeOperation (%" PRIu64 ") failed: %s", pid, strerror(errno));
+ m_result = false;
+ }
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class SingleStepOperation
+/// @brief Implements ProcessMonitor::SingleStep.
+class SingleStepOperation : public Operation
+{
+public:
+ SingleStepOperation(uint32_t signo, bool &result)
+ : m_signo(signo), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ uint32_t m_signo;
+ bool &m_result;
+};
+
+void
+SingleStepOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+ int data = 0;
+
+ if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
+ data = m_signo;
+
+ if (PTRACE(PT_STEP, pid, NULL, data))
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class LwpInfoOperation
+/// @brief Implements ProcessMonitor::GetLwpInfo.
+class LwpInfoOperation : public Operation
+{
+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);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_info;
+ bool &m_result;
+ int &m_err;
+};
+
+void
+LwpInfoOperation::Execute(ProcessMonitor *monitor)
+{
+ struct ptrace_lwpinfo plwp;
+
+ if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp))) {
+ m_result = false;
+ m_err = errno;
+ } else {
+ memcpy(m_info, &plwp, sizeof(plwp));
+ m_result = true;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// @class ThreadSuspendOperation
+/// @brief Implements ProcessMonitor::ThreadSuspend.
+class ThreadSuspendOperation : public Operation
+{
+public:
+ ThreadSuspendOperation(lldb::tid_t tid, bool suspend, bool &result)
+ : m_tid(tid), m_suspend(suspend), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ bool m_suspend;
+ bool &m_result;
+} ;
+
+void
+ThreadSuspendOperation::Execute(ProcessMonitor *monitor)
+{
+ m_result = !PTRACE(m_suspend ? PT_SUSPEND : PT_RESUME, m_tid, NULL, 0);
+}
+
+
+
+//------------------------------------------------------------------------------
+/// @class EventMessageOperation
+/// @brief Implements ProcessMonitor::GetEventMessage.
+class EventMessageOperation : public Operation
+{
+public:
+ EventMessageOperation(lldb::tid_t tid, unsigned long *message, bool &result)
+ : m_tid(tid), m_message(message), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ unsigned long *m_message;
+ bool &m_result;
+};
+
+void
+EventMessageOperation::Execute(ProcessMonitor *monitor)
+{
+ struct ptrace_lwpinfo plwp;
+
+ if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp)))
+ m_result = false;
+ else {
+ if (plwp.pl_flags & PL_FLAG_FORKED) {
+ *m_message = plwp.pl_child_pid;
+ m_result = true;
+ } else
+ m_result = false;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// @class KillOperation
+/// @brief Implements ProcessMonitor::Kill.
+class KillOperation : public Operation
+{
+public:
+ KillOperation(bool &result) : m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ bool &m_result;
+};
+
+void
+KillOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ if (PTRACE(PT_KILL, pid, NULL, 0))
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class DetachOperation
+/// @brief Implements ProcessMonitor::Detach.
+class DetachOperation : public Operation
+{
+public:
+ DetachOperation(Error &result) : m_error(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ Error &m_error;
+};
+
+void
+DetachOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ if (PTRACE(PT_DETACH, pid, NULL, 0) < 0)
+ m_error.SetErrorToErrno();
+
+}
+
+ProcessMonitor::OperationArgs::OperationArgs(ProcessMonitor *monitor)
+ : m_monitor(monitor)
+{
+ sem_init(&m_semaphore, 0, 0);
+}
+
+ProcessMonitor::OperationArgs::~OperationArgs()
+{
+ sem_destroy(&m_semaphore);
+}
+
+ProcessMonitor::LaunchArgs::LaunchArgs(ProcessMonitor *monitor,
+ lldb_private::Module *module,
+ char const **argv,
+ char const **envp,
+ const FileSpec &stdin_file_spec,
+ const FileSpec &stdout_file_spec,
+ const FileSpec &stderr_file_spec,
+ const FileSpec &working_dir)
+ : OperationArgs(monitor),
+ m_module(module),
+ m_argv(argv),
+ m_envp(envp),
+ m_stdin_file_spec(stdin_file_spec),
+ m_stdout_file_spec(stdout_file_spec),
+ m_stderr_file_spec(stderr_file_spec),
+ m_working_dir(working_dir) { }
+
+ProcessMonitor::LaunchArgs::~LaunchArgs()
+{ }
+
+ProcessMonitor::AttachArgs::AttachArgs(ProcessMonitor *monitor,
+ lldb::pid_t pid)
+ : OperationArgs(monitor), m_pid(pid) { }
+
+ProcessMonitor::AttachArgs::~AttachArgs()
+{ }
+
+//------------------------------------------------------------------------------
+/// The basic design of the ProcessMonitor is built around two threads.
+///
+/// One thread (@see SignalThread) simply blocks on a call to waitpid() looking
+/// for changes in the debugee state. When a change is detected a
+/// ProcessMessage is sent to the associated ProcessFreeBSD instance. This thread
+/// "drives" state changes in the debugger.
+///
+/// The second thread (@see OperationThread) is responsible for two things 1)
+/// launching or attaching to the inferior process, and then 2) servicing
+/// operations such as register reads/writes, stepping, etc. See the comments
+/// on the Operation class for more info as to why this is needed.
+ProcessMonitor::ProcessMonitor(ProcessPOSIX *process,
+ Module *module,
+ const char *argv[],
+ const char *envp[],
+ const FileSpec &stdin_file_spec,
+ const FileSpec &stdout_file_spec,
+ const FileSpec &stderr_file_spec,
+ const FileSpec &working_dir,
+ const lldb_private::ProcessLaunchInfo & /* launch_info */,
+ lldb_private::Error &error)
+ : m_process(static_cast<ProcessFreeBSD *>(process)),
+ m_pid(LLDB_INVALID_PROCESS_ID),
+ m_terminal_fd(-1),
+ m_operation(0)
+{
+ std::unique_ptr<LaunchArgs> args(new LaunchArgs(this, module, argv, envp,
+ stdin_file_spec,
+ stdout_file_spec,
+ stderr_file_spec,
+ working_dir));
+
+
+ sem_init(&m_operation_pending, 0, 0);
+ sem_init(&m_operation_done, 0, 0);
+
+ StartLaunchOpThread(args.get(), error);
+ if (!error.Success())
+ return;
+
+WAIT_AGAIN:
+ // Wait for the operation thread to initialize.
+ if (sem_wait(&args->m_semaphore))
+ {
+ if (errno == EINTR)
+ goto WAIT_AGAIN;
+ else
+ {
+ error.SetErrorToErrno();
+ return;
+ }
+ }
+
+ // Check that the launch was a success.
+ if (!args->m_error.Success())
+ {
+ StopOpThread();
+ error = args->m_error;
+ return;
+ }
+
+ // Finally, start monitoring the child process for change in state.
+ m_monitor_thread = Host::StartMonitoringChildProcess(
+ ProcessMonitor::MonitorCallback, this, GetPID(), true);
+ if (!m_monitor_thread.IsJoinable())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Process launch failed.");
+ return;
+ }
+}
+
+ProcessMonitor::ProcessMonitor(ProcessPOSIX *process,
+ lldb::pid_t pid,
+ lldb_private::Error &error)
+ : m_process(static_cast<ProcessFreeBSD *>(process)),
+ m_pid(pid),
+ m_terminal_fd(-1),
+ m_operation(0)
+{
+ sem_init(&m_operation_pending, 0, 0);
+ sem_init(&m_operation_done, 0, 0);
+
+
+ std::unique_ptr<AttachArgs> args(new AttachArgs(this, pid));
+
+ StartAttachOpThread(args.get(), error);
+ if (!error.Success())
+ return;
+
+WAIT_AGAIN:
+ // Wait for the operation thread to initialize.
+ if (sem_wait(&args->m_semaphore))
+ {
+ if (errno == EINTR)
+ goto WAIT_AGAIN;
+ else
+ {
+ error.SetErrorToErrno();
+ return;
+ }
+ }
+
+ // Check that the attach was a success.
+ if (!args->m_error.Success())
+ {
+ StopOpThread();
+ error = args->m_error;
+ return;
+ }
+
+ // Finally, start monitoring the child process for change in state.
+ m_monitor_thread = Host::StartMonitoringChildProcess(
+ ProcessMonitor::MonitorCallback, this, GetPID(), true);
+ if (!m_monitor_thread.IsJoinable())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Process attach failed.");
+ return;
+ }
+}
+
+ProcessMonitor::~ProcessMonitor()
+{
+ StopMonitor();
+}
+
+//------------------------------------------------------------------------------
+// Thread setup and tear down.
+void
+ProcessMonitor::StartLaunchOpThread(LaunchArgs *args, Error &error)
+{
+ static const char *g_thread_name = "lldb.process.freebsd.operation";
+
+ if (m_operation_thread.IsJoinable())
+ return;
+
+ m_operation_thread = ThreadLauncher::LaunchThread(g_thread_name, LaunchOpThread, args, &error);
+}
+
+void *
+ProcessMonitor::LaunchOpThread(void *arg)
+{
+ LaunchArgs *args = static_cast<LaunchArgs*>(arg);
+
+ if (!Launch(args)) {
+ sem_post(&args->m_semaphore);
+ return NULL;
+ }
+
+ ServeOperation(args);
+ return NULL;
+}
+
+bool
+ProcessMonitor::Launch(LaunchArgs *args)
+{
+ ProcessMonitor *monitor = args->m_monitor;
+ ProcessFreeBSD &process = monitor->GetProcess();
+ const char **argv = args->m_argv;
+ const char **envp = args->m_envp;
+ const FileSpec &stdin_file_spec = args->m_stdin_file_spec;
+ const FileSpec &stdout_file_spec = args->m_stdout_file_spec;
+ const FileSpec &stderr_file_spec = args->m_stderr_file_spec;
+ const FileSpec &working_dir = args->m_working_dir;
+
+ lldb_utility::PseudoTerminal terminal;
+ const size_t err_len = 1024;
+ char err_str[err_len];
+ ::pid_t pid;
+
+ // Propagate the environment if one is not supplied.
+ if (envp == NULL || envp[0] == NULL)
+ envp = const_cast<const char **>(environ);
+
+ if ((pid = terminal.Fork(err_str, err_len)) == -1)
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("Process fork failed.");
+ goto FINISH;
+ }
+
+ // Recognized child exit status codes.
+ enum {
+ ePtraceFailed = 1,
+ eDupStdinFailed,
+ eDupStdoutFailed,
+ eDupStderrFailed,
+ eChdirFailed,
+ eExecFailed,
+ eSetGidFailed
+ };
+
+ // Child process.
+ if (pid == 0)
+ {
+ // Trace this process.
+ if (PTRACE(PT_TRACE_ME, 0, NULL, 0) < 0)
+ exit(ePtraceFailed);
+
+ // terminal has already dupped the tty descriptors to stdin/out/err.
+ // This closes original fd from which they were copied (and avoids
+ // leaking descriptors to the debugged process.
+ terminal.CloseSlaveFileDescriptor();
+
+ // Do not inherit setgid powers.
+ if (setgid(getgid()) != 0)
+ exit(eSetGidFailed);
+
+ // Let us have our own process group.
+ setpgid(0, 0);
+
+ // Dup file descriptors if needed.
+ //
+ // FIXME: If two or more of the paths are the same we needlessly open
+ // the same file multiple times.
+ if (stdin_file_spec)
+ if (!DupDescriptor(stdin_file_spec, STDIN_FILENO, O_RDONLY))
+ exit(eDupStdinFailed);
+
+ if (stdout_file_spec)
+ if (!DupDescriptor(stdout_file_spec, STDOUT_FILENO, O_WRONLY | O_CREAT))
+ exit(eDupStdoutFailed);
+
+ if (stderr_file_spec)
+ if (!DupDescriptor(stderr_file_spec, STDERR_FILENO, O_WRONLY | O_CREAT))
+ exit(eDupStderrFailed);
+
+ // Change working directory
+ if (working_dir && 0 != ::chdir(working_dir.GetCString()))
+ exit(eChdirFailed);
+
+ // Execute. We should never return.
+ execve(argv[0],
+ const_cast<char *const *>(argv),
+ const_cast<char *const *>(envp));
+ exit(eExecFailed);
+ }
+
+ // 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)
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+ else if (WIFEXITED(status))
+ {
+ // open, dup or execve likely failed for some reason.
+ args->m_error.SetErrorToGenericError();
+ switch (WEXITSTATUS(status))
+ {
+ case ePtraceFailed:
+ args->m_error.SetErrorString("Child ptrace failed.");
+ break;
+ case eDupStdinFailed:
+ args->m_error.SetErrorString("Child open stdin failed.");
+ break;
+ case eDupStdoutFailed:
+ args->m_error.SetErrorString("Child open stdout failed.");
+ break;
+ case eDupStderrFailed:
+ args->m_error.SetErrorString("Child open stderr failed.");
+ break;
+ case eChdirFailed:
+ args->m_error.SetErrorString("Child failed to set working directory.");
+ break;
+ case eExecFailed:
+ args->m_error.SetErrorString("Child exec failed.");
+ break;
+ case eSetGidFailed:
+ args->m_error.SetErrorString("Child setgid failed.");
+ break;
+ default:
+ args->m_error.SetErrorString("Child returned unknown exit status.");
+ break;
+ }
+ goto FINISH;
+ }
+ 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)
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+#endif
+ // Release the master terminal descriptor and pass it off to the
+ // ProcessMonitor instance. Similarly stash the inferior pid.
+ monitor->m_terminal_fd = terminal.ReleaseMasterFileDescriptor();
+ 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
+ // descriptor to read from).
+ if (!EnsureFDFlags(monitor->m_terminal_fd, O_NONBLOCK, args->m_error))
+ goto FINISH;
+
+ process.SendMessage(ProcessMessage::Attach(pid));
+
+FINISH:
+ return args->m_error.Success();
+}
+
+void
+ProcessMonitor::StartAttachOpThread(AttachArgs *args, lldb_private::Error &error)
+{
+ static const char *g_thread_name = "lldb.process.freebsd.operation";
+
+ if (m_operation_thread.IsJoinable())
+ return;
+
+ m_operation_thread = ThreadLauncher::LaunchThread(g_thread_name, AttachOpThread, args, &error);
+}
+
+void *
+ProcessMonitor::AttachOpThread(void *arg)
+{
+ AttachArgs *args = static_cast<AttachArgs*>(arg);
+
+ Attach(args);
+
+ ServeOperation(args);
+ return NULL;
+}
+
+void
+ProcessMonitor::Attach(AttachArgs *args)
+{
+ lldb::pid_t pid = args->m_pid;
+
+ ProcessMonitor *monitor = args->m_monitor;
+ ProcessFreeBSD &process = monitor->GetProcess();
+
+ if (pid <= 1)
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("Attaching to process 1 is not allowed.");
+ return;
+ }
+
+ // Attach to the requested process.
+ if (PTRACE(PT_ATTACH, pid, NULL, 0) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+ return;
+ }
+
+ int status;
+ if ((status = waitpid(pid, NULL, 0)) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+ return;
+ }
+
+ process.SendMessage(ProcessMessage::Attach(pid));
+}
+
+size_t
+ProcessMonitor::GetCurrentThreadIDs(std::vector<lldb::tid_t>&thread_ids)
+{
+ lwpid_t *tids;
+ int tdcnt;
+
+ thread_ids.clear();
+
+ tdcnt = PTRACE(PT_GETNUMLWPS, m_pid, NULL, 0);
+ if (tdcnt <= 0)
+ return 0;
+ tids = (lwpid_t *)malloc(tdcnt * sizeof(*tids));
+ if (tids == NULL)
+ return 0;
+ if (PTRACE(PT_GETLWPLIST, m_pid, (void *)tids, tdcnt) < 0) {
+ free(tids);
+ return 0;
+ }
+ thread_ids = std::vector<lldb::tid_t>(tids, tids + tdcnt);
+ free(tids);
+ return thread_ids.size();
+}
+
+bool
+ProcessMonitor::MonitorCallback(void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal,
+ int status)
+{
+ ProcessMessage message;
+ ProcessMonitor *monitor = static_cast<ProcessMonitor*>(callback_baton);
+ ProcessFreeBSD *process = monitor->m_process;
+ assert(process);
+ bool stop_monitoring;
+ struct ptrace_lwpinfo plwp;
+ int ptrace_err;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ if (exited)
+ {
+ if (log)
+ log->Printf ("ProcessMonitor::%s() got exit signal, tid = %" PRIu64, __FUNCTION__, pid);
+ message = ProcessMessage::Exit(pid, status);
+ process->SendMessage(message);
+ return pid == process->GetID();
+ }
+
+ if (!monitor->GetLwpInfo(pid, &plwp, ptrace_err))
+ stop_monitoring = true; // pid is gone. Bail.
+ else {
+ switch (plwp.pl_siginfo.si_signo)
+ {
+ case SIGTRAP:
+ message = MonitorSIGTRAP(monitor, &plwp.pl_siginfo, plwp.pl_lwpid);
+ break;
+
+ default:
+ message = MonitorSignal(monitor, &plwp.pl_siginfo, plwp.pl_lwpid);
+ break;
+ }
+
+ process->SendMessage(message);
+ stop_monitoring = message.GetKind() == ProcessMessage::eExitMessage;
+ }
+
+ return stop_monitoring;
+}
+
+ProcessMessage
+ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::tid_t tid)
+{
+ ProcessMessage message;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ assert(monitor);
+ assert(info && info->si_signo == SIGTRAP && "Unexpected child signal!");
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "Unexpected SIGTRAP code!");
+ break;
+
+ case (SIGTRAP /* | (PTRACE_EVENT_EXIT << 8) */):
+ {
+ // The inferior process is about to exit. Maintain the process in a
+ // state of "limbo" until we are explicitly commanded to detach,
+ // destroy, resume, etc.
+ unsigned long data = 0;
+ if (!monitor->GetEventMessage(tid, &data))
+ data = -1;
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received exit? event, data = %lx, tid = %" PRIu64, __FUNCTION__, data, tid);
+ message = ProcessMessage::Limbo(tid, (data >> 8));
+ break;
+ }
+
+ case 0:
+ case TRAP_TRACE:
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received trace event, tid = %" PRIu64 " : si_code = %d", __FUNCTION__, tid, info->si_code);
+ message = ProcessMessage::Trace(tid);
+ break;
+
+ case SI_KERNEL:
+ case TRAP_BRKPT:
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received breakpoint event, tid = %" PRIu64, __FUNCTION__, tid);
+ message = ProcessMessage::Break(tid);
+ break;
+ }
+
+ return message;
+}
+
+ProcessMessage
+ProcessMonitor::MonitorSignal(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::tid_t tid)
+{
+ ProcessMessage message;
+ int signo = info->si_signo;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ // POSIX says that process behaviour is undefined after it ignores a SIGFPE,
+ // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a
+ // kill(2) or raise(3). Similarly for tgkill(2) on FreeBSD.
+ //
+ // IOW, user generated signals never generate what we consider to be a
+ // "crash".
+ //
+ // Similarly, ACK signals generated by this monitor.
+ if (info->si_code == SI_USER)
+ {
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received signal %s with code %s, pid = %d",
+ __FUNCTION__,
+ monitor->m_process->GetUnixSignals()->GetSignalAsCString (signo),
+ "SI_USER",
+ info->si_pid);
+ if (info->si_pid == getpid())
+ return ProcessMessage::SignalDelivered(tid, signo);
+ else
+ return ProcessMessage::Signal(tid, signo);
+ }
+
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received signal %s", __FUNCTION__, monitor->m_process->GetUnixSignals()->GetSignalAsCString (signo));
+
+ switch (signo)
+ {
+ case SIGSEGV:
+ case SIGILL:
+ case SIGFPE:
+ case SIGBUS:
+ lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ const auto reason = GetCrashReason(*info);
+ return ProcessMessage::Crash(tid, reason, signo, fault_addr);
+ }
+
+ // Everything else is "normal" and does not require any special action on
+ // our part.
+ return ProcessMessage::Signal(tid, signo);
+}
+
+void
+ProcessMonitor::ServeOperation(OperationArgs *args)
+{
+ ProcessMonitor *monitor = args->m_monitor;
+
+ // We are finised with the arguments and are ready to go. Sync with the
+ // parent thread and start serving operations on the inferior.
+ sem_post(&args->m_semaphore);
+
+ for (;;)
+ {
+ // wait for next pending operation
+ sem_wait(&monitor->m_operation_pending);
+
+ monitor->m_operation->Execute(monitor);
+
+ // notify calling thread that operation is complete
+ sem_post(&monitor->m_operation_done);
+ }
+}
+
+void
+ProcessMonitor::DoOperation(Operation *op)
+{
+ Mutex::Locker lock(m_operation_mutex);
+
+ m_operation = op;
+
+ // notify operation thread that an operation is ready to be processed
+ sem_post(&m_operation_pending);
+
+ // wait for operation to complete
+ sem_wait(&m_operation_done);
+}
+
+size_t
+ProcessMonitor::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ Error &error)
+{
+ size_t result;
+ ReadOperation op(vm_addr, buf, size, error, result);
+ DoOperation(&op);
+ return result;
+}
+
+size_t
+ProcessMonitor::WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+ lldb_private::Error &error)
+{
+ size_t result;
+ WriteOperation op(vm_addr, buf, size, error, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char* reg_name,
+ unsigned size, RegisterValue &value)
+{
+ bool result;
+ ReadRegOperation op(tid, offset, size, value, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::WriteRegisterValue(lldb::tid_t tid, unsigned offset,
+ const char* reg_name, const RegisterValue &value)
+{
+ bool result;
+ WriteRegOperation op(tid, offset, value, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadDebugRegisterValue(lldb::tid_t tid, unsigned offset,
+ const char *reg_name, unsigned size,
+ lldb_private::RegisterValue &value)
+{
+ bool result;
+ ReadDebugRegOperation op(tid, offset, size, value, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::WriteDebugRegisterValue(lldb::tid_t tid, unsigned offset,
+ const char *reg_name,
+ const lldb_private::RegisterValue &value)
+{
+ bool result;
+ WriteDebugRegOperation op(tid, offset, value, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ ReadGPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ ReadFPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+ return false;
+}
+
+bool
+ProcessMonitor::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ WriteGPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ WriteFPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+ return false;
+}
+
+bool
+ProcessMonitor::ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value)
+{
+ return false;
+}
+
+bool
+ProcessMonitor::Resume(lldb::tid_t unused, uint32_t signo)
+{
+ bool result;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ if (log) {
+ const char *signame = m_process->GetUnixSignals()->GetSignalAsCString (signo);
+ if (signame == nullptr)
+ signame = "<none>";
+ log->Printf("ProcessMonitor::%s() resuming pid %" PRIu64 " with signal %s",
+ __FUNCTION__, GetPID(), signame);
+ }
+ ResumeOperation op(signo, result);
+ DoOperation(&op);
+ if (log)
+ log->Printf ("ProcessMonitor::%s() resuming result = %s", __FUNCTION__, result ? "true" : "false");
+ return result;
+}
+
+bool
+ProcessMonitor::SingleStep(lldb::tid_t unused, uint32_t signo)
+{
+ bool result;
+ SingleStepOperation op(signo, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::Kill()
+{
+ bool result;
+ KillOperation op(result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &ptrace_err)
+{
+ bool result;
+ LwpInfoOperation op(tid, lwpinfo, result, ptrace_err);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ThreadSuspend(lldb::tid_t tid, bool suspend)
+{
+ bool result;
+ ThreadSuspendOperation op(tid, suspend, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::GetEventMessage(lldb::tid_t tid, unsigned long *message)
+{
+ bool result;
+ EventMessageOperation op(tid, message, result);
+ DoOperation(&op);
+ return result;
+}
+
+lldb_private::Error
+ProcessMonitor::Detach(lldb::tid_t tid)
+{
+ lldb_private::Error error;
+ if (tid != LLDB_INVALID_THREAD_ID)
+ {
+ DetachOperation op(error);
+ DoOperation(&op);
+ }
+ return error;
+}
+
+bool
+ProcessMonitor::DupDescriptor(const FileSpec &file_spec, int fd, int flags)
+{
+ int target_fd = open(file_spec.GetCString(), flags, 0666);
+
+ if (target_fd == -1)
+ return false;
+
+ if (dup2(target_fd, fd) == -1)
+ return false;
+
+ return (close(target_fd) == -1) ? false : true;
+}
+
+void
+ProcessMonitor::StopMonitoringChildProcess()
+{
+ if (m_monitor_thread.IsJoinable())
+ {
+ m_monitor_thread.Cancel();
+ m_monitor_thread.Join(nullptr);
+ m_monitor_thread.Reset();
+ }
+}
+
+void
+ProcessMonitor::StopMonitor()
+{
+ StopMonitoringChildProcess();
+ StopOpThread();
+ sem_destroy(&m_operation_pending);
+ sem_destroy(&m_operation_done);
+ if (m_terminal_fd >= 0) {
+ close(m_terminal_fd);
+ m_terminal_fd = -1;
+ }
+}
+
+// FIXME: On Linux, when a new thread is created, we receive to notifications,
+// (1) a SIGTRAP|PTRACE_EVENT_CLONE from the main process thread with the
+// child thread id as additional information, and (2) a SIGSTOP|SI_USER from
+// the new child thread indicating that it has is stopped because we attached.
+// We have no guarantee of the order in which these arrive, but we need both
+// before we are ready to proceed. We currently keep a list of threads which
+// have sent the initial SIGSTOP|SI_USER event. Then when we receive the
+// SIGTRAP|PTRACE_EVENT_CLONE notification, if the initial stop has not occurred
+// we call ProcessMonitor::WaitForInitialTIDStop() to wait for it.
+//
+// Right now, the above logic is in ProcessPOSIX, so we need a definition of
+// this function in the FreeBSD ProcessMonitor implementation even if it isn't
+// logically needed.
+//
+// We really should figure out what actually happens on FreeBSD and move the
+// Linux-specific logic out of ProcessPOSIX as needed.
+
+bool
+ProcessMonitor::WaitForInitialTIDStop(lldb::tid_t tid)
+{
+ return true;
+}
+
+void
+ProcessMonitor::StopOpThread()
+{
+ if (!m_operation_thread.IsJoinable())
+ return;
+
+ m_operation_thread.Cancel();
+ m_operation_thread.Join(nullptr);
+ m_operation_thread.Reset();
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h
new file mode 100644
index 0000000..20ce582
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h
@@ -0,0 +1,328 @@
+//===-- ProcessMonitor.h -------------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessMonitor_H_
+#define liblldb_ProcessMonitor_H_
+
+// C Includes
+#include <semaphore.h>
+#include <signal.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/lldb-types.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private
+{
+class Error;
+class Module;
+class Scalar;
+} // End lldb_private namespace.
+
+class ProcessFreeBSD;
+class Operation;
+
+/// @class ProcessMonitor
+/// @brief 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 propagated to the associated
+/// ProcessFreeBSD instance by calling ProcessFreeBSD::SendMessage with the
+/// appropriate ProcessMessage events.
+///
+/// A purposely minimal set of operations are provided to interrogate and change
+/// the inferior process state.
+class ProcessMonitor
+{
+public:
+
+ /// Launches an inferior process ready for debugging. Forms the
+ /// implementation of Process::DoLaunch.
+ ProcessMonitor(ProcessPOSIX *process,
+ lldb_private::Module *module,
+ char const *argv[],
+ char const *envp[],
+ const lldb_private::FileSpec &stdin_file_spec,
+ const lldb_private::FileSpec &stdout_file_spec,
+ const lldb_private::FileSpec &stderr_file_spec,
+ const lldb_private::FileSpec &working_dir,
+ const lldb_private::ProcessLaunchInfo &launch_info,
+ lldb_private::Error &error);
+
+ ProcessMonitor(ProcessPOSIX *process,
+ lldb::pid_t pid,
+ lldb_private::Error &error);
+
+ ~ProcessMonitor();
+
+ /// Provides the process number of debugee.
+ lldb::pid_t
+ GetPID() const { return m_pid; }
+
+ /// Returns the process associated with this ProcessMonitor.
+ ProcessFreeBSD &
+ GetProcess() { return *m_process; }
+
+ /// Returns a file descriptor to the controlling terminal of the inferior
+ /// process.
+ ///
+ /// Reads from this file descriptor yield both the standard output and
+ /// standard error of this debugee. Even if stderr and stdout were
+ /// redirected on launch it may still happen that data is available on this
+ /// descriptor (if the inferior process opens /dev/tty, for example). This descriptor is
+ /// closed after a call to StopMonitor().
+ ///
+ /// If this monitor was attached to an existing process this method returns
+ /// -1.
+ int
+ GetTerminalFD() const { return m_terminal_fd; }
+
+ /// Reads @p size bytes from address @vm_adder in the inferior process
+ /// address space.
+ ///
+ /// This method is provided to implement Process::DoReadMemory.
+ size_t
+ ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ lldb_private::Error &error);
+
+ /// Writes @p size bytes from address @p vm_adder in the inferior process
+ /// address space.
+ ///
+ /// This method is provided to implement Process::DoWriteMemory.
+ size_t
+ WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+ lldb_private::Error &error);
+
+ /// Reads the contents from the register identified by the given (architecture
+ /// dependent) offset.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ bool
+ ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
+ unsigned size, lldb_private::RegisterValue &value);
+
+ /// Writes the given value to the register identified by the given
+ /// (architecture dependent) offset.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ bool
+ WriteRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
+ const lldb_private::RegisterValue &value);
+
+ /// Reads the contents from the debug register identified by the given
+ /// (architecture dependent) offset.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ bool
+ ReadDebugRegisterValue(lldb::tid_t tid, unsigned offset,
+ const char *reg_name, unsigned size,
+ lldb_private::RegisterValue &value);
+
+ /// Writes the given value to the debug register identified by the given
+ /// (architecture dependent) offset.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ bool
+ WriteDebugRegisterValue(lldb::tid_t tid, unsigned offset,
+ const char *reg_name,
+ const lldb_private::RegisterValue &value);
+ /// Reads all general purpose registers into the specified buffer.
+ bool
+ ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Reads all floating point registers into the specified buffer.
+ bool
+ ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Reads the specified register set into the specified buffer.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ bool
+ ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
+
+ /// Writes all general purpose registers into the specified buffer.
+ bool
+ WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Writes all floating point registers into the specified buffer.
+ bool
+ WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Writes the specified register set into the specified buffer.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ bool
+ WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
+
+ /// Reads the value of the thread-specific pointer for a given thread ID.
+ bool
+ ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value);
+
+ /// Returns current thread IDs in process
+ size_t
+ GetCurrentThreadIDs(std::vector<lldb::tid_t> &thread_ids);
+
+ /// Writes a ptrace_lwpinfo structure corresponding to the given thread ID
+ /// to the memory region pointed to by @p lwpinfo.
+ bool
+ GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &error_no);
+
+ /// Suspends or unsuspends a thread prior to process resume or step.
+ bool
+ ThreadSuspend(lldb::tid_t tid, bool suspend);
+
+ /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
+ /// corresponding to the given thread IDto the memory pointed to by @p
+ /// message.
+ bool
+ GetEventMessage(lldb::tid_t tid, unsigned long *message);
+
+ /// Resumes the process. If @p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process.
+ bool
+ Resume(lldb::tid_t unused, uint32_t signo);
+
+ /// Single steps the process. If @p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process.
+ bool
+ SingleStep(lldb::tid_t unused, uint32_t signo);
+
+ /// Terminate the traced process.
+ bool
+ Kill();
+
+ lldb_private::Error
+ Detach(lldb::tid_t tid);
+
+ void
+ StopMonitor();
+
+ // Waits for the initial stop message from a new thread.
+ bool
+ WaitForInitialTIDStop(lldb::tid_t tid);
+
+private:
+ ProcessFreeBSD *m_process;
+
+ lldb_private::HostThread m_operation_thread;
+ lldb_private::HostThread m_monitor_thread;
+ lldb::pid_t m_pid;
+
+ int m_terminal_fd;
+
+ // current operation which must be executed on the privileged thread
+ Operation *m_operation;
+ lldb_private::Mutex m_operation_mutex;
+
+ // semaphores notified when Operation is ready to be processed and when
+ // the operation is complete.
+ sem_t m_operation_pending;
+ sem_t m_operation_done;
+
+ struct OperationArgs
+ {
+ OperationArgs(ProcessMonitor *monitor);
+
+ ~OperationArgs();
+
+ ProcessMonitor *m_monitor; // The monitor performing the attach.
+ sem_t m_semaphore; // Posted to once operation complete.
+ lldb_private::Error m_error; // Set if process operation failed.
+ };
+
+ /// @class LauchArgs
+ ///
+ /// @brief Simple structure to pass data to the thread responsible for
+ /// launching a child process.
+ struct LaunchArgs : OperationArgs
+ {
+ LaunchArgs(ProcessMonitor *monitor,
+ lldb_private::Module *module,
+ char const **argv,
+ char const **envp,
+ const lldb_private::FileSpec &stdin_file_spec,
+ const lldb_private::FileSpec &stdout_file_spec,
+ const lldb_private::FileSpec &stderr_file_spec,
+ const lldb_private::FileSpec &working_dir);
+
+ ~LaunchArgs();
+
+ lldb_private::Module *m_module; // The executable image to launch.
+ char const **m_argv; // Process arguments.
+ char const **m_envp; // Process environment.
+ const lldb_private::FileSpec m_stdin_file_spec; // Redirect stdin or empty.
+ const lldb_private::FileSpec m_stdout_file_spec; // Redirect stdout or empty.
+ const lldb_private::FileSpec m_stderr_file_spec; // Redirect stderr or empty.
+ const lldb_private::FileSpec m_working_dir; // Working directory or empty.
+ };
+
+ void
+ StartLaunchOpThread(LaunchArgs *args, lldb_private::Error &error);
+
+ static void *
+ LaunchOpThread(void *arg);
+
+ static bool
+ Launch(LaunchArgs *args);
+
+ struct AttachArgs : OperationArgs
+ {
+ AttachArgs(ProcessMonitor *monitor,
+ lldb::pid_t pid);
+
+ ~AttachArgs();
+
+ lldb::pid_t m_pid; // pid of the process to be attached.
+ };
+
+ void
+ StartAttachOpThread(AttachArgs *args, lldb_private::Error &error);
+
+ static void *
+ AttachOpThread(void *args);
+
+ static void
+ Attach(AttachArgs *args);
+
+ static void
+ ServeOperation(OperationArgs *args);
+
+ static bool
+ DupDescriptor(const lldb_private::FileSpec &file_spec, int fd, int flags);
+
+ static bool
+ MonitorCallback(void *callback_baton,
+ lldb::pid_t pid, bool exited, int signal, int status);
+
+ static ProcessMessage
+ MonitorSIGTRAP(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::pid_t pid);
+
+ static ProcessMessage
+ MonitorSignal(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::pid_t pid);
+
+ void
+ DoOperation(Operation *op);
+
+ /// Stops the child monitor thread.
+ void
+ StopMonitoringChildProcess();
+
+ /// Stops the operation thread used to attach/launch a process.
+ void
+ StopOpThread();
+};
+
+#endif // #ifndef liblldb_ProcessMonitor_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessPOSIX.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessPOSIX.cpp
new file mode 100644
index 0000000..360382e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessPOSIX.cpp
@@ -0,0 +1,939 @@
+//===-- ProcessPOSIX.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Target.h"
+
+#include "ProcessPOSIX.h"
+#include "ProcessPOSIXLog.h"
+#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "POSIXThread.h"
+#include "ProcessMonitor.h"
+
+#include "lldb/Host/posix/Fcntl.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------------------
+// Constructors and destructors.
+
+ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener, UnixSignalsSP &unix_signals_sp)
+ : Process(target, listener, unix_signals_sp),
+ m_byte_order(lldb::endian::InlHostByteOrder()),
+ m_monitor(NULL),
+ m_module(NULL),
+ m_message_mutex (Mutex::eMutexTypeRecursive),
+ m_exit_now(false),
+ m_seen_initial_stop()
+{
+ // FIXME: Putting this code in the ctor and saving the byte order in a
+ // member variable is a hack to avoid const qual issues in GetByteOrder.
+ lldb::ModuleSP module = GetTarget().GetExecutableModule();
+ if (module && module->GetObjectFile())
+ m_byte_order = module->GetObjectFile()->GetByteOrder();
+}
+
+ProcessPOSIX::~ProcessPOSIX()
+{
+ delete m_monitor;
+}
+
+//------------------------------------------------------------------------------
+// Process protocol.
+void
+ProcessPOSIX::Finalize()
+{
+ Process::Finalize();
+
+ if (m_monitor)
+ m_monitor->StopMonitor();
+}
+
+bool
+ProcessPOSIX::CanDebug(Target &target, bool plugin_specified_by_name)
+{
+ // For now we are just making sure the file exists for a given module
+ ModuleSP exe_module_sp(target.GetExecutableModule());
+ if (exe_module_sp.get())
+ return exe_module_sp->GetFileSpec().Exists();
+ // If there is no executable module, we return true since we might be preparing to attach.
+ return true;
+}
+
+Error
+ProcessPOSIX::DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info)
+{
+ Error error;
+ assert(m_monitor == NULL);
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s(pid = %" PRIi64 ")", __FUNCTION__, GetID());
+
+ m_monitor = new ProcessMonitor(this, pid, error);
+
+ if (!error.Success())
+ return error;
+
+ PlatformSP platform_sp (m_target.GetPlatform ());
+ assert (platform_sp.get());
+ if (!platform_sp)
+ return error; // FIXME: Detatch?
+
+ // Find out what we can about this process
+ ProcessInstanceInfo process_info;
+ platform_sp->GetProcessInfo (pid, process_info);
+
+ // Resolve the executable module
+ ModuleSP exe_module_sp;
+ FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
+ ModuleSpec exe_module_spec(process_info.GetExecutableFile(), m_target.GetArchitecture());
+ error = platform_sp->ResolveExecutable(exe_module_spec,
+ exe_module_sp,
+ executable_search_paths.GetSize() ? &executable_search_paths : NULL);
+ if (!error.Success())
+ return error;
+
+ // Fix the target architecture if necessary
+ const ArchSpec &module_arch = exe_module_sp->GetArchitecture();
+ if (module_arch.IsValid() && !m_target.GetArchitecture().IsExactMatch(module_arch))
+ m_target.SetArchitecture(module_arch);
+
+ // Initialize the target module list
+ m_target.SetExecutableModule (exe_module_sp, true);
+
+ SetSTDIOFileDescriptor(m_monitor->GetTerminalFD());
+
+ SetID(pid);
+
+ return error;
+}
+
+Error
+ProcessPOSIX::WillLaunch(Module* module)
+{
+ Error error;
+ return error;
+}
+
+FileSpec
+ProcessPOSIX::GetFileSpec(const lldb_private::FileAction *file_action,
+ const FileSpec &default_file_spec,
+ const FileSpec &dbg_pts_file_spec)
+{
+ FileSpec file_spec{};
+
+ if (file_action && file_action->GetAction() == FileAction::eFileActionOpen)
+ {
+ file_spec = file_action->GetFileSpec();
+ // By default the stdio paths passed in will be pseudo-terminal
+ // (/dev/pts). If so, convert to using a different default path
+ // instead to redirect I/O to the debugger console. This should
+ // also handle user overrides to /dev/null or a different file.
+ if (!file_spec || file_spec == dbg_pts_file_spec)
+ file_spec = default_file_spec;
+ }
+ return file_spec;
+}
+
+Error
+ProcessPOSIX::DoLaunch (Module *module,
+ ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ assert(m_monitor == NULL);
+
+ FileSpec working_dir = launch_info.GetWorkingDirectory();
+ if (working_dir &&
+ (!working_dir.ResolvePath() ||
+ working_dir.GetFileType() != FileSpec::eFileTypeDirectory))
+ {
+ error.SetErrorStringWithFormat("No such file or directory: %s",
+ working_dir.GetCString());
+ return error;
+ }
+
+ SetPrivateState(eStateLaunching);
+
+ const lldb_private::FileAction *file_action;
+
+ // Default of empty will mean to use existing open file descriptors
+ FileSpec stdin_file_spec{};
+ FileSpec stdout_file_spec{};
+ FileSpec stderr_file_spec{};
+
+ const FileSpec dbg_pts_file_spec{launch_info.GetPTY().GetSlaveName(NULL,0), false};
+
+ file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
+ stdin_file_spec = GetFileSpec(file_action, stdin_file_spec, dbg_pts_file_spec);
+
+ file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
+ stdout_file_spec = GetFileSpec(file_action, stdout_file_spec, dbg_pts_file_spec);
+
+ file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
+ stderr_file_spec = GetFileSpec(file_action, stderr_file_spec, dbg_pts_file_spec);
+
+ m_monitor = new ProcessMonitor(this,
+ module,
+ launch_info.GetArguments().GetConstArgumentVector(),
+ launch_info.GetEnvironmentEntries().GetConstArgumentVector(),
+ stdin_file_spec,
+ stdout_file_spec,
+ stderr_file_spec,
+ working_dir,
+ launch_info,
+ error);
+
+ m_module = module;
+
+ if (!error.Success())
+ return error;
+
+ int terminal = m_monitor->GetTerminalFD();
+ if (terminal >= 0) {
+ // The reader thread will close the file descriptor when done, so we pass it a copy.
+ int stdio = fcntl(terminal, F_DUPFD_CLOEXEC, 0);
+ if (stdio == -1) {
+ error.SetErrorToErrno();
+ return error;
+ }
+ SetSTDIOFileDescriptor(stdio);
+ }
+
+ SetID(m_monitor->GetPID());
+ return error;
+}
+
+void
+ProcessPOSIX::DidLaunch()
+{
+}
+
+Error
+ProcessPOSIX::DoResume()
+{
+ StateType state = GetPrivateState();
+
+ assert(state == eStateStopped);
+
+ SetPrivateState(eStateRunning);
+
+ bool did_resume = false;
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ did_resume = thread->Resume() || did_resume;
+ }
+ assert(did_resume && "Process resume failed!");
+
+ return Error();
+}
+
+addr_t
+ProcessPOSIX::GetImageInfoAddress()
+{
+ Target *target = &GetTarget();
+ ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
+ Address addr = obj_file->GetImageInfoAddress(target);
+
+ if (addr.IsValid())
+ return addr.GetLoadAddress(target);
+ return LLDB_INVALID_ADDRESS;
+}
+
+Error
+ProcessPOSIX::DoHalt(bool &caused_stop)
+{
+ Error error;
+
+ if (IsStopped())
+ {
+ caused_stop = false;
+ }
+ else if (kill(GetID(), SIGSTOP))
+ {
+ caused_stop = false;
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ caused_stop = true;
+ }
+ return error;
+}
+
+Error
+ProcessPOSIX::DoSignal(int signal)
+{
+ Error error;
+
+ if (kill(GetID(), signal))
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Error
+ProcessPOSIX::DoDestroy()
+{
+ Error error;
+
+ if (!HasExited())
+ {
+ assert(m_monitor);
+ m_exit_now = true;
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ error.SetErrorString("invalid process id");
+ return error;
+ }
+ if (!m_monitor->Kill())
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ SetPrivateState(eStateExited);
+ }
+
+ return error;
+}
+
+void
+ProcessPOSIX::DoDidExec()
+{
+ Target *target = &GetTarget();
+ if (target)
+ {
+ PlatformSP platform_sp (target->GetPlatform());
+ assert (platform_sp.get());
+ if (platform_sp)
+ {
+ ProcessInstanceInfo process_info;
+ platform_sp->GetProcessInfo(GetID(), process_info);
+ ModuleSP exe_module_sp;
+ ModuleSpec exe_module_spec(process_info.GetExecutableFile(), target->GetArchitecture());
+ FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
+ Error error = platform_sp->ResolveExecutable(exe_module_spec,
+ exe_module_sp,
+ executable_search_paths.GetSize() ? &executable_search_paths : NULL);
+ if (!error.Success())
+ return;
+ target->SetExecutableModule(exe_module_sp, true);
+ }
+ }
+}
+
+void
+ProcessPOSIX::SendMessage(const ProcessMessage &message)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ Mutex::Locker lock(m_message_mutex);
+
+ Mutex::Locker thread_lock(m_thread_list.GetMutex());
+
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.FindThreadByID(message.GetTID(), false).get());
+
+ switch (message.GetKind())
+ {
+ case ProcessMessage::eInvalidMessage:
+ return;
+
+ case ProcessMessage::eAttachMessage:
+ SetPrivateState(eStateStopped);
+ return;
+
+ case ProcessMessage::eLimboMessage:
+ assert(thread);
+ thread->SetState(eStateStopped);
+ if (message.GetTID() == GetID())
+ {
+ m_exit_status = message.GetExitStatus();
+ if (m_exit_now)
+ {
+ SetPrivateState(eStateExited);
+ m_monitor->Detach(GetID());
+ }
+ else
+ {
+ SetPrivateState(eStateStopped);
+ }
+ }
+ else
+ {
+ SetPrivateState(eStateStopped);
+ }
+ break;
+
+ case ProcessMessage::eExitMessage:
+ if (thread != nullptr)
+ thread->SetState(eStateExited);
+ else
+ {
+ if (log)
+ log->Warning ("ProcessPOSIX::%s eExitMessage for TID %" PRIu64 " failed to find a thread to mark as eStateExited, ignoring", __FUNCTION__, message.GetTID ());
+ }
+
+ // FIXME: I'm not sure we need to do this.
+ if (message.GetTID() == GetID())
+ {
+ SetExitStatus(message.GetExitStatus(), NULL);
+ }
+ else if (!IsAThreadRunning())
+ SetPrivateState(eStateStopped);
+ break;
+
+ case ProcessMessage::eSignalMessage:
+ case ProcessMessage::eSignalDeliveredMessage:
+ if (message.GetSignal() == SIGSTOP &&
+ AddThreadForInitialStopIfNeeded(message.GetTID()))
+ return;
+ // Intentional fall-through
+
+ case ProcessMessage::eBreakpointMessage:
+ case ProcessMessage::eTraceMessage:
+ case ProcessMessage::eWatchpointMessage:
+ case ProcessMessage::eCrashMessage:
+ assert(thread);
+ thread->SetState(eStateStopped);
+ SetPrivateState(eStateStopped);
+ break;
+
+ case ProcessMessage::eNewThreadMessage:
+ {
+ lldb::tid_t new_tid = message.GetChildTID();
+ if (WaitingForInitialStop(new_tid))
+ {
+ m_monitor->WaitForInitialTIDStop(new_tid);
+ }
+ assert(thread);
+ thread->SetState(eStateStopped);
+ SetPrivateState(eStateStopped);
+ break;
+ }
+
+ case ProcessMessage::eExecMessage:
+ {
+ assert(thread);
+ thread->SetState(eStateStopped);
+ SetPrivateState(eStateStopped);
+ break;
+ }
+ }
+
+
+ m_message_queue.push(message);
+}
+
+bool
+ProcessPOSIX::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid)
+{
+ bool added_to_set = false;
+ ThreadStopSet::iterator it = m_seen_initial_stop.find(stop_tid);
+ if (it == m_seen_initial_stop.end())
+ {
+ m_seen_initial_stop.insert(stop_tid);
+ added_to_set = true;
+ }
+ return added_to_set;
+}
+
+bool
+ProcessPOSIX::WaitingForInitialStop(lldb::tid_t stop_tid)
+{
+ return (m_seen_initial_stop.find(stop_tid) == m_seen_initial_stop.end());
+}
+
+POSIXThread *
+ProcessPOSIX::CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid)
+{
+ return new POSIXThread(process, tid);
+}
+
+void
+ProcessPOSIX::RefreshStateAfterStop()
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s(), message_queue size = %d", __FUNCTION__, (int)m_message_queue.size());
+
+ Mutex::Locker lock(m_message_mutex);
+
+ // This method used to only handle one message. Changing it to loop allows
+ // it to handle the case where we hit a breakpoint while handling a different
+ // breakpoint.
+ while (!m_message_queue.empty())
+ {
+ ProcessMessage &message = m_message_queue.front();
+
+ // Resolve the thread this message corresponds to and pass it along.
+ lldb::tid_t tid = message.GetTID();
+ if (log)
+ log->Printf ("ProcessPOSIX::%s(), message_queue size = %d, pid = %" PRIi64, __FUNCTION__, (int)m_message_queue.size(), tid);
+
+ if (message.GetKind() == ProcessMessage::eNewThreadMessage)
+ {
+ if (log)
+ log->Printf ("ProcessPOSIX::%s() adding thread, tid = %" PRIi64, __FUNCTION__, message.GetChildTID());
+ lldb::tid_t child_tid = message.GetChildTID();
+ ThreadSP thread_sp;
+ thread_sp.reset(CreateNewPOSIXThread(*this, child_tid));
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+
+ m_thread_list.AddThread(thread_sp);
+ }
+
+ m_thread_list.RefreshStateAfterStop();
+
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ GetThreadList().FindThreadByID(tid, false).get());
+ if (thread)
+ thread->Notify(message);
+
+ if (message.GetKind() == ProcessMessage::eExitMessage)
+ {
+ // FIXME: We should tell the user about this, but the limbo message is probably better for that.
+ if (log)
+ log->Printf ("ProcessPOSIX::%s() removing thread, tid = %" PRIi64, __FUNCTION__, tid);
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+
+ ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false);
+ thread_sp.reset();
+ m_seen_initial_stop.erase(tid);
+ }
+
+ m_message_queue.pop();
+ }
+}
+
+bool
+ProcessPOSIX::IsAlive()
+{
+ StateType state = GetPrivateState();
+ return state != eStateDetached
+ && state != eStateExited
+ && state != eStateInvalid
+ && state != eStateUnloaded;
+}
+
+size_t
+ProcessPOSIX::DoReadMemory(addr_t vm_addr,
+ void *buf, size_t size, Error &error)
+{
+ assert(m_monitor);
+ return m_monitor->ReadMemory(vm_addr, buf, size, error);
+}
+
+size_t
+ProcessPOSIX::DoWriteMemory(addr_t vm_addr, const void *buf, size_t size,
+ Error &error)
+{
+ assert(m_monitor);
+ return m_monitor->WriteMemory(vm_addr, buf, size, error);
+}
+
+addr_t
+ProcessPOSIX::DoAllocateMemory(size_t size, uint32_t permissions,
+ Error &error)
+{
+ addr_t allocated_addr = LLDB_INVALID_ADDRESS;
+
+ unsigned prot = 0;
+ if (permissions & lldb::ePermissionsReadable)
+ prot |= eMmapProtRead;
+ if (permissions & lldb::ePermissionsWritable)
+ prot |= eMmapProtWrite;
+ if (permissions & lldb::ePermissionsExecutable)
+ prot |= eMmapProtExec;
+
+ if (InferiorCallMmap(this, allocated_addr, 0, size, prot,
+ eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) {
+ m_addr_to_mmap_size[allocated_addr] = size;
+ error.Clear();
+ } else {
+ allocated_addr = LLDB_INVALID_ADDRESS;
+ error.SetErrorStringWithFormat("unable to allocate %zu bytes of memory with permissions %s", size, GetPermissionsAsCString (permissions));
+ }
+
+ return allocated_addr;
+}
+
+Error
+ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr)
+{
+ Error error;
+ MMapMap::iterator pos = m_addr_to_mmap_size.find(addr);
+ if (pos != m_addr_to_mmap_size.end() &&
+ InferiorCallMunmap(this, addr, pos->second))
+ m_addr_to_mmap_size.erase (pos);
+ else
+ error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr);
+
+ return error;
+}
+
+size_t
+ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site)
+{
+ static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xD4 };
+ static const uint8_t g_i386_opcode[] = { 0xCC };
+
+ ArchSpec arch = GetTarget().GetArchitecture();
+ const uint8_t *opcode = NULL;
+ size_t opcode_size = 0;
+
+ switch (arch.GetMachine())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case llvm::Triple::arm:
+ {
+ // The ARM reference recommends the use of 0xe7fddefe and 0xdefe
+ // but the linux kernel does otherwise.
+ static const uint8_t g_arm_breakpoint_opcode[] = { 0xf0, 0x01, 0xf0, 0xe7 };
+ static const uint8_t g_thumb_breakpoint_opcode[] = { 0x01, 0xde };
+
+ lldb::BreakpointLocationSP bp_loc_sp (bp_site->GetOwnerAtIndex (0));
+ AddressClass addr_class = eAddressClassUnknown;
+
+ if (bp_loc_sp)
+ addr_class = bp_loc_sp->GetAddress ().GetAddressClass ();
+
+ if (addr_class == eAddressClassCodeAlternateISA
+ || (addr_class == eAddressClassUnknown
+ && bp_loc_sp->GetAddress().GetOffset() & 1))
+ {
+ opcode = g_thumb_breakpoint_opcode;
+ opcode_size = sizeof(g_thumb_breakpoint_opcode);
+ }
+ else
+ {
+ opcode = g_arm_breakpoint_opcode;
+ opcode_size = sizeof(g_arm_breakpoint_opcode);
+ }
+ }
+ break;
+ case llvm::Triple::aarch64:
+ opcode = g_aarch64_opcode;
+ opcode_size = sizeof(g_aarch64_opcode);
+ break;
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ opcode = g_i386_opcode;
+ opcode_size = sizeof(g_i386_opcode);
+ break;
+ }
+
+ bp_site->SetTrapOpcode(opcode, opcode_size);
+ return opcode_size;
+}
+
+Error
+ProcessPOSIX::EnableBreakpointSite(BreakpointSite *bp_site)
+{
+ return EnableSoftwareBreakpoint(bp_site);
+}
+
+Error
+ProcessPOSIX::DisableBreakpointSite(BreakpointSite *bp_site)
+{
+ return DisableSoftwareBreakpoint(bp_site);
+}
+
+Error
+ProcessPOSIX::EnableWatchpoint(Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+ addr_t addr = wp->GetLoadAddress();
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64 ")",
+ watchID);
+ if (wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64
+ ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.",
+ watchID, (uint64_t)addr);
+ return error;
+ }
+
+ // Try to find a vacant watchpoint slot in the inferiors' main thread
+ uint32_t wp_hw_index = LLDB_INVALID_INDEX32;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(0, false).get());
+
+ if (thread)
+ wp_hw_index = thread->FindVacantWatchpointIndex();
+
+ if (wp_hw_index == LLDB_INVALID_INDEX32)
+ {
+ error.SetErrorString("Setting hardware watchpoint failed.");
+ }
+ else
+ {
+ wp->SetHardwareIndex(wp_hw_index);
+ bool wp_enabled = true;
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ if (thread)
+ wp_enabled &= thread->EnableHardwareWatchpoint(wp);
+ else
+ wp_enabled = false;
+ }
+ if (wp_enabled)
+ {
+ wp->SetEnabled(true, notify);
+ return error;
+ }
+ else
+ {
+ // Watchpoint enabling failed on at least one
+ // of the threads so roll back all of them
+ DisableWatchpoint(wp, false);
+ error.SetErrorString("Setting hardware watchpoint failed");
+ }
+ }
+ }
+ else
+ error.SetErrorString("Watchpoint argument was NULL.");
+ return error;
+}
+
+Error
+ProcessPOSIX::DisableWatchpoint(Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+ addr_t addr = wp->GetLoadAddress();
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64 ")",
+ watchID);
+ if (!wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64
+ ") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.",
+ watchID, (uint64_t)addr);
+ // This is needed (for now) to keep watchpoints disabled correctly
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+
+ if (wp->IsHardware())
+ {
+ bool wp_disabled = true;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ if (thread)
+ wp_disabled &= thread->DisableHardwareWatchpoint(wp);
+ else
+ wp_disabled = false;
+ }
+ if (wp_disabled)
+ {
+ wp->SetHardwareIndex(LLDB_INVALID_INDEX32);
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+ else
+ error.SetErrorString("Disabling hardware watchpoint failed");
+ }
+ }
+ else
+ error.SetErrorString("Watchpoint argument was NULL.");
+ return error;
+}
+
+Error
+ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num)
+{
+ Error error;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(0, false).get());
+ if (thread)
+ num = thread->NumSupportedHardwareWatchpoints();
+ else
+ error.SetErrorString("Process does not exist.");
+ return error;
+}
+
+Error
+ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num, bool &after)
+{
+ Error error = GetWatchpointSupportInfo(num);
+ // Watchpoints trigger and halt the inferior after
+ // the corresponding instruction has been executed.
+ after = true;
+ return error;
+}
+
+uint32_t
+ProcessPOSIX::UpdateThreadListIfNeeded()
+{
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ // Do not allow recursive updates.
+ return m_thread_list.GetSize(false);
+}
+
+bool
+ProcessPOSIX::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s() (pid = %" PRIi64 ")", __FUNCTION__, GetID());
+
+ bool has_updated = false;
+ // Update the process thread list with this new thread.
+ // FIXME: We should be using tid, not pid.
+ assert(m_monitor);
+ ThreadSP thread_sp (old_thread_list.FindThreadByID (GetID(), false));
+ if (!thread_sp) {
+ thread_sp.reset(CreateNewPOSIXThread(*this, GetID()));
+ has_updated = true;
+ }
+
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s() updated pid = %" PRIi64, __FUNCTION__, GetID());
+ new_thread_list.AddThread(thread_sp);
+
+ return has_updated; // the list has been updated
+}
+
+ByteOrder
+ProcessPOSIX::GetByteOrder() const
+{
+ // FIXME: We should be able to extract this value directly. See comment in
+ // ProcessPOSIX().
+ return m_byte_order;
+}
+
+size_t
+ProcessPOSIX::PutSTDIN(const char *buf, size_t len, Error &error)
+{
+ ssize_t status;
+ if ((status = write(m_monitor->GetTerminalFD(), buf, len)) < 0)
+ {
+ error.SetErrorToErrno();
+ return 0;
+ }
+ return status;
+}
+
+//------------------------------------------------------------------------------
+// Utility functions.
+
+bool
+ProcessPOSIX::HasExited()
+{
+ switch (GetPrivateState())
+ {
+ default:
+ break;
+
+ case eStateDetached:
+ case eStateExited:
+ return true;
+ }
+
+ return false;
+}
+
+bool
+ProcessPOSIX::IsStopped()
+{
+ switch (GetPrivateState())
+ {
+ default:
+ break;
+
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ return true;
+ }
+
+ return false;
+}
+
+bool
+ProcessPOSIX::IsAThreadRunning()
+{
+ bool is_running = false;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ StateType thread_state = thread->GetState();
+ if (thread_state == eStateRunning || thread_state == eStateStepping)
+ {
+ is_running = true;
+ break;
+ }
+ }
+ return is_running;
+}
+
+const DataBufferSP
+ProcessPOSIX::GetAuxvData ()
+{
+ // If we're the local platform, we can ask the host for auxv data.
+ PlatformSP platform_sp = m_target.GetPlatform ();
+ if (platform_sp && platform_sp->IsHost ())
+ return lldb_private::Host::GetAuxvData(this);
+
+ // Somewhat unexpected - the process is not running locally or we don't have a platform.
+ assert (false && "no platform or not the host - how did we get here with ProcessPOSIX?");
+ return DataBufferSP ();
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessPOSIX.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessPOSIX.h
new file mode 100644
index 0000000..ee44e92
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessPOSIX.h
@@ -0,0 +1,205 @@
+//===-- ProcessPOSIX.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessPOSIX_H_
+#define liblldb_ProcessPOSIX_H_
+
+// C Includes
+
+// C++ Includes
+#include <queue>
+#include <set>
+
+// Other libraries and framework includes
+#include "lldb/Target/Process.h"
+#include "Plugins/Process/POSIX/ProcessMessage.h"
+
+class ProcessMonitor;
+class POSIXThread;
+
+class ProcessPOSIX :
+ public lldb_private::Process
+{
+public:
+
+ //------------------------------------------------------------------
+ // Constructors and destructors
+ //------------------------------------------------------------------
+ ProcessPOSIX(lldb_private::Target& target,
+ lldb_private::Listener &listener,
+ lldb::UnixSignalsSP &unix_signals_sp);
+
+ virtual
+ ~ProcessPOSIX();
+
+ //------------------------------------------------------------------
+ // Process protocol.
+ //------------------------------------------------------------------
+ void
+ Finalize() override;
+
+ bool
+ CanDebug(lldb_private::Target &target, bool plugin_specified_by_name) override;
+
+ lldb_private::Error
+ WillLaunch(lldb_private::Module *module) override;
+
+ lldb_private::Error
+ DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info) override;
+
+ lldb_private::Error
+ DoLaunch (lldb_private::Module *exe_module,
+ lldb_private::ProcessLaunchInfo &launch_info) override;
+
+ void
+ DidLaunch() override;
+
+ lldb_private::Error
+ DoResume() override;
+
+ lldb_private::Error
+ DoHalt(bool &caused_stop) override;
+
+ lldb_private::Error
+ DoDetach(bool keep_stopped) override = 0;
+
+ lldb_private::Error
+ DoSignal(int signal) override;
+
+ lldb_private::Error
+ DoDestroy() override;
+
+ void
+ DoDidExec() override;
+
+ void
+ RefreshStateAfterStop() override;
+
+ bool
+ IsAlive() override;
+
+ size_t
+ DoReadMemory(lldb::addr_t vm_addr,
+ void *buf,
+ size_t size,
+ lldb_private::Error &error) override;
+
+ size_t
+ DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+ lldb_private::Error &error) override;
+
+ lldb::addr_t
+ DoAllocateMemory(size_t size, uint32_t permissions,
+ lldb_private::Error &error) override;
+
+ lldb_private::Error
+ DoDeallocateMemory(lldb::addr_t ptr) override;
+
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site);
+
+ lldb_private::Error
+ EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override;
+
+ lldb_private::Error
+ DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override;
+
+ lldb_private::Error
+ EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override;
+
+ lldb_private::Error
+ DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true) override;
+
+ lldb_private::Error
+ GetWatchpointSupportInfo(uint32_t &num) override;
+
+ lldb_private::Error
+ GetWatchpointSupportInfo(uint32_t &num, bool &after) override;
+
+ virtual uint32_t
+ UpdateThreadListIfNeeded();
+
+ bool
+ UpdateThreadList(lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list) override = 0;
+
+ virtual lldb::ByteOrder
+ GetByteOrder() const;
+
+ lldb::addr_t
+ GetImageInfoAddress() override;
+
+ size_t
+ PutSTDIN(const char *buf, size_t len, lldb_private::Error &error) override;
+
+ const lldb::DataBufferSP
+ GetAuxvData () override;
+
+ //--------------------------------------------------------------------------
+ // ProcessPOSIX internal API.
+
+ /// Registers the given message with this process.
+ virtual void
+ SendMessage(const ProcessMessage &message);
+
+ ProcessMonitor &
+ GetMonitor() { assert(m_monitor); return *m_monitor; }
+
+ lldb_private::FileSpec
+ GetFileSpec(const lldb_private::FileAction *file_action,
+ const lldb_private::FileSpec &default_file_spec,
+ const lldb_private::FileSpec &dbg_pts_file_spec);
+
+ /// Adds the thread to the list of threads for which we have received the initial stopping signal.
+ /// The \p stop_tid parameter indicates the thread which the stop happened for.
+ bool
+ AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid);
+
+ bool
+ WaitingForInitialStop(lldb::tid_t stop_tid);
+
+ virtual POSIXThread *
+ CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid);
+
+protected:
+ /// Target byte order.
+ lldb::ByteOrder m_byte_order;
+
+ /// Process monitor;
+ ProcessMonitor *m_monitor;
+
+ /// The module we are executing.
+ lldb_private::Module *m_module;
+
+ /// Message queue notifying this instance of inferior process state changes.
+ lldb_private::Mutex m_message_mutex;
+ std::queue<ProcessMessage> m_message_queue;
+
+ /// Drive any exit events to completion.
+ bool m_exit_now;
+
+ /// Returns true if the process has exited.
+ bool HasExited();
+
+ /// Returns true if the process is stopped.
+ bool IsStopped();
+
+ /// Returns true if at least one running is currently running
+ bool IsAThreadRunning();
+
+ typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
+ MMapMap m_addr_to_mmap_size;
+
+ typedef std::set<lldb::tid_t> ThreadStopSet;
+ /// Every thread begins with a stop signal. This keeps track
+ /// of the threads for which we have received the stop signal.
+ ThreadStopSet m_seen_initial_stop;
+};
+
+#endif // liblldb_MacOSXProcess_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp
new file mode 100644
index 0000000..f6d029e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.cpp
@@ -0,0 +1,322 @@
+//===-- RegisterContextPOSIXProcessMonitor_arm.cpp -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h"
+#include "ProcessPOSIX.h"
+#include "RegisterContextPOSIXProcessMonitor_arm.h"
+#include "ProcessMonitor.h"
+
+using namespace lldb_private;
+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)
+{
+}
+
+ProcessMonitor &
+RegisterContextPOSIXProcessMonitor_arm::GetMonitor()
+{
+ ProcessSP base = CalculateProcess();
+ ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
+ return process->GetMonitor();
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::ReadGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::ReadFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr));
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::WriteGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::WriteFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof(m_fpr));
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::ReadRegister(const unsigned reg,
+ RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterName(reg),
+ GetRegisterSize(reg),
+ value);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::WriteRegister(const unsigned reg,
+ const RegisterValue &value)
+{
+ unsigned reg_to_write = reg;
+ RegisterValue value_to_write = value;
+
+ // Check if this is a subregister of a full register.
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
+ {
+ RegisterValue full_value;
+ uint32_t full_reg = reg_info->invalidate_regs[0];
+ const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
+
+ // Read the full register.
+ if (ReadRegister(full_reg_info, full_value))
+ {
+ Error error;
+ ByteOrder byte_order = GetByteOrder();
+ uint8_t dst[RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the full register.
+ const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
+ dst,
+ sizeof(dst),
+ byte_order,
+ error);
+ if (error.Success() && dest_size)
+ {
+ uint8_t src[RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the source data.
+ const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
+ if (error.Success() && src_size && (src_size < dest_size))
+ {
+ // Copy the src bytes to the destination.
+ memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
+ // Set this full register as the value to write.
+ value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
+ value_to_write.SetType(full_reg_info);
+ reg_to_write = full_reg;
+ }
+ }
+ }
+ }
+
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg_to_write),
+ GetRegisterName(reg_to_write),
+ value_to_write);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (IsFPR(reg))
+ {
+ if (!ReadFPR())
+ return false;
+ }
+ else
+ {
+ return ReadRegister(reg, value);
+ }
+
+ // Get pointer to m_fpr variable and set the data from it.
+ assert (reg_info->byte_offset < sizeof m_fpr);
+ uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
+ switch (reg_info->byte_size)
+ {
+ case 2:
+ value.SetUInt16(*(uint16_t *)src);
+ return true;
+ case 4:
+ value.SetUInt32(*(uint32_t *)src);
+ return true;
+ case 8:
+ value.SetUInt64(*(uint64_t *)src);
+ return true;
+ default:
+ assert(false && "Unhandled data size.");
+ return false;
+ }
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (IsGPR(reg))
+ {
+ return WriteRegister(reg, value);
+ }
+ else if (IsFPR(reg))
+ {
+ return WriteFPR();
+ }
+
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::ReadAllRegisterValues(DataBufferSP &data_sp)
+{
+ bool success = false;
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp && ReadGPR () && ReadFPR ())
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ success = dst != 0;
+
+ if (success)
+ {
+ ::memcpy (dst, &m_gpr_arm, GetGPRSize());
+ dst += GetGPRSize();
+ ::memcpy (dst, &m_fpr, sizeof(m_fpr));
+ }
+ }
+ return success;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::WriteAllRegisterValues(const DataBufferSP &data_sp)
+{
+ bool success = false;
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ uint8_t *src = data_sp->GetBytes();
+ if (src)
+ {
+ ::memcpy (&m_gpr_arm, src, GetGPRSize());
+
+ if (WriteGPR())
+ {
+ src += GetGPRSize();
+ ::memcpy (&m_fpr, src, sizeof(m_fpr));
+
+ success = WriteFPR();
+ }
+ }
+ }
+ return success;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpoint(addr_t addr, size_t size,
+ bool read, bool write)
+{
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+ uint32_t hw_index;
+
+ for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index)
+ {
+ if (IsWatchpointVacant(hw_index))
+ return SetHardwareWatchpointWithIndex(addr, size,
+ read, write,
+ hw_index);
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::ClearHardwareWatchpoint(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::HardwareSingleStep(bool enable)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::UpdateAfterBreakpoint()
+{
+ lldb::addr_t pc;
+
+ if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
+ return false;
+
+ return true;
+}
+
+unsigned
+RegisterContextPOSIXProcessMonitor_arm::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg;
+ for (reg = 0; reg < k_num_registers_arm; reg++)
+ {
+ if (GetRegisterInfo()[reg].byte_offset == offset)
+ break;
+ }
+ assert(reg < k_num_registers_arm && "Invalid register offset.");
+ return reg;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::IsWatchpointHit(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::ClearWatchpointHits()
+{
+ return false;
+}
+
+addr_t
+RegisterContextPOSIXProcessMonitor_arm::GetWatchpointAddress(uint32_t hw_index)
+{
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::IsWatchpointVacant(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm::SetHardwareWatchpointWithIndex(addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index)
+{
+ return false;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_arm::NumSupportedHardwareWatchpoints()
+{
+ return 0;
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h
new file mode 100644
index 0000000..12a43c7
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm.h
@@ -0,0 +1,95 @@
+//===-- RegisterContextPOSIXProcessMonitor_arm.h --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextPOSIXProcessMonitor_arm_H_
+#define liblldb_RegisterContextPOSIXProcessMonitor_arm_H_
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h"
+
+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);
+
+protected:
+ bool
+ ReadGPR();
+
+ bool
+ ReadFPR();
+
+ bool
+ WriteGPR();
+
+ bool
+ WriteFPR();
+
+ // lldb_private::RegisterContext
+ bool
+ ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ uint32_t
+ SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write);
+
+ bool
+ ClearHardwareWatchpoint(uint32_t hw_index);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ // POSIXBreakpointProtocol
+ bool
+ UpdateAfterBreakpoint();
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ bool
+ IsWatchpointHit(uint32_t hw_index);
+
+ bool
+ ClearWatchpointHits();
+
+ lldb::addr_t
+ GetWatchpointAddress(uint32_t hw_index);
+
+ bool
+ IsWatchpointVacant(uint32_t hw_index);
+
+ bool
+ SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index);
+
+ uint32_t
+ NumSupportedHardwareWatchpoints();
+
+private:
+ ProcessMonitor &
+ GetMonitor();
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp
new file mode 100644
index 0000000..44cb603
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.cpp
@@ -0,0 +1,318 @@
+//===-- RegisterContextPOSIXProcessMonitor_arm64.cpp -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
+#include "ProcessPOSIX.h"
+#include "ProcessMonitor.h"
+#include "RegisterContextPOSIXProcessMonitor_arm64.h"
+
+#define REG_CONTEXT_SIZE (GetGPRSize())
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextPOSIXProcessMonitor_arm64::RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info)
+ : RegisterContextPOSIX_arm64(thread, concrete_frame_idx, register_info)
+{
+}
+
+ProcessMonitor &
+RegisterContextPOSIXProcessMonitor_arm64::GetMonitor()
+{
+ lldb::ProcessSP base = CalculateProcess();
+ ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
+ return process->GetMonitor();
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::ReadGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::ReadFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::WriteGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteGPR(m_thread.GetID(), &m_gpr_arm64, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::WriteFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteFPR(m_thread.GetID(), &m_fpr, sizeof m_fpr);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const unsigned reg,
+ lldb_private::RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterName(reg),
+ GetRegisterSize(reg),
+ value);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const unsigned reg,
+ const lldb_private::RegisterValue &value)
+{
+ unsigned reg_to_write = reg;
+ lldb_private::RegisterValue value_to_write = value;
+
+ // Check if this is a subregister of a full register.
+ const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
+ {
+ lldb_private::RegisterValue full_value;
+ uint32_t full_reg = reg_info->invalidate_regs[0];
+ const lldb_private::RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
+
+ // Read the full register.
+ if (ReadRegister(full_reg_info, full_value))
+ {
+ lldb_private::Error error;
+ lldb::ByteOrder byte_order = GetByteOrder();
+ uint8_t dst[lldb_private::RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the full register.
+ const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
+ dst,
+ sizeof(dst),
+ byte_order,
+ error);
+ if (error.Success() && dest_size)
+ {
+ uint8_t src[lldb_private::RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the source data.
+ const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
+ if (error.Success() && src_size && (src_size < dest_size))
+ {
+ // Copy the src bytes to the destination.
+ ::memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
+ // Set this full register as the value to write.
+ value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
+ value_to_write.SetType(full_reg_info);
+ reg_to_write = full_reg;
+ }
+ }
+ }
+ }
+
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg_to_write),
+ GetRegisterName(reg_to_write),
+ value_to_write);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+ if (IsFPR(reg))
+ {
+ if (!ReadFPR())
+ return false;
+ }
+ else
+ {
+ uint32_t full_reg = reg;
+ bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
+
+ if (is_subreg)
+ {
+ // Read the full aligned 64-bit register.
+ full_reg = reg_info->invalidate_regs[0];
+ }
+ return ReadRegister(full_reg, value);
+ }
+
+ // Get pointer to m_fpr variable and set the data from it.
+ assert (reg_info->byte_offset < sizeof m_fpr);
+ uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
+ switch (reg_info->byte_size)
+ {
+ case 2:
+ value.SetUInt16(*(uint16_t *)src);
+ return true;
+ case 4:
+ value.SetUInt32(*(uint32_t *)src);
+ return true;
+ case 8:
+ value.SetUInt64(*(uint64_t *)src);
+ return true;
+ default:
+ assert(false && "Unhandled data size.");
+ return false;
+ }
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+
+ if (IsGPR(reg))
+ return WriteRegister(reg, value);
+
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ bool success = false;
+ data_sp.reset (new lldb_private::DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp && ReadGPR () && ReadFPR ())
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ success = dst != 0;
+
+ if (success)
+ {
+ ::memcpy (dst, &m_gpr_arm64, GetGPRSize());
+ dst += GetGPRSize();
+ ::memcpy (dst, &m_fpr, sizeof m_fpr);
+ }
+ }
+ return success;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ bool success = false;
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ uint8_t *src = data_sp->GetBytes();
+ if (src)
+ {
+ ::memcpy (&m_gpr_arm64, src, GetGPRSize());
+ if (WriteGPR()) {
+ src += GetGPRSize();
+ ::memcpy (&m_fpr, src, sizeof m_fpr);
+ success = WriteFPR();
+ }
+ }
+ }
+ return success;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
+ bool read, bool write)
+{
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+ uint32_t hw_index;
+
+ for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index)
+ {
+ if (IsWatchpointVacant(hw_index))
+ return SetHardwareWatchpointWithIndex(addr, size,
+ read, write,
+ hw_index);
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::ClearHardwareWatchpoint(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::HardwareSingleStep(bool enable)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::UpdateAfterBreakpoint()
+{
+ if (GetPC() == LLDB_INVALID_ADDRESS)
+ return false;
+
+ return true;
+}
+
+unsigned
+RegisterContextPOSIXProcessMonitor_arm64::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg;
+ for (reg = 0; reg < k_num_registers_arm64; reg++)
+ {
+ if (GetRegisterInfo()[reg].byte_offset == offset)
+ break;
+ }
+ assert(reg < k_num_registers_arm64 && "Invalid register offset.");
+ return reg;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointHit(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::ClearWatchpointHits()
+{
+ return false;
+}
+
+lldb::addr_t
+RegisterContextPOSIXProcessMonitor_arm64::GetWatchpointAddress(uint32_t hw_index)
+{
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::IsWatchpointVacant(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_arm64::SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index)
+{
+ return false;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_arm64::NumSupportedHardwareWatchpoints()
+{
+ return 0;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h
new file mode 100644
index 0000000..eb24d48
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_arm64.h
@@ -0,0 +1,95 @@
+//===-- RegisterContextPOSIXProcessMonitor_arm64.h --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_
+#define liblldb_RegisterContextPOSIXProcessMonitor_arm64_H_
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
+
+class RegisterContextPOSIXProcessMonitor_arm64:
+ public RegisterContextPOSIX_arm64,
+ public POSIXBreakpointProtocol
+{
+public:
+ RegisterContextPOSIXProcessMonitor_arm64(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+protected:
+ bool
+ ReadGPR();
+
+ bool
+ ReadFPR();
+
+ bool
+ WriteGPR();
+
+ bool
+ WriteFPR();
+
+ // lldb_private::RegisterContext
+ bool
+ ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ uint32_t
+ SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write);
+
+ bool
+ ClearHardwareWatchpoint(uint32_t hw_index);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ // POSIXBreakpointProtocol
+ bool
+ UpdateAfterBreakpoint();
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ bool
+ IsWatchpointHit(uint32_t hw_index);
+
+ bool
+ ClearWatchpointHits();
+
+ lldb::addr_t
+ GetWatchpointAddress(uint32_t hw_index);
+
+ bool
+ IsWatchpointVacant(uint32_t hw_index);
+
+ bool
+ SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index);
+
+ uint32_t
+ NumSupportedHardwareWatchpoints();
+
+private:
+ ProcessMonitor &
+ GetMonitor();
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp
new file mode 100644
index 0000000..893a0f2
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.cpp
@@ -0,0 +1,318 @@
+//===-- RegisterContextPOSIXProcessMonitor_mips64.h ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h"
+#include "ProcessPOSIX.h"
+#include "ProcessMonitor.h"
+#include "RegisterContextPOSIXProcessMonitor_mips64.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+#define REG_CONTEXT_SIZE (GetGPRSize())
+
+RegisterContextPOSIXProcessMonitor_mips64::RegisterContextPOSIXProcessMonitor_mips64(Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info)
+ : RegisterContextPOSIX_mips64(thread, concrete_frame_idx, register_info)
+{
+}
+
+ProcessMonitor &
+RegisterContextPOSIXProcessMonitor_mips64::GetMonitor()
+{
+ ProcessSP base = CalculateProcess();
+ ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
+ return process->GetMonitor();
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::ReadGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::ReadFPR()
+{
+ // XXX not yet implemented
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::WriteGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteGPR(m_thread.GetID(), &m_gpr_mips64, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::WriteFPR()
+{
+ // XXX not yet implemented
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::ReadRegister(const unsigned reg,
+ RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterName(reg),
+ GetRegisterSize(reg),
+ value);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::WriteRegister(const unsigned reg,
+ const RegisterValue &value)
+{
+ unsigned reg_to_write = reg;
+ RegisterValue value_to_write = value;
+
+ // Check if this is a subregister of a full register.
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
+ {
+ RegisterValue full_value;
+ uint32_t full_reg = reg_info->invalidate_regs[0];
+ const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
+
+ // Read the full register.
+ if (ReadRegister(full_reg_info, full_value))
+ {
+ Error error;
+ ByteOrder byte_order = GetByteOrder();
+ uint8_t dst[RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the full register.
+ const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
+ dst,
+ sizeof(dst),
+ byte_order,
+ error);
+ if (error.Success() && dest_size)
+ {
+ uint8_t src[RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the source data.
+ const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
+ if (error.Success() && src_size && (src_size < dest_size))
+ {
+ // Copy the src bytes to the destination.
+ memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
+ // Set this full register as the value to write.
+ value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
+ value_to_write.SetType(full_reg_info);
+ reg_to_write = full_reg;
+ }
+ }
+ }
+ }
+
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg_to_write),
+ GetRegisterName(reg_to_write),
+ value_to_write);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (IsFPR(reg))
+ {
+ if (!ReadFPR())
+ return false;
+ }
+ else
+ {
+ uint32_t full_reg = reg;
+ bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
+
+ if (is_subreg)
+ {
+ // Read the full aligned 64-bit register.
+ full_reg = reg_info->invalidate_regs[0];
+ }
+
+ bool success = ReadRegister(full_reg, value);
+
+ if (success)
+ {
+ // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
+ if (is_subreg && (reg_info->byte_offset & 0x1))
+ value.SetUInt64(value.GetAsUInt64() >> 8);
+
+ // If our return byte size was greater than the return value reg size, then
+ // use the type specified by reg_info rather than the uint64_t default
+ if (value.GetByteSize() > reg_info->byte_size)
+ value.SetType(reg_info);
+ }
+ return success;
+ }
+
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (IsGPR(reg))
+ return WriteRegister(reg, value);
+
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::ReadAllRegisterValues(DataBufferSP &data_sp)
+{
+ bool success = false;
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp && ReadGPR () && ReadFPR ())
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ success = dst != 0;
+
+ if (success)
+ {
+ ::memcpy (dst, &m_gpr_mips64, GetGPRSize());
+ }
+ }
+ return success;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::WriteAllRegisterValues(const DataBufferSP &data_sp)
+{
+ bool success = false;
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ uint8_t *src = data_sp->GetBytes();
+ if (src)
+ {
+ ::memcpy (&m_gpr_mips64, src, GetGPRSize());
+
+ if (WriteGPR())
+ {
+ src += GetGPRSize();
+ }
+ }
+ }
+ return success;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpoint(addr_t addr, size_t size,
+ bool read, bool write)
+{
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+ uint32_t hw_index;
+
+ for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index)
+ {
+ if (IsWatchpointVacant(hw_index))
+ return SetHardwareWatchpointWithIndex(addr, size,
+ read, write,
+ hw_index);
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::ClearHardwareWatchpoint(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::HardwareSingleStep(bool enable)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::UpdateAfterBreakpoint()
+{
+ // PC points one byte past the int3 responsible for the breakpoint.
+ lldb::addr_t pc;
+
+ if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
+ return false;
+
+ SetPC(pc - 1);
+ return true;
+}
+
+unsigned
+RegisterContextPOSIXProcessMonitor_mips64::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg;
+ for (reg = 0; reg < k_num_registers_mips64; reg++)
+ {
+ if (GetRegisterInfo()[reg].byte_offset == offset)
+ break;
+ }
+ assert(reg < k_num_registers_mips64 && "Invalid register offset.");
+ return reg;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointHit(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::ClearWatchpointHits()
+{
+ return false;
+}
+
+addr_t
+RegisterContextPOSIXProcessMonitor_mips64::GetWatchpointAddress(uint32_t hw_index)
+{
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::IsWatchpointVacant(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_mips64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index)
+{
+ return false;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_mips64::NumSupportedHardwareWatchpoints()
+{
+ return 0;
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h
new file mode 100644
index 0000000..79e4468
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_mips64.h
@@ -0,0 +1,95 @@
+//===-- RegisterContextPOSIXProcessMonitor_mips64.h -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_
+#define liblldb_RegisterContextPOSIXProcessMonitor_mips64_H_
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h"
+
+class RegisterContextPOSIXProcessMonitor_mips64:
+ public RegisterContextPOSIX_mips64,
+ public POSIXBreakpointProtocol
+{
+public:
+ RegisterContextPOSIXProcessMonitor_mips64(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+protected:
+ bool
+ ReadGPR();
+
+ bool
+ ReadFPR();
+
+ bool
+ WriteGPR();
+
+ bool
+ WriteFPR();
+
+ // lldb_private::RegisterContext
+ bool
+ ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ uint32_t
+ SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write);
+
+ bool
+ ClearHardwareWatchpoint(uint32_t hw_index);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ // POSIXBreakpointProtocol
+ bool
+ UpdateAfterBreakpoint();
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ bool
+ IsWatchpointHit(uint32_t hw_index);
+
+ bool
+ ClearWatchpointHits();
+
+ lldb::addr_t
+ GetWatchpointAddress(uint32_t hw_index);
+
+ bool
+ IsWatchpointVacant(uint32_t hw_index);
+
+ bool
+ SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index);
+
+ uint32_t
+ NumSupportedHardwareWatchpoints();
+
+private:
+ ProcessMonitor &
+ GetMonitor();
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp
new file mode 100644
index 0000000..1e4a402
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.cpp
@@ -0,0 +1,337 @@
+//===-- RegisterContextPOSIXProcessMonitor_powerpc.h ------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h"
+#include "ProcessPOSIX.h"
+#include "RegisterContextPOSIXProcessMonitor_powerpc.h"
+#include "ProcessMonitor.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+#define REG_CONTEXT_SIZE (GetGPRSize())
+
+RegisterContextPOSIXProcessMonitor_powerpc::RegisterContextPOSIXProcessMonitor_powerpc(Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info)
+ : RegisterContextPOSIX_powerpc(thread, concrete_frame_idx, register_info)
+{
+}
+
+ProcessMonitor &
+RegisterContextPOSIXProcessMonitor_powerpc::GetMonitor()
+{
+ ProcessSP base = CalculateProcess();
+ ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
+ return process->GetMonitor();
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::ReadGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::ReadFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadFPR(m_thread.GetID(), &m_fpr_powerpc, sizeof(m_fpr_powerpc));
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::ReadVMX()
+{
+ // XXX: Need a way to read/write process VMX registers with ptrace.
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::WriteGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteGPR(m_thread.GetID(), &m_gpr_powerpc, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::WriteFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteFPR(m_thread.GetID(), &m_fpr_powerpc, sizeof(m_fpr_powerpc));
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::WriteVMX()
+{
+ // XXX: Need a way to read/write process VMX registers with ptrace.
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister(const unsigned reg,
+ RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterName(reg),
+ GetRegisterSize(reg),
+ value);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(const unsigned reg,
+ const RegisterValue &value)
+{
+ unsigned reg_to_write = reg;
+ RegisterValue value_to_write = value;
+
+ // Check if this is a subregister of a full register.
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
+ {
+ RegisterValue full_value;
+ uint32_t full_reg = reg_info->invalidate_regs[0];
+ const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
+
+ // Read the full register.
+ if (ReadRegister(full_reg_info, full_value))
+ {
+ Error error;
+ ByteOrder byte_order = GetByteOrder();
+ uint8_t dst[RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the full register.
+ const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
+ dst,
+ sizeof(dst),
+ byte_order,
+ error);
+ if (error.Success() && dest_size)
+ {
+ uint8_t src[RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the source data.
+ const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
+ if (error.Success() && src_size && (src_size < dest_size))
+ {
+ // Copy the src bytes to the destination.
+ memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
+ // Set this full register as the value to write.
+ value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
+ value_to_write.SetType(full_reg_info);
+ reg_to_write = full_reg;
+ }
+ }
+ }
+ }
+
+ ProcessMonitor &monitor = GetMonitor();
+ // Account for the fact that 32-bit targets on powerpc64 really use 64-bit
+ // registers in ptrace, but expose here 32-bit registers with a higher
+ // offset.
+ uint64_t offset = GetRegisterOffset(reg_to_write);
+ offset &= ~(sizeof(uintptr_t) - 1);
+ return monitor.WriteRegisterValue(m_thread.GetID(),
+ offset,
+ GetRegisterName(reg_to_write),
+ value_to_write);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (IsFPR(reg))
+ {
+ if (!ReadFPR())
+ return false;
+ uint8_t *src = (uint8_t *)&m_fpr_powerpc + reg_info->byte_offset;
+ value.SetUInt64(*(uint64_t*)src);
+ }
+ else if (IsGPR(reg))
+ {
+ bool success = ReadRegister(reg, value);
+
+ if (success)
+ {
+ // If our return byte size was greater than the return value reg size, then
+ // use the type specified by reg_info rather than the uint64_t default
+ if (value.GetByteSize() > reg_info->byte_size)
+ value.SetType(reg_info);
+ }
+ return success;
+ }
+
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (IsGPR(reg))
+ {
+ return WriteRegister(reg, value);
+ }
+ else if (IsFPR(reg))
+ {
+ assert (reg_info->byte_offset < sizeof(m_fpr_powerpc));
+ uint8_t *dst = (uint8_t *)&m_fpr_powerpc + reg_info->byte_offset;
+ *(uint64_t *)dst = value.GetAsUInt64();
+ return WriteFPR();
+ }
+
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::ReadAllRegisterValues(DataBufferSP &data_sp)
+{
+ bool success = false;
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp && ReadGPR () && ReadFPR ())
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ success = dst != 0;
+
+ if (success)
+ {
+ ::memcpy (dst, &m_gpr_powerpc, GetGPRSize());
+ dst += GetGPRSize();
+ }
+ }
+ return success;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::WriteAllRegisterValues(const DataBufferSP &data_sp)
+{
+ bool success = false;
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ uint8_t *src = data_sp->GetBytes();
+ if (src)
+ {
+ ::memcpy (&m_gpr_powerpc, src, GetGPRSize());
+
+ if (WriteGPR())
+ {
+ src += GetGPRSize();
+ ::memcpy (&m_fpr_powerpc, src, sizeof(m_fpr_powerpc));
+
+ success = WriteFPR();
+ }
+ }
+ }
+ return success;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpoint(addr_t addr, size_t size,
+ bool read, bool write)
+{
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+ uint32_t hw_index;
+
+ for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index)
+ {
+ if (IsWatchpointVacant(hw_index))
+ return SetHardwareWatchpointWithIndex(addr, size,
+ read, write,
+ hw_index);
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::ClearHardwareWatchpoint(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::HardwareSingleStep(bool enable)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::UpdateAfterBreakpoint()
+{
+ lldb::addr_t pc;
+
+ if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
+ return false;
+
+ return true;
+}
+
+unsigned
+RegisterContextPOSIXProcessMonitor_powerpc::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg;
+ for (reg = 0; reg < k_num_registers_powerpc; reg++)
+ {
+ if (GetRegisterInfo()[reg].byte_offset == offset)
+ break;
+ }
+ assert(reg < k_num_registers_powerpc && "Invalid register offset.");
+ return reg;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointHit(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::ClearWatchpointHits()
+{
+ return false;
+}
+
+addr_t
+RegisterContextPOSIXProcessMonitor_powerpc::GetWatchpointAddress(uint32_t hw_index)
+{
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::IsWatchpointVacant(uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_powerpc::SetHardwareWatchpointWithIndex(addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index)
+{
+ return false;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_powerpc::NumSupportedHardwareWatchpoints()
+{
+ return 0;
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h
new file mode 100644
index 0000000..5c686df
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_powerpc.h
@@ -0,0 +1,104 @@
+//===-- RegisterContextPOSIXProcessMonitor_powerpc.h -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_
+#define liblldb_RegisterContextPOSIXProcessMonitor_powerpc_H_
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h"
+
+class RegisterContextPOSIXProcessMonitor_powerpc:
+ public RegisterContextPOSIX_powerpc,
+ public POSIXBreakpointProtocol
+{
+public:
+ RegisterContextPOSIXProcessMonitor_powerpc(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+protected:
+ bool
+ IsVMX();
+
+ bool
+ ReadGPR();
+
+ bool
+ ReadFPR();
+
+ bool
+ ReadVMX();
+
+ bool
+ WriteGPR();
+
+ bool
+ WriteFPR();
+
+ bool
+ WriteVMX();
+
+ // lldb_private::RegisterContext
+ bool
+ ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ uint32_t
+ SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write);
+
+ bool
+ ClearHardwareWatchpoint(uint32_t hw_index);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ // POSIXBreakpointProtocol
+ bool
+ UpdateAfterBreakpoint();
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ bool
+ IsWatchpointHit(uint32_t hw_index);
+
+ bool
+ ClearWatchpointHits();
+
+ lldb::addr_t
+ GetWatchpointAddress(uint32_t hw_index);
+
+ bool
+ IsWatchpointVacant(uint32_t hw_index);
+
+ bool
+ SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index);
+
+ uint32_t
+ NumSupportedHardwareWatchpoints();
+
+private:
+ ProcessMonitor &
+ GetMonitor();
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp
new file mode 100644
index 0000000..9245441
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.cpp
@@ -0,0 +1,650 @@
+//===-- RegisterContextPOSIXProcessMonitor_x86.h ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+
+#include "Plugins/Process/FreeBSD/ProcessPOSIX.h"
+#include "RegisterContextPOSIXProcessMonitor_x86.h"
+#include "Plugins/Process/FreeBSD/ProcessMonitor.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// Support ptrace extensions even when compiled without required kernel support
+#ifndef NT_X86_XSTATE
+ #define NT_X86_XSTATE 0x202
+#endif
+
+#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(FPR))
+
+static uint32_t
+size_and_rw_bits(size_t size, bool read, bool write)
+{
+ uint32_t rw;
+
+ if (read)
+ rw = 0x3; // READ or READ/WRITE
+ else if (write)
+ rw = 0x1; // WRITE
+ else
+ assert(0 && "read and write cannot both be false");
+
+ switch (size)
+ {
+ case 1:
+ return rw;
+ case 2:
+ return (0x1 << 2) | rw;
+ case 4:
+ return (0x3 << 2) | rw;
+ case 8:
+ return (0x2 << 2) | rw;
+ default:
+ assert(0 && "invalid size, must be one of 1, 2, 4, or 8");
+ return 0; // Unreachable. Just to silence compiler.
+ }
+}
+
+RegisterContextPOSIXProcessMonitor_x86_64::RegisterContextPOSIXProcessMonitor_x86_64(Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info)
+ : RegisterContextPOSIX_x86(thread, concrete_frame_idx, register_info)
+{
+}
+
+ProcessMonitor &
+RegisterContextPOSIXProcessMonitor_x86_64::GetMonitor()
+{
+ ProcessSP base = CalculateProcess();
+ ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
+ return process->GetMonitor();
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::ReadGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::ReadFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ if (GetFPRType() == eFXSAVE)
+ return monitor.ReadFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
+
+ if (GetFPRType() == eXSAVE)
+ return monitor.ReadRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::WriteGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteGPR(m_thread.GetID(), &m_gpr_x86_64, GetGPRSize());
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::WriteFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ if (GetFPRType() == eFXSAVE)
+ return monitor.WriteFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
+
+ if (GetFPRType() == eXSAVE)
+ return monitor.WriteRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister(const unsigned reg,
+ RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+
+#if defined(__FreeBSD__)
+ if (reg >= m_reg_info.first_dr)
+ return monitor.ReadDebugRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterName(reg),
+ GetRegisterSize(reg),
+ value);
+#endif
+ return monitor.ReadRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterName(reg),
+ GetRegisterSize(reg),
+ value);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister(const unsigned reg,
+ const RegisterValue &value)
+{
+ unsigned reg_to_write = reg;
+ RegisterValue value_to_write = value;
+
+ // Check if this is a subregister of a full register.
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
+ {
+ RegisterValue full_value;
+ uint32_t full_reg = reg_info->invalidate_regs[0];
+ const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
+
+ // Read the full register.
+ if (ReadRegister(full_reg_info, full_value))
+ {
+ Error error;
+ ByteOrder byte_order = GetByteOrder();
+ uint8_t dst[RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the full register.
+ const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
+ dst,
+ sizeof(dst),
+ byte_order,
+ error);
+ if (error.Success() && dest_size)
+ {
+ uint8_t src[RegisterValue::kMaxRegisterByteSize];
+
+ // Get the bytes for the source data.
+ const uint32_t src_size = value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
+ if (error.Success() && src_size && (src_size < dest_size))
+ {
+ // Copy the src bytes to the destination.
+ memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
+ // Set this full register as the value to write.
+ value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
+ value_to_write.SetType(full_reg_info);
+ reg_to_write = full_reg;
+ }
+ }
+ }
+ }
+
+ ProcessMonitor &monitor = GetMonitor();
+#if defined(__FreeBSD__)
+ if (reg >= m_reg_info.first_dr)
+ return monitor.WriteDebugRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg_to_write),
+ GetRegisterName(reg_to_write),
+ value_to_write);
+#endif
+ return monitor.WriteRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg_to_write),
+ GetRegisterName(reg_to_write),
+ value_to_write);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (IsFPR(reg, GetFPRType()))
+ {
+ if (!ReadFPR())
+ return false;
+ }
+ else
+ {
+ uint32_t full_reg = reg;
+ bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM);
+
+ if (is_subreg)
+ {
+ // Read the full aligned 64-bit register.
+ full_reg = reg_info->invalidate_regs[0];
+ }
+
+ bool success = ReadRegister(full_reg, value);
+
+ if (success)
+ {
+ // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right.
+ if (is_subreg && (reg_info->byte_offset & 0x1))
+ value.SetUInt64(value.GetAsUInt64() >> 8);
+
+ // If our return byte size was greater than the return value reg size, then
+ // use the type specified by reg_info rather than the uint64_t default
+ if (value.GetByteSize() > reg_info->byte_size)
+ value.SetType(reg_info);
+ }
+ return success;
+ }
+
+ if (reg_info->encoding == eEncodingVector)
+ {
+ ByteOrder byte_order = GetByteOrder();
+
+ if (byte_order != ByteOrder::eByteOrderInvalid)
+ {
+ if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st)
+ value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, reg_info->byte_size, byte_order);
+ if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm)
+ value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, reg_info->byte_size, byte_order);
+ if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm)
+ value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, reg_info->byte_size, byte_order);
+ if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm)
+ {
+ // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes
+ if (GetFPRType() == eXSAVE && CopyXSTATEtoYMM(reg, byte_order))
+ value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, reg_info->byte_size, byte_order);
+ else
+ return false;
+ }
+ return value.GetType() == RegisterValue::eTypeBytes;
+ }
+ return false;
+ }
+
+ // Get pointer to m_fpr.xstate.fxsave variable and set the data from it.
+ assert (reg_info->byte_offset < sizeof(m_fpr));
+ uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
+ switch (reg_info->byte_size)
+ {
+ case 2:
+ value.SetUInt16(*(uint16_t *)src);
+ return true;
+ case 4:
+ value.SetUInt32(*(uint32_t *)src);
+ return true;
+ case 8:
+ value.SetUInt64(*(uint64_t *)src);
+ return true;
+ default:
+ assert(false && "Unhandled data size.");
+ return false;
+ }
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (IsGPR(reg))
+ return WriteRegister(reg, value);
+
+ if (IsFPR(reg, GetFPRType()))
+ {
+ if (reg_info->encoding == eEncodingVector)
+ {
+ if (reg >= m_reg_info.first_st && reg <= m_reg_info.last_st)
+ ::memcpy (m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_st].bytes, value.GetBytes(), value.GetByteSize());
+
+ if (reg >= m_reg_info.first_mm && reg <= m_reg_info.last_mm)
+ ::memcpy (m_fpr.xstate.fxsave.stmm[reg - m_reg_info.first_mm].bytes, value.GetBytes(), value.GetByteSize());
+
+ if (reg >= m_reg_info.first_xmm && reg <= m_reg_info.last_xmm)
+ ::memcpy (m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_xmm].bytes, value.GetBytes(), value.GetByteSize());
+
+ if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm)
+ {
+ if (GetFPRType() != eXSAVE)
+ return false; // the target processor does not support AVX
+
+ // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes
+ ::memcpy (m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes, value.GetBytes(), value.GetByteSize());
+ if (false == CopyYMMtoXSTATE(reg, GetByteOrder()))
+ return false;
+ }
+ }
+ else
+ {
+ // Get pointer to m_fpr.xstate.fxsave variable and set the data to it.
+ assert (reg_info->byte_offset < sizeof(m_fpr));
+ uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset;
+ switch (reg_info->byte_size)
+ {
+ case 2:
+ *(uint16_t *)dst = value.GetAsUInt16();
+ break;
+ case 4:
+ *(uint32_t *)dst = value.GetAsUInt32();
+ break;
+ case 8:
+ *(uint64_t *)dst = value.GetAsUInt64();
+ break;
+ default:
+ assert(false && "Unhandled data size.");
+ return false;
+ }
+ }
+
+ if (WriteFPR())
+ {
+ if (IsAVX(reg))
+ return CopyYMMtoXSTATE(reg, GetByteOrder());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::ReadAllRegisterValues(DataBufferSP &data_sp)
+{
+ bool success = false;
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp && ReadGPR () && ReadFPR ())
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ success = dst != 0;
+
+ if (success)
+ {
+ ::memcpy (dst, &m_gpr_x86_64, GetGPRSize());
+ dst += GetGPRSize();
+ if (GetFPRType() == eFXSAVE)
+ ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
+ }
+
+ if (GetFPRType() == eXSAVE)
+ {
+ ByteOrder byte_order = GetByteOrder();
+
+ // Assemble the YMM register content from the register halves.
+ for (uint32_t reg = m_reg_info.first_ymm; success && reg <= m_reg_info.last_ymm; ++reg)
+ success = CopyXSTATEtoYMM(reg, byte_order);
+
+ if (success)
+ {
+ // Copy the extended register state including the assembled ymm registers.
+ ::memcpy (dst, &m_fpr, sizeof(m_fpr));
+ }
+ }
+ }
+ return success;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::WriteAllRegisterValues(const DataBufferSP &data_sp)
+{
+ bool success = false;
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ uint8_t *src = data_sp->GetBytes();
+ if (src)
+ {
+ ::memcpy (&m_gpr_x86_64, src, GetGPRSize());
+
+ if (WriteGPR())
+ {
+ src += GetGPRSize();
+ if (GetFPRType() == eFXSAVE)
+ ::memcpy (&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave));
+ if (GetFPRType() == eXSAVE)
+ ::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave));
+
+ success = WriteFPR();
+ if (success)
+ {
+ if (GetFPRType() == eXSAVE)
+ {
+ ByteOrder byte_order = GetByteOrder();
+
+ // Parse the YMM register content from the register halves.
+ for (uint32_t reg = m_reg_info.first_ymm; success && reg <= m_reg_info.last_ymm; ++reg)
+ success = CopyYMMtoXSTATE(reg, byte_order);
+ }
+ }
+ }
+ }
+ }
+ return success;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_x86_64::SetHardwareWatchpoint(addr_t addr, size_t size,
+ bool read, bool write)
+{
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+ uint32_t hw_index;
+
+ for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index)
+ {
+ if (IsWatchpointVacant(hw_index))
+ return SetHardwareWatchpointWithIndex(addr, size,
+ read, write,
+ hw_index);
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::ClearHardwareWatchpoint(uint32_t hw_index)
+{
+ if (hw_index < NumSupportedHardwareWatchpoints())
+ {
+ RegisterValue current_dr7_bits;
+
+ if (ReadRegister(m_reg_info.first_dr + 7, current_dr7_bits))
+ {
+ uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() & ~(3 << (2*hw_index));
+
+ if (WriteRegister(m_reg_info.first_dr + 7, RegisterValue(new_dr7_bits)))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::HardwareSingleStep(bool enable)
+{
+ enum { TRACE_BIT = 0x100 };
+ uint64_t rflags;
+
+ if ((rflags = ReadRegisterAsUnsigned(m_reg_info.gpr_flags, -1UL)) == -1UL)
+ return false;
+
+ if (enable)
+ {
+ if (rflags & TRACE_BIT)
+ return true;
+
+ rflags |= TRACE_BIT;
+ }
+ else
+ {
+ if (!(rflags & TRACE_BIT))
+ return false;
+
+ rflags &= ~TRACE_BIT;
+ }
+
+ return WriteRegisterFromUnsigned(m_reg_info.gpr_flags, rflags);
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::UpdateAfterBreakpoint()
+{
+ // PC points one byte past the int3 responsible for the breakpoint.
+ lldb::addr_t pc;
+
+ if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
+ return false;
+
+ SetPC(pc - 1);
+ return true;
+}
+
+unsigned
+RegisterContextPOSIXProcessMonitor_x86_64::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg;
+ for (reg = 0; reg < m_reg_info.num_registers; reg++)
+ {
+ if (GetRegisterInfo()[reg].byte_offset == offset)
+ break;
+ }
+ assert(reg < m_reg_info.num_registers && "Invalid register offset.");
+ return reg;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::IsWatchpointHit(uint32_t hw_index)
+{
+ bool is_hit = false;
+
+ if (m_watchpoints_initialized == false)
+ {
+ // Reset the debug status and debug control registers
+ RegisterValue zero_bits = RegisterValue(uint64_t(0));
+ if (!WriteRegister(m_reg_info.first_dr + 6, zero_bits) || !WriteRegister(m_reg_info.first_dr + 7, zero_bits))
+ assert(false && "Could not initialize watchpoint registers");
+ m_watchpoints_initialized = true;
+ }
+
+ if (hw_index < NumSupportedHardwareWatchpoints())
+ {
+ RegisterValue value;
+
+ if (ReadRegister(m_reg_info.first_dr + 6, value))
+ {
+ uint64_t val = value.GetAsUInt64();
+ is_hit = val & (1 << hw_index);
+ }
+ }
+
+ return is_hit;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::ClearWatchpointHits()
+{
+ return WriteRegister(m_reg_info.first_dr + 6, RegisterValue((uint64_t)0));
+}
+
+addr_t
+RegisterContextPOSIXProcessMonitor_x86_64::GetWatchpointAddress(uint32_t hw_index)
+{
+ addr_t wp_monitor_addr = LLDB_INVALID_ADDRESS;
+
+ if (hw_index < NumSupportedHardwareWatchpoints())
+ {
+ if (!IsWatchpointVacant(hw_index))
+ {
+ RegisterValue value;
+
+ if (ReadRegister(m_reg_info.first_dr + hw_index, value))
+ wp_monitor_addr = value.GetAsUInt64();
+ }
+ }
+
+ return wp_monitor_addr;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::IsWatchpointVacant(uint32_t hw_index)
+{
+ bool is_vacant = false;
+ RegisterValue value;
+
+ assert(hw_index < NumSupportedHardwareWatchpoints());
+
+ if (m_watchpoints_initialized == false)
+ {
+ // Reset the debug status and debug control registers
+ RegisterValue zero_bits = RegisterValue(uint64_t(0));
+ if (!WriteRegister(m_reg_info.first_dr + 6, zero_bits) || !WriteRegister(m_reg_info.first_dr + 7, zero_bits))
+ assert(false && "Could not initialize watchpoint registers");
+ m_watchpoints_initialized = true;
+ }
+
+ if (ReadRegister(m_reg_info.first_dr + 7, value))
+ {
+ uint64_t val = value.GetAsUInt64();
+ is_vacant = (val & (3 << 2*hw_index)) == 0;
+ }
+
+ return is_vacant;
+}
+
+bool
+RegisterContextPOSIXProcessMonitor_x86_64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index)
+{
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+
+ if (num_hw_watchpoints == 0 || hw_index >= num_hw_watchpoints)
+ return false;
+
+ if (!(size == 1 || size == 2 || size == 4 || size == 8))
+ return false;
+
+ if (read == false && write == false)
+ return false;
+
+ if (!IsWatchpointVacant(hw_index))
+ return false;
+
+ // Set both dr7 (debug control register) and dri (debug address register).
+
+ // dr7{7-0} encodes the local/global enable bits:
+ // global enable --. .-- local enable
+ // | |
+ // v v
+ // dr0 -> bits{1-0}
+ // dr1 -> bits{3-2}
+ // dr2 -> bits{5-4}
+ // dr3 -> bits{7-6}
+ //
+ // dr7{31-16} encodes the rw/len bits:
+ // b_x+3, b_x+2, b_x+1, b_x
+ // where bits{x+1, x} => rw
+ // 0b00: execute, 0b01: write, 0b11: read-or-write,
+ // 0b10: io read-or-write (unused)
+ // and bits{x+3, x+2} => len
+ // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte
+ //
+ // dr0 -> bits{19-16}
+ // dr1 -> bits{23-20}
+ // dr2 -> bits{27-24}
+ // dr3 -> bits{31-28}
+ if (hw_index < num_hw_watchpoints)
+ {
+ RegisterValue current_dr7_bits;
+
+ if (ReadRegister(m_reg_info.first_dr + 7, current_dr7_bits))
+ {
+ uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() |
+ (1 << (2*hw_index) |
+ size_and_rw_bits(size, read, write) <<
+ (16+4*hw_index));
+
+ if (WriteRegister(m_reg_info.first_dr + hw_index, RegisterValue(addr)) &&
+ WriteRegister(m_reg_info.first_dr + 7, RegisterValue(new_dr7_bits)))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+uint32_t
+RegisterContextPOSIXProcessMonitor_x86_64::NumSupportedHardwareWatchpoints()
+{
+ // Available debug address registers: dr0, dr1, dr2, dr3
+ return 4;
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h
new file mode 100644
index 0000000..2afb195
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/RegisterContextPOSIXProcessMonitor_x86.h
@@ -0,0 +1,95 @@
+//===-- RegisterContextPOSIXProcessMonitor_x86.h ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextPOSIXProcessMonitor_x86_H_
+#define liblldb_RegisterContextPOSIXProcessMonitor_x86_H_
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h"
+
+class RegisterContextPOSIXProcessMonitor_x86_64:
+ public RegisterContextPOSIX_x86,
+ public POSIXBreakpointProtocol
+{
+public:
+ RegisterContextPOSIXProcessMonitor_x86_64(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+protected:
+ bool
+ ReadGPR();
+
+ bool
+ ReadFPR();
+
+ bool
+ WriteGPR();
+
+ bool
+ WriteFPR();
+
+ // lldb_private::RegisterContext
+ bool
+ ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ uint32_t
+ SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write);
+
+ bool
+ ClearHardwareWatchpoint(uint32_t hw_index);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ // POSIXBreakpointProtocol
+ bool
+ UpdateAfterBreakpoint();
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ bool
+ IsWatchpointHit(uint32_t hw_index);
+
+ bool
+ ClearWatchpointHits();
+
+ lldb::addr_t
+ GetWatchpointAddress(uint32_t hw_index);
+
+ bool
+ IsWatchpointVacant(uint32_t hw_index);
+
+ bool
+ SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, bool read, bool write, uint32_t hw_index);
+
+ uint32_t
+ NumSupportedHardwareWatchpoints();
+
+private:
+ ProcessMonitor &
+ GetMonitor();
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/CrashReason.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/CrashReason.cpp
new file mode 100644
index 0000000..6de13f4
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/CrashReason.cpp
@@ -0,0 +1,315 @@
+//===-- CrashReason.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CrashReason.h"
+
+#include <sstream>
+
+namespace {
+
+void
+AppendFaultAddr (std::string& str, lldb::addr_t addr)
+{
+ std::stringstream ss;
+ ss << " (fault address: 0x" << std::hex << addr << ")";
+ str += ss.str();
+}
+
+CrashReason
+GetCrashReasonForSIGSEGV(const siginfo_t& info)
+{
+ assert(info.si_signo == SIGSEGV);
+
+ switch (info.si_code)
+ {
+ case SI_KERNEL:
+ // Linux will occasionally send spurious SI_KERNEL codes.
+ // (this is poorly documented in sigaction)
+ // One way to get this is via unaligned SIMD loads.
+ return CrashReason::eInvalidAddress; // for lack of anything better
+ case SEGV_MAPERR:
+ return CrashReason::eInvalidAddress;
+ case SEGV_ACCERR:
+ return CrashReason::ePrivilegedAddress;
+ }
+
+ assert(false && "unexpected si_code for SIGSEGV");
+ return CrashReason::eInvalidCrashReason;
+}
+
+CrashReason
+GetCrashReasonForSIGILL(const siginfo_t& info)
+{
+ assert(info.si_signo == SIGILL);
+
+ switch (info.si_code)
+ {
+ case ILL_ILLOPC:
+ return CrashReason::eIllegalOpcode;
+ case ILL_ILLOPN:
+ return CrashReason::eIllegalOperand;
+ case ILL_ILLADR:
+ return CrashReason::eIllegalAddressingMode;
+ case ILL_ILLTRP:
+ return CrashReason::eIllegalTrap;
+ case ILL_PRVOPC:
+ return CrashReason::ePrivilegedOpcode;
+ case ILL_PRVREG:
+ return CrashReason::ePrivilegedRegister;
+ case ILL_COPROC:
+ return CrashReason::eCoprocessorError;
+ case ILL_BADSTK:
+ return CrashReason::eInternalStackError;
+ }
+
+ assert(false && "unexpected si_code for SIGILL");
+ return CrashReason::eInvalidCrashReason;
+}
+
+CrashReason
+GetCrashReasonForSIGFPE(const siginfo_t& info)
+{
+ assert(info.si_signo == SIGFPE);
+
+ switch (info.si_code)
+ {
+ case FPE_INTDIV:
+ return CrashReason::eIntegerDivideByZero;
+ case FPE_INTOVF:
+ return CrashReason::eIntegerOverflow;
+ case FPE_FLTDIV:
+ return CrashReason::eFloatDivideByZero;
+ case FPE_FLTOVF:
+ return CrashReason::eFloatOverflow;
+ case FPE_FLTUND:
+ return CrashReason::eFloatUnderflow;
+ case FPE_FLTRES:
+ return CrashReason::eFloatInexactResult;
+ case FPE_FLTINV:
+ return CrashReason::eFloatInvalidOperation;
+ case FPE_FLTSUB:
+ return CrashReason::eFloatSubscriptRange;
+ }
+
+ assert(false && "unexpected si_code for SIGFPE");
+ return CrashReason::eInvalidCrashReason;
+}
+
+CrashReason
+GetCrashReasonForSIGBUS(const siginfo_t& info)
+{
+ assert(info.si_signo == SIGBUS);
+
+ switch (info.si_code)
+ {
+ case BUS_ADRALN:
+ return CrashReason::eIllegalAlignment;
+ case BUS_ADRERR:
+ return CrashReason::eIllegalAddress;
+ case BUS_OBJERR:
+ return CrashReason::eHardwareError;
+ }
+
+ assert(false && "unexpected si_code for SIGBUS");
+ return CrashReason::eInvalidCrashReason;
+}
+
+}
+
+std::string
+GetCrashReasonString (CrashReason reason, lldb::addr_t fault_addr)
+{
+ std::string str;
+
+ switch (reason)
+ {
+ default:
+ assert(false && "invalid CrashReason");
+ break;
+
+ case CrashReason::eInvalidAddress:
+ str = "signal SIGSEGV: invalid address";
+ AppendFaultAddr (str, fault_addr);
+ break;
+ case CrashReason::ePrivilegedAddress:
+ str = "signal SIGSEGV: address access protected";
+ AppendFaultAddr (str, fault_addr);
+ break;
+ case CrashReason::eIllegalOpcode:
+ str = "signal SIGILL: illegal instruction";
+ break;
+ case CrashReason::eIllegalOperand:
+ str = "signal SIGILL: illegal instruction operand";
+ break;
+ case CrashReason::eIllegalAddressingMode:
+ str = "signal SIGILL: illegal addressing mode";
+ break;
+ case CrashReason::eIllegalTrap:
+ str = "signal SIGILL: illegal trap";
+ break;
+ case CrashReason::ePrivilegedOpcode:
+ str = "signal SIGILL: privileged instruction";
+ break;
+ case CrashReason::ePrivilegedRegister:
+ str = "signal SIGILL: privileged register";
+ break;
+ case CrashReason::eCoprocessorError:
+ str = "signal SIGILL: coprocessor error";
+ break;
+ case CrashReason::eInternalStackError:
+ str = "signal SIGILL: internal stack error";
+ break;
+ case CrashReason::eIllegalAlignment:
+ str = "signal SIGBUS: illegal alignment";
+ break;
+ case CrashReason::eIllegalAddress:
+ str = "signal SIGBUS: illegal address";
+ break;
+ case CrashReason::eHardwareError:
+ str = "signal SIGBUS: hardware error";
+ break;
+ case CrashReason::eIntegerDivideByZero:
+ str = "signal SIGFPE: integer divide by zero";
+ break;
+ case CrashReason::eIntegerOverflow:
+ str = "signal SIGFPE: integer overflow";
+ break;
+ case CrashReason::eFloatDivideByZero:
+ str = "signal SIGFPE: floating point divide by zero";
+ break;
+ case CrashReason::eFloatOverflow:
+ str = "signal SIGFPE: floating point overflow";
+ break;
+ case CrashReason::eFloatUnderflow:
+ str = "signal SIGFPE: floating point underflow";
+ break;
+ case CrashReason::eFloatInexactResult:
+ str = "signal SIGFPE: inexact floating point result";
+ break;
+ case CrashReason::eFloatInvalidOperation:
+ str = "signal SIGFPE: invalid floating point operation";
+ break;
+ case CrashReason::eFloatSubscriptRange:
+ str = "signal SIGFPE: invalid floating point subscript range";
+ break;
+ }
+
+ return str;
+}
+
+const char *
+CrashReasonAsString (CrashReason reason)
+{
+#ifdef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+ // Just return the code in ascii for integration builds.
+ chcar str[8];
+ sprintf(str, "%d", reason);
+#else
+ const char *str = nullptr;
+
+ switch (reason)
+ {
+ case CrashReason::eInvalidCrashReason:
+ str = "eInvalidCrashReason";
+ break;
+
+ // SIGSEGV crash reasons.
+ case CrashReason::eInvalidAddress:
+ str = "eInvalidAddress";
+ break;
+ case CrashReason::ePrivilegedAddress:
+ str = "ePrivilegedAddress";
+ break;
+
+ // SIGILL crash reasons.
+ case CrashReason::eIllegalOpcode:
+ str = "eIllegalOpcode";
+ break;
+ case CrashReason::eIllegalOperand:
+ str = "eIllegalOperand";
+ break;
+ case CrashReason::eIllegalAddressingMode:
+ str = "eIllegalAddressingMode";
+ break;
+ case CrashReason::eIllegalTrap:
+ str = "eIllegalTrap";
+ break;
+ case CrashReason::ePrivilegedOpcode:
+ str = "ePrivilegedOpcode";
+ break;
+ case CrashReason::ePrivilegedRegister:
+ str = "ePrivilegedRegister";
+ break;
+ case CrashReason::eCoprocessorError:
+ str = "eCoprocessorError";
+ break;
+ case CrashReason::eInternalStackError:
+ str = "eInternalStackError";
+ break;
+
+ // SIGBUS crash reasons:
+ case CrashReason::eIllegalAlignment:
+ str = "eIllegalAlignment";
+ break;
+ case CrashReason::eIllegalAddress:
+ str = "eIllegalAddress";
+ break;
+ case CrashReason::eHardwareError:
+ str = "eHardwareError";
+ break;
+
+ // SIGFPE crash reasons:
+ case CrashReason::eIntegerDivideByZero:
+ str = "eIntegerDivideByZero";
+ break;
+ case CrashReason::eIntegerOverflow:
+ str = "eIntegerOverflow";
+ break;
+ case CrashReason::eFloatDivideByZero:
+ str = "eFloatDivideByZero";
+ break;
+ case CrashReason::eFloatOverflow:
+ str = "eFloatOverflow";
+ break;
+ case CrashReason::eFloatUnderflow:
+ str = "eFloatUnderflow";
+ break;
+ case CrashReason::eFloatInexactResult:
+ str = "eFloatInexactResult";
+ break;
+ case CrashReason::eFloatInvalidOperation:
+ str = "eFloatInvalidOperation";
+ break;
+ case CrashReason::eFloatSubscriptRange:
+ str = "eFloatSubscriptRange";
+ break;
+ }
+#endif
+
+ return str;
+}
+
+CrashReason
+GetCrashReason(const siginfo_t& info)
+{
+ switch(info.si_signo)
+ {
+ case SIGSEGV:
+ return GetCrashReasonForSIGSEGV(info);
+ case SIGBUS:
+ return GetCrashReasonForSIGBUS(info);
+ case SIGFPE:
+ return GetCrashReasonForSIGFPE(info);
+ case SIGILL:
+ return GetCrashReasonForSIGILL(info);
+ }
+
+ assert(false && "unexpected signal");
+ return CrashReason::eInvalidCrashReason;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/CrashReason.h b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/CrashReason.h
new file mode 100644
index 0000000..f6d9ba5
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/CrashReason.h
@@ -0,0 +1,62 @@
+//===-- CrashReason.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_CrashReason_H_
+#define liblldb_CrashReason_H_
+
+#include "lldb/lldb-types.h"
+
+#include <signal.h>
+
+#include <string>
+
+enum class CrashReason
+{
+ eInvalidCrashReason,
+
+ // SIGSEGV crash reasons.
+ eInvalidAddress,
+ ePrivilegedAddress,
+
+ // SIGILL crash reasons.
+ eIllegalOpcode,
+ eIllegalOperand,
+ eIllegalAddressingMode,
+ eIllegalTrap,
+ ePrivilegedOpcode,
+ ePrivilegedRegister,
+ eCoprocessorError,
+ eInternalStackError,
+
+ // SIGBUS crash reasons,
+ eIllegalAlignment,
+ eIllegalAddress,
+ eHardwareError,
+
+ // SIGFPE crash reasons,
+ eIntegerDivideByZero,
+ eIntegerOverflow,
+ eFloatDivideByZero,
+ eFloatOverflow,
+ eFloatUnderflow,
+ eFloatInexactResult,
+ eFloatInvalidOperation,
+ eFloatSubscriptRange
+};
+
+std::string
+GetCrashReasonString (CrashReason reason, lldb::addr_t fault_addr);
+
+const char *
+CrashReasonAsString (CrashReason reason);
+
+CrashReason
+GetCrashReason(const siginfo_t& info);
+
+#endif // #ifndef liblldb_CrashReason_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessMessage.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessMessage.cpp
new file mode 100644
index 0000000..02049a2
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessMessage.cpp
@@ -0,0 +1,78 @@
+//===-- ProcessMessage.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessMessage.h"
+
+using namespace lldb_private;
+
+const char *
+ProcessMessage::PrintCrashReason() const
+{
+ return CrashReasonAsString(m_crash_reason);
+}
+
+const char *
+ProcessMessage::PrintKind(Kind kind)
+{
+#ifdef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+ // Just return the code in ascii for integration builds.
+ chcar str[8];
+ sprintf(str, "%d", reason);
+#else
+ const char *str = NULL;
+
+ switch (kind)
+ {
+ case eInvalidMessage:
+ str = "eInvalidMessage";
+ break;
+ case eAttachMessage:
+ str = "eAttachMessage";
+ break;
+ case eExitMessage:
+ str = "eExitMessage";
+ break;
+ case eLimboMessage:
+ str = "eLimboMessage";
+ break;
+ case eSignalMessage:
+ str = "eSignalMessage";
+ break;
+ case eSignalDeliveredMessage:
+ str = "eSignalDeliveredMessage";
+ break;
+ case eTraceMessage:
+ str = "eTraceMessage";
+ break;
+ case eBreakpointMessage:
+ str = "eBreakpointMessage";
+ break;
+ case eWatchpointMessage:
+ str = "eWatchpointMessage";
+ break;
+ case eCrashMessage:
+ str = "eCrashMessage";
+ break;
+ case eNewThreadMessage:
+ str = "eNewThreadMessage";
+ break;
+ case eExecMessage:
+ str = "eExecMessage";
+ break;
+ }
+#endif
+
+ return str;
+}
+
+const char *
+ProcessMessage::PrintKind() const
+{
+ return PrintKind(m_kind);
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessMessage.h b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessMessage.h
new file mode 100644
index 0000000..f932e9f
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessMessage.h
@@ -0,0 +1,182 @@
+//===-- ProcessMessage.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessMessage_H_
+#define liblldb_ProcessMessage_H_
+
+#include "CrashReason.h"
+
+#include <cassert>
+#include <string>
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-types.h"
+
+class ProcessMessage
+{
+public:
+
+ /// The type of signal this message can correspond to.
+ enum Kind
+ {
+ eInvalidMessage,
+ eAttachMessage,
+ eExitMessage,
+ eLimboMessage,
+ eSignalMessage,
+ eSignalDeliveredMessage,
+ eTraceMessage,
+ eBreakpointMessage,
+ eWatchpointMessage,
+ eCrashMessage,
+ eNewThreadMessage,
+ eExecMessage
+ };
+
+ ProcessMessage()
+ : m_tid(LLDB_INVALID_PROCESS_ID),
+ m_kind(eInvalidMessage),
+ m_crash_reason(CrashReason::eInvalidCrashReason),
+ m_status(0),
+ m_addr(0) { }
+
+ Kind GetKind() const { return m_kind; }
+
+ lldb::tid_t GetTID() const { return m_tid; }
+
+ /// Indicates that the process @p pid has successfully attached.
+ static ProcessMessage Attach(lldb::pid_t pid) {
+ return ProcessMessage(pid, eAttachMessage);
+ }
+
+ /// Indicates that the thread @p tid is about to exit with status @p status.
+ static ProcessMessage Limbo(lldb::tid_t tid, int status) {
+ return ProcessMessage(tid, eLimboMessage, status);
+ }
+
+ /// Indicates that the thread @p tid had the signal @p signum delivered.
+ static ProcessMessage Signal(lldb::tid_t tid, int signum) {
+ return ProcessMessage(tid, eSignalMessage, signum);
+ }
+
+ /// Indicates that a signal @p signum generated by the debugging process was
+ /// delivered to the thread @p tid.
+ static ProcessMessage SignalDelivered(lldb::tid_t tid, int signum) {
+ return ProcessMessage(tid, eSignalDeliveredMessage, signum);
+ }
+
+ /// Indicates that the thread @p tid encountered a trace point.
+ static ProcessMessage Trace(lldb::tid_t tid) {
+ return ProcessMessage(tid, eTraceMessage);
+ }
+
+ /// Indicates that the thread @p tid encountered a break point.
+ static ProcessMessage Break(lldb::tid_t tid) {
+ return ProcessMessage(tid, eBreakpointMessage);
+ }
+
+ static ProcessMessage Watch(lldb::tid_t tid, lldb::addr_t wp_addr) {
+ return ProcessMessage(tid, eWatchpointMessage, 0, wp_addr);
+ }
+
+ /// Indicates that the thread @p tid crashed.
+ static ProcessMessage Crash(lldb::pid_t pid, CrashReason reason,
+ int signo, lldb::addr_t fault_addr) {
+ ProcessMessage message(pid, eCrashMessage, signo, fault_addr);
+ message.m_crash_reason = reason;
+ return message;
+ }
+
+ /// Indicates that the thread @p child_tid was spawned.
+ static ProcessMessage NewThread(lldb::tid_t parent_tid, lldb::tid_t child_tid) {
+ return ProcessMessage(parent_tid, eNewThreadMessage, child_tid);
+ }
+
+ /// Indicates that the thread @p tid is about to exit with status @p status.
+ static ProcessMessage Exit(lldb::tid_t tid, int status) {
+ return ProcessMessage(tid, eExitMessage, status);
+ }
+
+ /// Indicates that the thread @p pid has exec'd.
+ static ProcessMessage Exec(lldb::tid_t tid) {
+ return ProcessMessage(tid, eExecMessage);
+ }
+
+ int GetExitStatus() const {
+ assert(GetKind() == eExitMessage || GetKind() == eLimboMessage);
+ return m_status;
+ }
+
+ int GetSignal() const {
+ assert(GetKind() == eSignalMessage || GetKind() == eCrashMessage ||
+ GetKind() == eSignalDeliveredMessage);
+ return m_status;
+ }
+
+ int GetStopStatus() const {
+ assert(GetKind() == eSignalMessage);
+ return m_status;
+ }
+
+ CrashReason GetCrashReason() const {
+ assert(GetKind() == eCrashMessage);
+ return m_crash_reason;
+ }
+
+ lldb::addr_t GetFaultAddress() const {
+ assert(GetKind() == eCrashMessage);
+ return m_addr;
+ }
+
+ lldb::addr_t GetHWAddress() const {
+ assert(GetKind() == eWatchpointMessage || GetKind() == eTraceMessage);
+ return m_addr;
+ }
+
+ lldb::tid_t GetChildTID() const {
+ assert(GetKind() == eNewThreadMessage);
+ return m_child_tid;
+ }
+
+ const char *
+ PrintCrashReason() const;
+
+ const char *
+ PrintKind() const;
+
+ static const char *
+ PrintKind(Kind);
+
+private:
+ ProcessMessage(lldb::tid_t tid, Kind kind,
+ int status = 0, lldb::addr_t addr = 0)
+ : m_tid(tid),
+ m_kind(kind),
+ m_crash_reason(CrashReason::eInvalidCrashReason),
+ m_status(status),
+ m_addr(addr),
+ m_child_tid(0) { }
+
+ ProcessMessage(lldb::tid_t tid, Kind kind, lldb::tid_t child_tid)
+ : m_tid(tid),
+ m_kind(kind),
+ m_crash_reason(CrashReason::eInvalidCrashReason),
+ m_status(0),
+ m_addr(0),
+ m_child_tid(child_tid) { }
+
+ lldb::tid_t m_tid;
+ Kind m_kind : 8;
+ CrashReason m_crash_reason;
+ int m_status;
+ lldb::addr_t m_addr;
+ lldb::tid_t m_child_tid;
+};
+
+#endif // #ifndef liblldb_ProcessMessage_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
new file mode 100644
index 0000000..b259804
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
@@ -0,0 +1,210 @@
+//===-- ProcessPOSIXLog.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessPOSIXLog.h"
+
+#include <mutex>
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/StreamFile.h"
+
+#include "ProcessPOSIXLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+// We want to avoid global constructors where code needs to be run so here we
+// control access to our static g_log_sp by hiding it in a singleton function
+// that will construct the static g_log_sp the first time this function is
+// called.
+static bool g_log_enabled = false;
+static Log * g_log = NULL;
+static Log *
+GetLog ()
+{
+ if (!g_log_enabled)
+ return NULL;
+ return g_log;
+}
+
+void
+ProcessPOSIXLog::Initialize(ConstString name)
+{
+ static std::once_flag g_once_flag;
+
+ std::call_once(g_once_flag, [name](){
+ Log::Callbacks log_callbacks = {
+ DisableLog,
+ EnableLog,
+ ListLogCategories
+ };
+
+ Log::RegisterLogChannel (name, log_callbacks);
+ RegisterPluginName(name);
+ });
+}
+
+Log *
+ProcessPOSIXLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().Get();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+static uint32_t
+GetFlagBits (const char *arg)
+{
+ if (::strcasecmp (arg, "all") == 0 ) return POSIX_LOG_ALL;
+ else if (::strcasecmp (arg, "async") == 0 ) return POSIX_LOG_ASYNC;
+ else if (::strncasecmp (arg, "break", 5) == 0 ) return POSIX_LOG_BREAKPOINTS;
+ else if (::strncasecmp (arg, "comm", 4) == 0 ) return POSIX_LOG_COMM;
+ else if (::strcasecmp (arg, "default") == 0 ) return POSIX_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "packets") == 0 ) return POSIX_LOG_PACKETS;
+ else if (::strcasecmp (arg, "memory") == 0 ) return POSIX_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) return POSIX_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) return POSIX_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "process") == 0 ) return POSIX_LOG_PROCESS;
+ else if (::strcasecmp (arg, "ptrace") == 0 ) return POSIX_LOG_PTRACE;
+ else if (::strcasecmp (arg, "registers") == 0 ) return POSIX_LOG_REGISTERS;
+ else if (::strcasecmp (arg, "step") == 0 ) return POSIX_LOG_STEP;
+ else if (::strcasecmp (arg, "thread") == 0 ) return POSIX_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) return POSIX_LOG_VERBOSE;
+ else if (::strncasecmp (arg, "watch", 5) == 0 ) return POSIX_LOG_WATCHPOINTS;
+ return 0;
+}
+
+void
+ProcessPOSIXLog::DisableLog (const char **args, Stream *feedback_strm)
+{
+ Log *log (GetLog ());
+ if (log)
+ {
+ uint32_t flag_bits = 0;
+
+ flag_bits = log->GetMask().Get();
+ for (; args[0]; args++)
+ {
+ const char *arg = args[0];
+ uint32_t bits = GetFlagBits(arg);
+
+ if (bits)
+ {
+ flag_bits &= ~bits;
+ }
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ ListLogCategories (feedback_strm);
+ }
+ }
+
+ log->GetMask().Reset (flag_bits);
+ if (flag_bits == 0)
+ g_log_enabled = false;
+ }
+
+ return;
+}
+
+Log *
+ProcessPOSIXLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **args, Stream *feedback_strm)
+{
+ // Try see if there already is a log - that way we can reuse its settings.
+ // We could reuse the log in toto, but we don't know that the stream is the same.
+ uint32_t flag_bits = 0;
+ if (g_log)
+ flag_bits = g_log->GetMask().Get();
+
+ // Now make a new log with this stream if one was provided
+ if (log_stream_sp)
+ {
+ if (g_log)
+ g_log->SetStream(log_stream_sp);
+ else
+ g_log = new Log(log_stream_sp);
+ }
+
+ if (g_log)
+ {
+ bool got_unknown_category = false;
+ for (; args[0]; args++)
+ {
+ const char *arg = args[0];
+ uint32_t bits = GetFlagBits(arg);
+
+ if (bits)
+ {
+ flag_bits |= bits;
+ }
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ if (got_unknown_category == false)
+ {
+ got_unknown_category = true;
+ ListLogCategories (feedback_strm);
+ }
+ }
+ }
+ if (flag_bits == 0)
+ flag_bits = POSIX_LOG_DEFAULT;
+ g_log->GetMask().Reset(flag_bits);
+ g_log->GetOptions().Reset(log_options);
+ g_log_enabled = true;
+ }
+ return g_log;
+}
+
+void
+ProcessPOSIXLog::ListLogCategories (Stream *strm)
+{
+ strm->Printf ("Logging categories for '%s':\n"
+ " all - turn on all available logging categories\n"
+ " async - log asynchronous activity\n"
+ " break - log breakpoints\n"
+ " communication - log communication activity\n"
+ " default - enable the default set of logging categories for liblldb\n"
+ " packets - log gdb remote packets\n"
+ " memory - log memory reads and writes\n"
+ " data-short - log memory bytes for memory reads and writes for short transactions only\n"
+ " data-long - log memory bytes for memory reads and writes for all transactions\n"
+ " process - log process events and activities\n"
+#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+ " ptrace - log all calls to ptrace\n"
+#endif
+ " registers - log register read/writes\n"
+ " thread - log thread events and activities\n"
+ " step - log step related activities\n"
+ " verbose - enable verbose logging\n"
+ " watch - log watchpoint related activities\n", ProcessPOSIXLog::m_pluginname);
+}
+
+
+void
+ProcessPOSIXLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (mask));
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
+
+int ProcessPOSIXLog::m_nestinglevel;
+const char *ProcessPOSIXLog::m_pluginname = "";
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
new file mode 100644
index 0000000..7edd839
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
@@ -0,0 +1,117 @@
+//===-- ProcessPOSIXLog.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessPOSIXLog_h_
+#define liblldb_ProcessPOSIXLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Log.h"
+
+#define POSIX_LOG_VERBOSE (1u << 0)
+#define POSIX_LOG_PROCESS (1u << 1)
+#define POSIX_LOG_THREAD (1u << 2)
+#define POSIX_LOG_PACKETS (1u << 3)
+#define POSIX_LOG_MEMORY (1u << 4) // Log memory reads/writes calls
+#define POSIX_LOG_MEMORY_DATA_SHORT (1u << 5) // Log short memory reads/writes bytes
+#define POSIX_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes
+#define POSIX_LOG_BREAKPOINTS (1u << 7)
+#define POSIX_LOG_WATCHPOINTS (1u << 8)
+#define POSIX_LOG_STEP (1u << 9)
+#define POSIX_LOG_COMM (1u << 10)
+#define POSIX_LOG_ASYNC (1u << 11)
+#define POSIX_LOG_PTRACE (1u << 12)
+#define POSIX_LOG_REGISTERS (1u << 13)
+#define POSIX_LOG_ALL (UINT32_MAX)
+#define POSIX_LOG_DEFAULT POSIX_LOG_PACKETS
+
+// The size which determines "short memory reads/writes".
+#define POSIX_LOG_MEMORY_SHORT_BYTES (4 * sizeof(ptrdiff_t))
+
+class ProcessPOSIXLog
+{
+ static int m_nestinglevel;
+ static const char *m_pluginname;
+
+public:
+ // ---------------------------------------------------------------------
+ // Public Static Methods
+ // ---------------------------------------------------------------------
+ static void
+ Initialize(lldb_private::ConstString name);
+
+ static void
+ RegisterPluginName(const char *pluginName)
+ {
+ m_pluginname = pluginName;
+ }
+
+ static void
+ RegisterPluginName(lldb_private::ConstString pluginName)
+ {
+ m_pluginname = pluginName.GetCString();
+ }
+
+ static lldb_private::Log *
+ GetLogIfAllCategoriesSet(uint32_t mask = 0);
+
+ static void
+ DisableLog (const char **args, lldb_private::Stream *feedback_strm);
+
+ static lldb_private::Log *
+ EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options,
+ const char **args, lldb_private::Stream *feedback_strm);
+
+ static void
+ ListLogCategories (lldb_private::Stream *strm);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+
+ // The following functions can be used to enable the client to limit
+ // logging to only the top level function calls. This is useful for
+ // recursive functions. FIXME: not thread safe!
+ // Example:
+ // void NestingFunc() {
+ // LogSP log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_ALL));
+ // if (log)
+ // {
+ // ProcessPOSIXLog::IncNestLevel();
+ // if (ProcessPOSIXLog::AtTopNestLevel())
+ // log->Print(msg);
+ // }
+ // NestingFunc();
+ // if (log)
+ // ProcessPOSIXLog::DecNestLevel();
+ // }
+
+ static bool
+ AtTopNestLevel()
+ {
+ return m_nestinglevel == 1;
+ }
+
+ static void
+ IncNestLevel()
+ {
+ ++m_nestinglevel;
+ }
+
+ static void
+ DecNestLevel()
+ {
+ --m_nestinglevel;
+ assert(m_nestinglevel >= 0);
+ }
+};
+
+#endif // liblldb_ProcessPOSIXLog_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMDefines.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMDefines.h
new file mode 100644
index 0000000..cfb33be
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMDefines.h
@@ -0,0 +1,142 @@
+//===-- lldb_ARMDefines.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_ARMDefines_h_
+#define lldb_ARMDefines_h_
+
+// Common definitions for the ARM/Thumb Instruction Set Architecture.
+
+namespace lldb_private {
+
+// ARM shifter types
+typedef enum
+{
+ SRType_LSL,
+ SRType_LSR,
+ SRType_ASR,
+ SRType_ROR,
+ SRType_RRX,
+ SRType_Invalid
+} ARM_ShifterType;
+
+// ARM conditions // Meaning (integer) Meaning (floating-point) Condition flags
+#define COND_EQ 0x0 // Equal Equal Z == 1
+#define COND_NE 0x1 // Not equal Not equal, or unordered Z == 0
+#define COND_CS 0x2 // Carry set >, ==, or unordered C == 1
+#define COND_HS 0x2
+#define COND_CC 0x3 // Carry clear Less than C == 0
+#define COND_LO 0x3
+#define COND_MI 0x4 // Minus, negative Less than N == 1
+#define COND_PL 0x5 // Plus, positive or zero >, ==, or unordered N == 0
+#define COND_VS 0x6 // Overflow Unordered V == 1
+#define COND_VC 0x7 // No overflow Not unordered V == 0
+#define COND_HI 0x8 // Unsigned higher Greater than, or unordered C == 1 and Z == 0
+#define COND_LS 0x9 // Unsigned lower or same Less than or equal C == 0 or Z == 1
+#define COND_GE 0xA // Greater than or equal Greater than or equal N == V
+#define COND_LT 0xB // Less than Less than, or unordered N != V
+#define COND_GT 0xC // Greater than Greater than Z == 0 and N == V
+#define COND_LE 0xD // Less than or equal <, ==, or unordered Z == 1 or N != V
+#define COND_AL 0xE // Always (unconditional) Always (unconditional) Any
+#define COND_UNCOND 0xF
+
+static inline const char *
+ARMCondCodeToString(uint32_t CC)
+{
+ switch (CC) {
+ default: assert(0 && "Unknown condition code");
+ case COND_EQ: return "eq";
+ case COND_NE: return "ne";
+ case COND_HS: return "hs";
+ case COND_LO: return "lo";
+ case COND_MI: return "mi";
+ case COND_PL: return "pl";
+ case COND_VS: return "vs";
+ case COND_VC: return "vc";
+ case COND_HI: return "hi";
+ case COND_LS: return "ls";
+ case COND_GE: return "ge";
+ case COND_LT: return "lt";
+ case COND_GT: return "gt";
+ case COND_LE: return "le";
+ case COND_AL: return "al";
+ }
+}
+
+static inline bool
+ARMConditionPassed(const uint32_t condition, const uint32_t cpsr)
+{
+ const uint32_t cpsr_n = (cpsr >> 31) & 1u; // Negative condition code flag
+ const uint32_t cpsr_z = (cpsr >> 30) & 1u; // Zero condition code flag
+ const uint32_t cpsr_c = (cpsr >> 29) & 1u; // Carry condition code flag
+ const uint32_t cpsr_v = (cpsr >> 28) & 1u; // Overflow condition code flag
+
+ switch (condition) {
+ case COND_EQ: return (cpsr_z == 1);
+ case COND_NE: return (cpsr_z == 0);
+ case COND_CS: return (cpsr_c == 1);
+ case COND_CC: return (cpsr_c == 0);
+ case COND_MI: return (cpsr_n == 1);
+ case COND_PL: return (cpsr_n == 0);
+ case COND_VS: return (cpsr_v == 1);
+ case COND_VC: return (cpsr_v == 0);
+ case COND_HI: return ((cpsr_c == 1) && (cpsr_z == 0));
+ case COND_LS: return ((cpsr_c == 0) || (cpsr_z == 1));
+ case COND_GE: return (cpsr_n == cpsr_v);
+ case COND_LT: return (cpsr_n != cpsr_v);
+ case COND_GT: return ((cpsr_z == 0) && (cpsr_n == cpsr_v));
+ case COND_LE: return ((cpsr_z == 1) || (cpsr_n != cpsr_v));
+ case COND_AL:
+ case COND_UNCOND:
+ default:
+ return true;
+ }
+ return false;
+}
+
+// Bit positions for CPSR
+#define CPSR_T_POS 5
+#define CPSR_F_POS 6
+#define CPSR_I_POS 7
+#define CPSR_A_POS 8
+#define CPSR_E_POS 9
+#define CPSR_J_POS 24
+#define CPSR_Q_POS 27
+#define CPSR_V_POS 28
+#define CPSR_C_POS 29
+#define CPSR_Z_POS 30
+#define CPSR_N_POS 31
+
+// CPSR mode definitions
+#define CPSR_MODE_USR 0x10u
+#define CPSR_MODE_FIQ 0x11u
+#define CPSR_MODE_IRQ 0x12u
+#define CPSR_MODE_SVC 0x13u
+#define CPSR_MODE_ABT 0x17u
+#define CPSR_MODE_UND 0x1bu
+#define CPSR_MODE_SYS 0x1fu
+
+// Masks for CPSR
+#define MASK_CPSR_MODE_MASK (0x0000001fu)
+#define MASK_CPSR_IT_MASK (0x0600fc00u)
+#define MASK_CPSR_T (1u << CPSR_T_POS)
+#define MASK_CPSR_F (1u << CPSR_F_POS)
+#define MASK_CPSR_I (1u << CPSR_I_POS)
+#define MASK_CPSR_A (1u << CPSR_A_POS)
+#define MASK_CPSR_E (1u << CPSR_E_POS)
+#define MASK_CPSR_GE_MASK (0x000f0000u)
+#define MASK_CPSR_J (1u << CPSR_J_POS)
+#define MASK_CPSR_Q (1u << CPSR_Q_POS)
+#define MASK_CPSR_V (1u << CPSR_V_POS)
+#define MASK_CPSR_C (1u << CPSR_C_POS)
+#define MASK_CPSR_Z (1u << CPSR_Z_POS)
+#define MASK_CPSR_N (1u << CPSR_N_POS)
+
+} // namespace lldb_private
+
+#endif // lldb_ARMDefines_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMUtils.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMUtils.h
new file mode 100644
index 0000000..b6ba3fe
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ARMUtils.h
@@ -0,0 +1,394 @@
+//===-- ARMUtils.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_ARMUtils_h_
+#define lldb_ARMUtils_h_
+
+#include "ARMDefines.h"
+#include "InstructionUtils.h"
+#include "llvm/Support/MathExtras.h" // for SignExtend64 template function
+
+// Common utilities for the ARM/Thumb Instruction Set Architecture.
+
+namespace lldb_private {
+
+static inline uint32_t Align(uint32_t val, uint32_t alignment)
+{
+ return alignment * (val / alignment);
+}
+
+static inline uint32_t DecodeImmShift(const uint32_t type, const uint32_t imm5, ARM_ShifterType &shift_t)
+{
+ switch (type)
+ {
+ default:
+ //assert(0 && "Invalid shift type");
+ case 0:
+ shift_t = SRType_LSL;
+ return imm5;
+ case 1:
+ shift_t = SRType_LSR;
+ return (imm5 == 0 ? 32 : imm5);
+ case 2:
+ shift_t = SRType_ASR;
+ return (imm5 == 0 ? 32 : imm5);
+ case 3:
+ if (imm5 == 0)
+ {
+ shift_t = SRType_RRX;
+ return 1;
+ }
+ else
+ {
+ shift_t = SRType_ROR;
+ return imm5;
+ }
+ }
+ shift_t = SRType_Invalid;
+ return UINT32_MAX;
+
+}
+
+// A8.6.35 CMP (register) -- Encoding T3
+// Convenience function.
+static inline uint32_t DecodeImmShiftThumb(const uint32_t opcode, ARM_ShifterType &shift_t)
+{
+ return DecodeImmShift(Bits32(opcode, 5, 4), Bits32(opcode, 14, 12)<<2 | Bits32(opcode, 7, 6), shift_t);
+}
+
+// A8.6.35 CMP (register) -- Encoding A1
+// Convenience function.
+static inline uint32_t DecodeImmShiftARM(const uint32_t opcode, ARM_ShifterType &shift_t)
+{
+ return DecodeImmShift(Bits32(opcode, 6, 5), Bits32(opcode, 11, 7), shift_t);
+}
+
+static inline uint32_t DecodeImmShift(const ARM_ShifterType shift_t, const uint32_t imm5)
+{
+ ARM_ShifterType dont_care;
+ return DecodeImmShift(shift_t, imm5, dont_care);
+}
+
+static inline ARM_ShifterType DecodeRegShift(const uint32_t type)
+{
+ switch (type) {
+ default:
+ //assert(0 && "Invalid shift type");
+ return SRType_Invalid;
+ case 0:
+ return SRType_LSL;
+ case 1:
+ return SRType_LSR;
+ case 2:
+ return SRType_ASR;
+ case 3:
+ return SRType_ROR;
+ }
+}
+
+static inline uint32_t LSL_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ carry_out = amount <= 32 ? Bit32(value, 32 - amount) : 0;
+ return value << amount;
+}
+
+static inline uint32_t LSL(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = LSL_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t LSR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ carry_out = amount <= 32 ? Bit32(value, amount - 1) : 0;
+ return value >> amount;
+}
+
+static inline uint32_t LSR(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = LSR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t ASR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0 || amount > 32) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ bool negative = BitIsSet(value, 31);
+ if (amount <= 32)
+ {
+ carry_out = Bit32(value, amount - 1);
+ int64_t extended = llvm::SignExtend64<32>(value);
+ return UnsignedBits(extended, amount + 31, amount);
+ }
+ else
+ {
+ carry_out = (negative ? 1 : 0);
+ return (negative ? 0xffffffff : 0);
+ }
+}
+
+static inline uint32_t ASR(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = ASR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t ROR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ uint32_t amt = amount % 32;
+ uint32_t result = Rotr32(value, amt);
+ carry_out = Bit32(value, 31);
+ return result;
+}
+
+static inline uint32_t ROR(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = ROR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t RRX_C(const uint32_t value, const uint32_t carry_in, uint32_t &carry_out, bool *success)
+{
+ *success = true;
+ carry_out = Bit32(value, 0);
+ return Bit32(carry_in, 0) << 31 | Bits32(value, 31, 1);
+}
+
+static inline uint32_t RRX(const uint32_t value, const uint32_t carry_in, bool *success)
+{
+ *success = true;
+ uint32_t dont_care;
+ uint32_t result = RRX_C(value, carry_in, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t Shift_C(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
+ const uint32_t carry_in, uint32_t &carry_out, bool *success)
+{
+ if (type == SRType_RRX && amount != 1) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+
+ if (amount == 0) {
+ carry_out = carry_in;
+ return value;
+ }
+ uint32_t result;
+ switch (type) {
+ case SRType_LSL:
+ result = LSL_C(value, amount, carry_out, success);
+ break;
+ case SRType_LSR:
+ result = LSR_C(value, amount, carry_out, success);
+ break;
+ case SRType_ASR:
+ result = ASR_C(value, amount, carry_out, success);
+ break;
+ case SRType_ROR:
+ result = ROR_C(value, amount, carry_out, success);
+ break;
+ case SRType_RRX:
+ result = RRX_C(value, carry_in, carry_out, success);
+ break;
+ default:
+ *success = false;
+ break;
+ }
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t Shift(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
+ const uint32_t carry_in, bool *success)
+{
+ // Don't care about carry out in this case.
+ uint32_t dont_care;
+ uint32_t result = Shift_C(value, type, amount, carry_in, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t bits(const uint32_t val, const uint32_t msbit, const uint32_t lsbit)
+{
+ return Bits32(val, msbit, lsbit);
+}
+
+static inline uint32_t bit(const uint32_t val, const uint32_t msbit)
+{
+ return bits(val, msbit, msbit);
+}
+
+static uint32_t ror(uint32_t val, uint32_t N, uint32_t shift)
+{
+ uint32_t m = shift % N;
+ return (val >> m) | (val << (N - m));
+}
+
+// (imm32, carry_out) = ARMExpandImm_C(imm12, carry_in)
+static inline uint32_t ARMExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
+{
+ uint32_t imm32; // the expanded result
+ uint32_t imm = bits(opcode, 7, 0); // immediate value
+ uint32_t amt = 2 * bits(opcode, 11, 8); // rotate amount
+ if (amt == 0)
+ {
+ imm32 = imm;
+ carry_out = carry_in;
+ }
+ else
+ {
+ imm32 = ror(imm, 32, amt);
+ carry_out = Bit32(imm32, 31);
+ }
+ return imm32;
+}
+
+static inline uint32_t ARMExpandImm(uint32_t opcode)
+{
+ // 'carry_in' argument to following function call does not affect the imm32 result.
+ uint32_t carry_in = 0;
+ uint32_t carry_out;
+ return ARMExpandImm_C(opcode, carry_in, carry_out);
+}
+
+// (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)
+static inline uint32_t ThumbExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
+{
+ uint32_t imm32; // the expanded result
+ const uint32_t i = bit(opcode, 26);
+ const uint32_t imm3 = bits(opcode, 14, 12);
+ const uint32_t abcdefgh = bits(opcode, 7, 0);
+ const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;
+
+ if (bits(imm12, 11, 10) == 0)
+ {
+ switch (bits(imm12, 9, 8)) {
+ default: // Keep static analyzer happy with a default case
+ case 0:
+ imm32 = abcdefgh;
+ break;
+
+ case 1:
+ imm32 = abcdefgh << 16 | abcdefgh;
+ break;
+
+ case 2:
+ imm32 = abcdefgh << 24 | abcdefgh << 8;
+ break;
+
+ case 3:
+ imm32 = abcdefgh << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;
+ break;
+ }
+ carry_out = carry_in;
+ }
+ else
+ {
+ const uint32_t unrotated_value = 0x80 | bits(imm12, 6, 0);
+ imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7));
+ carry_out = Bit32(imm32, 31);
+ }
+ return imm32;
+}
+
+static inline uint32_t ThumbExpandImm(uint32_t opcode)
+{
+ // 'carry_in' argument to following function call does not affect the imm32 result.
+ uint32_t carry_in = 0;
+ uint32_t carry_out;
+ return ThumbExpandImm_C(opcode, carry_in, carry_out);
+}
+
+// imm32 = ZeroExtend(i:imm3:imm8, 32)
+static inline uint32_t ThumbImm12(uint32_t opcode)
+{
+ const uint32_t i = bit(opcode, 26);
+ const uint32_t imm3 = bits(opcode, 14, 12);
+ const uint32_t imm8 = bits(opcode, 7, 0);
+ const uint32_t imm12 = i << 11 | imm3 << 8 | imm8;
+ return imm12;
+}
+
+// imm32 = ZeroExtend(imm7:'00', 32)
+static inline uint32_t ThumbImm7Scaled(uint32_t opcode)
+{
+ const uint32_t imm7 = bits(opcode, 6, 0);
+ return imm7 * 4;
+}
+
+// imm32 = ZeroExtend(imm8:'00', 32)
+static inline uint32_t ThumbImm8Scaled(uint32_t opcode)
+{
+ const uint32_t imm8 = bits(opcode, 7, 0);
+ return imm8 * 4;
+}
+
+// This function performs the check for the register numbers 13 and 15 that are
+// not permitted for many Thumb register specifiers.
+static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }
+
+} // namespace lldb_private
+
+#endif // lldb_ARMUtils_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
new file mode 100644
index 0000000..4eff442
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
@@ -0,0 +1,766 @@
+//===-- DynamicRegisterInfo.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DynamicRegisterInfo.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StructuredData.h"
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Host/StringConvert.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+DynamicRegisterInfo::DynamicRegisterInfo () :
+ m_regs (),
+ m_sets (),
+ m_set_reg_nums (),
+ m_set_names (),
+ m_value_regs_map (),
+ m_invalidate_regs_map (),
+ m_reg_data_byte_size (0),
+ m_finalized (false)
+{
+}
+
+DynamicRegisterInfo::DynamicRegisterInfo(const lldb_private::StructuredData::Dictionary &dict,
+ const lldb_private::ArchSpec &arch) :
+ m_regs (),
+ m_sets (),
+ m_set_reg_nums (),
+ m_set_names (),
+ m_value_regs_map (),
+ m_invalidate_regs_map (),
+ m_reg_data_byte_size (0),
+ m_finalized (false)
+{
+ SetRegisterInfo (dict, arch);
+}
+
+DynamicRegisterInfo::~DynamicRegisterInfo ()
+{
+}
+
+size_t
+DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, const ArchSpec &arch)
+{
+ assert(!m_finalized);
+ StructuredData::Array *sets = nullptr;
+ if (dict.GetValueForKeyAsArray("sets", sets))
+ {
+ const uint32_t num_sets = sets->GetSize();
+ for (uint32_t i=0; i<num_sets; ++i)
+ {
+ std::string set_name_str;
+ ConstString set_name;
+ if (sets->GetItemAtIndexAsString(i, set_name_str))
+ set_name.SetCString(set_name_str.c_str());
+ if (set_name)
+ {
+ RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
+ m_sets.push_back (new_set);
+ }
+ else
+ {
+ Clear();
+ printf("error: register sets must have valid names\n");
+ return 0;
+ }
+ }
+ m_set_reg_nums.resize(m_sets.size());
+ }
+ StructuredData::Array *regs = nullptr;
+ if (!dict.GetValueForKeyAsArray("registers", regs))
+ return 0;
+
+ const uint32_t num_regs = regs->GetSize();
+// typedef std::map<std::string, std::vector<std::string> > InvalidateNameMap;
+// InvalidateNameMap invalidate_map;
+ for (uint32_t i = 0; i < num_regs; ++i)
+ {
+ StructuredData::Dictionary *reg_info_dict = nullptr;
+ if (!regs->GetItemAtIndexAsDictionary(i, reg_info_dict))
+ {
+ Clear();
+ printf("error: items in the 'registers' array must be dictionaries\n");
+ regs->DumpToStdout();
+ return 0;
+ }
+
+ // { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 2,
+ // 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', },
+ RegisterInfo reg_info;
+ std::vector<uint32_t> value_regs;
+ std::vector<uint32_t> invalidate_regs;
+ memset(&reg_info, 0, sizeof(reg_info));
+
+ ConstString name_val;
+ ConstString alt_name_val;
+ if (!reg_info_dict->GetValueForKeyAsString("name", name_val, nullptr))
+ {
+ Clear();
+ printf("error: registers must have valid names and offsets\n");
+ reg_info_dict->DumpToStdout();
+ return 0;
+ }
+ reg_info.name = name_val.GetCString();
+ reg_info_dict->GetValueForKeyAsString("alt-name", alt_name_val, nullptr);
+ reg_info.alt_name = alt_name_val.GetCString();
+
+ reg_info_dict->GetValueForKeyAsInteger("offset", reg_info.byte_offset, UINT32_MAX);
+
+ const ByteOrder byte_order = arch.GetByteOrder();
+
+ if (reg_info.byte_offset == UINT32_MAX)
+ {
+ // No offset for this register, see if the register has a value expression
+ // which indicates this register is part of another register. Value expressions
+ // are things like "rax[31:0]" which state that the current register's value
+ // is in a concrete register "rax" in bits 31:0. If there is a value expression
+ // we can calculate the offset
+ bool success = false;
+ std::string slice_str;
+ if (reg_info_dict->GetValueForKeyAsString("slice", slice_str, nullptr))
+ {
+ // Slices use the following format:
+ // REGNAME[MSBIT:LSBIT]
+ // REGNAME - name of the register to grab a slice of
+ // MSBIT - the most significant bit at which the current register value starts at
+ // LSBIT - the least significant bit at which the current register value ends at
+ static RegularExpression g_bitfield_regex("([A-Za-z_][A-Za-z0-9_]*)\\[([0-9]+):([0-9]+)\\]");
+ RegularExpression::Match regex_match(3);
+ if (g_bitfield_regex.Execute(slice_str.c_str(), &regex_match))
+ {
+ llvm::StringRef reg_name_str;
+ std::string msbit_str;
+ std::string lsbit_str;
+ if (regex_match.GetMatchAtIndex(slice_str.c_str(), 1, reg_name_str) &&
+ regex_match.GetMatchAtIndex(slice_str.c_str(), 2, msbit_str) &&
+ regex_match.GetMatchAtIndex(slice_str.c_str(), 3, lsbit_str))
+ {
+ const uint32_t msbit = StringConvert::ToUInt32(msbit_str.c_str(), UINT32_MAX);
+ const uint32_t lsbit = StringConvert::ToUInt32(lsbit_str.c_str(), UINT32_MAX);
+ if (msbit != UINT32_MAX && lsbit != UINT32_MAX)
+ {
+ if (msbit > lsbit)
+ {
+ const uint32_t msbyte = msbit / 8;
+ const uint32_t lsbyte = lsbit / 8;
+
+ ConstString containing_reg_name(reg_name_str);
+
+ RegisterInfo *containing_reg_info = GetRegisterInfo(containing_reg_name);
+ if (containing_reg_info)
+ {
+ const uint32_t max_bit = containing_reg_info->byte_size * 8;
+ if (msbit < max_bit && lsbit < max_bit)
+ {
+ m_invalidate_regs_map[containing_reg_info->kinds[eRegisterKindLLDB]].push_back(i);
+ m_value_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]);
+ m_invalidate_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]);
+
+ if (byte_order == eByteOrderLittle)
+ {
+ success = true;
+ reg_info.byte_offset = containing_reg_info->byte_offset + lsbyte;
+ }
+ else if (byte_order == eByteOrderBig)
+ {
+ success = true;
+ reg_info.byte_offset = containing_reg_info->byte_offset + msbyte;
+ }
+ else
+ {
+ assert(!"Invalid byte order");
+ }
+ }
+ else
+ {
+ if (msbit > max_bit)
+ printf("error: msbit (%u) must be less than the bitsize of the register (%u)\n", msbit,
+ max_bit);
+ else
+ printf("error: lsbit (%u) must be less than the bitsize of the register (%u)\n", lsbit,
+ max_bit);
+ }
+ }
+ else
+ {
+ printf("error: invalid concrete register \"%s\"\n", containing_reg_name.GetCString());
+ }
+ }
+ else
+ {
+ printf("error: msbit (%u) must be greater than lsbit (%u)\n", msbit, lsbit);
+ }
+ }
+ else
+ {
+ printf("error: msbit (%u) and lsbit (%u) must be valid\n", msbit, lsbit);
+ }
+ }
+ else
+ {
+ // TODO: print error invalid slice string that doesn't follow the format
+ printf("error: failed to extract regex matches for parsing the register bitfield regex\n");
+ }
+ }
+ else
+ {
+ // TODO: print error invalid slice string that doesn't follow the format
+ printf("error: failed to match against register bitfield regex\n");
+ }
+ }
+ else
+ {
+ StructuredData::Array *composite_reg_list = nullptr;
+ if (reg_info_dict->GetValueForKeyAsArray("composite", composite_reg_list))
+ {
+ const size_t num_composite_regs = composite_reg_list->GetSize();
+ if (num_composite_regs > 0)
+ {
+ uint32_t composite_offset = UINT32_MAX;
+ for (uint32_t composite_idx = 0; composite_idx < num_composite_regs; ++composite_idx)
+ {
+ ConstString composite_reg_name;
+ if (composite_reg_list->GetItemAtIndexAsString(composite_idx, composite_reg_name, nullptr))
+ {
+ RegisterInfo *composite_reg_info = GetRegisterInfo(composite_reg_name);
+ if (composite_reg_info)
+ {
+ composite_offset = std::min(composite_offset, composite_reg_info->byte_offset);
+ m_value_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]);
+ m_invalidate_regs_map[composite_reg_info->kinds[eRegisterKindLLDB]].push_back(i);
+ m_invalidate_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]);
+ }
+ else
+ {
+ // TODO: print error invalid slice string that doesn't follow the format
+ printf("error: failed to find composite register by name: \"%s\"\n", composite_reg_name.GetCString());
+ }
+ }
+ else
+ {
+ printf("error: 'composite' list value wasn't a python string\n");
+ }
+ }
+ if (composite_offset != UINT32_MAX)
+ {
+ reg_info.byte_offset = composite_offset;
+ success = m_value_regs_map.find(i) != m_value_regs_map.end();
+ }
+ else
+ {
+ printf("error: 'composite' registers must specify at least one real register\n");
+ }
+ }
+ else
+ {
+ printf("error: 'composite' list was empty\n");
+ }
+ }
+ }
+
+ if (!success)
+ {
+ Clear();
+ reg_info_dict->DumpToStdout();
+ return 0;
+ }
+ }
+
+ int64_t bitsize = 0;
+ if (!reg_info_dict->GetValueForKeyAsInteger("bitsize", bitsize))
+ {
+ Clear();
+ printf("error: invalid or missing 'bitsize' key/value pair in register dictionary\n");
+ reg_info_dict->DumpToStdout();
+ return 0;
+ }
+
+ reg_info.byte_size = bitsize / 8;
+
+ std::string format_str;
+ if (reg_info_dict->GetValueForKeyAsString("format", format_str, nullptr))
+ {
+ if (Args::StringToFormat(format_str.c_str(), reg_info.format, NULL).Fail())
+ {
+ Clear();
+ printf("error: invalid 'format' value in register dictionary\n");
+ reg_info_dict->DumpToStdout();
+ return 0;
+ }
+ }
+ else
+ {
+ reg_info_dict->GetValueForKeyAsInteger("format", reg_info.format, eFormatHex);
+ }
+
+ std::string encoding_str;
+ if (reg_info_dict->GetValueForKeyAsString("encoding", encoding_str))
+ reg_info.encoding = Args::StringToEncoding(encoding_str.c_str(), eEncodingUint);
+ else
+ reg_info_dict->GetValueForKeyAsInteger("encoding", reg_info.encoding, eEncodingUint);
+
+ size_t set = 0;
+ if (!reg_info_dict->GetValueForKeyAsInteger<size_t>("set", set, -1) || set >= m_sets.size())
+ {
+ Clear();
+ printf("error: invalid 'set' value in register dictionary, valid values are 0 - %i\n", (int)set);
+ reg_info_dict->DumpToStdout();
+ return 0;
+ }
+
+ // Fill in the register numbers
+ reg_info.kinds[lldb::eRegisterKindLLDB] = i;
+ reg_info.kinds[lldb::eRegisterKindGDB] = i;
+ reg_info_dict->GetValueForKeyAsInteger("gcc", reg_info.kinds[lldb::eRegisterKindGCC], LLDB_INVALID_REGNUM);
+ reg_info_dict->GetValueForKeyAsInteger("dwarf", reg_info.kinds[lldb::eRegisterKindDWARF], LLDB_INVALID_REGNUM);
+ std::string generic_str;
+ if (reg_info_dict->GetValueForKeyAsString("generic", generic_str))
+ reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister(generic_str.c_str());
+ else
+ reg_info_dict->GetValueForKeyAsInteger("generic", reg_info.kinds[lldb::eRegisterKindGeneric], LLDB_INVALID_REGNUM);
+
+ // Check if this register invalidates any other register values when it is modified
+ StructuredData::Array *invalidate_reg_list = nullptr;
+ if (reg_info_dict->GetValueForKeyAsArray("invalidate-regs", invalidate_reg_list))
+ {
+ const size_t num_regs = invalidate_reg_list->GetSize();
+ if (num_regs > 0)
+ {
+ for (uint32_t idx = 0; idx < num_regs; ++idx)
+ {
+ ConstString invalidate_reg_name;
+ uint64_t invalidate_reg_num;
+ if (invalidate_reg_list->GetItemAtIndexAsString(idx, invalidate_reg_name))
+ {
+ RegisterInfo *invalidate_reg_info = GetRegisterInfo(invalidate_reg_name);
+ if (invalidate_reg_info)
+ {
+ m_invalidate_regs_map[i].push_back(invalidate_reg_info->kinds[eRegisterKindLLDB]);
+ }
+ else
+ {
+ // TODO: print error invalid slice string that doesn't follow the format
+ printf("error: failed to find a 'invalidate-regs' register for \"%s\" while parsing register \"%s\"\n",
+ invalidate_reg_name.GetCString(), reg_info.name);
+ }
+ }
+ else if (invalidate_reg_list->GetItemAtIndexAsInteger(idx, invalidate_reg_num))
+ {
+ if (invalidate_reg_num != UINT64_MAX)
+ m_invalidate_regs_map[i].push_back(invalidate_reg_num);
+ else
+ printf("error: 'invalidate-regs' list value wasn't a valid integer\n");
+ }
+ else
+ {
+ printf("error: 'invalidate-regs' list value wasn't a python string or integer\n");
+ }
+ }
+ }
+ else
+ {
+ printf("error: 'invalidate-regs' contained an empty list\n");
+ }
+ }
+
+ // Calculate the register offset
+ const 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;
+
+ m_regs.push_back(reg_info);
+ m_set_reg_nums[set].push_back(i);
+ }
+ Finalize(arch);
+ return m_regs.size();
+}
+
+
+void
+DynamicRegisterInfo::AddRegister (RegisterInfo &reg_info,
+ ConstString &reg_name,
+ ConstString &reg_alt_name,
+ ConstString &set_name)
+{
+ assert(!m_finalized);
+ const uint32_t reg_num = m_regs.size();
+ reg_info.name = reg_name.AsCString();
+ assert (reg_info.name);
+ reg_info.alt_name = reg_alt_name.AsCString(NULL);
+ uint32_t i;
+ if (reg_info.value_regs)
+ {
+ for (i=0; reg_info.value_regs[i] != LLDB_INVALID_REGNUM; ++i)
+ m_value_regs_map[reg_num].push_back(reg_info.value_regs[i]);
+ }
+ if (reg_info.invalidate_regs)
+ {
+ for (i=0; reg_info.invalidate_regs[i] != LLDB_INVALID_REGNUM; ++i)
+ m_invalidate_regs_map[reg_num].push_back(reg_info.invalidate_regs[i]);
+ }
+ m_regs.push_back (reg_info);
+ uint32_t set = GetRegisterSetIndexByName (set_name, true);
+ assert (set < m_sets.size());
+ 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)
+{
+ if (m_finalized)
+ return;
+
+ m_finalized = true;
+ const size_t num_sets = m_sets.size();
+ for (size_t set = 0; set < num_sets; ++set)
+ {
+ assert (m_sets.size() == m_set_reg_nums.size());
+ m_sets[set].num_registers = m_set_reg_nums[set].size();
+ m_sets[set].registers = &m_set_reg_nums[set][0];
+ }
+
+ // sort and unique all value registers and make sure each is terminated with
+ // LLDB_INVALID_REGNUM
+
+ for (reg_to_regs_map::iterator pos = m_value_regs_map.begin(), end = m_value_regs_map.end();
+ pos != end;
+ ++pos)
+ {
+ if (pos->second.size() > 1)
+ {
+ std::sort (pos->second.begin(), pos->second.end());
+ reg_num_collection::iterator unique_end = std::unique (pos->second.begin(), pos->second.end());
+ if (unique_end != pos->second.end())
+ pos->second.erase(unique_end, pos->second.end());
+ }
+ assert (!pos->second.empty());
+ if (pos->second.back() != LLDB_INVALID_REGNUM)
+ pos->second.push_back(LLDB_INVALID_REGNUM);
+ }
+
+ // Now update all value_regs with each register info as needed
+ const size_t num_regs = m_regs.size();
+ for (size_t i=0; i<num_regs; ++i)
+ {
+ if (m_value_regs_map.find(i) != m_value_regs_map.end())
+ m_regs[i].value_regs = m_value_regs_map[i].data();
+ else
+ m_regs[i].value_regs = NULL;
+ }
+
+ // Expand all invalidation dependencies
+ for (reg_to_regs_map::iterator pos = m_invalidate_regs_map.begin(), end = m_invalidate_regs_map.end();
+ pos != end;
+ ++pos)
+ {
+ const uint32_t reg_num = pos->first;
+
+ if (m_regs[reg_num].value_regs)
+ {
+ reg_num_collection extra_invalid_regs;
+ for (const uint32_t invalidate_reg_num : pos->second)
+ {
+ reg_to_regs_map::iterator invalidate_pos = m_invalidate_regs_map.find(invalidate_reg_num);
+ if (invalidate_pos != m_invalidate_regs_map.end())
+ {
+ for (const uint32_t concrete_invalidate_reg_num : invalidate_pos->second)
+ {
+ if (concrete_invalidate_reg_num != reg_num)
+ extra_invalid_regs.push_back(concrete_invalidate_reg_num);
+ }
+ }
+ }
+ pos->second.insert(pos->second.end(), extra_invalid_regs.begin(), extra_invalid_regs.end());
+ }
+ }
+
+ // sort and unique all invalidate registers and make sure each is terminated with
+ // LLDB_INVALID_REGNUM
+ for (reg_to_regs_map::iterator pos = m_invalidate_regs_map.begin(), end = m_invalidate_regs_map.end();
+ pos != end;
+ ++pos)
+ {
+ if (pos->second.size() > 1)
+ {
+ std::sort (pos->second.begin(), pos->second.end());
+ reg_num_collection::iterator unique_end = std::unique (pos->second.begin(), pos->second.end());
+ if (unique_end != pos->second.end())
+ pos->second.erase(unique_end, pos->second.end());
+ }
+ assert (!pos->second.empty());
+ if (pos->second.back() != LLDB_INVALID_REGNUM)
+ pos->second.push_back(LLDB_INVALID_REGNUM);
+ }
+
+ // Now update all invalidate_regs with each register info as needed
+ for (size_t i=0; i<num_regs; ++i)
+ {
+ if (m_invalidate_regs_map.find(i) != m_invalidate_regs_map.end())
+ m_regs[i].invalidate_regs = m_invalidate_regs_map[i].data();
+ else
+ m_regs[i].invalidate_regs = NULL;
+ }
+
+ // Check if we need to automatically set the generic registers in case
+ // they weren't set
+ bool generic_regs_specified = false;
+ for (const auto &reg: m_regs)
+ {
+ if (reg.kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM)
+ {
+ generic_regs_specified = true;
+ break;
+ }
+ }
+
+ if (!generic_regs_specified)
+ {
+ switch (arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::aarch64_be:
+ for (auto &reg: m_regs)
+ {
+ if (strcmp(reg.name, "pc") == 0)
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ else if ((strcmp(reg.name, "fp") == 0) || (strcmp(reg.name, "x29") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+ else if ((strcmp(reg.name, "lr") == 0) || (strcmp(reg.name, "x30") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
+ else if ((strcmp(reg.name, "sp") == 0) || (strcmp(reg.name, "x31") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+ else if (strcmp(reg.name, "cpsr") == 0)
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+ }
+ break;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::armeb:
+ case llvm::Triple::thumb:
+ case llvm::Triple::thumbeb:
+ for (auto &reg: m_regs)
+ {
+ if ((strcmp(reg.name, "pc") == 0) || (strcmp(reg.name, "r15") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ else if ((strcmp(reg.name, "sp") == 0) || (strcmp(reg.name, "r13") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+ else if ((strcmp(reg.name, "lr") == 0) || (strcmp(reg.name, "r14") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA;
+ else if ((strcmp(reg.name, "r7") == 0) && arch.GetTriple().getVendor() == llvm::Triple::Apple)
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+ else if ((strcmp(reg.name, "r11") == 0) && arch.GetTriple().getVendor() != llvm::Triple::Apple)
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+ else if (strcmp(reg.name, "fp") == 0)
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+ else if (strcmp(reg.name, "cpsr") == 0)
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+ }
+ break;
+
+ case llvm::Triple::x86:
+ for (auto &reg: m_regs)
+ {
+ if ((strcmp(reg.name, "eip") == 0) || (strcmp(reg.name, "pc") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ else if ((strcmp(reg.name, "esp") == 0) || (strcmp(reg.name, "sp") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+ else if ((strcmp(reg.name, "ebp") == 0) || (strcmp(reg.name, "fp") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+ else if ((strcmp(reg.name, "eflags") == 0) || (strcmp(reg.name, "flags") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+ }
+ break;
+
+ case llvm::Triple::x86_64:
+ for (auto &reg: m_regs)
+ {
+ if ((strcmp(reg.name, "rip") == 0) || (strcmp(reg.name, "pc") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ else if ((strcmp(reg.name, "rsp") == 0) || (strcmp(reg.name, "sp") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP;
+ else if ((strcmp(reg.name, "rbp") == 0) || (strcmp(reg.name, "fp") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP;
+ else if ((strcmp(reg.name, "rflags") == 0) || (strcmp(reg.name, "flags") == 0))
+ reg.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+size_t
+DynamicRegisterInfo::GetNumRegisters() const
+{
+ return m_regs.size();
+}
+
+size_t
+DynamicRegisterInfo::GetNumRegisterSets() const
+{
+ return m_sets.size();
+}
+
+size_t
+DynamicRegisterInfo::GetRegisterDataByteSize() const
+{
+ return m_reg_data_byte_size;
+}
+
+const RegisterInfo *
+DynamicRegisterInfo::GetRegisterInfoAtIndex (uint32_t i) const
+{
+ if (i < m_regs.size())
+ return &m_regs[i];
+ return NULL;
+}
+
+const RegisterSet *
+DynamicRegisterInfo::GetRegisterSet (uint32_t i) const
+{
+ if (i < m_sets.size())
+ return &m_sets[i];
+ return NULL;
+}
+
+uint32_t
+DynamicRegisterInfo::GetRegisterSetIndexByName (ConstString &set_name, bool can_create)
+{
+ name_collection::iterator pos, end = m_set_names.end();
+ for (pos = m_set_names.begin(); pos != end; ++pos)
+ {
+ if (*pos == set_name)
+ return std::distance (m_set_names.begin(), pos);
+ }
+
+ m_set_names.push_back(set_name);
+ m_set_reg_nums.resize(m_set_reg_nums.size()+1);
+ RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
+ m_sets.push_back (new_set);
+ return m_sets.size() - 1;
+}
+
+uint32_t
+DynamicRegisterInfo::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const
+{
+ reg_collection::const_iterator pos, end = m_regs.end();
+ for (pos = m_regs.begin(); pos != end; ++pos)
+ {
+ if (pos->kinds[kind] == num)
+ return std::distance (m_regs.begin(), pos);
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+void
+DynamicRegisterInfo::Clear()
+{
+ m_regs.clear();
+ m_sets.clear();
+ m_set_reg_nums.clear();
+ m_set_names.clear();
+ m_value_regs_map.clear();
+ m_invalidate_regs_map.clear();
+ m_reg_data_byte_size = 0;
+ m_finalized = false;
+}
+
+void
+DynamicRegisterInfo::Dump () const
+{
+ StreamFile s(stdout, false);
+ const size_t num_regs = m_regs.size();
+ s.Printf("%p: DynamicRegisterInfo contains %" PRIu64 " registers:\n",
+ static_cast<const void*>(this), static_cast<uint64_t>(num_regs));
+ for (size_t i=0; i<num_regs; ++i)
+ {
+ s.Printf("[%3" PRIu64 "] name = %-10s", (uint64_t)i, m_regs[i].name);
+ s.Printf(", size = %2u, offset = %4u, encoding = %u, format = %-10s",
+ m_regs[i].byte_size,
+ m_regs[i].byte_offset,
+ m_regs[i].encoding,
+ FormatManager::GetFormatAsCString (m_regs[i].format));
+ if (m_regs[i].kinds[eRegisterKindGDB] != LLDB_INVALID_REGNUM)
+ s.Printf(", gdb = %3u", m_regs[i].kinds[eRegisterKindGDB]);
+ if (m_regs[i].kinds[eRegisterKindDWARF] != LLDB_INVALID_REGNUM)
+ s.Printf(", dwarf = %3u", m_regs[i].kinds[eRegisterKindDWARF]);
+ if (m_regs[i].kinds[eRegisterKindGCC] != LLDB_INVALID_REGNUM)
+ s.Printf(", gcc = %3u", m_regs[i].kinds[eRegisterKindGCC]);
+ if (m_regs[i].kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM)
+ s.Printf(", generic = %3u", m_regs[i].kinds[eRegisterKindGeneric]);
+ if (m_regs[i].alt_name)
+ s.Printf(", alt-name = %s", m_regs[i].alt_name);
+ if (m_regs[i].value_regs)
+ {
+ s.Printf(", value_regs = [ ");
+ for (size_t j=0; m_regs[i].value_regs[j] != LLDB_INVALID_REGNUM; ++j)
+ {
+ s.Printf("%s ", m_regs[m_regs[i].value_regs[j]].name);
+ }
+ s.Printf("]");
+ }
+ if (m_regs[i].invalidate_regs)
+ {
+ s.Printf(", invalidate_regs = [ ");
+ for (size_t j=0; m_regs[i].invalidate_regs[j] != LLDB_INVALID_REGNUM; ++j)
+ {
+ s.Printf("%s ", m_regs[m_regs[i].invalidate_regs[j]].name);
+ }
+ s.Printf("]");
+ }
+ s.EOL();
+ }
+
+ const size_t num_sets = m_sets.size();
+ s.Printf("%p: DynamicRegisterInfo contains %" PRIu64 " register sets:\n",
+ static_cast<const void*>(this), static_cast<uint64_t>(num_sets));
+ for (size_t i=0; i<num_sets; ++i)
+ {
+ s.Printf("set[%" PRIu64 "] name = %s, regs = [", (uint64_t)i, m_sets[i].name);
+ for (size_t idx=0; idx<m_sets[i].num_registers; ++idx)
+ {
+ s.Printf("%s ", m_regs[m_sets[i].registers[idx]].name);
+ }
+ s.Printf("]\n");
+ }
+}
+
+
+
+lldb_private::RegisterInfo *
+DynamicRegisterInfo::GetRegisterInfo (const lldb_private::ConstString &reg_name)
+{
+ for (auto &reg_info : m_regs)
+ {
+ // We can use pointer comparison since we used a ConstString to set
+ // the "name" member in AddRegister()
+ if (reg_info.name == reg_name.GetCString())
+ {
+ return &reg_info;
+ }
+ }
+ return NULL;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h
new file mode 100644
index 0000000..1b99e2f
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h
@@ -0,0 +1,98 @@
+//===-- DynamicRegisterInfo.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_DynamicRegisterInfo_h_
+#define lldb_DynamicRegisterInfo_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+#include <map>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/StructuredData.h"
+
+class DynamicRegisterInfo
+{
+public:
+ DynamicRegisterInfo ();
+
+ DynamicRegisterInfo(const lldb_private::StructuredData::Dictionary &dict,
+ const lldb_private::ArchSpec &arch);
+
+ virtual
+ ~DynamicRegisterInfo ();
+
+ size_t SetRegisterInfo(const lldb_private::StructuredData::Dictionary &dict,
+ const lldb_private::ArchSpec &arch);
+
+ void
+ AddRegister (lldb_private::RegisterInfo &reg_info,
+ lldb_private::ConstString &reg_name,
+ lldb_private::ConstString &reg_alt_name,
+ lldb_private::ConstString &set_name);
+
+ void
+ Finalize (const lldb_private::ArchSpec &arch);
+
+ size_t
+ GetNumRegisters() const;
+
+ size_t
+ GetNumRegisterSets() const;
+
+ size_t
+ GetRegisterDataByteSize() const;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t i) const;
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet (uint32_t i) const;
+
+ uint32_t
+ GetRegisterSetIndexByName (lldb_private::ConstString &set_name, bool can_create);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const;
+
+ void
+ Dump () const;
+
+ void
+ Clear();
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from DynamicRegisterInfo can see and modify these
+ //------------------------------------------------------------------
+ typedef std::vector <lldb_private::RegisterInfo> reg_collection;
+ typedef std::vector <lldb_private::RegisterSet> set_collection;
+ typedef std::vector <uint32_t> reg_num_collection;
+ typedef std::vector <reg_num_collection> set_reg_num_collection;
+ typedef std::vector <lldb_private::ConstString> name_collection;
+ typedef std::map<uint32_t, reg_num_collection> reg_to_regs_map;
+
+ lldb_private::RegisterInfo *
+ GetRegisterInfo (const lldb_private::ConstString &reg_name);
+
+ reg_collection m_regs;
+ set_collection m_sets;
+ set_reg_num_collection m_set_reg_nums;
+ name_collection m_set_names;
+ reg_to_regs_map m_value_regs_map;
+ reg_to_regs_map m_invalidate_regs_map;
+ size_t m_reg_data_byte_size; // The number of bytes required to store all registers
+ bool m_finalized;
+};
+
+#endif // lldb_DynamicRegisterInfo_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/FreeBSDSignals.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/FreeBSDSignals.cpp
new file mode 100644
index 0000000..c143d36
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/FreeBSDSignals.cpp
@@ -0,0 +1,95 @@
+//===-- FreeBSDSignals.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "FreeBSDSignals.h"
+
+using namespace lldb_private;
+
+FreeBSDSignals::FreeBSDSignals()
+ : UnixSignals()
+{
+ Reset();
+}
+
+void
+FreeBSDSignals::Reset()
+{
+ UnixSignals::Reset();
+
+ // SIGNO NAME SHORT NAME SUPPRESS STOP NOTIFY DESCRIPTION
+ // ====== ============ ========== ======== ====== ====== ===================================================
+ AddSignal (32, "SIGTHR", "THR", false, true , true , "thread interrupt");
+ AddSignal (33, "SIGLIBRT", "LIBRT", false, true , true , "reserved by real-time library");
+ AddSignal (65, "SIGRTMIN", "RTMIN", false, true , true , "real time signal 0");
+ AddSignal (66, "SIGRTMIN+1", "RTMIN+1", false, true , true , "real time signal 1");
+ AddSignal (67, "SIGRTMIN+2", "RTMIN+2", false, true , true , "real time signal 2");
+ AddSignal (68, "SIGRTMIN+3", "RTMIN+3", false, true , true , "real time signal 3");
+ AddSignal (69, "SIGRTMIN+4", "RTMIN+4", false, true , true , "real time signal 4");
+ AddSignal (70, "SIGRTMIN+5", "RTMIN+5", false, true , true , "real time signal 5");
+ AddSignal (71, "SIGRTMIN+6", "RTMIN+6", false, true , true , "real time signal 6");
+ AddSignal (72, "SIGRTMIN+7", "RTMIN+7", false, true , true , "real time signal 7");
+ AddSignal (73, "SIGRTMIN+8", "RTMIN+8", false, true , true , "real time signal 8");
+ AddSignal (74, "SIGRTMIN+9", "RTMIN+9", false, true , true , "real time signal 9");
+ AddSignal (75, "SIGRTMIN+10", "RTMIN+10", false, true , true , "real time signal 10");
+ AddSignal (76, "SIGRTMIN+11", "RTMIN+11", false, true , true , "real time signal 11");
+ AddSignal (77, "SIGRTMIN+12", "RTMIN+12", false, true , true , "real time signal 12");
+ AddSignal (78, "SIGRTMIN+13", "RTMIN+13", false, true , true , "real time signal 13");
+ AddSignal (79, "SIGRTMIN+14", "RTMIN+14", false, true , true , "real time signal 14");
+ AddSignal (80, "SIGRTMIN+15", "RTMIN+15", false, true , true , "real time signal 15");
+ AddSignal (81, "SIGRTMIN+16", "RTMIN+16", false, true , true , "real time signal 16");
+ AddSignal (82, "SIGRTMIN+17", "RTMIN+17", false, true , true , "real time signal 17");
+ AddSignal (83, "SIGRTMIN+18", "RTMIN+18", false, true , true , "real time signal 18");
+ AddSignal (84, "SIGRTMIN+19", "RTMIN+19", false, true , true , "real time signal 19");
+ AddSignal (85, "SIGRTMIN+20", "RTMIN+20", false, true , true , "real time signal 20");
+ AddSignal (86, "SIGRTMIN+21", "RTMIN+21", false, true , true , "real time signal 21");
+ AddSignal (87, "SIGRTMIN+22", "RTMIN+22", false, true , true , "real time signal 22");
+ AddSignal (88, "SIGRTMIN+23", "RTMIN+23", false, true , true , "real time signal 23");
+ AddSignal (89, "SIGRTMIN+24", "RTMIN+24", false, true , true , "real time signal 24");
+ AddSignal (90, "SIGRTMIN+25", "RTMIN+25", false, true , true , "real time signal 25");
+ AddSignal (91, "SIGRTMIN+26", "RTMIN+26", false, true , true , "real time signal 26");
+ AddSignal (92, "SIGRTMIN+27", "RTMIN+27", false, true , true , "real time signal 27");
+ AddSignal (93, "SIGRTMIN+28", "RTMIN+28", false, true , true , "real time signal 28");
+ AddSignal (94, "SIGRTMIN+29", "RTMIN+29", false, true , true , "real time signal 29");
+ AddSignal (95, "SIGRTMIN+30", "RTMIN+30", false, true , true , "real time signal 30");
+ AddSignal (96, "SIGRTMAX-30", "RTMAX-30", false, true , true , "real time signal 31");
+ AddSignal (97, "SIGRTMAX-29", "RTMAX-29", false, true , true , "real time signal 32");
+ AddSignal (98, "SIGRTMAX-28", "RTMAX-28", false, true , true , "real time signal 33");
+ AddSignal (99, "SIGRTMAX-27", "RTMAX-27", false, true , true , "real time signal 34");
+ AddSignal (100, "SIGRTMAX-26", "RTMAX-26", false, true , true , "real time signal 35");
+ AddSignal (101, "SIGRTMAX-25", "RTMAX-25", false, true , true , "real time signal 36");
+ AddSignal (102, "SIGRTMAX-24", "RTMAX-24", false, true , true , "real time signal 37");
+ AddSignal (103, "SIGRTMAX-23", "RTMAX-23", false, true , true , "real time signal 38");
+ AddSignal (104, "SIGRTMAX-22", "RTMAX-22", false, true , true , "real time signal 39");
+ AddSignal (105, "SIGRTMAX-21", "RTMAX-21", false, true , true , "real time signal 40");
+ AddSignal (106, "SIGRTMAX-20", "RTMAX-20", false, true , true , "real time signal 41");
+ AddSignal (107, "SIGRTMAX-19", "RTMAX-19", false, true , true , "real time signal 42");
+ AddSignal (108, "SIGRTMAX-18", "RTMAX-18", false, true , true , "real time signal 43");
+ AddSignal (109, "SIGRTMAX-17", "RTMAX-17", false, true , true , "real time signal 44");
+ AddSignal (110, "SIGRTMAX-16", "RTMAX-16", false, true , true , "real time signal 45");
+ AddSignal (111, "SIGRTMAX-15", "RTMAX-15", false, true , true , "real time signal 46");
+ AddSignal (112, "SIGRTMAX-14", "RTMAX-14", false, true , true , "real time signal 47");
+ AddSignal (113, "SIGRTMAX-13", "RTMAX-13", false, true , true , "real time signal 48");
+ AddSignal (114, "SIGRTMAX-12", "RTMAX-12", false, true , true , "real time signal 49");
+ AddSignal (115, "SIGRTMAX-11", "RTMAX-11", false, true , true , "real time signal 50");
+ AddSignal (116, "SIGRTMAX-10", "RTMAX-10", false, true , true , "real time signal 51");
+ AddSignal (117, "SIGRTMAX-9", "RTMAX-9", false, true , true , "real time signal 52");
+ AddSignal (118, "SIGRTMAX-8", "RTMAX-8", false, true , true , "real time signal 53");
+ AddSignal (119, "SIGRTMAX-7", "RTMAX-7", false, true , true , "real time signal 54");
+ AddSignal (120, "SIGRTMAX-6", "RTMAX-6", false, true , true , "real time signal 55");
+ AddSignal (121, "SIGRTMAX-5", "RTMAX-5", false, true , true , "real time signal 56");
+ AddSignal (122, "SIGRTMAX-4", "RTMAX-4", false, true , true , "real time signal 57");
+ AddSignal (123, "SIGRTMAX-3", "RTMAX-3", false, true , true , "real time signal 58");
+ AddSignal (124, "SIGRTMAX-2", "RTMAX-2", false, true , true , "real time signal 59");
+ AddSignal (125, "SIGRTMAX-1", "RTMAX-1", false, true , true , "real time signal 60");
+ AddSignal (126, "SIGRTMAX", "RTMAX", false, true , true , "real time signal 61");
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/FreeBSDSignals.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/FreeBSDSignals.h
new file mode 100644
index 0000000..b715c62
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/FreeBSDSignals.h
@@ -0,0 +1,31 @@
+//===-- FreeBSDSignals.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_FreeBSDSignals_H_
+#define liblldb_FreeBSDSignals_H_
+
+// Project includes
+#include "lldb/Target/UnixSignals.h"
+
+namespace lldb_private {
+
+/// FreeBSD specific set of Unix signals.
+class FreeBSDSignals : public UnixSignals
+{
+public:
+ FreeBSDSignals();
+
+private:
+ void
+ Reset() override;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_FreeBSDSignals_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp
new file mode 100644
index 0000000..4e355c6
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.cpp
@@ -0,0 +1,32 @@
+//===-- GDBRemoteSignals.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "GDBRemoteSignals.h"
+
+using namespace lldb_private;
+
+GDBRemoteSignals::GDBRemoteSignals()
+ : UnixSignals()
+{
+ Reset();
+}
+
+GDBRemoteSignals::GDBRemoteSignals(const lldb::UnixSignalsSP &rhs)
+ : UnixSignals(*rhs)
+{
+}
+
+void
+GDBRemoteSignals::Reset()
+{
+ m_signals.clear();
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.h
new file mode 100644
index 0000000..bbb631a
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/GDBRemoteSignals.h
@@ -0,0 +1,36 @@
+//===-- GDBRemoteSignals.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_GDBRemoteSignals_H_
+#define liblldb_GDBRemoteSignals_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/UnixSignals.h"
+
+namespace lldb_private {
+
+/// Empty set of Unix signals to be filled by PlatformRemoteGDBServer
+class GDBRemoteSignals : public UnixSignals
+{
+public:
+ GDBRemoteSignals();
+
+ GDBRemoteSignals(const lldb::UnixSignalsSP &rhs);
+
+private:
+ void
+ Reset() override;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_GDBRemoteSignals_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
new file mode 100644
index 0000000..206b829
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp
@@ -0,0 +1,101 @@
+//===-- HistoryThread.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-private.h"
+
+#include "Plugins/Process/Utility/HistoryUnwind.h"
+#include "Plugins/Process/Utility/HistoryThread.h"
+#include "Plugins/Process/Utility/RegisterContextHistory.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Target/StackFrameList.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Constructor
+
+HistoryThread::HistoryThread (lldb_private::Process &process,
+ lldb::tid_t tid,
+ std::vector<lldb::addr_t> pcs,
+ uint32_t stop_id,
+ bool stop_id_is_valid) :
+ Thread (process, tid, true),
+ m_framelist_mutex(),
+ m_framelist(),
+ m_pcs (pcs),
+ m_stop_id (stop_id),
+ m_stop_id_is_valid (stop_id_is_valid),
+ m_extended_unwind_token (LLDB_INVALID_ADDRESS),
+ m_queue_name (),
+ m_thread_name (),
+ m_originating_unique_thread_id (tid),
+ m_queue_id (LLDB_INVALID_QUEUE_ID)
+{
+ m_unwinder_ap.reset (new HistoryUnwind (*this, pcs, stop_id_is_valid));
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p HistoryThread::HistoryThread",
+ static_cast<void*>(this));
+}
+
+// Destructor
+
+HistoryThread::~HistoryThread ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p HistoryThread::~HistoryThread (tid=0x%" PRIx64 ")",
+ static_cast<void*>(this), GetID());
+ DestroyThread();
+}
+
+lldb::RegisterContextSP
+HistoryThread::GetRegisterContext ()
+{
+ RegisterContextSP rctx ;
+ if (m_pcs.size() > 0)
+ {
+ rctx.reset (new RegisterContextHistory (*this, 0, GetProcess()->GetAddressByteSize(), m_pcs[0]));
+ }
+ return rctx;
+
+}
+
+lldb::RegisterContextSP
+HistoryThread::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ return m_unwinder_ap->CreateRegisterContextForFrame (frame);
+}
+
+lldb::StackFrameListSP
+HistoryThread::GetStackFrameList ()
+{
+ Mutex::Locker (m_framelist_mutex); // FIXME do not throw away the lock after we acquire it..
+ if (m_framelist.get() == NULL)
+ {
+ m_framelist.reset (new StackFrameList (*this, StackFrameListSP(), true));
+ }
+
+ return m_framelist;
+}
+
+uint32_t
+HistoryThread::GetExtendedBacktraceOriginatingIndexID ()
+{
+ if (m_originating_unique_thread_id != LLDB_INVALID_THREAD_ID)
+ {
+ if (GetProcess()->HasAssignedIndexIDToThread (m_originating_unique_thread_id))
+ {
+ return GetProcess()->AssignIndexIDToThread (m_originating_unique_thread_id);
+ }
+ }
+ return LLDB_INVALID_THREAD_ID;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h
new file mode 100644
index 0000000..51173c6
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h
@@ -0,0 +1,136 @@
+//===-- HistoryThread.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_HistoryThread_h_
+#define liblldb_HistoryThread_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Core/UserSettingsController.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/StackFrameList.h"
+#include "lldb/Target/Thread.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class HistoryThread HistoryThread.h "HistoryThread.h"
+/// @brief A thread object representing a backtrace from a previous point in the process execution
+///
+/// This subclass of Thread is used to provide a backtrace from earlier in
+/// process execution. It is given a backtrace list of pc addresses and
+/// optionally a stop_id of when those pc addresses were collected, and it will
+/// create stack frames for them.
+//----------------------------------------------------------------------
+
+class HistoryThread : public lldb_private::Thread
+{
+public:
+ HistoryThread (lldb_private::Process &process, lldb::tid_t tid, std::vector<lldb::addr_t> pcs, uint32_t stop_id, bool stop_id_is_valid);
+
+ virtual ~HistoryThread ();
+
+ virtual lldb::RegisterContextSP
+ GetRegisterContext ();
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (StackFrame *frame);
+
+ virtual void
+ RefreshStateAfterStop() { }
+
+ bool
+ CalculateStopInfo () { return false; }
+
+ void
+ SetExtendedBacktraceToken (uint64_t token)
+ {
+ m_extended_unwind_token = token;
+ }
+
+ uint64_t
+ GetExtendedBacktraceToken ()
+ {
+ return m_extended_unwind_token;
+ }
+
+ const char *
+ GetQueueName ()
+ {
+ return m_queue_name.c_str();
+ }
+
+ void
+ SetQueueName (const char *name)
+ {
+ m_queue_name = name;
+ }
+
+ lldb::queue_id_t
+ GetQueueID ()
+ {
+ return m_queue_id;
+ }
+
+ void
+ SetQueueID (lldb::queue_id_t queue)
+ {
+ m_queue_id = queue;
+ }
+
+ const char *
+ GetThreadName ()
+ {
+ return m_thread_name.c_str();
+ }
+
+ uint32_t
+ GetExtendedBacktraceOriginatingIndexID ();
+
+ void
+ SetThreadName (const char *name)
+ {
+ m_thread_name = name;
+ }
+
+ virtual const char *
+ GetName ()
+ {
+ return m_thread_name.c_str();
+ }
+
+ virtual void
+ SetName(const char *name)
+ {
+ m_thread_name = name;
+ }
+
+protected:
+ virtual lldb::StackFrameListSP
+ GetStackFrameList ();
+
+ mutable Mutex m_framelist_mutex;
+ lldb::StackFrameListSP m_framelist;
+ std::vector<lldb::addr_t> m_pcs;
+ uint32_t m_stop_id;
+ bool m_stop_id_is_valid;
+
+ uint64_t m_extended_unwind_token;
+ std::string m_queue_name;
+ std::string m_thread_name;
+ lldb::tid_t m_originating_unique_thread_id;
+ lldb::queue_id_t m_queue_id;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_HistoryThread_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp
new file mode 100644
index 0000000..14afcbe
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp
@@ -0,0 +1,81 @@
+//===-- HistoryUnwind.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-private.h"
+
+#include "Plugins/Process/Utility/RegisterContextHistory.h"
+#include "Plugins/Process/Utility/HistoryUnwind.h"
+
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Constructor
+
+HistoryUnwind::HistoryUnwind (Thread &thread,
+ std::vector<lldb::addr_t> pcs,
+ bool stop_id_is_valid) :
+ Unwind (thread),
+ m_pcs (pcs),
+ m_stop_id_is_valid (stop_id_is_valid)
+{
+}
+
+// Destructor
+
+HistoryUnwind::~HistoryUnwind ()
+{
+}
+
+void
+HistoryUnwind::DoClear ()
+{
+ Mutex::Locker locker(m_unwind_mutex);
+ m_pcs.clear();
+ m_stop_id_is_valid = false;
+}
+
+lldb::RegisterContextSP
+HistoryUnwind::DoCreateRegisterContextForFrame (StackFrame *frame)
+{
+ RegisterContextSP rctx;
+ if (frame)
+ {
+ addr_t pc = frame->GetFrameCodeAddress().GetLoadAddress (&frame->GetThread()->GetProcess()->GetTarget());
+ if (pc != LLDB_INVALID_ADDRESS)
+ {
+ rctx.reset (new RegisterContextHistory (*frame->GetThread().get(), frame->GetConcreteFrameIndex(),
+ frame->GetThread()->GetProcess()->GetAddressByteSize(), pc));
+ }
+ }
+ return rctx;
+}
+
+bool
+HistoryUnwind::DoGetFrameInfoAtIndex (uint32_t frame_idx, lldb::addr_t& cfa, lldb::addr_t& pc)
+{
+ Mutex::Locker (m_unwind_mutex); // FIXME do not throw away the lock after we acquire it..
+ if (frame_idx < m_pcs.size())
+ {
+ cfa = frame_idx;
+ pc = m_pcs[frame_idx];
+ return true;
+ }
+ return false;
+}
+
+uint32_t
+HistoryUnwind::DoGetFrameCount ()
+{
+ return m_pcs.size();
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryUnwind.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryUnwind.h
new file mode 100644
index 0000000..733f93e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryUnwind.h
@@ -0,0 +1,50 @@
+//===-- HistoryUnwind.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_HistoryUnwind_h_
+#define liblldb_HistoryUnwind_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Unwind.h"
+
+namespace lldb_private {
+
+class HistoryUnwind : public lldb_private::Unwind
+{
+public:
+ HistoryUnwind (Thread &thread, std::vector<lldb::addr_t> pcs, bool stop_id_is_valid);
+
+ virtual ~HistoryUnwind ();
+
+protected:
+ void
+ DoClear();
+
+ lldb::RegisterContextSP
+ DoCreateRegisterContextForFrame (StackFrame *frame);
+
+ bool
+ DoGetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& pc);
+ uint32_t
+ DoGetFrameCount ();
+
+private:
+
+ std::vector<lldb::addr_t> m_pcs;
+ bool m_stop_id_is_valid;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_HistoryUnwind_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
new file mode 100644
index 0000000..3923c54
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -0,0 +1,280 @@
+//===-- InferiorCallPOSIX.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InferiorCallPOSIX.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Host/Config.h"
+
+#ifndef LLDB_DISABLE_POSIX
+#include <sys/mman.h>
+#else
+// define them
+#define PROT_NONE 0
+#define PROT_READ 1
+#define PROT_WRITE 2
+#define PROT_EXEC 4
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool
+lldb_private::InferiorCallMmap (Process *process,
+ addr_t &allocated_addr,
+ addr_t addr,
+ addr_t length,
+ unsigned prot,
+ unsigned flags,
+ addr_t fd,
+ addr_t offset)
+{
+ Thread *thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL)
+ return false;
+
+ const bool append = true;
+ const bool include_symbols = true;
+ const bool include_inlines = false;
+ SymbolContextList sc_list;
+ const uint32_t count
+ = process->GetTarget().GetImages().FindFunctions (ConstString ("mmap"),
+ eFunctionNameTypeFull,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ if (count > 0)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc))
+ {
+ const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = false;
+ EvaluateExpressionOptions options;
+ options.SetStopOthers(true);
+ options.SetUnwindOnError(true);
+ options.SetIgnoreBreakpoints(true);
+ options.SetTryAllThreads(true);
+ options.SetDebug (false);
+ options.SetTimeoutUsec(500000);
+
+ addr_t prot_arg, flags_arg = 0;
+ if (prot == eMmapProtNone)
+ prot_arg = PROT_NONE;
+ else {
+ prot_arg = 0;
+ if (prot & eMmapProtExec)
+ prot_arg |= PROT_EXEC;
+ if (prot & eMmapProtRead)
+ prot_arg |= PROT_READ;
+ if (prot & eMmapProtWrite)
+ prot_arg |= PROT_WRITE;
+ }
+
+ const ArchSpec arch = process->GetTarget().GetArchitecture();
+ flags_arg = process->GetTarget().GetPlatform()->ConvertMmapFlagsToPlatform(arch,flags);
+
+ AddressRange mmap_range;
+ if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, mmap_range))
+ {
+ ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
+ ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ lldb::addr_t args[] = { addr, length, prot_arg, flags_arg, fd, offset };
+ lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread,
+ mmap_range.GetBaseAddress(),
+ clang_void_ptr_type,
+ args,
+ options));
+ if (call_plan_sp)
+ {
+ StreamFile error_strm;
+ // This plan is a utility plan, so set it to discard itself when done.
+ call_plan_sp->SetIsMasterPlan (true);
+ call_plan_sp->SetOkayToDiscard(true);
+
+ StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+ if (frame)
+ {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext (exe_ctx);
+ ExpressionResults result = process->RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ options,
+ error_strm);
+ if (result == eExpressionCompleted)
+ {
+
+ allocated_addr = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ if (process->GetAddressByteSize() == 4)
+ {
+ if (allocated_addr == UINT32_MAX)
+ return false;
+ }
+ else if (process->GetAddressByteSize() == 8)
+ {
+ if (allocated_addr == UINT64_MAX)
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool
+lldb_private::InferiorCallMunmap (Process *process,
+ addr_t addr,
+ addr_t length)
+{
+ Thread *thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL)
+ return false;
+
+ const bool append = true;
+ const bool include_symbols = true;
+ const bool include_inlines = false;
+ SymbolContextList sc_list;
+ const uint32_t count
+ = process->GetTarget().GetImages().FindFunctions (ConstString ("munmap"),
+ eFunctionNameTypeFull,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ if (count > 0)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc))
+ {
+ const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = false;
+ EvaluateExpressionOptions options;
+ options.SetStopOthers(true);
+ options.SetUnwindOnError(true);
+ options.SetIgnoreBreakpoints(true);
+ options.SetTryAllThreads(true);
+ options.SetDebug (false);
+ options.SetTimeoutUsec(500000);
+
+ AddressRange munmap_range;
+ if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range))
+ {
+ lldb::addr_t args[] = { addr, length };
+ lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread,
+ munmap_range.GetBaseAddress(),
+ ClangASTType(),
+ args,
+ options));
+ if (call_plan_sp)
+ {
+ StreamFile error_strm;
+ // This plan is a utility plan, so set it to discard itself when done.
+ call_plan_sp->SetIsMasterPlan (true);
+ call_plan_sp->SetOkayToDiscard(true);
+
+ StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+ if (frame)
+ {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext (exe_ctx);
+ ExpressionResults result = process->RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ options,
+ error_strm);
+ if (result == eExpressionCompleted)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+// FIXME: This has nothing to do with Posix, it is just a convenience function that calls a
+// function of the form "void * (*)(void)". We should find a better place to put this.
+
+bool
+lldb_private::InferiorCall (Process *process,
+ const Address *address,
+ addr_t &returned_func)
+{
+ Thread *thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL || address == NULL)
+ return false;
+
+ EvaluateExpressionOptions options;
+ options.SetStopOthers(true);
+ options.SetUnwindOnError(true);
+ options.SetIgnoreBreakpoints(true);
+ options.SetTryAllThreads(true);
+ options.SetDebug (false);
+ options.SetTimeoutUsec(500000);
+
+ ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
+ ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread,
+ *address,
+ clang_void_ptr_type,
+ llvm::ArrayRef<addr_t>(),
+ options));
+ if (call_plan_sp)
+ {
+ StreamString error_strm;
+ // This plan is a utility plan, so set it to discard itself when done.
+ call_plan_sp->SetIsMasterPlan (true);
+ call_plan_sp->SetOkayToDiscard(true);
+
+ StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+ if (frame)
+ {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext (exe_ctx);
+ ExpressionResults result = process->RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ options,
+ error_strm);
+ if (result == eExpressionCompleted)
+ {
+ returned_func = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+
+ if (process->GetAddressByteSize() == 4)
+ {
+ if (returned_func == UINT32_MAX)
+ return false;
+ }
+ else if (process->GetAddressByteSize() == 8)
+ {
+ if (returned_func == UINT64_MAX)
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h
new file mode 100644
index 0000000..e56e95c
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.h
@@ -0,0 +1,38 @@
+//===-- InferiorCallPOSIX.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_InferiorCallPOSIX_h_
+#define lldb_InferiorCallPOSIX_h_
+
+// Inferior execution of POSIX functions.
+
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+
+class Process;
+
+enum MmapProt {
+ eMmapProtNone = 0,
+ eMmapProtExec = 1,
+ eMmapProtRead = 2,
+ eMmapProtWrite = 4
+};
+
+bool InferiorCallMmap(Process *proc, lldb::addr_t &allocated_addr,
+ lldb::addr_t addr, lldb::addr_t length, unsigned prot,
+ unsigned flags, lldb::addr_t fd, lldb::addr_t offset);
+
+bool InferiorCallMunmap(Process *proc, lldb::addr_t addr, lldb::addr_t length);
+
+bool InferiorCall(Process *proc, const Address *address, lldb::addr_t &returned_func);
+
+} // namespace lldb_private
+
+#endif // lldb_InferiorCallPOSIX_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InstructionUtils.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InstructionUtils.h
new file mode 100644
index 0000000..6226fbc
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InstructionUtils.h
@@ -0,0 +1,138 @@
+//===-- InstructionUtils.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_InstructionUtils_h_
+#define lldb_InstructionUtils_h_
+
+// Common utilities for manipulating instruction bit fields.
+
+namespace lldb_private {
+
+// Return the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 64-bit unsigned value.
+static inline uint64_t
+Bits64 (const uint64_t bits, const uint32_t msbit, const uint32_t lsbit)
+{
+ assert(msbit < 64 && lsbit <= msbit);
+ return (bits >> lsbit) & ((1ull << (msbit - lsbit + 1)) - 1);
+}
+
+// Return the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 32-bit unsigned value.
+static inline uint32_t
+Bits32 (const uint32_t bits, const uint32_t msbit, const uint32_t lsbit)
+{
+ assert(msbit < 32 && lsbit <= msbit);
+ return (bits >> lsbit) & ((1u << (msbit - lsbit + 1)) - 1);
+}
+
+// Return the bit value from the 'bit' position of a 32-bit unsigned value.
+static inline uint32_t
+Bit32 (const uint32_t bits, const uint32_t bit)
+{
+ return (bits >> bit) & 1u;
+}
+
+static inline uint64_t
+Bit64 (const uint64_t bits, const uint32_t bit)
+{
+ return (bits >> bit) & 1ull;
+}
+
+// Set the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 32-bit unsigned value to 'val'.
+static inline void
+SetBits32(uint32_t &bits, const uint32_t msbit, const uint32_t lsbit, const uint32_t val)
+{
+ assert(msbit < 32 && lsbit < 32 && msbit >= lsbit);
+ uint32_t mask = ((1u << (msbit - lsbit + 1)) - 1);
+ bits &= ~(mask << lsbit);
+ bits |= (val & mask) << lsbit;
+}
+
+// Set the 'bit' position of a 32-bit unsigned value to 'val'.
+static inline void
+SetBit32(uint32_t &bits, const uint32_t bit, const uint32_t val)
+{
+ SetBits32(bits, bit, bit, val);
+}
+
+// Rotate a 32-bit unsigned value right by the specified amount.
+static inline uint32_t
+Rotr32 (uint32_t bits, uint32_t amt)
+{
+ assert(amt < 32 && "Invalid rotate amount");
+ return (bits >> amt) | (bits << ((32-amt)&31));
+}
+
+// Rotate a 32-bit unsigned value left by the specified amount.
+static inline uint32_t
+Rotl32 (uint32_t bits, uint32_t amt)
+{
+ assert(amt < 32 && "Invalid rotate amount");
+ return (bits << amt) | (bits >> ((32-amt)&31));
+}
+
+// Create a mask that starts at bit zero and includes "bit"
+static inline uint64_t
+MaskUpToBit (const uint64_t bit)
+{
+ if (bit >= 63)
+ return -1ll;
+ return (1ull << (bit + 1ull)) - 1ull;
+}
+
+// Return an integer result equal to the number of bits of x that are ones.
+static inline uint32_t
+BitCount (uint64_t x)
+{
+ // c accumulates the total bits set in x
+ uint32_t c;
+ for (c = 0; x; ++c)
+ {
+ x &= x - 1; // clear the least significant bit set
+ }
+ return c;
+}
+
+static inline bool
+BitIsSet (const uint64_t value, const uint64_t bit)
+{
+ return (value & (1ull << bit)) != 0;
+}
+
+static inline bool
+BitIsClear (const uint64_t value, const uint64_t bit)
+{
+ return (value & (1ull << bit)) == 0;
+}
+
+static inline uint64_t
+UnsignedBits (const uint64_t value, const uint64_t msbit, const uint64_t lsbit)
+{
+ uint64_t result = value >> lsbit;
+ result &= MaskUpToBit (msbit - lsbit);
+ return result;
+}
+
+static inline int64_t
+SignedBits (const uint64_t value, const uint64_t msbit, const uint64_t lsbit)
+{
+ uint64_t result = UnsignedBits (value, msbit, lsbit);
+ if (BitIsSet(value, msbit))
+ {
+ // Sign extend
+ result |= ~MaskUpToBit (msbit - lsbit);
+ }
+ return result;
+}
+
+} // namespace lldb_private
+
+#endif // lldb_InstructionUtils_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp
new file mode 100644
index 0000000..cd1fc81
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp
@@ -0,0 +1,95 @@
+//===-- LinuxSignals.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "LinuxSignals.h"
+
+using namespace lldb_private;
+
+LinuxSignals::LinuxSignals()
+ : UnixSignals()
+{
+ Reset();
+}
+
+void
+LinuxSignals::Reset()
+{
+ m_signals.clear();
+
+ AddSignal (1, "SIGHUP", "HUP", false, true , true , "hangup");
+ AddSignal (2, "SIGINT", "INT", true , true , true , "interrupt");
+ AddSignal (3, "SIGQUIT", "QUIT", false, true , true , "quit");
+ AddSignal (4, "SIGILL", "ILL", false, true , true , "illegal instruction");
+ AddSignal (5, "SIGTRAP", "TRAP", true , true , true , "trace trap (not reset when caught)");
+ AddSignal (6, "SIGABRT", "ABRT", false, true , true , "abort()");
+ AddSignal (6, "SIGIOT", "IOT", false, true , true , "IOT trap");
+ AddSignal (7, "SIGBUS", "BUS", false, true , true , "bus error");
+ AddSignal (8, "SIGFPE", "FPE", false, true , true , "floating point exception");
+ AddSignal (9, "SIGKILL", "KILL", false, true , true , "kill");
+ AddSignal (10, "SIGUSR1", "USR1", false, true , true , "user defined signal 1");
+ AddSignal (11, "SIGSEGV", "SEGV", false, true , true , "segmentation violation");
+ AddSignal (12, "SIGUSR2", "USR2", false, true , true , "user defined signal 2");
+ AddSignal (13, "SIGPIPE", "PIPE", false, true , true , "write to pipe with reading end closed");
+ AddSignal (14, "SIGALRM", "ALRM", false, false, false, "alarm");
+ AddSignal (15, "SIGTERM", "TERM", false, true , true , "termination requested");
+ AddSignal (16, "SIGSTKFLT", "STKFLT", false, true , true , "stack fault");
+ AddSignal (16, "SIGCLD", "CLD", false, false, true , "same as SIGCHLD");
+ AddSignal (17, "SIGCHLD", "CHLD", false, false, true , "child status has changed");
+ AddSignal (18, "SIGCONT", "CONT", false, true , true , "process continue");
+ AddSignal (19, "SIGSTOP", "STOP", true , true , true , "process stop");
+ AddSignal (20, "SIGTSTP", "TSTP", false, true , true , "tty stop");
+ AddSignal (21, "SIGTTIN", "TTIN", false, true , true , "background tty read");
+ AddSignal (22, "SIGTTOU", "TTOU", false, true , true , "background tty write");
+ AddSignal (23, "SIGURG", "URG", false, true , true , "urgent data on socket");
+ AddSignal (24, "SIGXCPU", "XCPU", false, true , true , "CPU resource exceeded");
+ AddSignal (25, "SIGXFSZ", "XFSZ", false, true , true , "file size limit exceeded");
+ AddSignal (26, "SIGVTALRM", "VTALRM", false, true , true , "virtual time alarm");
+ AddSignal (27, "SIGPROF", "PROF", false, false, false, "profiling time alarm");
+ AddSignal (28, "SIGWINCH", "WINCH", false, true , true , "window size changes");
+ AddSignal (29, "SIGPOLL", "POLL", false, true , true , "pollable event");
+ AddSignal (29, "SIGIO", "IO", false, true , true , "input/output ready");
+ AddSignal (30, "SIGPWR", "PWR", false, true , true , "power failure");
+ AddSignal (31, "SIGSYS", "SYS", false, true , true , "invalid system call");
+ AddSignal (32, "SIG32", "SIG32", false, true , true , "threading library internal signal 1");
+ AddSignal (33, "SIG33", "SIG33", false, true , true , "threading library internal signal 2");
+ AddSignal (34, "SIGRTMIN", "RTMIN", false, true , true , "real time signal 0");
+ AddSignal (35, "SIGRTMIN+1", "RTMIN+1", false, true , true , "real time signal 1");
+ AddSignal (36, "SIGRTMIN+2", "RTMIN+2", false, true , true , "real time signal 2");
+ AddSignal (37, "SIGRTMIN+3", "RTMIN+3", false, true , true , "real time signal 3");
+ AddSignal (38, "SIGRTMIN+4", "RTMIN+4", false, true , true , "real time signal 4");
+ AddSignal (39, "SIGRTMIN+5", "RTMIN+5", false, true , true , "real time signal 5");
+ AddSignal (40, "SIGRTMIN+6", "RTMIN+6", false, true , true , "real time signal 6");
+ AddSignal (41, "SIGRTMIN+7", "RTMIN+7", false, true , true , "real time signal 7");
+ AddSignal (42, "SIGRTMIN+8", "RTMIN+8", false, true , true , "real time signal 8");
+ AddSignal (43, "SIGRTMIN+9", "RTMIN+9", false, true , true , "real time signal 9");
+ AddSignal (44, "SIGRTMIN+10", "RTMIN+10", false, true , true , "real time signal 10");
+ AddSignal (45, "SIGRTMIN+11", "RTMIN+11", false, true , true , "real time signal 11");
+ AddSignal (46, "SIGRTMIN+12", "RTMIN+12", false, true , true , "real time signal 12");
+ AddSignal (47, "SIGRTMIN+13", "RTMIN+13", false, true , true , "real time signal 13");
+ AddSignal (48, "SIGRTMIN+14", "RTMIN+14", false, true , true , "real time signal 14");
+ AddSignal (49, "SIGRTMIN+15", "RTMIN+15", false, true , true , "real time signal 15");
+ AddSignal (50, "SIGRTMAX-14", "RTMAX-14", false, true , true , "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output
+ AddSignal (51, "SIGRTMAX-13", "RTMAX-13", false, true , true , "real time signal 17");
+ AddSignal (52, "SIGRTMAX-12", "RTMAX-12", false, true , true , "real time signal 18");
+ AddSignal (53, "SIGRTMAX-11", "RTMAX-11", false, true , true , "real time signal 19");
+ AddSignal (54, "SIGRTMAX-10", "RTMAX-10", false, true , true , "real time signal 20");
+ AddSignal (55, "SIGRTMAX-9", "RTMAX-9", false, true , true , "real time signal 21");
+ AddSignal (56, "SIGRTMAX-8", "RTMAX-8", false, true , true , "real time signal 22");
+ AddSignal (57, "SIGRTMAX-7", "RTMAX-7", false, true , true , "real time signal 23");
+ AddSignal (58, "SIGRTMAX-6", "RTMAX-6", false, true , true , "real time signal 24");
+ AddSignal (59, "SIGRTMAX-5", "RTMAX-5", false, true , true , "real time signal 25");
+ AddSignal (60, "SIGRTMAX-4", "RTMAX-4", false, true , true , "real time signal 26");
+ AddSignal (61, "SIGRTMAX-3", "RTMAX-3", false, true , true , "real time signal 27");
+ AddSignal (62, "SIGRTMAX-2", "RTMAX-2", false, true , true , "real time signal 28");
+ AddSignal (63, "SIGRTMAX-1", "RTMAX-1", false, true , true , "real time signal 29");
+ AddSignal (64, "SIGRTMAX", "RTMAX", false, true , true , "real time signal 30");
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/LinuxSignals.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/LinuxSignals.h
new file mode 100644
index 0000000..dd9062f
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/LinuxSignals.h
@@ -0,0 +1,34 @@
+//===-- LinuxSignals.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_LinuxSignals_H_
+#define liblldb_LinuxSignals_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/UnixSignals.h"
+
+namespace lldb_private {
+
+/// Linux specific set of Unix signals.
+class LinuxSignals : public UnixSignals
+{
+public:
+ LinuxSignals();
+
+private:
+ void
+ Reset() override;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_LinuxSignals_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp
new file mode 100644
index 0000000..1dc0be8
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp
@@ -0,0 +1,95 @@
+//===-- MipsLinuxSignals.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "MipsLinuxSignals.h"
+
+using namespace lldb_private;
+
+MipsLinuxSignals::MipsLinuxSignals()
+ : UnixSignals()
+{
+ Reset();
+}
+
+void
+MipsLinuxSignals::Reset()
+{
+ m_signals.clear();
+
+ AddSignal (1, "SIGHUP", "HUP", false, true , true , "hangup");
+ AddSignal (2, "SIGINT", "INT", true , true , true , "interrupt");
+ AddSignal (3, "SIGQUIT", "QUIT", false, true , true , "quit");
+ AddSignal (4, "SIGILL", "ILL", false, true , true , "illegal instruction");
+ AddSignal (5, "SIGTRAP", "TRAP", true , true , true , "trace trap (not reset when caught)");
+ AddSignal (6, "SIGABRT", "ABRT", false, true , true , "abort()");
+ AddSignal (6, "SIGIOT", "IOT", false, true , true , "IOT trap");
+ AddSignal (7, "SIGEMT", "EMT", false, true , true , "terminate process with core dump");
+ AddSignal (8, "SIGFPE", "FPE", false, true , true , "floating point exception");
+ AddSignal (9, "SIGKILL", "KILL", false, true , true , "kill");
+ AddSignal (10, "SIGBUS", "BUS", false, true , true , "bus error");
+ AddSignal (11, "SIGSEGV", "SEGV", false, true , true , "segmentation violation");
+ AddSignal (12, "SIGSYS", "SYS", false, true , true , "invalid system call");
+ AddSignal (13, "SIGPIPE", "PIPE", false, true , true , "write to pipe with reading end closed");
+ AddSignal (14, "SIGALRM", "ALRM", false, false, false, "alarm");
+ AddSignal (15, "SIGTERM", "TERM", false, true , true , "termination requested");
+ AddSignal (16, "SIGUSR1", "USR1", false, true , true , "user defined signal 1");
+ AddSignal (17, "SIGUSR2", "USR2", false, true , true , "user defined signal 2");
+ AddSignal (18, "SIGCLD", "CLD", false, false, true , "same as SIGCHLD");
+ AddSignal (18, "SIGCHLD", "CHLD", false, false, true , "child status has changed");
+ AddSignal (19, "SIGPWR", "PWR", false, true , true , "power failure");
+ AddSignal (20, "SIGWINCH", "WINCH", false, true , true , "window size changes");
+ AddSignal (21, "SIGURG", "URG", false, true , true , "urgent data on socket");
+ AddSignal (22, "SIGIO", "IO", false, true , true , "input/output ready");
+ AddSignal (22, "SIGPOLL", "POLL", false, true , true , "pollable event");
+ AddSignal (23, "SIGSTOP", "STOP", true , true , true , "process stop");
+ AddSignal (24, "SIGTSTP", "TSTP", false, true , true , "tty stop");
+ AddSignal (25, "SIGCONT", "CONT", false, true , true , "process continue");
+ AddSignal (26, "SIGTTIN", "TTIN", false, true , true , "background tty read");
+ AddSignal (27, "SIGTTOU", "TTOU", false, true , true , "background tty write");
+ AddSignal (28, "SIGVTALRM", "VTALRM", false, true , true , "virtual time alarm");
+ AddSignal (29, "SIGPROF", "PROF", false, false, false, "profiling time alarm");
+ AddSignal (30, "SIGXCPU", "XCPU", false, true , true , "CPU resource exceeded");
+ AddSignal (31, "SIGXFSZ", "XFSZ", false, true , true , "file size limit exceeded");
+ AddSignal (32, "SIG32", "SIG32", false, true , true , "threading library internal signal 1");
+ AddSignal (33, "SIG33", "SIG33", false, true , true , "threading library internal signal 2");
+ AddSignal (34, "SIGRTMIN", "RTMIN", false, true , true , "real time signal 0");
+ AddSignal (35, "SIGRTMIN+1", "RTMIN+1", false, true , true , "real time signal 1");
+ AddSignal (36, "SIGRTMIN+2", "RTMIN+2", false, true , true , "real time signal 2");
+ AddSignal (37, "SIGRTMIN+3", "RTMIN+3", false, true , true , "real time signal 3");
+ AddSignal (38, "SIGRTMIN+4", "RTMIN+4", false, true , true , "real time signal 4");
+ AddSignal (39, "SIGRTMIN+5", "RTMIN+5", false, true , true , "real time signal 5");
+ AddSignal (40, "SIGRTMIN+6", "RTMIN+6", false, true , true , "real time signal 6");
+ AddSignal (41, "SIGRTMIN+7", "RTMIN+7", false, true , true , "real time signal 7");
+ AddSignal (42, "SIGRTMIN+8", "RTMIN+8", false, true , true , "real time signal 8");
+ AddSignal (43, "SIGRTMIN+9", "RTMIN+9", false, true , true , "real time signal 9");
+ AddSignal (44, "SIGRTMIN+10", "RTMIN+10", false, true , true , "real time signal 10");
+ AddSignal (45, "SIGRTMIN+11", "RTMIN+11", false, true , true , "real time signal 11");
+ AddSignal (46, "SIGRTMIN+12", "RTMIN+12", false, true , true , "real time signal 12");
+ AddSignal (47, "SIGRTMIN+13", "RTMIN+13", false, true , true , "real time signal 13");
+ AddSignal (48, "SIGRTMIN+14", "RTMIN+14", false, true , true , "real time signal 14");
+ AddSignal (49, "SIGRTMIN+15", "RTMIN+15", false, true , true , "real time signal 15");
+ AddSignal (50, "SIGRTMAX-14", "RTMAX-14", false, true , true , "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output
+ AddSignal (51, "SIGRTMAX-13", "RTMAX-13", false, true , true , "real time signal 17");
+ AddSignal (52, "SIGRTMAX-12", "RTMAX-12", false, true , true , "real time signal 18");
+ AddSignal (53, "SIGRTMAX-11", "RTMAX-11", false, true , true , "real time signal 19");
+ AddSignal (54, "SIGRTMAX-10", "RTMAX-10", false, true , true , "real time signal 20");
+ AddSignal (55, "SIGRTMAX-9", "RTMAX-9", false, true , true , "real time signal 21");
+ AddSignal (56, "SIGRTMAX-8", "RTMAX-8", false, true , true , "real time signal 22");
+ AddSignal (57, "SIGRTMAX-7", "RTMAX-7", false, true , true , "real time signal 23");
+ AddSignal (58, "SIGRTMAX-6", "RTMAX-6", false, true , true , "real time signal 24");
+ AddSignal (59, "SIGRTMAX-5", "RTMAX-5", false, true , true , "real time signal 25");
+ AddSignal (60, "SIGRTMAX-4", "RTMAX-4", false, true , true , "real time signal 26");
+ AddSignal (61, "SIGRTMAX-3", "RTMAX-3", false, true , true , "real time signal 27");
+ AddSignal (62, "SIGRTMAX-2", "RTMAX-2", false, true , true , "real time signal 28");
+ AddSignal (63, "SIGRTMAX-1", "RTMAX-1", false, true , true , "real time signal 29");
+ AddSignal (64, "SIGRTMAX", "RTMAX", false, true , true , "real time signal 30");
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.h
new file mode 100644
index 0000000..a5041b5
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.h
@@ -0,0 +1,34 @@
+//===-- MipsLinuxSignals.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MipsLinuxSignals_H_
+#define liblldb_MipsLinuxSignals_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/UnixSignals.h"
+
+namespace lldb_private {
+
+/// Linux specific set of Unix signals.
+class MipsLinuxSignals : public UnixSignals
+{
+public:
+ MipsLinuxSignals();
+
+private:
+ void
+ Reset() override;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_MipsLinuxSignals_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
new file mode 100644
index 0000000..4138a6a
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
@@ -0,0 +1,1228 @@
+//===-- RegisterContextDarwin_arm.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+#include "RegisterContextDarwin_arm.h"
+
+// C Includes
+#include <mach/mach_types.h>
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+#include "Plugins/Process/Utility/InstructionUtils.h"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "ARM_GCC_Registers.h"
+#include "ARM_DWARF_Registers.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gpr_r0 = 0,
+ 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_r13, gpr_sp = gpr_r13,
+ gpr_r14, gpr_lr = gpr_r14,
+ gpr_r15, gpr_pc = gpr_r15,
+ gpr_cpsr,
+
+ 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,
+
+ exc_exception,
+ exc_fsr,
+ exc_far,
+
+ dbg_bvr0,
+ dbg_bvr1,
+ dbg_bvr2,
+ dbg_bvr3,
+ dbg_bvr4,
+ dbg_bvr5,
+ dbg_bvr6,
+ dbg_bvr7,
+ dbg_bvr8,
+ dbg_bvr9,
+ dbg_bvr10,
+ dbg_bvr11,
+ dbg_bvr12,
+ dbg_bvr13,
+ dbg_bvr14,
+ dbg_bvr15,
+
+ dbg_bcr0,
+ dbg_bcr1,
+ dbg_bcr2,
+ dbg_bcr3,
+ dbg_bcr4,
+ dbg_bcr5,
+ dbg_bcr6,
+ dbg_bcr7,
+ dbg_bcr8,
+ dbg_bcr9,
+ dbg_bcr10,
+ dbg_bcr11,
+ dbg_bcr12,
+ dbg_bcr13,
+ dbg_bcr14,
+ dbg_bcr15,
+
+ dbg_wvr0,
+ dbg_wvr1,
+ dbg_wvr2,
+ dbg_wvr3,
+ dbg_wvr4,
+ dbg_wvr5,
+ dbg_wvr6,
+ dbg_wvr7,
+ dbg_wvr8,
+ dbg_wvr9,
+ dbg_wvr10,
+ dbg_wvr11,
+ dbg_wvr12,
+ dbg_wvr13,
+ dbg_wvr14,
+ dbg_wvr15,
+
+ dbg_wcr0,
+ dbg_wcr1,
+ dbg_wcr2,
+ dbg_wcr3,
+ dbg_wcr4,
+ dbg_wcr5,
+ dbg_wcr6,
+ dbg_wcr7,
+ dbg_wcr8,
+ dbg_wcr9,
+ dbg_wcr10,
+ dbg_wcr11,
+ dbg_wcr12,
+ dbg_wcr13,
+ dbg_wcr14,
+ dbg_wcr15,
+
+ k_num_registers
+};
+
+
+RegisterContextDarwin_arm::RegisterContextDarwin_arm(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContext(thread, concrete_frame_idx),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_arm::~RegisterContextDarwin_arm()
+{
+}
+
+
+#define GPR_OFFSET(idx) ((idx) * 4)
+#define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextDarwin_arm::GPR))
+#define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU))
+#define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextDarwin_arm::DBG, reg) + sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU) + sizeof (RegisterContextDarwin_arm::EXC)))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextDarwin_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU) + sizeof (RegisterContextDarwin_arm::EXC))
+
+static RegisterInfo g_register_infos[] = {
+// General purpose registers
+// NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== ===============
+{ "r0", NULL, 4, GPR_OFFSET(0), eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_INVALID_REGNUM, gdb_arm_r0, gpr_r0 }, NULL, NULL},
+{ "r1", NULL, 4, GPR_OFFSET(1), eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_INVALID_REGNUM, gdb_arm_r1, gpr_r1 }, NULL, NULL},
+{ "r2", NULL, 4, GPR_OFFSET(2), eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_INVALID_REGNUM, gdb_arm_r2, gpr_r2 }, NULL, NULL},
+{ "r3", NULL, 4, GPR_OFFSET(3), eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_INVALID_REGNUM, gdb_arm_r3, gpr_r3 }, NULL, NULL},
+{ "r4", NULL, 4, GPR_OFFSET(4), eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, gdb_arm_r4, gpr_r4 }, NULL, NULL},
+{ "r5", NULL, 4, GPR_OFFSET(5), eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, gdb_arm_r5, gpr_r5 }, NULL, NULL},
+{ "r6", NULL, 4, GPR_OFFSET(6), eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, gdb_arm_r6, gpr_r6 }, NULL, NULL},
+{ "r7", NULL, 4, GPR_OFFSET(7), eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, gdb_arm_r7, gpr_r7 }, NULL, NULL},
+{ "r8", NULL, 4, GPR_OFFSET(8), eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, gdb_arm_r8, gpr_r8 }, NULL, NULL},
+{ "r9", NULL, 4, GPR_OFFSET(9), eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, gdb_arm_r9, gpr_r9 }, NULL, NULL},
+{ "r10", NULL, 4, GPR_OFFSET(10), eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, gdb_arm_r10, gpr_r10 }, NULL, NULL},
+{ "r11", NULL, 4, GPR_OFFSET(11), eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM, gdb_arm_r11, gpr_r11 }, NULL, NULL},
+{ "r12", NULL, 4, GPR_OFFSET(12), eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, gdb_arm_r12, gpr_r12 }, NULL, NULL},
+{ "sp", "r13", 4, GPR_OFFSET(13), eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, gdb_arm_sp, gpr_sp }, NULL, NULL},
+{ "lr", "r14", 4, GPR_OFFSET(14), eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_arm_lr, gpr_lr }, NULL, NULL},
+{ "pc", "r15", 4, GPR_OFFSET(15), eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, gdb_arm_pc, gpr_pc }, NULL, NULL},
+{ "cpsr", "psr", 4, GPR_OFFSET(16), eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, gdb_arm_cpsr, gpr_cpsr }, NULL, NULL},
+
+{ "s0", NULL, 4, FPU_OFFSET(0), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, gdb_arm_s0, fpu_s0 }, NULL, NULL},
+{ "s1", NULL, 4, FPU_OFFSET(1), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, gdb_arm_s1, fpu_s1 }, NULL, NULL},
+{ "s2", NULL, 4, FPU_OFFSET(2), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, gdb_arm_s2, fpu_s2 }, NULL, NULL},
+{ "s3", NULL, 4, FPU_OFFSET(3), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, gdb_arm_s3, fpu_s3 }, NULL, NULL},
+{ "s4", NULL, 4, FPU_OFFSET(4), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, gdb_arm_s4, fpu_s4 }, NULL, NULL},
+{ "s5", NULL, 4, FPU_OFFSET(5), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, gdb_arm_s5, fpu_s5 }, NULL, NULL},
+{ "s6", NULL, 4, FPU_OFFSET(6), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, gdb_arm_s6, fpu_s6 }, NULL, NULL},
+{ "s7", NULL, 4, FPU_OFFSET(7), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, gdb_arm_s7, fpu_s7 }, NULL, NULL},
+{ "s8", NULL, 4, FPU_OFFSET(8), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, gdb_arm_s8, fpu_s8 }, NULL, NULL},
+{ "s9", NULL, 4, FPU_OFFSET(9), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, gdb_arm_s9, fpu_s9 }, NULL, NULL},
+{ "s10", NULL, 4, FPU_OFFSET(10), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, gdb_arm_s10, fpu_s10 }, NULL, NULL},
+{ "s11", NULL, 4, FPU_OFFSET(11), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, gdb_arm_s11, fpu_s11 }, NULL, NULL},
+{ "s12", NULL, 4, FPU_OFFSET(12), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, gdb_arm_s12, fpu_s12 }, NULL, NULL},
+{ "s13", NULL, 4, FPU_OFFSET(13), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, gdb_arm_s13, fpu_s13 }, NULL, NULL},
+{ "s14", NULL, 4, FPU_OFFSET(14), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, gdb_arm_s14, fpu_s14 }, NULL, NULL},
+{ "s15", NULL, 4, FPU_OFFSET(15), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, gdb_arm_s15, fpu_s15 }, NULL, NULL},
+{ "s16", NULL, 4, FPU_OFFSET(16), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, gdb_arm_s16, fpu_s16 }, NULL, NULL},
+{ "s17", NULL, 4, FPU_OFFSET(17), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, gdb_arm_s17, fpu_s17 }, NULL, NULL},
+{ "s18", NULL, 4, FPU_OFFSET(18), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, gdb_arm_s18, fpu_s18 }, NULL, NULL},
+{ "s19", NULL, 4, FPU_OFFSET(19), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, gdb_arm_s19, fpu_s19 }, NULL, NULL},
+{ "s20", NULL, 4, FPU_OFFSET(20), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, gdb_arm_s20, fpu_s20 }, NULL, NULL},
+{ "s21", NULL, 4, FPU_OFFSET(21), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, gdb_arm_s21, fpu_s21 }, NULL, NULL},
+{ "s22", NULL, 4, FPU_OFFSET(22), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, gdb_arm_s22, fpu_s22 }, NULL, NULL},
+{ "s23", NULL, 4, FPU_OFFSET(23), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, gdb_arm_s23, fpu_s23 }, NULL, NULL},
+{ "s24", NULL, 4, FPU_OFFSET(24), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, gdb_arm_s24, fpu_s24 }, NULL, NULL},
+{ "s25", NULL, 4, FPU_OFFSET(25), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, gdb_arm_s25, fpu_s25 }, NULL, NULL},
+{ "s26", NULL, 4, FPU_OFFSET(26), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, gdb_arm_s26, fpu_s26 }, NULL, NULL},
+{ "s27", NULL, 4, FPU_OFFSET(27), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, gdb_arm_s27, fpu_s27 }, NULL, NULL},
+{ "s28", NULL, 4, FPU_OFFSET(28), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, gdb_arm_s28, fpu_s28 }, NULL, NULL},
+{ "s29", NULL, 4, FPU_OFFSET(29), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, gdb_arm_s29, fpu_s29 }, NULL, NULL},
+{ "s30", NULL, 4, FPU_OFFSET(30), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, gdb_arm_s30, fpu_s30 }, NULL, NULL},
+{ "s31", NULL, 4, FPU_OFFSET(31), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, gdb_arm_s31, fpu_s31 }, NULL, NULL},
+{ "fpscr", NULL, 4, FPU_OFFSET(32), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, gdb_arm_fpscr, fpu_fpscr }, NULL, NULL},
+
+{ "exception",NULL, 4, EXC_OFFSET(0), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL},
+{ "fsr", NULL, 4, EXC_OFFSET(1), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_fsr }, NULL, NULL},
+{ "far", NULL, 4, EXC_OFFSET(2), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, NULL, NULL},
+
+{ DEFINE_DBG (bvr, 0) },
+{ DEFINE_DBG (bvr, 1) },
+{ DEFINE_DBG (bvr, 2) },
+{ DEFINE_DBG (bvr, 3) },
+{ DEFINE_DBG (bvr, 4) },
+{ DEFINE_DBG (bvr, 5) },
+{ DEFINE_DBG (bvr, 6) },
+{ DEFINE_DBG (bvr, 7) },
+{ DEFINE_DBG (bvr, 8) },
+{ DEFINE_DBG (bvr, 9) },
+{ DEFINE_DBG (bvr, 10) },
+{ DEFINE_DBG (bvr, 11) },
+{ DEFINE_DBG (bvr, 12) },
+{ DEFINE_DBG (bvr, 13) },
+{ DEFINE_DBG (bvr, 14) },
+{ DEFINE_DBG (bvr, 15) },
+
+{ DEFINE_DBG (bcr, 0) },
+{ DEFINE_DBG (bcr, 1) },
+{ DEFINE_DBG (bcr, 2) },
+{ DEFINE_DBG (bcr, 3) },
+{ DEFINE_DBG (bcr, 4) },
+{ DEFINE_DBG (bcr, 5) },
+{ DEFINE_DBG (bcr, 6) },
+{ DEFINE_DBG (bcr, 7) },
+{ DEFINE_DBG (bcr, 8) },
+{ DEFINE_DBG (bcr, 9) },
+{ DEFINE_DBG (bcr, 10) },
+{ DEFINE_DBG (bcr, 11) },
+{ DEFINE_DBG (bcr, 12) },
+{ DEFINE_DBG (bcr, 13) },
+{ DEFINE_DBG (bcr, 14) },
+{ DEFINE_DBG (bcr, 15) },
+
+{ DEFINE_DBG (wvr, 0) },
+{ DEFINE_DBG (wvr, 1) },
+{ DEFINE_DBG (wvr, 2) },
+{ DEFINE_DBG (wvr, 3) },
+{ DEFINE_DBG (wvr, 4) },
+{ DEFINE_DBG (wvr, 5) },
+{ DEFINE_DBG (wvr, 6) },
+{ DEFINE_DBG (wvr, 7) },
+{ DEFINE_DBG (wvr, 8) },
+{ DEFINE_DBG (wvr, 9) },
+{ DEFINE_DBG (wvr, 10) },
+{ DEFINE_DBG (wvr, 11) },
+{ DEFINE_DBG (wvr, 12) },
+{ DEFINE_DBG (wvr, 13) },
+{ DEFINE_DBG (wvr, 14) },
+{ DEFINE_DBG (wvr, 15) },
+
+{ DEFINE_DBG (wcr, 0) },
+{ DEFINE_DBG (wcr, 1) },
+{ DEFINE_DBG (wcr, 2) },
+{ DEFINE_DBG (wcr, 3) },
+{ DEFINE_DBG (wcr, 4) },
+{ DEFINE_DBG (wcr, 5) },
+{ DEFINE_DBG (wcr, 6) },
+{ DEFINE_DBG (wcr, 7) },
+{ DEFINE_DBG (wcr, 8) },
+{ DEFINE_DBG (wcr, 9) },
+{ DEFINE_DBG (wcr, 10) },
+{ DEFINE_DBG (wcr, 11) },
+{ DEFINE_DBG (wcr, 12) },
+{ DEFINE_DBG (wcr, 13) },
+{ DEFINE_DBG (wcr, 14) },
+{ DEFINE_DBG (wcr, 15) }
+};
+
+// General purpose registers
+static uint32_t
+g_gpr_regnums[] =
+{
+ 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
+};
+
+// Floating point registers
+static uint32_t
+g_fpu_regnums[] =
+{
+ 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,
+};
+
+// Exception registers
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_exception,
+ exc_fsr,
+ exc_far,
+};
+
+static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
+
+void
+RegisterContextDarwin_arm::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_arm::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_arm::GetRegisterInfoAtIndex (size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+size_t
+RegisterContextDarwin_arm::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_arm::GetRegisterInfos ()
+{
+ return g_register_infos;
+}
+
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums);
+const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums);
+const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums);
+
+//----------------------------------------------------------------------
+// Register set definitions. The first definitions at register set index
+// of zero is for all registers, followed by other registers sets. The
+// register information for the all register set need not be filled in.
+//----------------------------------------------------------------------
+static const RegisterSet g_reg_sets[] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums },
+ { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
+};
+
+const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets);
+
+
+size_t
+RegisterContextDarwin_arm::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_arm::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Register information definitions for 32 bit i386.
+//----------------------------------------------------------------------
+int
+RegisterContextDarwin_arm::GetSetForNativeRegNum (int reg)
+{
+ if (reg < fpu_s0)
+ return GPRRegSet;
+ else if (reg < exc_exception)
+ return FPURegSet;
+ else if (reg < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+int
+RegisterContextDarwin_arm::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::ReadDBG (bool force)
+{
+ int set = DBGRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadDBG(GetThreadID(), set, dbg));
+ }
+ return GetError(DBGRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError(GPRRegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError(FPURegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError(EXCRegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm::WriteDBG ()
+{
+ int set = DBGRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteDBG(GetThreadID(), set, dbg));
+ SetError (set, Read, -1);
+ return GetError(DBGRegSet, Write);
+}
+
+
+int
+RegisterContextDarwin_arm::ReadRegisterSet (uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR(force);
+ case FPURegSet: return ReadFPU(force);
+ case EXCRegSet: return ReadEXC(force);
+ case DBGRegSet: return ReadDBG(force);
+ default: break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+int
+RegisterContextDarwin_arm::WriteRegisterSet (uint32_t set)
+{
+ // Make sure we have a valid context to set.
+ if (RegisterSetIsCached(set))
+ {
+ switch (set)
+ {
+ case GPRRegSet: return WriteGPR();
+ case FPURegSet: return WriteFPU();
+ case EXCRegSet: return WriteEXC();
+ case DBGRegSet: return WriteDBG();
+ default: break;
+ }
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+void
+RegisterContextDarwin_arm::LogDBGRegisters (Log *log, const DBG& dbg)
+{
+ if (log)
+ {
+ for (uint32_t i=0; i<16; i++)
+ log->Printf("BVR%-2u/BCR%-2u = { 0x%8.8x, 0x%8.8x } WVR%-2u/WCR%-2u = { 0x%8.8x, 0x%8.8x }",
+ i, i, dbg.bvr[i], dbg.bcr[i],
+ i, i, dbg.wvr[i], dbg.wcr[i]);
+ }
+}
+
+
+bool
+RegisterContextDarwin_arm::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_arm::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_r0:
+ case gpr_r1:
+ case gpr_r2:
+ case gpr_r3:
+ case gpr_r4:
+ case gpr_r5:
+ case gpr_r6:
+ case gpr_r7:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ value.SetUInt32 (gpr.r[reg - gpr_r0]);
+ break;
+
+ case fpu_s0:
+ case fpu_s1:
+ case fpu_s2:
+ case fpu_s3:
+ case fpu_s4:
+ case fpu_s5:
+ case fpu_s6:
+ case fpu_s7:
+ case fpu_s8:
+ case fpu_s9:
+ case fpu_s10:
+ case fpu_s11:
+ case fpu_s12:
+ case fpu_s13:
+ case fpu_s14:
+ case fpu_s15:
+ case fpu_s16:
+ case fpu_s17:
+ case fpu_s18:
+ case fpu_s19:
+ case fpu_s20:
+ case fpu_s21:
+ case fpu_s22:
+ case fpu_s23:
+ case fpu_s24:
+ case fpu_s25:
+ case fpu_s26:
+ case fpu_s27:
+ case fpu_s28:
+ case fpu_s29:
+ case fpu_s30:
+ case fpu_s31:
+ value.SetUInt32 (fpu.floats.s[reg], RegisterValue::eTypeFloat);
+ break;
+
+ case fpu_fpscr:
+ value.SetUInt32 (fpu.fpscr);
+ break;
+
+ case exc_exception:
+ value.SetUInt32 (exc.exception);
+ break;
+ case exc_fsr:
+ value.SetUInt32 (exc.fsr);
+ break;
+ case exc_far:
+ value.SetUInt32 (exc.far);
+ break;
+
+ default:
+ value.SetValueToInvalid();
+ return false;
+
+ }
+ return true;
+}
+
+
+bool
+RegisterContextDarwin_arm::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_r0:
+ case gpr_r1:
+ case gpr_r2:
+ case gpr_r3:
+ case gpr_r4:
+ case gpr_r5:
+ case gpr_r6:
+ case gpr_r7:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ gpr.r[reg - gpr_r0] = value.GetAsUInt32();
+ break;
+
+ case fpu_s0:
+ case fpu_s1:
+ case fpu_s2:
+ case fpu_s3:
+ case fpu_s4:
+ case fpu_s5:
+ case fpu_s6:
+ case fpu_s7:
+ case fpu_s8:
+ case fpu_s9:
+ case fpu_s10:
+ case fpu_s11:
+ case fpu_s12:
+ case fpu_s13:
+ case fpu_s14:
+ case fpu_s15:
+ case fpu_s16:
+ case fpu_s17:
+ case fpu_s18:
+ case fpu_s19:
+ case fpu_s20:
+ case fpu_s21:
+ case fpu_s22:
+ case fpu_s23:
+ case fpu_s24:
+ case fpu_s25:
+ case fpu_s26:
+ case fpu_s27:
+ case fpu_s28:
+ case fpu_s29:
+ case fpu_s30:
+ case fpu_s31:
+ fpu.floats.s[reg] = value.GetAsUInt32();
+ break;
+
+ case fpu_fpscr:
+ fpu.fpscr = value.GetAsUInt32();
+ break;
+
+ case exc_exception:
+ exc.exception = value.GetAsUInt32();
+ break;
+ case exc_fsr:
+ exc.fsr = value.GetAsUInt32();
+ break;
+ case exc_far:
+ exc.far = value.GetAsUInt32();
+ break;
+
+ default:
+ return false;
+
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextDarwin_arm::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == KERN_SUCCESS &&
+ ReadFPU (false) == KERN_SUCCESS &&
+ ReadEXC (false) == KERN_SUCCESS)
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy (dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDarwin_arm::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy (&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy (&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy (&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteFPU() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteEXC() == KERN_SUCCESS)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+uint32_t
+RegisterContextDarwin_arm::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_pc;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_sp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_r7;
+ case LLDB_REGNUM_GENERIC_RA: return gpr_lr;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_cpsr;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case dwarf_r0: return gpr_r0;
+ case dwarf_r1: return gpr_r1;
+ case dwarf_r2: return gpr_r2;
+ case dwarf_r3: return gpr_r3;
+ case dwarf_r4: return gpr_r4;
+ case dwarf_r5: return gpr_r5;
+ case dwarf_r6: return gpr_r6;
+ case dwarf_r7: return gpr_r7;
+ case dwarf_r8: return gpr_r8;
+ case dwarf_r9: return gpr_r9;
+ case dwarf_r10: return gpr_r10;
+ case dwarf_r11: return gpr_r11;
+ case dwarf_r12: return gpr_r12;
+ case dwarf_sp: return gpr_sp;
+ case dwarf_lr: return gpr_lr;
+ case dwarf_pc: return gpr_pc;
+ case dwarf_spsr: return gpr_cpsr;
+
+ case dwarf_s0: return fpu_s0;
+ case dwarf_s1: return fpu_s1;
+ case dwarf_s2: return fpu_s2;
+ case dwarf_s3: return fpu_s3;
+ case dwarf_s4: return fpu_s4;
+ case dwarf_s5: return fpu_s5;
+ case dwarf_s6: return fpu_s6;
+ case dwarf_s7: return fpu_s7;
+ case dwarf_s8: return fpu_s8;
+ case dwarf_s9: return fpu_s9;
+ case dwarf_s10: return fpu_s10;
+ case dwarf_s11: return fpu_s11;
+ case dwarf_s12: return fpu_s12;
+ case dwarf_s13: return fpu_s13;
+ case dwarf_s14: return fpu_s14;
+ case dwarf_s15: return fpu_s15;
+ case dwarf_s16: return fpu_s16;
+ case dwarf_s17: return fpu_s17;
+ case dwarf_s18: return fpu_s18;
+ case dwarf_s19: return fpu_s19;
+ case dwarf_s20: return fpu_s20;
+ case dwarf_s21: return fpu_s21;
+ case dwarf_s22: return fpu_s22;
+ case dwarf_s23: return fpu_s23;
+ case dwarf_s24: return fpu_s24;
+ case dwarf_s25: return fpu_s25;
+ case dwarf_s26: return fpu_s26;
+ case dwarf_s27: return fpu_s27;
+ case dwarf_s28: return fpu_s28;
+ case dwarf_s29: return fpu_s29;
+ case dwarf_s30: return fpu_s30;
+ case dwarf_s31: return fpu_s31;
+
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC)
+ {
+ switch (reg)
+ {
+ case gcc_r0: return gpr_r0;
+ case gcc_r1: return gpr_r1;
+ case gcc_r2: return gpr_r2;
+ case gcc_r3: return gpr_r3;
+ case gcc_r4: return gpr_r4;
+ case gcc_r5: return gpr_r5;
+ case gcc_r6: return gpr_r6;
+ case gcc_r7: return gpr_r7;
+ case gcc_r8: return gpr_r8;
+ case gcc_r9: return gpr_r9;
+ case gcc_r10: return gpr_r10;
+ case gcc_r11: return gpr_r11;
+ case gcc_r12: return gpr_r12;
+ case gcc_sp: return gpr_sp;
+ case gcc_lr: return gpr_lr;
+ case gcc_pc: return gpr_pc;
+ case gcc_cpsr: return gpr_cpsr;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+uint32_t
+RegisterContextDarwin_arm::NumSupportedHardwareBreakpoints ()
+{
+#if defined (__arm__)
+ // Set the init value to something that will let us know that we need to
+ // autodetect how many breakpoints are supported dynamically...
+ static uint32_t g_num_supported_hw_breakpoints = UINT32_MAX;
+ if (g_num_supported_hw_breakpoints == UINT32_MAX)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_breakpoints = 0;
+
+ uint32_t register_DBGDIDR;
+
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ g_num_supported_hw_breakpoints = Bits32 (register_DBGDIDR, 27, 24);
+ // Zero is reserved for the BRP count, so don't increment it if it is zero
+ if (g_num_supported_hw_breakpoints > 0)
+ g_num_supported_hw_breakpoints++;
+// if (log) log->Printf ("DBGDIDR=0x%8.8x (number BRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_breakpoints);
+
+ }
+ return g_num_supported_hw_breakpoints;
+#else
+ // TODO: figure out remote case here!
+ return 6;
+#endif
+}
+
+uint32_t
+RegisterContextDarwin_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ // Make sure our address isn't bogus
+ if (addr & 1)
+ return LLDB_INVALID_INDEX32;
+
+ int kret = ReadDBG (false);
+
+ if (kret == KERN_SUCCESS)
+ {
+ const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints();
+ uint32_t i;
+ for (i=0; i<num_hw_breakpoints; ++i)
+ {
+ if ((dbg.bcr[i] & BCR_ENABLE) == 0)
+ break; // We found an available hw breakpoint slot (in i)
+ }
+
+ // See if we found an available hw breakpoint slot above
+ if (i < num_hw_breakpoints)
+ {
+ // Make sure bits 1:0 are clear in our address
+ dbg.bvr[i] = addr & ~((lldb::addr_t)3);
+
+ if (size == 2 || addr & 2)
+ {
+ uint32_t byte_addr_select = (addr & 2) ? BAS_IMVA_2_3 : BAS_IMVA_0_1;
+
+ // We have a thumb breakpoint
+ // We have an ARM breakpoint
+ dbg.bcr[i] = BCR_M_IMVA_MATCH | // Stop on address mismatch
+ byte_addr_select | // Set the correct byte address select so we only trigger on the correct opcode
+ S_USER | // Which modes should this breakpoint stop in?
+ BCR_ENABLE; // Enable this hardware breakpoint
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (Thumb)",
+// addr,
+// size,
+// i,
+// i,
+// dbg.bvr[i],
+// dbg.bcr[i]);
+ }
+ else if (size == 4)
+ {
+ // We have an ARM breakpoint
+ dbg.bcr[i] = BCR_M_IMVA_MATCH | // Stop on address mismatch
+ BAS_IMVA_ALL | // Stop on any of the four bytes following the IMVA
+ S_USER | // Which modes should this breakpoint stop in?
+ BCR_ENABLE; // Enable this hardware breakpoint
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (ARM)",
+// addr,
+// size,
+// i,
+// i,
+// dbg.bvr[i],
+// dbg.bcr[i]);
+ }
+
+ kret = WriteDBG();
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+// else
+// {
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint(addr = %8.8p, size = %u) => all hardware breakpoint resources are being used.", addr, size);
+// }
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextDarwin_arm::ClearHardwareBreakpoint (uint32_t hw_index)
+{
+ int kret = ReadDBG (false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareBreakpoints();
+ if (kret == KERN_SUCCESS)
+ {
+ if (hw_index < num_hw_points)
+ {
+ dbg.bcr[hw_index] = 0;
+// if (log) log->Printf ("RegisterContextDarwin_arm::SetHardwareBreakpoint( %u ) - BVR%u = 0x%8.8x BCR%u = 0x%8.8x",
+// hw_index,
+// hw_index,
+// dbg.bvr[hw_index],
+// hw_index,
+// dbg.bcr[hw_index]);
+
+ kret = WriteDBG();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
+
+uint32_t
+RegisterContextDarwin_arm::NumSupportedHardwareWatchpoints ()
+{
+#if defined (__arm__)
+ // Set the init value to something that will let us know that we need to
+ // autodetect how many watchpoints are supported dynamically...
+ static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX;
+ if (g_num_supported_hw_watchpoints == UINT32_MAX)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_watchpoints = 0;
+
+ uint32_t register_DBGDIDR;
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ g_num_supported_hw_watchpoints = Bits32 (register_DBGDIDR, 31, 28) + 1;
+// if (log) log->Printf ("DBGDIDR=0x%8.8x (number WRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_watchpoints);
+ }
+ return g_num_supported_hw_watchpoints;
+#else
+ // TODO: figure out remote case here!
+ return 2;
+#endif
+}
+
+
+uint32_t
+RegisterContextDarwin_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint(addr = %8.8p, size = %u, read = %u, write = %u)", addr, size, read, write);
+
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+
+ // Can't watch zero bytes
+ if (size == 0)
+ return LLDB_INVALID_INDEX32;
+
+ // We must watch for either read or write
+ if (read == false && write == false)
+ return LLDB_INVALID_INDEX32;
+
+ // Can't watch more than 4 bytes per WVR/WCR pair
+ if (size > 4)
+ return LLDB_INVALID_INDEX32;
+
+ // We can only watch up to four bytes that follow a 4 byte aligned address
+ // per watchpoint register pair. Since we have at most so we can only watch
+ // until the next 4 byte boundary and we need to make sure we can properly
+ // encode this.
+ uint32_t addr_word_offset = addr % 4;
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset);
+
+ uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset;
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask);
+ if (byte_mask > 0xfu)
+ return LLDB_INVALID_INDEX32;
+
+ // Read the debug state
+ int kret = ReadDBG (false);
+
+ if (kret == KERN_SUCCESS)
+ {
+ // Check to make sure we have the needed hardware support
+ uint32_t i = 0;
+
+ for (i=0; i<num_hw_watchpoints; ++i)
+ {
+ if ((dbg.wcr[i] & WCR_ENABLE) == 0)
+ break; // We found an available hw breakpoint slot (in i)
+ }
+
+ // See if we found an available hw breakpoint slot above
+ if (i < num_hw_watchpoints)
+ {
+ // Make the byte_mask into a valid Byte Address Select mask
+ uint32_t byte_address_select = byte_mask << 5;
+ // Make sure bits 1:0 are clear in our address
+ dbg.wvr[i] = addr & ~((lldb::addr_t)3);
+ dbg.wcr[i] = byte_address_select | // Which bytes that follow the IMVA that we will watch
+ S_USER | // Stop only in user mode
+ (read ? WCR_LOAD : 0) | // Stop on read access?
+ (write ? WCR_STORE : 0) | // Stop on write access?
+ WCR_ENABLE; // Enable this watchpoint;
+
+ kret = WriteDBG();
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+ else
+ {
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints);
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextDarwin_arm::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ int kret = ReadDBG (false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareWatchpoints();
+ if (kret == KERN_SUCCESS)
+ {
+ if (hw_index < num_hw_points)
+ {
+ dbg.wcr[hw_index] = 0;
+// if (log) log->Printf ("RegisterContextDarwin_arm::ClearHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x",
+// hw_index,
+// hw_index,
+// dbg.wvr[hw_index],
+// hw_index,
+// dbg.wcr[hw_index]);
+
+ kret = WriteDBG();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h
new file mode 100644
index 0000000..23134ef
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h
@@ -0,0 +1,333 @@
+//===-- RegisterContextDarwin_arm.h -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextDarwin_arm_h_
+#define liblldb_RegisterContextDarwin_arm_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+// BCR address match type
+#define BCR_M_IMVA_MATCH ((uint32_t)(0u << 21))
+#define BCR_M_CONTEXT_ID_MATCH ((uint32_t)(1u << 21))
+#define BCR_M_IMVA_MISMATCH ((uint32_t)(2u << 21))
+#define BCR_M_RESERVED ((uint32_t)(3u << 21))
+
+// Link a BVR/BCR or WVR/WCR pair to another
+#define E_ENABLE_LINKING ((uint32_t)(1u << 20))
+
+// Byte Address Select
+#define BAS_IMVA_PLUS_0 ((uint32_t)(1u << 5))
+#define BAS_IMVA_PLUS_1 ((uint32_t)(1u << 6))
+#define BAS_IMVA_PLUS_2 ((uint32_t)(1u << 7))
+#define BAS_IMVA_PLUS_3 ((uint32_t)(1u << 8))
+#define BAS_IMVA_0_1 ((uint32_t)(3u << 5))
+#define BAS_IMVA_2_3 ((uint32_t)(3u << 7))
+#define BAS_IMVA_ALL ((uint32_t)(0xfu << 5))
+
+// Break only in privileged or user mode
+#define S_RSVD ((uint32_t)(0u << 1))
+#define S_PRIV ((uint32_t)(1u << 1))
+#define S_USER ((uint32_t)(2u << 1))
+#define S_PRIV_USER ((S_PRIV) | (S_USER))
+
+#define BCR_ENABLE ((uint32_t)(1u))
+#define WCR_ENABLE ((uint32_t)(1u))
+
+// Watchpoint load/store
+#define WCR_LOAD ((uint32_t)(1u << 3))
+#define WCR_STORE ((uint32_t)(1u << 4))
+
+class RegisterContextDarwin_arm : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextDarwin_arm(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_arm();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
+
+ virtual uint32_t
+ NumSupportedHardwareBreakpoints ();
+
+ virtual uint32_t
+ SetHardwareBreakpoint (lldb::addr_t addr, size_t size);
+
+ virtual bool
+ ClearHardwareBreakpoint (uint32_t hw_idx);
+
+ virtual uint32_t
+ NumSupportedHardwareWatchpoints ();
+
+ virtual uint32_t
+ SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write);
+
+ virtual bool
+ ClearHardwareWatchpoint (uint32_t hw_index);
+
+ struct GPR
+ {
+ uint32_t r[16]; // R0-R15
+ uint32_t cpsr; // CPSR
+ };
+
+
+ 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;
+ };
+
+// struct NeonReg
+// {
+// uint8_t bytes[16];
+// };
+//
+// struct VFPv3
+// {
+// union {
+// uint32_t s[32];
+// uint64_t d[32];
+// NeonReg q[16];
+// } v3;
+// uint32_t fpscr;
+// };
+
+ struct EXC
+ {
+ uint32_t exception;
+ uint32_t fsr; /* Fault status */
+ uint32_t far; /* Virtual Fault Address */
+ };
+
+ struct DBG
+ {
+ uint32_t bvr[16];
+ uint32_t bcr[16];
+ uint32_t wvr[16];
+ uint32_t wcr[16];
+ };
+
+ static void
+ LogDBGRegisters (lldb_private::Log *log, const DBG& dbg);
+
+protected:
+
+ enum
+ {
+ GPRRegSet = 1, // ARM_THREAD_STATE
+ FPURegSet = 2, // ARM_VFP_STATE
+ EXCRegSet = 3, // ARM_EXCEPTION_STATE
+ DBGRegSet = 4 // ARM_DEBUG_STATE
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t),
+ DBGWordCount = sizeof(DBG)/sizeof(uint32_t)
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ DBG dbg;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+ int dbg_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ int
+ GetError (int flavor, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet: return gpr_errs[err_idx];
+ case FPURegSet: return fpu_errs[err_idx];
+ case EXCRegSet: return exc_errs[err_idx];
+ case DBGRegSet: return dbg_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+
+ bool
+ SetError (int flavor, uint32_t err_idx, int err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ case DBGRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == 0;
+ }
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ ReadDBG (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ int
+ WriteDBG ();
+
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+ {
+ return -1;
+ }
+
+ virtual int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int
+ DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) = 0;
+
+ virtual int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ virtual int
+ DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) = 0;
+
+ int
+ ReadRegisterSet (uint32_t set, bool force);
+
+ int
+ WriteRegisterSet (uint32_t set);
+
+ static uint32_t
+ GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num);
+
+ static int
+ GetSetForNativeRegNum (int reg_num);
+
+ static size_t
+ GetRegisterInfosCount ();
+
+ static const lldb_private::RegisterInfo *
+ GetRegisterInfos ();
+};
+
+#endif // liblldb_RegisterContextDarwin_arm_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp
new file mode 100644
index 0000000..e08a873
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp
@@ -0,0 +1,944 @@
+//===-- RegisterContextDarwin_arm64.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+#include "RegisterContextDarwin_arm64.h"
+
+// C Includes
+#include <mach/mach_types.h>
+#include <mach/thread_act.h>
+#include <sys/sysctl.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+
+#include "Plugins/Process/Utility/InstructionUtils.h"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "ARM64_GCC_Registers.h"
+#include "ARM64_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextDarwin_arm64::RegisterContextDarwin_arm64(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContext(thread, concrete_frame_idx),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_arm64::~RegisterContextDarwin_arm64()
+{
+}
+
+
+#define GPR_OFFSET(idx) ((idx) * 8)
+#define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::GPR, reg))
+
+#define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextDarwin_arm64::GPR))
+#define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::FPU, reg))
+
+#define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::EXC, reg) + sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU))
+#define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::DBG, reg) + sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU) + sizeof (RegisterContextDarwin_arm64::EXC))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextDarwin_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU) + sizeof (RegisterContextDarwin_arm64::EXC))
+
+//-----------------------------------------------------------------------------
+// Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure.
+//-----------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_ARM64_STRUCT
+#include "RegisterInfos_arm64.h"
+#undef DECLARE_REGISTER_INFOS_ARM64_STRUCT
+
+// General purpose registers
+static uint32_t
+g_gpr_regnums[] =
+{
+ gpr_x0,
+ gpr_x1,
+ gpr_x2,
+ gpr_x3,
+ gpr_x4,
+ gpr_x5,
+ gpr_x6,
+ gpr_x7,
+ gpr_x8,
+ gpr_x9,
+ gpr_x10,
+ gpr_x11,
+ gpr_x12,
+ gpr_x13,
+ gpr_x14,
+ gpr_x15,
+ gpr_x16,
+ gpr_x17,
+ gpr_x18,
+ gpr_x19,
+ gpr_x20,
+ gpr_x21,
+ gpr_x22,
+ gpr_x23,
+ gpr_x24,
+ gpr_x25,
+ gpr_x26,
+ gpr_x27,
+ gpr_x28,
+ gpr_fp,
+ gpr_lr,
+ gpr_sp,
+ gpr_pc,
+ gpr_cpsr
+};
+
+// Floating point registers
+static uint32_t
+g_fpu_regnums[] =
+{
+ fpu_v0,
+ fpu_v1,
+ fpu_v2,
+ fpu_v3,
+ fpu_v4,
+ fpu_v5,
+ fpu_v6,
+ fpu_v7,
+ fpu_v8,
+ fpu_v9,
+ fpu_v10,
+ fpu_v11,
+ fpu_v12,
+ fpu_v13,
+ fpu_v14,
+ fpu_v15,
+ fpu_v16,
+ fpu_v17,
+ fpu_v18,
+ fpu_v19,
+ fpu_v20,
+ fpu_v21,
+ fpu_v22,
+ fpu_v23,
+ fpu_v24,
+ fpu_v25,
+ fpu_v26,
+ fpu_v27,
+ fpu_v28,
+ fpu_v29,
+ fpu_v30,
+ fpu_v31,
+ fpu_fpsr,
+ fpu_fpcr
+};
+
+// Exception registers
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_far,
+ exc_esr,
+ exc_exception
+};
+
+static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos_arm64);
+
+void
+RegisterContextDarwin_arm64::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_arm64::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_arm64::GetRegisterInfoAtIndex (size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos_arm64[reg];
+ return NULL;
+}
+
+size_t
+RegisterContextDarwin_arm64::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_arm64::GetRegisterInfos ()
+{
+ return g_register_infos_arm64;
+}
+
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums);
+const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums);
+const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums);
+
+//----------------------------------------------------------------------
+// Register set definitions. The first definitions at register set index
+// of zero is for all registers, followed by other registers sets. The
+// register information for the all register set need not be filled in.
+//----------------------------------------------------------------------
+static const RegisterSet g_reg_sets[] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums },
+ { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
+};
+
+const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets);
+
+
+size_t
+RegisterContextDarwin_arm64::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_arm64::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Register information definitions for arm64
+//----------------------------------------------------------------------
+int
+RegisterContextDarwin_arm64::GetSetForNativeRegNum (int reg)
+{
+ if (reg < fpu_v0)
+ return GPRRegSet;
+ else if (reg < exc_far)
+ return FPURegSet;
+ else if (reg < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+int
+RegisterContextDarwin_arm64::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm64::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm64::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm64::ReadDBG (bool force)
+{
+ int set = DBGRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadDBG(GetThreadID(), set, dbg));
+ }
+ return GetError(DBGRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm64::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError(GPRRegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm64::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError(FPURegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm64::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError(EXCRegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm64::WriteDBG ()
+{
+ int set = DBGRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteDBG(GetThreadID(), set, dbg));
+ SetError (set, Read, -1);
+ return GetError(DBGRegSet, Write);
+}
+
+
+int
+RegisterContextDarwin_arm64::ReadRegisterSet (uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR(force);
+ case FPURegSet: return ReadFPU(force);
+ case EXCRegSet: return ReadEXC(force);
+ case DBGRegSet: return ReadDBG(force);
+ default: break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+int
+RegisterContextDarwin_arm64::WriteRegisterSet (uint32_t set)
+{
+ // Make sure we have a valid context to set.
+ if (RegisterSetIsCached(set))
+ {
+ switch (set)
+ {
+ case GPRRegSet: return WriteGPR();
+ case FPURegSet: return WriteFPU();
+ case EXCRegSet: return WriteEXC();
+ case DBGRegSet: return WriteDBG();
+ default: break;
+ }
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+void
+RegisterContextDarwin_arm64::LogDBGRegisters (Log *log, const DBG& dbg)
+{
+ if (log)
+ {
+ for (uint32_t i=0; i<16; i++)
+ log->Printf("BVR%-2u/BCR%-2u = { 0x%8.8llx, 0x%8.8llx } WVR%-2u/WCR%-2u = { 0x%8.8llx, 0x%8.8llx }",
+ i, i, dbg.bvr[i], dbg.bcr[i],
+ i, i, dbg.wvr[i], dbg.wcr[i]);
+ }
+}
+
+
+bool
+RegisterContextDarwin_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_arm64::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_x0:
+ case gpr_x1:
+ case gpr_x2:
+ case gpr_x3:
+ case gpr_x4:
+ case gpr_x5:
+ case gpr_x6:
+ case gpr_x7:
+ case gpr_x8:
+ case gpr_x9:
+ case gpr_x10:
+ case gpr_x11:
+ case gpr_x12:
+ case gpr_x13:
+ case gpr_x14:
+ case gpr_x15:
+ case gpr_x16:
+ case gpr_x17:
+ case gpr_x18:
+ case gpr_x19:
+ case gpr_x20:
+ case gpr_x21:
+ case gpr_x22:
+ case gpr_x23:
+ case gpr_x24:
+ case gpr_x25:
+ case gpr_x26:
+ case gpr_x27:
+ case gpr_x28:
+ case gpr_fp:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ value.SetUInt64 (gpr.x[reg - gpr_x0]);
+ break;
+
+ case fpu_v0:
+ case fpu_v1:
+ case fpu_v2:
+ case fpu_v3:
+ case fpu_v4:
+ case fpu_v5:
+ case fpu_v6:
+ case fpu_v7:
+ case fpu_v8:
+ case fpu_v9:
+ case fpu_v10:
+ case fpu_v11:
+ case fpu_v12:
+ case fpu_v13:
+ case fpu_v14:
+ case fpu_v15:
+ case fpu_v16:
+ case fpu_v17:
+ case fpu_v18:
+ case fpu_v19:
+ case fpu_v20:
+ case fpu_v21:
+ case fpu_v22:
+ case fpu_v23:
+ case fpu_v24:
+ case fpu_v25:
+ case fpu_v26:
+ case fpu_v27:
+ case fpu_v28:
+ case fpu_v29:
+ case fpu_v30:
+ case fpu_v31:
+ value.SetBytes(fpu.v[reg].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder());
+ break;
+
+ case fpu_fpsr:
+ value.SetUInt32 (fpu.fpsr);
+ break;
+
+ case fpu_fpcr:
+ value.SetUInt32 (fpu.fpcr);
+ break;
+
+ case exc_exception:
+ value.SetUInt32 (exc.exception);
+ break;
+ case exc_esr:
+ value.SetUInt32 (exc.esr);
+ break;
+ case exc_far:
+ value.SetUInt64 (exc.far);
+ break;
+
+ default:
+ value.SetValueToInvalid();
+ return false;
+
+ }
+ return true;
+}
+
+
+bool
+RegisterContextDarwin_arm64::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_x0:
+ case gpr_x1:
+ case gpr_x2:
+ case gpr_x3:
+ case gpr_x4:
+ case gpr_x5:
+ case gpr_x6:
+ case gpr_x7:
+ case gpr_x8:
+ case gpr_x9:
+ case gpr_x10:
+ case gpr_x11:
+ case gpr_x12:
+ case gpr_x13:
+ case gpr_x14:
+ case gpr_x15:
+ case gpr_x16:
+ case gpr_x17:
+ case gpr_x18:
+ case gpr_x19:
+ case gpr_x20:
+ case gpr_x21:
+ case gpr_x22:
+ case gpr_x23:
+ case gpr_x24:
+ case gpr_x25:
+ case gpr_x26:
+ case gpr_x27:
+ case gpr_x28:
+ case gpr_fp:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ gpr.x[reg - gpr_x0] = value.GetAsUInt64();
+ break;
+
+ case fpu_v0:
+ case fpu_v1:
+ case fpu_v2:
+ case fpu_v3:
+ case fpu_v4:
+ case fpu_v5:
+ case fpu_v6:
+ case fpu_v7:
+ case fpu_v8:
+ case fpu_v9:
+ case fpu_v10:
+ case fpu_v11:
+ case fpu_v12:
+ case fpu_v13:
+ case fpu_v14:
+ case fpu_v15:
+ case fpu_v16:
+ case fpu_v17:
+ case fpu_v18:
+ case fpu_v19:
+ case fpu_v20:
+ case fpu_v21:
+ case fpu_v22:
+ case fpu_v23:
+ case fpu_v24:
+ case fpu_v25:
+ case fpu_v26:
+ case fpu_v27:
+ case fpu_v28:
+ case fpu_v29:
+ case fpu_v30:
+ case fpu_v31:
+ ::memcpy (fpu.v[reg].bytes, value.GetBytes(), value.GetByteSize());
+ break;
+
+ case fpu_fpsr:
+ fpu.fpsr = value.GetAsUInt32();
+ break;
+
+ case fpu_fpcr:
+ fpu.fpcr = value.GetAsUInt32();
+ break;
+
+ case exc_exception:
+ exc.exception = value.GetAsUInt32();
+ break;
+ case exc_esr:
+ exc.esr = value.GetAsUInt32();
+ break;
+ case exc_far:
+ exc.far = value.GetAsUInt64();
+ break;
+
+ default:
+ return false;
+
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextDarwin_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == KERN_SUCCESS &&
+ ReadFPU (false) == KERN_SUCCESS &&
+ ReadEXC (false) == KERN_SUCCESS)
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy (dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDarwin_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy (&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy (&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy (&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteFPU() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteEXC() == KERN_SUCCESS)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+uint32_t
+RegisterContextDarwin_arm64::ConvertRegisterKindToRegisterNumber (RegisterKind kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_pc;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_sp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_fp;
+ case LLDB_REGNUM_GENERIC_RA: return gpr_lr;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_cpsr;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case arm64_dwarf::x0: return gpr_x0;
+ case arm64_dwarf::x1: return gpr_x1;
+ case arm64_dwarf::x2: return gpr_x2;
+ case arm64_dwarf::x3: return gpr_x3;
+ case arm64_dwarf::x4: return gpr_x4;
+ case arm64_dwarf::x5: return gpr_x5;
+ case arm64_dwarf::x6: return gpr_x6;
+ case arm64_dwarf::x7: return gpr_x7;
+ case arm64_dwarf::x8: return gpr_x8;
+ case arm64_dwarf::x9: return gpr_x9;
+ case arm64_dwarf::x10: return gpr_x10;
+ case arm64_dwarf::x11: return gpr_x11;
+ case arm64_dwarf::x12: return gpr_x12;
+ case arm64_dwarf::x13: return gpr_x13;
+ case arm64_dwarf::x14: return gpr_x14;
+ case arm64_dwarf::x15: return gpr_x15;
+ case arm64_dwarf::x16: return gpr_x16;
+ case arm64_dwarf::x17: return gpr_x17;
+ case arm64_dwarf::x18: return gpr_x18;
+ case arm64_dwarf::x19: return gpr_x19;
+ case arm64_dwarf::x20: return gpr_x20;
+ case arm64_dwarf::x21: return gpr_x21;
+ case arm64_dwarf::x22: return gpr_x22;
+ case arm64_dwarf::x23: return gpr_x23;
+ case arm64_dwarf::x24: return gpr_x24;
+ case arm64_dwarf::x25: return gpr_x25;
+ case arm64_dwarf::x26: return gpr_x26;
+ case arm64_dwarf::x27: return gpr_x27;
+ case arm64_dwarf::x28: return gpr_x28;
+
+ case arm64_dwarf::fp: return gpr_fp;
+ case arm64_dwarf::sp: return gpr_sp;
+ case arm64_dwarf::lr: return gpr_lr;
+ case arm64_dwarf::pc: return gpr_pc;
+ case arm64_dwarf::cpsr: return gpr_cpsr;
+
+ case arm64_dwarf::v0: return fpu_v0;
+ case arm64_dwarf::v1: return fpu_v1;
+ case arm64_dwarf::v2: return fpu_v2;
+ case arm64_dwarf::v3: return fpu_v3;
+ case arm64_dwarf::v4: return fpu_v4;
+ case arm64_dwarf::v5: return fpu_v5;
+ case arm64_dwarf::v6: return fpu_v6;
+ case arm64_dwarf::v7: return fpu_v7;
+ case arm64_dwarf::v8: return fpu_v8;
+ case arm64_dwarf::v9: return fpu_v9;
+ case arm64_dwarf::v10: return fpu_v10;
+ case arm64_dwarf::v11: return fpu_v11;
+ case arm64_dwarf::v12: return fpu_v12;
+ case arm64_dwarf::v13: return fpu_v13;
+ case arm64_dwarf::v14: return fpu_v14;
+ case arm64_dwarf::v15: return fpu_v15;
+ case arm64_dwarf::v16: return fpu_v16;
+ case arm64_dwarf::v17: return fpu_v17;
+ case arm64_dwarf::v18: return fpu_v18;
+ case arm64_dwarf::v19: return fpu_v19;
+ case arm64_dwarf::v20: return fpu_v20;
+ case arm64_dwarf::v21: return fpu_v21;
+ case arm64_dwarf::v22: return fpu_v22;
+ case arm64_dwarf::v23: return fpu_v23;
+ case arm64_dwarf::v24: return fpu_v24;
+ case arm64_dwarf::v25: return fpu_v25;
+ case arm64_dwarf::v26: return fpu_v26;
+ case arm64_dwarf::v27: return fpu_v27;
+ case arm64_dwarf::v28: return fpu_v28;
+ case arm64_dwarf::v29: return fpu_v29;
+ case arm64_dwarf::v30: return fpu_v30;
+ case arm64_dwarf::v31: return fpu_v31;
+
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC)
+ {
+ switch (reg)
+ {
+ case arm64_gcc::x0: return gpr_x0;
+ case arm64_gcc::x1: return gpr_x1;
+ case arm64_gcc::x2: return gpr_x2;
+ case arm64_gcc::x3: return gpr_x3;
+ case arm64_gcc::x4: return gpr_x4;
+ case arm64_gcc::x5: return gpr_x5;
+ case arm64_gcc::x6: return gpr_x6;
+ case arm64_gcc::x7: return gpr_x7;
+ case arm64_gcc::x8: return gpr_x8;
+ case arm64_gcc::x9: return gpr_x9;
+ case arm64_gcc::x10: return gpr_x10;
+ case arm64_gcc::x11: return gpr_x11;
+ case arm64_gcc::x12: return gpr_x12;
+ case arm64_gcc::x13: return gpr_x13;
+ case arm64_gcc::x14: return gpr_x14;
+ case arm64_gcc::x15: return gpr_x15;
+ case arm64_gcc::x16: return gpr_x16;
+ case arm64_gcc::x17: return gpr_x17;
+ case arm64_gcc::x18: return gpr_x18;
+ case arm64_gcc::x19: return gpr_x19;
+ case arm64_gcc::x20: return gpr_x20;
+ case arm64_gcc::x21: return gpr_x21;
+ case arm64_gcc::x22: return gpr_x22;
+ case arm64_gcc::x23: return gpr_x23;
+ case arm64_gcc::x24: return gpr_x24;
+ case arm64_gcc::x25: return gpr_x25;
+ case arm64_gcc::x26: return gpr_x26;
+ case arm64_gcc::x27: return gpr_x27;
+ case arm64_gcc::x28: return gpr_x28;
+ case arm64_gcc::fp: return gpr_fp;
+ case arm64_gcc::sp: return gpr_sp;
+ case arm64_gcc::lr: return gpr_lr;
+ case arm64_gcc::pc: return gpr_pc;
+ case arm64_gcc::cpsr: return gpr_cpsr;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+uint32_t
+RegisterContextDarwin_arm64::NumSupportedHardwareWatchpoints ()
+{
+#if defined (__arm64__) || defined (__aarch64__)
+ // autodetect how many watchpoints are supported dynamically...
+ static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX;
+ if (g_num_supported_hw_watchpoints == UINT32_MAX)
+ {
+ size_t len;
+ uint32_t n = 0;
+ len = sizeof (n);
+ if (::sysctlbyname("hw.optional.watchpoint", &n, &len, NULL, 0) == 0)
+ {
+ g_num_supported_hw_watchpoints = n;
+ }
+ }
+ return g_num_supported_hw_watchpoints;
+#else
+ // TODO: figure out remote case here!
+ return 2;
+#endif
+}
+
+
+uint32_t
+RegisterContextDarwin_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(addr = %8.8p, size = %u, read = %u, write = %u)", addr, size, read, write);
+
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+
+ // Can't watch zero bytes
+ if (size == 0)
+ return LLDB_INVALID_INDEX32;
+
+ // We must watch for either read or write
+ if (read == false && write == false)
+ return LLDB_INVALID_INDEX32;
+
+ // Can't watch more than 4 bytes per WVR/WCR pair
+ if (size > 4)
+ return LLDB_INVALID_INDEX32;
+
+ // We can only watch up to four bytes that follow a 4 byte aligned address
+ // per watchpoint register pair. Since we have at most so we can only watch
+ // until the next 4 byte boundary and we need to make sure we can properly
+ // encode this.
+ uint32_t addr_word_offset = addr % 4;
+// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset);
+
+ uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset;
+// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask);
+ if (byte_mask > 0xfu)
+ return LLDB_INVALID_INDEX32;
+
+ // Read the debug state
+ int kret = ReadDBG (false);
+
+ if (kret == KERN_SUCCESS)
+ {
+ // Check to make sure we have the needed hardware support
+ uint32_t i = 0;
+
+ for (i=0; i<num_hw_watchpoints; ++i)
+ {
+ if ((dbg.wcr[i] & WCR_ENABLE) == 0)
+ break; // We found an available hw breakpoint slot (in i)
+ }
+
+ // See if we found an available hw breakpoint slot above
+ if (i < num_hw_watchpoints)
+ {
+ // Make the byte_mask into a valid Byte Address Select mask
+ uint32_t byte_address_select = byte_mask << 5;
+ // Make sure bits 1:0 are clear in our address
+ dbg.wvr[i] = addr & ~((lldb::addr_t)3);
+ dbg.wcr[i] = byte_address_select | // Which bytes that follow the IMVA that we will watch
+ S_USER | // Stop only in user mode
+ (read ? WCR_LOAD : 0) | // Stop on read access?
+ (write ? WCR_STORE : 0) | // Stop on write access?
+ WCR_ENABLE; // Enable this watchpoint;
+
+ kret = WriteDBG();
+// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+ else
+ {
+// if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints);
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextDarwin_arm64::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ int kret = ReadDBG (false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareWatchpoints();
+ if (kret == KERN_SUCCESS)
+ {
+ if (hw_index < num_hw_points)
+ {
+ dbg.wcr[hw_index] = 0;
+// if (log) log->Printf ("RegisterContextDarwin_arm64::ClearHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x",
+// hw_index,
+// hw_index,
+// dbg.wvr[hw_index],
+// hw_index,
+// dbg.wcr[hw_index]);
+
+ kret = WriteDBG();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h
new file mode 100644
index 0000000..aeac15e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.h
@@ -0,0 +1,296 @@
+//===-- RegisterContextDarwin_arm64.h -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextDarwin_arm64_h_
+#define liblldb_RegisterContextDarwin_arm64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+// Break only in privileged or user mode
+#define S_RSVD ((uint32_t)(0u << 1))
+#define S_PRIV ((uint32_t)(1u << 1))
+#define S_USER ((uint32_t)(2u << 1))
+#define S_PRIV_USER ((S_PRIV) | (S_USER))
+
+#define WCR_ENABLE ((uint32_t)(1u))
+
+// Watchpoint load/store
+#define WCR_LOAD ((uint32_t)(1u << 3))
+#define WCR_STORE ((uint32_t)(1u << 4))
+
+class RegisterContextDarwin_arm64 : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextDarwin_arm64(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_arm64();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
+
+ virtual uint32_t
+ NumSupportedHardwareWatchpoints ();
+
+ virtual uint32_t
+ SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write);
+
+ virtual bool
+ ClearHardwareWatchpoint (uint32_t hw_index);
+
+ // mirrors <mach/arm/thread_status.h> arm_thread_state64_t
+ struct GPR
+ {
+ uint64_t x[29]; // x0-x28
+ uint64_t fp; // x29
+ uint64_t lr; // x30
+ uint64_t sp; // x31
+ uint64_t pc; // pc
+ uint32_t cpsr; // cpsr
+ };
+
+
+ struct VReg
+ {
+ uint8_t bytes[16];
+ };
+
+ // mirrors <mach/arm/thread_status.h> arm_neon_state64_t
+ struct FPU
+ {
+ VReg v[32];
+ uint32_t fpsr;
+ uint32_t fpcr;
+ };
+
+ // mirrors <mach/arm/thread_status.h> arm_exception_state64_t
+ struct EXC
+ {
+ uint64_t far; // Virtual Fault Address
+ uint32_t esr; // Exception syndrome
+ uint32_t exception; // number of arm exception token
+ };
+
+ // mirrors <mach/arm/thread_status.h> arm_debug_state64_t
+ struct DBG
+ {
+ uint64_t bvr[16];
+ uint64_t bcr[16];
+ uint64_t wvr[16];
+ uint64_t wcr[16];
+ uint64_t mdscr_el1;
+ };
+
+ static void
+ LogDBGRegisters (lldb_private::Log *log, const DBG& dbg);
+
+protected:
+
+ enum
+ {
+ GPRRegSet = 6, // ARM_THREAD_STATE64
+ FPURegSet = 17, // ARM_NEON_STATE64
+ EXCRegSet = 7, // ARM_EXCEPTION_STATE64
+ DBGRegSet = 15 // ARM_DEBUG_STATE64
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t), // ARM_THREAD_STATE64_COUNT
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t), // ARM_NEON_STATE64_COUNT
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t), // ARM_EXCEPTION_STATE64_COUNT
+ DBGWordCount = sizeof(DBG)/sizeof(uint32_t) // ARM_DEBUG_STATE64_COUNT
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ DBG dbg;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+ int dbg_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ int
+ GetError (int flavor, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet: return gpr_errs[err_idx];
+ case FPURegSet: return fpu_errs[err_idx];
+ case EXCRegSet: return exc_errs[err_idx];
+ case DBGRegSet: return dbg_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+
+ bool
+ SetError (int flavor, uint32_t err_idx, int err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ case DBGRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == 0;
+ }
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ ReadDBG (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ int
+ WriteDBG ();
+
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+ {
+ return -1;
+ }
+
+ virtual int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int
+ DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) = 0;
+
+ virtual int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ virtual int
+ DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) = 0;
+
+ int
+ ReadRegisterSet (uint32_t set, bool force);
+
+ int
+ WriteRegisterSet (uint32_t set);
+
+ static uint32_t
+ GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num);
+
+ static int
+ GetSetForNativeRegNum (int reg_num);
+
+ static size_t
+ GetRegisterInfosCount ();
+
+ static const lldb_private::RegisterInfo *
+ GetRegisterInfos ();
+};
+
+#endif // liblldb_RegisterContextDarwin_arm64_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
new file mode 100644
index 0000000..08144bf
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
@@ -0,0 +1,981 @@
+//===-- RegisterContextDarwin_i386.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+#include <stddef.h> // offsetof
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "RegisterContextDarwin_i386.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gpr_eax = 0,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs,
+
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr,
+
+ k_num_registers,
+
+ // Aliases
+ fpu_fctrl = fpu_fcw,
+ fpu_fstat = fpu_fsw,
+ fpu_ftag = fpu_ftw,
+ fpu_fiseg = fpu_cs,
+ fpu_fioff = fpu_ip,
+ fpu_foseg = fpu_ds,
+ fpu_fooff = fpu_dp
+};
+
+enum
+{
+ gcc_eax = 0,
+ gcc_ecx,
+ gcc_edx,
+ gcc_ebx,
+ gcc_ebp,
+ gcc_esp,
+ gcc_esi,
+ gcc_edi,
+ gcc_eip,
+ gcc_eflags
+};
+
+enum
+{
+ dwarf_eax = 0,
+ dwarf_ecx,
+ dwarf_edx,
+ dwarf_ebx,
+ dwarf_esp,
+ dwarf_ebp,
+ dwarf_esi,
+ dwarf_edi,
+ dwarf_eip,
+ dwarf_eflags,
+ dwarf_stmm0 = 11,
+ dwarf_stmm1,
+ dwarf_stmm2,
+ dwarf_stmm3,
+ dwarf_stmm4,
+ dwarf_stmm5,
+ dwarf_stmm6,
+ dwarf_stmm7,
+ dwarf_xmm0 = 21,
+ dwarf_xmm1,
+ dwarf_xmm2,
+ dwarf_xmm3,
+ dwarf_xmm4,
+ dwarf_xmm5,
+ dwarf_xmm6,
+ dwarf_xmm7
+};
+
+enum
+{
+ gdb_eax = 0,
+ gdb_ecx = 1,
+ gdb_edx = 2,
+ gdb_ebx = 3,
+ gdb_esp = 4,
+ gdb_ebp = 5,
+ gdb_esi = 6,
+ gdb_edi = 7,
+ gdb_eip = 8,
+ gdb_eflags = 9,
+ gdb_cs = 10,
+ gdb_ss = 11,
+ gdb_ds = 12,
+ gdb_es = 13,
+ gdb_fs = 14,
+ gdb_gs = 15,
+ gdb_stmm0 = 16,
+ gdb_stmm1 = 17,
+ gdb_stmm2 = 18,
+ gdb_stmm3 = 19,
+ gdb_stmm4 = 20,
+ gdb_stmm5 = 21,
+ gdb_stmm6 = 22,
+ gdb_stmm7 = 23,
+ gdb_fctrl = 24, gdb_fcw = gdb_fctrl,
+ gdb_fstat = 25, gdb_fsw = gdb_fstat,
+ gdb_ftag = 26, gdb_ftw = gdb_ftag,
+ gdb_fiseg = 27, gdb_fpu_cs = gdb_fiseg,
+ gdb_fioff = 28, gdb_ip = gdb_fioff,
+ gdb_foseg = 29, gdb_fpu_ds = gdb_foseg,
+ gdb_fooff = 30, gdb_dp = gdb_fooff,
+ gdb_fop = 31,
+ gdb_xmm0 = 32,
+ gdb_xmm1 = 33,
+ gdb_xmm2 = 34,
+ gdb_xmm3 = 35,
+ gdb_xmm4 = 36,
+ gdb_xmm5 = 37,
+ gdb_xmm6 = 38,
+ gdb_xmm7 = 39,
+ gdb_mxcsr = 40,
+ gdb_mm0 = 41,
+ gdb_mm1 = 42,
+ gdb_mm2 = 43,
+ gdb_mm3 = 44,
+ gdb_mm4 = 45,
+ gdb_mm5 = 46,
+ gdb_mm6 = 47,
+ gdb_mm7 = 48
+};
+
+RegisterContextDarwin_i386::RegisterContextDarwin_i386 (Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContext(thread, concrete_frame_idx),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_i386::~RegisterContextDarwin_i386()
+{
+}
+
+
+
+#define GPR_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_i386::GPR, reg))
+#define FPU_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_i386::FPU, reg) + sizeof (RegisterContextDarwin_i386::GPR))
+#define EXC_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_i386::EXC, reg) + sizeof (RegisterContextDarwin_i386::GPR) + sizeof (RegisterContextDarwin_i386::FPU))
+
+// These macros will auto define the register name, alt name, register size,
+// register offset, encoding, format and native register. This ensures that
+// the register state structures are defined correctly and have the correct
+// sizes and offsets.
+#define DEFINE_GPR(reg, alt) #reg, alt, sizeof(((RegisterContextDarwin_i386::GPR *)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_UINT(reg) #reg, NULL, sizeof(((RegisterContextDarwin_i386::FPU *)NULL)->reg), FPU_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_VECT(reg, i) #reg#i, NULL, sizeof(((RegisterContextDarwin_i386::FPU *)NULL)->reg[i].bytes), FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_##reg##i, LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i }, NULL, NULL
+
+#define DEFINE_EXC(reg) #reg, NULL, sizeof(((RegisterContextDarwin_i386::EXC *)NULL)->reg), EXC_OFFSET(reg), eEncodingUint, eFormatHex
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_i386::GPR) + sizeof (RegisterContextDarwin_i386::FPU) + sizeof (RegisterContextDarwin_i386::EXC))
+
+static RegisterInfo g_register_infos[] =
+{
+// Macro auto defines most stuff GCC DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS
+// =============================== ======================= =================== ========================= ================== ================= ========== ===============
+ { DEFINE_GPR(eax , NULL) , { gcc_eax , dwarf_eax , LLDB_INVALID_REGNUM , gdb_eax , gpr_eax }, NULL, NULL},
+ { DEFINE_GPR(ebx , NULL) , { gcc_ebx , dwarf_ebx , LLDB_INVALID_REGNUM , gdb_ebx , gpr_ebx }, NULL, NULL},
+ { DEFINE_GPR(ecx , NULL) , { gcc_ecx , dwarf_ecx , LLDB_INVALID_REGNUM , gdb_ecx , gpr_ecx }, NULL, NULL},
+ { DEFINE_GPR(edx , NULL) , { gcc_edx , dwarf_edx , LLDB_INVALID_REGNUM , gdb_edx , gpr_edx }, NULL, NULL},
+ { DEFINE_GPR(edi , NULL) , { gcc_edi , dwarf_edi , LLDB_INVALID_REGNUM , gdb_edi , gpr_edi }, NULL, NULL},
+ { DEFINE_GPR(esi , NULL) , { gcc_esi , dwarf_esi , LLDB_INVALID_REGNUM , gdb_esi , gpr_esi }, NULL, NULL},
+ { DEFINE_GPR(ebp , "fp") , { gcc_ebp , dwarf_ebp , LLDB_REGNUM_GENERIC_FP , gdb_ebp , gpr_ebp }, NULL, NULL},
+ { DEFINE_GPR(esp , "sp") , { gcc_esp , dwarf_esp , LLDB_REGNUM_GENERIC_SP , gdb_esp , gpr_esp }, NULL, NULL},
+ { DEFINE_GPR(ss , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ss , gpr_ss }, NULL, NULL},
+ { DEFINE_GPR(eflags , "flags") , { gcc_eflags , dwarf_eflags , LLDB_REGNUM_GENERIC_FLAGS , gdb_eflags , gpr_eflags }, NULL, NULL},
+ { DEFINE_GPR(eip , "pc") , { gcc_eip , dwarf_eip , LLDB_REGNUM_GENERIC_PC , gdb_eip , gpr_eip }, NULL, NULL},
+ { DEFINE_GPR(cs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_cs , gpr_cs }, NULL, NULL},
+ { DEFINE_GPR(ds , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ds , gpr_ds }, NULL, NULL},
+ { DEFINE_GPR(es , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_es , gpr_es }, NULL, NULL},
+ { DEFINE_GPR(fs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fs , gpr_fs }, NULL, NULL},
+ { DEFINE_GPR(gs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gs , gpr_gs }, NULL, NULL},
+
+ { DEFINE_FPU_UINT(fcw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fcw , fpu_fcw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fsw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fsw , fpu_fsw }, NULL, NULL},
+ { DEFINE_FPU_UINT(ftw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ftw , fpu_ftw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fop) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fop , fpu_fop }, NULL, NULL},
+ { DEFINE_FPU_UINT(ip) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ip , fpu_ip }, NULL, NULL},
+ { DEFINE_FPU_UINT(cs) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_cs , fpu_cs }, NULL, NULL},
+ { DEFINE_FPU_UINT(dp) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_dp , fpu_dp }, NULL, NULL},
+ { DEFINE_FPU_UINT(ds) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ds , fpu_ds }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_mxcsr , fpu_mxcsr }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsrmask) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, fpu_mxcsrmask}, NULL, NULL},
+ { DEFINE_FPU_VECT(stmm,0) },
+ { DEFINE_FPU_VECT(stmm,1) },
+ { DEFINE_FPU_VECT(stmm,2) },
+ { DEFINE_FPU_VECT(stmm,3) },
+ { DEFINE_FPU_VECT(stmm,4) },
+ { DEFINE_FPU_VECT(stmm,5) },
+ { DEFINE_FPU_VECT(stmm,6) },
+ { DEFINE_FPU_VECT(stmm,7) },
+ { DEFINE_FPU_VECT(xmm,0) },
+ { DEFINE_FPU_VECT(xmm,1) },
+ { DEFINE_FPU_VECT(xmm,2) },
+ { DEFINE_FPU_VECT(xmm,3) },
+ { DEFINE_FPU_VECT(xmm,4) },
+ { DEFINE_FPU_VECT(xmm,5) },
+ { DEFINE_FPU_VECT(xmm,6) },
+ { DEFINE_FPU_VECT(xmm,7) },
+
+ { DEFINE_EXC(trapno) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_trapno }, NULL, NULL},
+ { DEFINE_EXC(err) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_err }, NULL, NULL},
+ { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL}
+};
+
+static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
+
+void
+RegisterContextDarwin_i386::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_i386::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_i386::GetRegisterInfoAtIndex (size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+size_t
+RegisterContextDarwin_i386::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_i386::GetRegisterInfos ()
+{
+ return g_register_infos;
+}
+
+
+// General purpose registers
+static uint32_t
+g_gpr_regnums[] =
+{
+ gpr_eax,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs
+};
+
+// Floating point registers
+static uint32_t
+g_fpu_regnums[] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7
+};
+
+// Exception registers
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr
+};
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums);
+const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums);
+const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums);
+
+//----------------------------------------------------------------------
+// Register set definitions. The first definitions at register set index
+// of zero is for all registers, followed by other registers sets. The
+// register information for the all register set need not be filled in.
+//----------------------------------------------------------------------
+static const RegisterSet g_reg_sets[] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums },
+ { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
+};
+
+const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets);
+
+
+size_t
+RegisterContextDarwin_i386::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_i386::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Register information definitions for 32 bit i386.
+//----------------------------------------------------------------------
+int
+RegisterContextDarwin_i386::GetSetForNativeRegNum (int reg_num)
+{
+ if (reg_num < fpu_fcw)
+ return GPRRegSet;
+ else if (reg_num < exc_trapno)
+ return FPURegSet;
+ else if (reg_num < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+
+void
+RegisterContextDarwin_i386::LogGPR(Log *log, const char *title)
+{
+ if (log)
+ {
+ if (title)
+ log->Printf ("%s", title);
+ for (uint32_t i=0; i<k_num_gpr_registers; i++)
+ {
+ uint32_t reg = gpr_eax + i;
+ log->Printf("%12s = 0x%8.8x", g_register_infos[reg].name, (&gpr.eax)[reg]);
+ }
+ }
+}
+
+
+
+int
+RegisterContextDarwin_i386::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(set, Read);
+}
+
+int
+RegisterContextDarwin_i386::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(set, Read);
+}
+
+int
+RegisterContextDarwin_i386::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(set, Read);
+}
+
+int
+RegisterContextDarwin_i386::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+int
+RegisterContextDarwin_i386::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+int
+RegisterContextDarwin_i386::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+int
+RegisterContextDarwin_i386::ReadRegisterSet (uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR(force);
+ case FPURegSet: return ReadFPU(force);
+ case EXCRegSet: return ReadEXC(force);
+ default: break;
+ }
+ return -1;
+}
+
+int
+RegisterContextDarwin_i386::WriteRegisterSet (uint32_t set)
+{
+ // Make sure we have a valid context to set.
+ if (RegisterSetIsCached(set))
+ {
+ switch (set)
+ {
+ case GPRRegSet: return WriteGPR();
+ case FPURegSet: return WriteFPU();
+ case EXCRegSet: return WriteEXC();
+ default: break;
+ }
+ }
+ return -1;
+}
+
+bool
+RegisterContextDarwin_i386::ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_i386::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_eax:
+ case gpr_ebx:
+ case gpr_ecx:
+ case gpr_edx:
+ case gpr_edi:
+ case gpr_esi:
+ case gpr_ebp:
+ case gpr_esp:
+ case gpr_ss:
+ case gpr_eflags:
+ case gpr_eip:
+ case gpr_cs:
+ case gpr_ds:
+ case gpr_es:
+ case gpr_fs:
+ case gpr_gs:
+ value = (&gpr.eax)[reg - gpr_eax];
+ break;
+
+ case fpu_fcw:
+ value = fpu.fcw;
+ break;
+
+ case fpu_fsw:
+ value = fpu.fsw;
+ break;
+
+ case fpu_ftw:
+ value = fpu.ftw;
+ break;
+
+ case fpu_fop:
+ value = fpu.fop;
+ break;
+
+ case fpu_ip:
+ value = fpu.ip;
+ break;
+
+ case fpu_cs:
+ value = fpu.cs;
+ break;
+
+ case fpu_dp:
+ value = fpu.dp;
+ break;
+
+ case fpu_ds:
+ value = fpu.ds;
+ break;
+
+ case fpu_mxcsr:
+ value = fpu.mxcsr;
+ break;
+
+ case fpu_mxcsrmask:
+ value = fpu.mxcsrmask;
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ // These values don't fit into scalar types,
+ // RegisterContext::ReadRegisterBytes() must be used for these
+ // registers
+ //::memcpy (reg_value.value.vector.uint8, fpu.stmm[reg - fpu_stmm0].bytes, 10);
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ //::memcpy (reg_value.value.vector.uint8, fpu.xmm[reg - fpu_xmm0].bytes, 16);
+ return false;
+
+ case exc_trapno:
+ value = exc.trapno;
+ break;
+
+ case exc_err:
+ value = exc.err;
+ break;
+
+ case exc_faultvaddr:
+ value = exc.faultvaddr;
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+
+bool
+RegisterContextDarwin_i386::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_eax:
+ case gpr_ebx:
+ case gpr_ecx:
+ case gpr_edx:
+ case gpr_edi:
+ case gpr_esi:
+ case gpr_ebp:
+ case gpr_esp:
+ case gpr_ss:
+ case gpr_eflags:
+ case gpr_eip:
+ case gpr_cs:
+ case gpr_ds:
+ case gpr_es:
+ case gpr_fs:
+ case gpr_gs:
+ (&gpr.eax)[reg - gpr_eax] = value.GetAsUInt32();
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.GetAsUInt16();
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.GetAsUInt16();
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.GetAsUInt8();
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.GetAsUInt16();
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.GetAsUInt32();
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.GetAsUInt16();
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.GetAsUInt32();
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.GetAsUInt16();
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.GetAsUInt32();
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.GetAsUInt32();
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ ::memcpy (fpu.stmm[reg - fpu_stmm0].bytes, value.GetBytes(), value.GetByteSize());
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ ::memcpy (fpu.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize());
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.GetAsUInt32();
+ break;
+
+ case exc_err:
+ exc.err = value.GetAsUInt32();
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.GetAsUInt32();
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == 0;
+}
+
+bool
+RegisterContextDarwin_i386::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == 0 &&
+ ReadFPU (false) == 0 &&
+ ReadEXC (false) == 0)
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy (dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDarwin_i386::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy (&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy (&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy (&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == 0)
+ ++success_count;
+ if (WriteFPU() == 0)
+ ++success_count;
+ if (WriteEXC() == 0)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+
+uint32_t
+RegisterContextDarwin_i386::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_eip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_esp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_ebp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_eflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case dwarf_eax: return gpr_eax;
+ case dwarf_ecx: return gpr_ecx;
+ case dwarf_edx: return gpr_edx;
+ case dwarf_ebx: return gpr_ebx;
+ case dwarf_esp: return gpr_esp;
+ case dwarf_ebp: return gpr_ebp;
+ case dwarf_esi: return gpr_esi;
+ case dwarf_edi: return gpr_edi;
+ case dwarf_eip: return gpr_eip;
+ case dwarf_eflags: return gpr_eflags;
+ case dwarf_stmm0: return fpu_stmm0;
+ case dwarf_stmm1: return fpu_stmm1;
+ case dwarf_stmm2: return fpu_stmm2;
+ case dwarf_stmm3: return fpu_stmm3;
+ case dwarf_stmm4: return fpu_stmm4;
+ case dwarf_stmm5: return fpu_stmm5;
+ case dwarf_stmm6: return fpu_stmm6;
+ case dwarf_stmm7: return fpu_stmm7;
+ case dwarf_xmm0: return fpu_xmm0;
+ case dwarf_xmm1: return fpu_xmm1;
+ case dwarf_xmm2: return fpu_xmm2;
+ case dwarf_xmm3: return fpu_xmm3;
+ case dwarf_xmm4: return fpu_xmm4;
+ case dwarf_xmm5: return fpu_xmm5;
+ case dwarf_xmm6: return fpu_xmm6;
+ case dwarf_xmm7: return fpu_xmm7;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGDB)
+ {
+ switch (reg)
+ {
+ case gdb_eax : return gpr_eax;
+ case gdb_ebx : return gpr_ebx;
+ case gdb_ecx : return gpr_ecx;
+ case gdb_edx : return gpr_edx;
+ case gdb_esi : return gpr_esi;
+ case gdb_edi : return gpr_edi;
+ case gdb_ebp : return gpr_ebp;
+ case gdb_esp : return gpr_esp;
+ case gdb_eip : return gpr_eip;
+ case gdb_eflags : return gpr_eflags;
+ case gdb_cs : return gpr_cs;
+ case gdb_ss : return gpr_ss;
+ case gdb_ds : return gpr_ds;
+ case gdb_es : return gpr_es;
+ case gdb_fs : return gpr_fs;
+ case gdb_gs : return gpr_gs;
+ case gdb_stmm0 : return fpu_stmm0;
+ case gdb_stmm1 : return fpu_stmm1;
+ case gdb_stmm2 : return fpu_stmm2;
+ case gdb_stmm3 : return fpu_stmm3;
+ case gdb_stmm4 : return fpu_stmm4;
+ case gdb_stmm5 : return fpu_stmm5;
+ case gdb_stmm6 : return fpu_stmm6;
+ case gdb_stmm7 : return fpu_stmm7;
+ case gdb_fctrl : return fpu_fctrl;
+ case gdb_fstat : return fpu_fstat;
+ case gdb_ftag : return fpu_ftag;
+ case gdb_fiseg : return fpu_fiseg;
+ case gdb_fioff : return fpu_fioff;
+ case gdb_foseg : return fpu_foseg;
+ case gdb_fooff : return fpu_fooff;
+ case gdb_fop : return fpu_fop;
+ case gdb_xmm0 : return fpu_xmm0;
+ case gdb_xmm1 : return fpu_xmm1;
+ case gdb_xmm2 : return fpu_xmm2;
+ case gdb_xmm3 : return fpu_xmm3;
+ case gdb_xmm4 : return fpu_xmm4;
+ case gdb_xmm5 : return fpu_xmm5;
+ case gdb_xmm6 : return fpu_xmm6;
+ case gdb_xmm7 : return fpu_xmm7;
+ case gdb_mxcsr : return fpu_mxcsr;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+bool
+RegisterContextDarwin_i386::HardwareSingleStep (bool enable)
+{
+ if (ReadGPR(false) != 0)
+ return false;
+
+ const uint32_t trace_bit = 0x100u;
+ if (enable)
+ {
+ // If the trace bit is already set, there is nothing to do
+ if (gpr.eflags & trace_bit)
+ return true;
+ else
+ gpr.eflags |= trace_bit;
+ }
+ else
+ {
+ // If the trace bit is already cleared, there is nothing to do
+ if (gpr.eflags & trace_bit)
+ gpr.eflags &= ~trace_bit;
+ else
+ return true;
+ }
+
+ return WriteGPR() == 0;
+}
+
+
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h
new file mode 100644
index 0000000..1d03feb
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h
@@ -0,0 +1,269 @@
+//===-- RegisterContextDarwin_i386.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextDarwin_i386_h_
+#define liblldb_RegisterContextDarwin_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+class RegisterContextDarwin_i386 : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextDarwin_i386(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_i386();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ struct GPR
+ {
+ uint32_t eax;
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebp;
+ uint32_t esp;
+ uint32_t ss;
+ uint32_t eflags;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+ };
+
+ struct MMSReg
+ {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ uint32_t pad[2];
+ uint16_t fcw;
+ uint16_t fsw;
+ uint8_t ftw;
+ uint8_t pad1;
+ uint16_t fop;
+ uint32_t ip;
+ uint16_t cs;
+ uint16_t pad2;
+ uint32_t dp;
+ uint16_t ds;
+ uint16_t pad3;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[8];
+ uint8_t pad4[14*16];
+ int pad5;
+ };
+
+ struct EXC
+ {
+ uint32_t trapno;
+ uint32_t err;
+ uint32_t faultvaddr;
+ };
+
+protected:
+
+ enum
+ {
+ GPRRegSet = 1,
+ FPURegSet = 2,
+ EXCRegSet = 3
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t)
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ int
+ GetError (int flavor, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet: return gpr_errs[err_idx];
+ case FPURegSet: return fpu_errs[err_idx];
+ case EXCRegSet: return exc_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+
+ bool
+ SetError (int flavor, uint32_t err_idx, int err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == 0;
+ }
+
+ void
+ LogGPR (lldb_private::Log *log, const char *title);
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) = 0;
+
+ virtual int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ int
+ ReadRegisterSet (uint32_t set, bool force);
+
+ int
+ WriteRegisterSet (uint32_t set);
+
+ static uint32_t
+ GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num);
+
+ static int
+ GetSetForNativeRegNum (int reg_num);
+
+ static size_t
+ GetRegisterInfosCount ();
+
+ static const lldb_private::RegisterInfo *
+ GetRegisterInfos ();
+};
+
+#endif // liblldb_RegisterContextDarwin_i386_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
new file mode 100644
index 0000000..54124d1
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
@@ -0,0 +1,1068 @@
+//===-- RegisterContextDarwin_x86_64.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+#include <inttypes.h> // PRIx64
+#include <stdarg.h>
+#include <stddef.h> // offsetof
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "RegisterContextDarwin_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gpr_rax = 0,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs,
+
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15,
+
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr,
+
+ k_num_registers,
+
+ // Aliases
+ fpu_fctrl = fpu_fcw,
+ fpu_fstat = fpu_fsw,
+ fpu_ftag = fpu_ftw,
+ fpu_fiseg = fpu_cs,
+ fpu_fioff = fpu_ip,
+ fpu_foseg = fpu_ds,
+ fpu_fooff = fpu_dp
+};
+
+enum gcc_dwarf_regnums
+{
+ gcc_dwarf_gpr_rax = 0,
+ gcc_dwarf_gpr_rdx,
+ gcc_dwarf_gpr_rcx,
+ gcc_dwarf_gpr_rbx,
+ gcc_dwarf_gpr_rsi,
+ gcc_dwarf_gpr_rdi,
+ gcc_dwarf_gpr_rbp,
+ gcc_dwarf_gpr_rsp,
+ gcc_dwarf_gpr_r8,
+ gcc_dwarf_gpr_r9,
+ gcc_dwarf_gpr_r10,
+ gcc_dwarf_gpr_r11,
+ gcc_dwarf_gpr_r12,
+ gcc_dwarf_gpr_r13,
+ gcc_dwarf_gpr_r14,
+ gcc_dwarf_gpr_r15,
+ gcc_dwarf_gpr_rip,
+ gcc_dwarf_fpu_xmm0,
+ gcc_dwarf_fpu_xmm1,
+ gcc_dwarf_fpu_xmm2,
+ gcc_dwarf_fpu_xmm3,
+ gcc_dwarf_fpu_xmm4,
+ gcc_dwarf_fpu_xmm5,
+ gcc_dwarf_fpu_xmm6,
+ gcc_dwarf_fpu_xmm7,
+ gcc_dwarf_fpu_xmm8,
+ gcc_dwarf_fpu_xmm9,
+ gcc_dwarf_fpu_xmm10,
+ gcc_dwarf_fpu_xmm11,
+ gcc_dwarf_fpu_xmm12,
+ gcc_dwarf_fpu_xmm13,
+ gcc_dwarf_fpu_xmm14,
+ gcc_dwarf_fpu_xmm15,
+ gcc_dwarf_fpu_stmm0,
+ gcc_dwarf_fpu_stmm1,
+ gcc_dwarf_fpu_stmm2,
+ gcc_dwarf_fpu_stmm3,
+ gcc_dwarf_fpu_stmm4,
+ gcc_dwarf_fpu_stmm5,
+ gcc_dwarf_fpu_stmm6,
+ gcc_dwarf_fpu_stmm7
+
+};
+
+enum gdb_regnums
+{
+ gdb_gpr_rax = 0,
+ gdb_gpr_rbx = 1,
+ gdb_gpr_rcx = 2,
+ gdb_gpr_rdx = 3,
+ gdb_gpr_rsi = 4,
+ gdb_gpr_rdi = 5,
+ gdb_gpr_rbp = 6,
+ gdb_gpr_rsp = 7,
+ gdb_gpr_r8 = 8,
+ gdb_gpr_r9 = 9,
+ gdb_gpr_r10 = 10,
+ gdb_gpr_r11 = 11,
+ gdb_gpr_r12 = 12,
+ gdb_gpr_r13 = 13,
+ gdb_gpr_r14 = 14,
+ gdb_gpr_r15 = 15,
+ gdb_gpr_rip = 16,
+ gdb_gpr_rflags = 17,
+ gdb_gpr_cs = 18,
+ gdb_gpr_ss = 19,
+ gdb_gpr_ds = 20,
+ gdb_gpr_es = 21,
+ gdb_gpr_fs = 22,
+ gdb_gpr_gs = 23,
+ gdb_fpu_stmm0 = 24,
+ gdb_fpu_stmm1 = 25,
+ gdb_fpu_stmm2 = 26,
+ gdb_fpu_stmm3 = 27,
+ gdb_fpu_stmm4 = 28,
+ gdb_fpu_stmm5 = 29,
+ gdb_fpu_stmm6 = 30,
+ gdb_fpu_stmm7 = 31,
+ gdb_fpu_fctrl = 32, gdb_fpu_fcw = gdb_fpu_fctrl,
+ gdb_fpu_fstat = 33, gdb_fpu_fsw = gdb_fpu_fstat,
+ gdb_fpu_ftag = 34, gdb_fpu_ftw = gdb_fpu_ftag,
+ gdb_fpu_fiseg = 35, gdb_fpu_cs = gdb_fpu_fiseg,
+ gdb_fpu_fioff = 36, gdb_fpu_ip = gdb_fpu_fioff,
+ gdb_fpu_foseg = 37, gdb_fpu_ds = gdb_fpu_foseg,
+ gdb_fpu_fooff = 38, gdb_fpu_dp = gdb_fpu_fooff,
+ gdb_fpu_fop = 39,
+ gdb_fpu_xmm0 = 40,
+ gdb_fpu_xmm1 = 41,
+ gdb_fpu_xmm2 = 42,
+ gdb_fpu_xmm3 = 43,
+ gdb_fpu_xmm4 = 44,
+ gdb_fpu_xmm5 = 45,
+ gdb_fpu_xmm6 = 46,
+ gdb_fpu_xmm7 = 47,
+ gdb_fpu_xmm8 = 48,
+ gdb_fpu_xmm9 = 49,
+ gdb_fpu_xmm10 = 50,
+ gdb_fpu_xmm11 = 51,
+ gdb_fpu_xmm12 = 52,
+ gdb_fpu_xmm13 = 53,
+ gdb_fpu_xmm14 = 54,
+ gdb_fpu_xmm15 = 55,
+ gdb_fpu_mxcsr = 56
+};
+
+RegisterContextDarwin_x86_64::RegisterContextDarwin_x86_64 (Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContext (thread, concrete_frame_idx),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_x86_64::~RegisterContextDarwin_x86_64()
+{
+}
+
+#define GPR_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_x86_64::GPR, reg))
+#define FPU_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_x86_64::FPU, reg) + sizeof (RegisterContextDarwin_x86_64::GPR))
+#define EXC_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_x86_64::EXC, reg) + sizeof (RegisterContextDarwin_x86_64::GPR) + sizeof (RegisterContextDarwin_x86_64::FPU))
+
+// These macros will auto define the register name, alt name, register size,
+// register offset, encoding, format and native register. This ensures that
+// the register state structures are defined correctly and have the correct
+// sizes and offsets.
+#define DEFINE_GPR(reg, alt) #reg, alt, sizeof(((RegisterContextDarwin_x86_64::GPR *)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_UINT(reg) #reg, NULL, sizeof(((RegisterContextDarwin_x86_64::FPU *)NULL)->reg), FPU_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_VECT(reg, i) #reg#i, NULL, sizeof(((RegisterContextDarwin_x86_64::FPU *)NULL)->reg[i].bytes), FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL
+#define DEFINE_EXC(reg) #reg, NULL, sizeof(((RegisterContextDarwin_x86_64::EXC *)NULL)->reg), EXC_OFFSET(reg), eEncodingUint, eFormatHex
+
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_x86_64::GPR) + sizeof (RegisterContextDarwin_x86_64::FPU) + sizeof (RegisterContextDarwin_x86_64::EXC))
+
+// General purpose registers for 64 bit
+static RegisterInfo g_register_infos[] =
+{
+// Macro auto defines most stuff GCC DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS
+// =============================== ====================== =================== ========================== ==================== =================== ========== ===============
+ { DEFINE_GPR (rax , NULL) , { gcc_dwarf_gpr_rax , gcc_dwarf_gpr_rax , LLDB_INVALID_REGNUM , gdb_gpr_rax , gpr_rax }, NULL, NULL},
+ { DEFINE_GPR (rbx , NULL) , { gcc_dwarf_gpr_rbx , gcc_dwarf_gpr_rbx , LLDB_INVALID_REGNUM , gdb_gpr_rbx , gpr_rbx }, NULL, NULL},
+ { DEFINE_GPR (rcx , NULL) , { gcc_dwarf_gpr_rcx , gcc_dwarf_gpr_rcx , LLDB_INVALID_REGNUM , gdb_gpr_rcx , gpr_rcx }, NULL, NULL},
+ { DEFINE_GPR (rdx , NULL) , { gcc_dwarf_gpr_rdx , gcc_dwarf_gpr_rdx , LLDB_INVALID_REGNUM , gdb_gpr_rdx , gpr_rdx }, NULL, NULL},
+ { DEFINE_GPR (rdi , NULL) , { gcc_dwarf_gpr_rdi , gcc_dwarf_gpr_rdi , LLDB_INVALID_REGNUM , gdb_gpr_rdi , gpr_rdi }, NULL, NULL},
+ { DEFINE_GPR (rsi , NULL) , { gcc_dwarf_gpr_rsi , gcc_dwarf_gpr_rsi , LLDB_INVALID_REGNUM , gdb_gpr_rsi , gpr_rsi }, NULL, NULL},
+ { DEFINE_GPR (rbp , "fp") , { gcc_dwarf_gpr_rbp , gcc_dwarf_gpr_rbp , LLDB_REGNUM_GENERIC_FP , gdb_gpr_rbp , gpr_rbp }, NULL, NULL},
+ { DEFINE_GPR (rsp , "sp") , { gcc_dwarf_gpr_rsp , gcc_dwarf_gpr_rsp , LLDB_REGNUM_GENERIC_SP , gdb_gpr_rsp , gpr_rsp }, NULL, NULL},
+ { DEFINE_GPR (r8 , NULL) , { gcc_dwarf_gpr_r8 , gcc_dwarf_gpr_r8 , LLDB_INVALID_REGNUM , gdb_gpr_r8 , gpr_r8 }, NULL, NULL},
+ { DEFINE_GPR (r9 , NULL) , { gcc_dwarf_gpr_r9 , gcc_dwarf_gpr_r9 , LLDB_INVALID_REGNUM , gdb_gpr_r9 , gpr_r9 }, NULL, NULL},
+ { DEFINE_GPR (r10 , NULL) , { gcc_dwarf_gpr_r10 , gcc_dwarf_gpr_r10 , LLDB_INVALID_REGNUM , gdb_gpr_r10 , gpr_r10 }, NULL, NULL},
+ { DEFINE_GPR (r11 , NULL) , { gcc_dwarf_gpr_r11 , gcc_dwarf_gpr_r11 , LLDB_INVALID_REGNUM , gdb_gpr_r11 , gpr_r11 }, NULL, NULL},
+ { DEFINE_GPR (r12 , NULL) , { gcc_dwarf_gpr_r12 , gcc_dwarf_gpr_r12 , LLDB_INVALID_REGNUM , gdb_gpr_r12 , gpr_r12 }, NULL, NULL},
+ { DEFINE_GPR (r13 , NULL) , { gcc_dwarf_gpr_r13 , gcc_dwarf_gpr_r13 , LLDB_INVALID_REGNUM , gdb_gpr_r13 , gpr_r13 }, NULL, NULL},
+ { DEFINE_GPR (r14 , NULL) , { gcc_dwarf_gpr_r14 , gcc_dwarf_gpr_r14 , LLDB_INVALID_REGNUM , gdb_gpr_r14 , gpr_r14 }, NULL, NULL},
+ { DEFINE_GPR (r15 , NULL) , { gcc_dwarf_gpr_r15 , gcc_dwarf_gpr_r15 , LLDB_INVALID_REGNUM , gdb_gpr_r15 , gpr_r15 }, NULL, NULL},
+ { DEFINE_GPR (rip , "pc") , { gcc_dwarf_gpr_rip , gcc_dwarf_gpr_rip , LLDB_REGNUM_GENERIC_PC , gdb_gpr_rip , gpr_rip }, NULL, NULL},
+ { DEFINE_GPR (rflags, "flags") , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, gdb_gpr_rflags , gpr_rflags }, NULL, NULL},
+ { DEFINE_GPR (cs , NULL) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gpr_cs , gpr_cs }, NULL, NULL},
+ { DEFINE_GPR (fs , NULL) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gpr_fs , gpr_fs }, NULL, NULL},
+ { DEFINE_GPR (gs , NULL) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gpr_gs , gpr_gs }, NULL, NULL},
+
+ { DEFINE_FPU_UINT(fcw) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_fcw , fpu_fcw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fsw) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_fsw , fpu_fsw }, NULL, NULL},
+ { DEFINE_FPU_UINT(ftw) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_ftw , fpu_ftw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fop) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_fop , fpu_fop }, NULL, NULL},
+ { DEFINE_FPU_UINT(ip) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_ip , fpu_ip }, NULL, NULL},
+ { DEFINE_FPU_UINT(cs) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_cs , fpu_cs }, NULL, NULL},
+ { DEFINE_FPU_UINT(dp) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_dp , fpu_dp }, NULL, NULL},
+ { DEFINE_FPU_UINT(ds) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_ds , fpu_ds }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsr) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_mxcsr , fpu_mxcsr }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsrmask) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, fpu_mxcsrmask }, NULL, NULL},
+ { DEFINE_FPU_VECT(stmm,0) },
+ { DEFINE_FPU_VECT(stmm,1) },
+ { DEFINE_FPU_VECT(stmm,2) },
+ { DEFINE_FPU_VECT(stmm,3) },
+ { DEFINE_FPU_VECT(stmm,4) },
+ { DEFINE_FPU_VECT(stmm,5) },
+ { DEFINE_FPU_VECT(stmm,6) },
+ { DEFINE_FPU_VECT(stmm,7) },
+ { DEFINE_FPU_VECT(xmm,0) },
+ { DEFINE_FPU_VECT(xmm,1) },
+ { DEFINE_FPU_VECT(xmm,2) },
+ { DEFINE_FPU_VECT(xmm,3) },
+ { DEFINE_FPU_VECT(xmm,4) },
+ { DEFINE_FPU_VECT(xmm,5) },
+ { DEFINE_FPU_VECT(xmm,6) },
+ { DEFINE_FPU_VECT(xmm,7) },
+ { DEFINE_FPU_VECT(xmm,8) },
+ { DEFINE_FPU_VECT(xmm,9) },
+ { DEFINE_FPU_VECT(xmm,10) },
+ { DEFINE_FPU_VECT(xmm,11) },
+ { DEFINE_FPU_VECT(xmm,12) },
+ { DEFINE_FPU_VECT(xmm,13) },
+ { DEFINE_FPU_VECT(xmm,14) },
+ { DEFINE_FPU_VECT(xmm,15) },
+
+ { DEFINE_EXC(trapno) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_trapno }, NULL, NULL},
+ { DEFINE_EXC(err) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_err }, NULL, NULL},
+ { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL}
+};
+
+static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
+
+
+void
+RegisterContextDarwin_x86_64::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_x86_64::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+
+const RegisterInfo *
+RegisterContextDarwin_x86_64::GetRegisterInfoAtIndex (size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+
+size_t
+RegisterContextDarwin_x86_64::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextDarwin_x86_64::GetRegisterInfos ()
+{
+ return g_register_infos;
+}
+
+
+
+static uint32_t g_gpr_regnums[] =
+{
+ gpr_rax,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs
+};
+
+static uint32_t g_fpu_regnums[] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15
+};
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr
+};
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = llvm::array_lengthof(g_gpr_regnums);
+const size_t k_num_fpu_registers = llvm::array_lengthof(g_fpu_regnums);
+const size_t k_num_exc_registers = llvm::array_lengthof(g_exc_regnums);
+
+//----------------------------------------------------------------------
+// Register set definitions. The first definitions at register set index
+// of zero is for all registers, followed by other registers sets. The
+// register information for the all register set need not be filled in.
+//----------------------------------------------------------------------
+static const RegisterSet g_reg_sets[] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums },
+ { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
+};
+
+const size_t k_num_regsets = llvm::array_lengthof(g_reg_sets);
+
+
+size_t
+RegisterContextDarwin_x86_64::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_x86_64::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+int
+RegisterContextDarwin_x86_64::GetSetForNativeRegNum (int reg_num)
+{
+ if (reg_num < fpu_fcw)
+ return GPRRegSet;
+ else if (reg_num < exc_trapno)
+ return FPURegSet;
+ else if (reg_num < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+void
+RegisterContextDarwin_x86_64::LogGPR(Log *log, const char *format, ...)
+{
+ if (log)
+ {
+ if (format)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+ for (uint32_t i=0; i<k_num_gpr_registers; i++)
+ {
+ uint32_t reg = gpr_rax + i;
+ log->Printf("%12s = 0x%16.16" PRIx64, g_register_infos[reg].name, (&gpr.rax)[reg]);
+ }
+ }
+}
+
+int
+RegisterContextDarwin_x86_64::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+int
+RegisterContextDarwin_x86_64::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+int
+RegisterContextDarwin_x86_64::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+int
+RegisterContextDarwin_x86_64::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+int
+RegisterContextDarwin_x86_64::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+int
+RegisterContextDarwin_x86_64::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+int
+RegisterContextDarwin_x86_64::ReadRegisterSet(uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR (force);
+ case FPURegSet: return ReadFPU (force);
+ case EXCRegSet: return ReadEXC (force);
+ default: break;
+ }
+ return -1;
+}
+
+int
+RegisterContextDarwin_x86_64::WriteRegisterSet(uint32_t set)
+{
+ // Make sure we have a valid context to set.
+ switch (set)
+ {
+ case GPRRegSet: return WriteGPR ();
+ case FPURegSet: return WriteFPU ();
+ case EXCRegSet: return WriteEXC ();
+ default: break;
+ }
+ return -1;
+}
+
+
+bool
+RegisterContextDarwin_x86_64::ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_x86_64::GetSetForNativeRegNum (reg);
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_rax:
+ case gpr_rbx:
+ case gpr_rcx:
+ case gpr_rdx:
+ case gpr_rdi:
+ case gpr_rsi:
+ case gpr_rbp:
+ case gpr_rsp:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_r13:
+ case gpr_r14:
+ case gpr_r15:
+ case gpr_rip:
+ case gpr_rflags:
+ case gpr_cs:
+ case gpr_fs:
+ case gpr_gs:
+ value = (&gpr.rax)[reg - gpr_rax];
+ break;
+
+ case fpu_fcw:
+ value = fpu.fcw;
+ break;
+
+ case fpu_fsw:
+ value = fpu.fsw;
+ break;
+
+ case fpu_ftw:
+ value = fpu.ftw;
+ break;
+
+ case fpu_fop:
+ value = fpu.fop;
+ break;
+
+ case fpu_ip:
+ value = fpu.ip;
+ break;
+
+ case fpu_cs:
+ value = fpu.cs;
+ break;
+
+ case fpu_dp:
+ value = fpu.dp;
+ break;
+
+ case fpu_ds:
+ value = fpu.ds;
+ break;
+
+ case fpu_mxcsr:
+ value = fpu.mxcsr;
+ break;
+
+ case fpu_mxcsrmask:
+ value = fpu.mxcsrmask;
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ value.SetBytes(fpu.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder());
+ break;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ value.SetBytes(fpu.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder());
+ break;
+
+ case exc_trapno:
+ value = exc.trapno;
+ break;
+
+ case exc_err:
+ value = exc.err;
+ break;
+
+ case exc_faultvaddr:
+ value = exc.faultvaddr;
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+
+bool
+RegisterContextDarwin_x86_64::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_x86_64::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_rax:
+ case gpr_rbx:
+ case gpr_rcx:
+ case gpr_rdx:
+ case gpr_rdi:
+ case gpr_rsi:
+ case gpr_rbp:
+ case gpr_rsp:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_r13:
+ case gpr_r14:
+ case gpr_r15:
+ case gpr_rip:
+ case gpr_rflags:
+ case gpr_cs:
+ case gpr_fs:
+ case gpr_gs:
+ (&gpr.rax)[reg - gpr_rax] = value.GetAsUInt64();
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.GetAsUInt16();
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.GetAsUInt16();
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.GetAsUInt8();
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.GetAsUInt16();
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.GetAsUInt32();
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.GetAsUInt16();
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.GetAsUInt32();
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.GetAsUInt16();
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.GetAsUInt32();
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.GetAsUInt32();
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ ::memcpy (fpu.stmm[reg - fpu_stmm0].bytes, value.GetBytes(), value.GetByteSize());
+ break;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ ::memcpy (fpu.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize());
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.GetAsUInt32();
+ break;
+
+ case exc_err:
+ exc.err = value.GetAsUInt32();
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.GetAsUInt64();
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == 0;
+}
+
+bool
+RegisterContextDarwin_x86_64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == 0 &&
+ ReadFPU (false) == 0 &&
+ ReadEXC (false) == 0)
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy (dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDarwin_x86_64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy (&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy (&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy (&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == 0)
+ ++success_count;
+ if (WriteFPU() == 0)
+ ++success_count;
+ if (WriteEXC() == 0)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+
+uint32_t
+RegisterContextDarwin_x86_64::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_rip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_rsp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_rbp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_rflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case gcc_dwarf_gpr_rax: return gpr_rax;
+ case gcc_dwarf_gpr_rdx: return gpr_rdx;
+ case gcc_dwarf_gpr_rcx: return gpr_rcx;
+ case gcc_dwarf_gpr_rbx: return gpr_rbx;
+ case gcc_dwarf_gpr_rsi: return gpr_rsi;
+ case gcc_dwarf_gpr_rdi: return gpr_rdi;
+ case gcc_dwarf_gpr_rbp: return gpr_rbp;
+ case gcc_dwarf_gpr_rsp: return gpr_rsp;
+ case gcc_dwarf_gpr_r8: return gpr_r8;
+ case gcc_dwarf_gpr_r9: return gpr_r9;
+ case gcc_dwarf_gpr_r10: return gpr_r10;
+ case gcc_dwarf_gpr_r11: return gpr_r11;
+ case gcc_dwarf_gpr_r12: return gpr_r12;
+ case gcc_dwarf_gpr_r13: return gpr_r13;
+ case gcc_dwarf_gpr_r14: return gpr_r14;
+ case gcc_dwarf_gpr_r15: return gpr_r15;
+ case gcc_dwarf_gpr_rip: return gpr_rip;
+ case gcc_dwarf_fpu_xmm0: return fpu_xmm0;
+ case gcc_dwarf_fpu_xmm1: return fpu_xmm1;
+ case gcc_dwarf_fpu_xmm2: return fpu_xmm2;
+ case gcc_dwarf_fpu_xmm3: return fpu_xmm3;
+ case gcc_dwarf_fpu_xmm4: return fpu_xmm4;
+ case gcc_dwarf_fpu_xmm5: return fpu_xmm5;
+ case gcc_dwarf_fpu_xmm6: return fpu_xmm6;
+ case gcc_dwarf_fpu_xmm7: return fpu_xmm7;
+ case gcc_dwarf_fpu_xmm8: return fpu_xmm8;
+ case gcc_dwarf_fpu_xmm9: return fpu_xmm9;
+ case gcc_dwarf_fpu_xmm10: return fpu_xmm10;
+ case gcc_dwarf_fpu_xmm11: return fpu_xmm11;
+ case gcc_dwarf_fpu_xmm12: return fpu_xmm12;
+ case gcc_dwarf_fpu_xmm13: return fpu_xmm13;
+ case gcc_dwarf_fpu_xmm14: return fpu_xmm14;
+ case gcc_dwarf_fpu_xmm15: return fpu_xmm15;
+ case gcc_dwarf_fpu_stmm0: return fpu_stmm0;
+ case gcc_dwarf_fpu_stmm1: return fpu_stmm1;
+ case gcc_dwarf_fpu_stmm2: return fpu_stmm2;
+ case gcc_dwarf_fpu_stmm3: return fpu_stmm3;
+ case gcc_dwarf_fpu_stmm4: return fpu_stmm4;
+ case gcc_dwarf_fpu_stmm5: return fpu_stmm5;
+ case gcc_dwarf_fpu_stmm6: return fpu_stmm6;
+ case gcc_dwarf_fpu_stmm7: return fpu_stmm7;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGDB)
+ {
+ switch (reg)
+ {
+ case gdb_gpr_rax : return gpr_rax;
+ case gdb_gpr_rbx : return gpr_rbx;
+ case gdb_gpr_rcx : return gpr_rcx;
+ case gdb_gpr_rdx : return gpr_rdx;
+ case gdb_gpr_rsi : return gpr_rsi;
+ case gdb_gpr_rdi : return gpr_rdi;
+ case gdb_gpr_rbp : return gpr_rbp;
+ case gdb_gpr_rsp : return gpr_rsp;
+ case gdb_gpr_r8 : return gpr_r8;
+ case gdb_gpr_r9 : return gpr_r9;
+ case gdb_gpr_r10 : return gpr_r10;
+ case gdb_gpr_r11 : return gpr_r11;
+ case gdb_gpr_r12 : return gpr_r12;
+ case gdb_gpr_r13 : return gpr_r13;
+ case gdb_gpr_r14 : return gpr_r14;
+ case gdb_gpr_r15 : return gpr_r15;
+ case gdb_gpr_rip : return gpr_rip;
+ case gdb_gpr_rflags : return gpr_rflags;
+ case gdb_gpr_cs : return gpr_cs;
+ case gdb_gpr_ss : return gpr_gs; // HACK: For now for "ss", just copy what is in "gs"
+ case gdb_gpr_ds : return gpr_gs; // HACK: For now for "ds", just copy what is in "gs"
+ case gdb_gpr_es : return gpr_gs; // HACK: For now for "es", just copy what is in "gs"
+ case gdb_gpr_fs : return gpr_fs;
+ case gdb_gpr_gs : return gpr_gs;
+ case gdb_fpu_stmm0 : return fpu_stmm0;
+ case gdb_fpu_stmm1 : return fpu_stmm1;
+ case gdb_fpu_stmm2 : return fpu_stmm2;
+ case gdb_fpu_stmm3 : return fpu_stmm3;
+ case gdb_fpu_stmm4 : return fpu_stmm4;
+ case gdb_fpu_stmm5 : return fpu_stmm5;
+ case gdb_fpu_stmm6 : return fpu_stmm6;
+ case gdb_fpu_stmm7 : return fpu_stmm7;
+ case gdb_fpu_fctrl : return fpu_fctrl;
+ case gdb_fpu_fstat : return fpu_fstat;
+ case gdb_fpu_ftag : return fpu_ftag;
+ case gdb_fpu_fiseg : return fpu_fiseg;
+ case gdb_fpu_fioff : return fpu_fioff;
+ case gdb_fpu_foseg : return fpu_foseg;
+ case gdb_fpu_fooff : return fpu_fooff;
+ case gdb_fpu_fop : return fpu_fop;
+ case gdb_fpu_xmm0 : return fpu_xmm0;
+ case gdb_fpu_xmm1 : return fpu_xmm1;
+ case gdb_fpu_xmm2 : return fpu_xmm2;
+ case gdb_fpu_xmm3 : return fpu_xmm3;
+ case gdb_fpu_xmm4 : return fpu_xmm4;
+ case gdb_fpu_xmm5 : return fpu_xmm5;
+ case gdb_fpu_xmm6 : return fpu_xmm6;
+ case gdb_fpu_xmm7 : return fpu_xmm7;
+ case gdb_fpu_xmm8 : return fpu_xmm8;
+ case gdb_fpu_xmm9 : return fpu_xmm9;
+ case gdb_fpu_xmm10 : return fpu_xmm10;
+ case gdb_fpu_xmm11 : return fpu_xmm11;
+ case gdb_fpu_xmm12 : return fpu_xmm12;
+ case gdb_fpu_xmm13 : return fpu_xmm13;
+ case gdb_fpu_xmm14 : return fpu_xmm14;
+ case gdb_fpu_xmm15 : return fpu_xmm15;
+ case gdb_fpu_mxcsr : return fpu_mxcsr;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+bool
+RegisterContextDarwin_x86_64::HardwareSingleStep (bool enable)
+{
+ if (ReadGPR(true) != 0)
+ return false;
+
+ const uint64_t trace_bit = 0x100ull;
+ if (enable)
+ {
+
+ if (gpr.rflags & trace_bit)
+ return true; // trace bit is already set, there is nothing to do
+ else
+ gpr.rflags |= trace_bit;
+ }
+ else
+ {
+ if (gpr.rflags & trace_bit)
+ gpr.rflags &= ~trace_bit;
+ else
+ return true; // trace bit is clear, there is nothing to do
+ }
+
+ return WriteGPR() == 0;
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h
new file mode 100644
index 0000000..09e35e9
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h
@@ -0,0 +1,274 @@
+//===-- RegisterContextDarwin_x86_64.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextDarwin_x86_64_h_
+#define liblldb_RegisterContextDarwin_x86_64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+class RegisterContextDarwin_x86_64 : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextDarwin_x86_64 (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_x86_64();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ struct GPR
+ {
+ uint64_t rax;
+ uint64_t rbx;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rsp;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t rip;
+ uint64_t rflags;
+ uint64_t cs;
+ uint64_t fs;
+ uint64_t gs;
+ };
+
+ struct MMSReg
+ {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ uint32_t pad[2];
+ uint16_t fcw; // "fctrl"
+ uint16_t fsw; // "fstat"
+ uint8_t ftw; // "ftag"
+ uint8_t pad1;
+ uint16_t fop; // "fop"
+ uint32_t ip; // "fioff"
+ uint16_t cs; // "fiseg"
+ uint16_t pad2;
+ uint32_t dp; // "fooff"
+ uint16_t ds; // "foseg"
+ uint16_t pad3;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[16];
+ uint8_t pad4[6*16];
+ int pad5;
+ };
+
+ struct EXC
+ {
+ uint32_t trapno;
+ uint32_t err;
+ uint64_t faultvaddr;
+ };
+
+protected:
+
+ enum
+ {
+ GPRRegSet = 4,
+ FPURegSet = 5,
+ EXCRegSet = 6
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t)
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ int
+ GetError (int flavor, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet: return gpr_errs[err_idx];
+ case FPURegSet: return fpu_errs[err_idx];
+ case EXCRegSet: return exc_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+
+ bool
+ SetError (int flavor, uint32_t err_idx, int err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == 0;
+ }
+
+ void
+ LogGPR (lldb_private::Log *log, const char *format, ...);
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) = 0;
+
+ virtual int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ int
+ ReadRegisterSet (uint32_t set, bool force);
+
+ int
+ WriteRegisterSet (uint32_t set);
+
+ static uint32_t
+ GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num);
+
+ static int
+ GetSetForNativeRegNum (int reg_num);
+
+ static size_t
+ GetRegisterInfosCount ();
+
+ static const lldb_private::RegisterInfo *
+ GetRegisterInfos ();
+
+};
+
+#endif // liblldb_RegisterContextDarwin_x86_64_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp
new file mode 100644
index 0000000..329b0a7
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.cpp
@@ -0,0 +1,137 @@
+//===-- RegisterContextDummy.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "RegisterContextDummy.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextDummy::RegisterContextDummy (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size) :
+RegisterContext (thread, concrete_frame_idx)
+{
+ m_reg_set0.name = "General Purpose Registers";
+ m_reg_set0.short_name = "GPR";
+ m_reg_set0.num_registers = 1;
+ m_reg_set0.registers = new uint32_t(0);
+
+ m_pc_reg_info.name = "pc";
+ m_pc_reg_info.alt_name = "pc";
+ m_pc_reg_info.byte_offset = 0;
+ m_pc_reg_info.byte_size = address_byte_size;
+ m_pc_reg_info.encoding = eEncodingUint;
+ m_pc_reg_info.format = eFormatPointer;
+ m_pc_reg_info.invalidate_regs = NULL;
+ m_pc_reg_info.value_regs = NULL;
+ m_pc_reg_info.kinds[eRegisterKindGCC] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindDWARF] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ m_pc_reg_info.kinds[eRegisterKindGDB] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindLLDB] = LLDB_INVALID_REGNUM;
+}
+
+RegisterContextDummy::~RegisterContextDummy ()
+{
+ delete m_reg_set0.registers;
+ delete m_pc_reg_info.invalidate_regs;
+ delete m_pc_reg_info.value_regs;
+}
+
+void
+RegisterContextDummy::InvalidateAllRegisters () {}
+
+size_t
+RegisterContextDummy::GetRegisterCount ()
+{
+ return 1;
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextDummy::GetRegisterInfoAtIndex (size_t reg)
+{
+ if (reg)
+ return NULL;
+ return &m_pc_reg_info;
+}
+
+size_t
+RegisterContextDummy::GetRegisterSetCount ()
+{
+ return 1;
+}
+
+const lldb_private::RegisterSet *
+RegisterContextDummy::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set)
+ return NULL;
+ return &m_reg_set0;
+}
+
+bool
+RegisterContextDummy::ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+ uint32_t reg_number = reg_info->kinds[eRegisterKindGeneric];
+ if (reg_number == LLDB_REGNUM_GENERIC_PC)
+ {
+ value.SetUInt(LLDB_INVALID_ADDRESS, reg_info->byte_size);
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDummy::WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextDummy::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextDummy::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+uint32_t
+RegisterContextDummy::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num)
+{
+ if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC)
+ return 0;
+ return LLDB_INVALID_REGNUM;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h
new file mode 100644
index 0000000..ddf4667
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextDummy.h
@@ -0,0 +1,77 @@
+//===-- RegisterContextDummy.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextDummy_h_
+#define lldb_RegisterContextDummy_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+namespace lldb_private {
+
+class RegisterContextDummy : public lldb_private::RegisterContext
+{
+public:
+ typedef std::shared_ptr<RegisterContextDummy> SharedPtr;
+
+ RegisterContextDummy (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size);
+
+ ///
+ // pure virtual functions from the base class that we must implement
+ ///
+
+ virtual
+ ~RegisterContextDummy ();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
+
+private:
+ //------------------------------------------------------------------
+ // For RegisterContextLLDB only
+ //------------------------------------------------------------------
+
+ lldb_private::RegisterSet m_reg_set0; // register set 0 (PC only)
+ lldb_private::RegisterInfo m_pc_reg_info;
+
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextDummy);
+};
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextDummy_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp
new file mode 100644
index 0000000..8005a63
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp
@@ -0,0 +1,88 @@
+//===-- RegisterContextFreeBSD_arm.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include <stddef.h>
+#include <vector>
+#include <cassert>
+
+#include "llvm/Support/Compiler.h"
+#include "lldb/lldb-defines.h"
+
+#include "RegisterContextFreeBSD_arm.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Based on RegisterContextLinux_arm.cpp and
+// http://svnweb.freebsd.org/base/head/sys/arm/include/reg.h
+#define GPR_OFFSET(idx) ((idx) * 4)
+#define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextFreeBSD_arm::GPR))
+#define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextFreeBSD_arm::GPR) + sizeof (RegisterContextFreeBSD_arm::FPU))
+#define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm::DBG, reg) + sizeof (RegisterContextFreeBSD_arm::GPR) + sizeof (RegisterContextFreeBSD_arm::FPU) + sizeof (RegisterContextFreeBSD_arm::EXC)))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextFreeBSD_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextFreeBSD_arm::GPR) + sizeof (RegisterContextFreeBSD_arm::FPU) + sizeof (RegisterContextFreeBSD_arm::EXC))
+
+//-----------------------------------------------------------------------------
+// Include RegisterInfos_arm to declare our g_register_infos_arm structure.
+//-----------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_ARM_STRUCT
+#include "RegisterInfos_arm.h"
+#undef DECLARE_REGISTER_INFOS_ARM_STRUCT
+
+static const lldb_private::RegisterInfo *
+GetRegisterInfoPtr (const lldb_private::ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ return g_register_infos_arm;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return NULL;
+ }
+}
+
+static uint32_t
+GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ return static_cast<uint32_t>(sizeof(g_register_infos_arm) / sizeof(g_register_infos_arm[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextFreeBSD_arm::RegisterContextFreeBSD_arm(const lldb_private::ArchSpec &target_arch) :
+ lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p(GetRegisterInfoPtr(target_arch)),
+ m_register_info_count(GetRegisterInfoCount(target_arch))
+{
+}
+
+size_t
+RegisterContextFreeBSD_arm::GetGPRSize() const
+{
+ return sizeof(struct RegisterContextFreeBSD_arm::GPR);
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextFreeBSD_arm::GetRegisterInfo() const
+{
+ return m_register_info_p;
+}
+
+uint32_t
+RegisterContextFreeBSD_arm::GetRegisterCount() const
+{
+ return m_register_info_count;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.h
new file mode 100644
index 0000000..c4287e9
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.h
@@ -0,0 +1,75 @@
+//===-- RegisterContextFreeBSD_arm.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextFreeBSD_arm_h_
+#define liblldb_RegisterContextFreeBSD_arm_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "RegisterContextPOSIX.h"
+#include "RegisterInfoInterface.h"
+
+class RegisterContextFreeBSD_arm
+ : public lldb_private::RegisterInfoInterface
+{
+public:
+
+ struct GPR
+ {
+ uint32_t r[16]; // R0-R15
+ uint32_t cpsr; // CPSR
+ };
+
+
+ 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;
+ };
+ struct EXC
+ {
+ uint32_t exception;
+ uint32_t fsr; /* Fault status */
+ uint32_t far; /* Virtual Fault Address */
+ };
+
+ struct DBG
+ {
+ uint32_t bvr[16];
+ uint32_t bcr[16];
+ uint32_t wvr[16];
+ uint32_t wcr[16];
+ };
+
+ RegisterContextFreeBSD_arm(const lldb_private::ArchSpec &target_arch);
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
+};
+
+#endif // liblldb_RegisterContextFreeBSD_arm_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.cpp
new file mode 100644
index 0000000..d39a9da
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.cpp
@@ -0,0 +1,86 @@
+//===-- RegisterContextFreeBSD_arm64.cpp ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include <vector>
+#include "RegisterContextPOSIX_arm64.h"
+#include "RegisterContextFreeBSD_arm64.h"
+
+using namespace lldb;
+
+// Based on RegisterContextDarwin_arm64.cpp
+#define GPR_OFFSET(idx) ((idx) * 8)
+#define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::GPR, reg))
+
+#define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextFreeBSD_arm64::GPR))
+#define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::FPU, reg))
+
+#define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::EXC, reg) + sizeof (RegisterContextFreeBSD_arm64::GPR) + sizeof (RegisterContextFreeBSD_arm64::FPU))
+#define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::DBG, reg) + sizeof (RegisterContextFreeBSD_arm64::GPR) + sizeof (RegisterContextFreeBSD_arm64::FPU) + sizeof (RegisterContextFreeBSD_arm64::EXC))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextFreeBSD_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextFreeBSD_arm64::GPR) + sizeof (RegisterContextFreeBSD_arm64::FPU) + sizeof (RegisterContextFreeBSD_arm64::EXC))
+
+//-----------------------------------------------------------------------------
+// Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure.
+//-----------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_ARM64_STRUCT
+#include "RegisterInfos_arm64.h"
+#undef DECLARE_REGISTER_INFOS_ARM64_STRUCT
+
+static const lldb_private::RegisterInfo *
+GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ return g_register_infos_arm64;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+static uint32_t
+GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ return static_cast<uint32_t>(sizeof(g_register_infos_arm64) / sizeof(g_register_infos_arm64[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextFreeBSD_arm64::RegisterContextFreeBSD_arm64(const lldb_private::ArchSpec &target_arch) :
+ RegisterInfoInterface(target_arch),
+ m_register_info_p(GetRegisterInfoPtr(target_arch)),
+ m_register_info_count(GetRegisterInfoCount(target_arch))
+{
+}
+
+size_t
+RegisterContextFreeBSD_arm64::GetGPRSize() const
+{
+ return sizeof(struct RegisterContextFreeBSD_arm64::GPR);
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextFreeBSD_arm64::GetRegisterInfo() const
+{
+ return m_register_info_p;
+}
+
+uint32_t
+RegisterContextFreeBSD_arm64::GetRegisterCount() const
+{
+ return m_register_info_count;
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h
new file mode 100644
index 0000000..249027a
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h
@@ -0,0 +1,78 @@
+//===-- RegisterContextFreeBSD_arm64.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextFreeBSD_arm64_H_
+#define liblldb_RegisterContextFreeBSD_arm64_H_
+
+#include "RegisterContextPOSIX.h"
+
+class RegisterContextFreeBSD_arm64:
+ public lldb_private::RegisterInfoInterface
+{
+public:
+ // based on RegisterContextDarwin_arm64.h
+ struct GPR
+ {
+ uint64_t x[29]; // x0-x28
+ uint64_t fp; // x29
+ uint64_t lr; // x30
+ uint64_t sp; // x31
+ uint64_t pc; // pc
+ uint32_t cpsr; // cpsr
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct VReg
+ {
+ uint8_t bytes[16];
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct FPU
+ {
+ VReg v[32];
+ uint32_t fpsr;
+ uint32_t fpcr;
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct EXC
+ {
+ uint64_t far; // Virtual Fault Address
+ uint32_t esr; // Exception syndrome
+ uint32_t exception; // number of arm exception token
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct DBG
+ {
+ uint64_t bvr[16];
+ uint64_t bcr[16];
+ uint64_t wvr[16];
+ uint64_t wcr[16];
+ uint64_t mdscr_el1;
+ };
+
+ RegisterContextFreeBSD_arm64(const lldb_private::ArchSpec &target_arch);
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
new file mode 100644
index 0000000..0171da6
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp
@@ -0,0 +1,95 @@
+//===-- RegisterContextFreeBSD_i386.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "RegisterContextPOSIX_x86.h"
+#include "RegisterContextFreeBSD_i386.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// http://svnweb.freebsd.org/base/head/sys/x86/include/reg.h
+struct GPR
+{
+ uint32_t fs;
+ uint32_t es;
+ uint32_t ds;
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebp;
+ uint32_t isp;
+ uint32_t ebx;
+ uint32_t edx;
+ uint32_t ecx;
+ uint32_t eax;
+ uint32_t trapno;
+ uint32_t err;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t eflags;
+ uint32_t esp;
+ uint32_t ss;
+ uint32_t gs;
+};
+
+struct dbreg {
+ uint32_t dr[8]; /* debug registers */
+ /* Index 0-3: debug address registers */
+ /* Index 4-5: reserved */
+ /* Index 6: debug status */
+ /* Index 7: debug control */
+};
+
+using FPR_i386 = FXSAVE;
+
+struct UserArea
+{
+ GPR gpr;
+ FPR_i386 i387;
+};
+
+#define DR_SIZE sizeof(uint32_t)
+#define DR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(dbreg, dr[reg_index]))
+
+//---------------------------------------------------------------------------
+// Include RegisterInfos_i386 to declare our g_register_infos_i386 structure.
+//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_I386_STRUCT
+#include "RegisterInfos_i386.h"
+#undef DECLARE_REGISTER_INFOS_I386_STRUCT
+
+RegisterContextFreeBSD_i386::RegisterContextFreeBSD_i386(const ArchSpec &target_arch) :
+ RegisterInfoInterface(target_arch)
+{
+}
+
+size_t
+RegisterContextFreeBSD_i386::GetGPRSize() const
+{
+ return sizeof(GPR);
+}
+
+const RegisterInfo *
+RegisterContextFreeBSD_i386::GetRegisterInfo() const
+{
+ switch (m_target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ return g_register_infos_i386;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return NULL;
+ }
+}
+
+uint32_t
+RegisterContextFreeBSD_i386::GetRegisterCount () const
+{
+ return static_cast<uint32_t> (sizeof (g_register_infos_i386) / sizeof (g_register_infos_i386 [0]));
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h
new file mode 100644
index 0000000..62792c0
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.h
@@ -0,0 +1,31 @@
+//===-- RegisterContextFreeBSD_i386.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextFreeBSD_i386_H_
+#define liblldb_RegisterContextFreeBSD_i386_H_
+
+#include "RegisterContextPOSIX.h"
+
+class RegisterContextFreeBSD_i386
+ : public lldb_private::RegisterInfoInterface
+{
+public:
+ RegisterContextFreeBSD_i386(const lldb_private::ArchSpec &target_arch);
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp
new file mode 100644
index 0000000..53fa416
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.cpp
@@ -0,0 +1,93 @@
+//===-- RegisterContextFreeBSD_mips64.cpp ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include <vector>
+#include "RegisterContextPOSIX_mips64.h"
+#include "RegisterContextFreeBSD_mips64.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// http://svnweb.freebsd.org/base/head/sys/mips/include/regnum.h
+typedef struct _GPR
+{
+ uint64_t zero;
+ uint64_t r1;
+ uint64_t r2;
+ uint64_t r3;
+ uint64_t r4;
+ uint64_t r5;
+ uint64_t r6;
+ uint64_t r7;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t r16;
+ uint64_t r17;
+ uint64_t r18;
+ uint64_t r19;
+ uint64_t r20;
+ uint64_t r21;
+ uint64_t r22;
+ uint64_t r23;
+ uint64_t r24;
+ uint64_t r25;
+ uint64_t r26;
+ uint64_t r27;
+ uint64_t gp;
+ uint64_t sp;
+ uint64_t r30;
+ uint64_t ra;
+ uint64_t sr;
+ uint64_t mullo;
+ uint64_t mulhi;
+ uint64_t badvaddr;
+ uint64_t cause;
+ uint64_t pc;
+ uint64_t ic;
+ uint64_t dummy;
+} GPR_freebsd_mips;
+
+//---------------------------------------------------------------------------
+// Include RegisterInfos_mips64 to declare our g_register_infos_mips64 structure.
+//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_MIPS64_STRUCT
+#include "RegisterInfos_mips64.h"
+#undef DECLARE_REGISTER_INFOS_MIPS64_STRUCT
+
+RegisterContextFreeBSD_mips64::RegisterContextFreeBSD_mips64(const ArchSpec &target_arch) :
+ RegisterInfoInterface(target_arch)
+{
+}
+
+size_t
+RegisterContextFreeBSD_mips64::GetGPRSize() const
+{
+ return sizeof(GPR_freebsd_mips);
+}
+
+const RegisterInfo *
+RegisterContextFreeBSD_mips64::GetRegisterInfo() const
+{
+ assert (m_target_arch.GetCore() == ArchSpec::eCore_mips64);
+ return g_register_infos_mips64;
+}
+
+uint32_t
+RegisterContextFreeBSD_mips64::GetRegisterCount () const
+{
+ return static_cast<uint32_t> (sizeof (g_register_infos_mips64) / sizeof (g_register_infos_mips64 [0]));
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h
new file mode 100644
index 0000000..f9a3ce0
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h
@@ -0,0 +1,31 @@
+//===-- RegisterContextFreeBSD_mips64.h -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextFreeBSD_mips64_H_
+#define liblldb_RegisterContextFreeBSD_mips64_H_
+
+#include "RegisterContextPOSIX.h"
+
+class RegisterContextFreeBSD_mips64:
+ public lldb_private::RegisterInfoInterface
+{
+public:
+ RegisterContextFreeBSD_mips64(const lldb_private::ArchSpec &target_arch);
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp
new file mode 100644
index 0000000..5133d60
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp
@@ -0,0 +1,269 @@
+//===-- RegisterContextFreeBSD_powerpc.cpp ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include <vector>
+#include "RegisterContextPOSIX_powerpc.h"
+#include "RegisterContextFreeBSD_powerpc.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// http://svnweb.freebsd.org/base/head/sys/powerpc/include/reg.h
+typedef struct _GPR64
+{
+ uint64_t r0;
+ uint64_t r1;
+ uint64_t r2;
+ uint64_t r3;
+ uint64_t r4;
+ uint64_t r5;
+ uint64_t r6;
+ uint64_t r7;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t r16;
+ uint64_t r17;
+ uint64_t r18;
+ uint64_t r19;
+ uint64_t r20;
+ uint64_t r21;
+ uint64_t r22;
+ uint64_t r23;
+ uint64_t r24;
+ uint64_t r25;
+ uint64_t r26;
+ uint64_t r27;
+ uint64_t r28;
+ uint64_t r29;
+ uint64_t r30;
+ uint64_t r31;
+ uint64_t lr;
+ uint64_t cr;
+ uint64_t xer;
+ uint64_t ctr;
+ uint64_t pc;
+} GPR64;
+
+typedef struct _GPR32
+{
+ uint32_t r0;
+ uint32_t r1;
+ uint32_t r2;
+ uint32_t r3;
+ uint32_t r4;
+ uint32_t r5;
+ uint32_t r6;
+ uint32_t r7;
+ uint32_t r8;
+ uint32_t r9;
+ uint32_t r10;
+ uint32_t r11;
+ uint32_t r12;
+ uint32_t r13;
+ uint32_t r14;
+ uint32_t r15;
+ uint32_t r16;
+ uint32_t r17;
+ uint32_t r18;
+ uint32_t r19;
+ uint32_t r20;
+ uint32_t r21;
+ uint32_t r22;
+ uint32_t r23;
+ uint32_t r24;
+ uint32_t r25;
+ uint32_t r26;
+ uint32_t r27;
+ uint32_t r28;
+ uint32_t r29;
+ uint32_t r30;
+ uint32_t r31;
+ uint32_t lr;
+ uint32_t cr;
+ uint32_t xer;
+ uint32_t ctr;
+ uint32_t pc;
+} GPR32;
+
+typedef struct _FPR
+{
+ uint64_t f0;
+ uint64_t f1;
+ uint64_t f2;
+ uint64_t f3;
+ uint64_t f4;
+ uint64_t f5;
+ uint64_t f6;
+ uint64_t f7;
+ uint64_t f8;
+ uint64_t f9;
+ uint64_t f10;
+ uint64_t f11;
+ uint64_t f12;
+ uint64_t f13;
+ uint64_t f14;
+ uint64_t f15;
+ uint64_t f16;
+ uint64_t f17;
+ uint64_t f18;
+ uint64_t f19;
+ uint64_t f20;
+ uint64_t f21;
+ uint64_t f22;
+ uint64_t f23;
+ uint64_t f24;
+ uint64_t f25;
+ uint64_t f26;
+ uint64_t f27;
+ uint64_t f28;
+ uint64_t f29;
+ uint64_t f30;
+ uint64_t f31;
+ uint64_t fpscr;
+} FPR;
+
+typedef struct _VMX
+{
+ uint32_t v0[4];
+ uint32_t v1[4];
+ uint32_t v2[4];
+ uint32_t v3[4];
+ uint32_t v4[4];
+ uint32_t v5[4];
+ uint32_t v6[4];
+ uint32_t v7[4];
+ uint32_t v8[4];
+ uint32_t v9[4];
+ uint32_t v10[4];
+ uint32_t v11[4];
+ uint32_t v12[4];
+ uint32_t v13[4];
+ uint32_t v14[4];
+ uint32_t v15[4];
+ uint32_t v16[4];
+ uint32_t v17[4];
+ uint32_t v18[4];
+ uint32_t v19[4];
+ uint32_t v20[4];
+ uint32_t v21[4];
+ uint32_t v22[4];
+ uint32_t v23[4];
+ uint32_t v24[4];
+ uint32_t v25[4];
+ uint32_t v26[4];
+ uint32_t v27[4];
+ uint32_t v28[4];
+ uint32_t v29[4];
+ uint32_t v30[4];
+ uint32_t v31[4];
+ uint32_t pad[2];
+ uint32_t vrsave;
+ uint32_t vscr;
+} VMX;
+
+//---------------------------------------------------------------------------
+// Include RegisterInfos_powerpc to declare our g_register_infos_powerpc structure.
+//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_POWERPC_STRUCT
+#include "RegisterInfos_powerpc.h"
+#undef DECLARE_REGISTER_INFOS_POWERPC_STRUCT
+
+RegisterContextFreeBSD_powerpc::RegisterContextFreeBSD_powerpc(const ArchSpec &target_arch) :
+ RegisterInfoInterface(target_arch)
+{
+}
+
+RegisterContextFreeBSD_powerpc::~RegisterContextFreeBSD_powerpc()
+{
+}
+
+size_t
+RegisterContextFreeBSD_powerpc::GetGPRSize() const
+{
+ // This is an 'abstract' base, so no GPR struct.
+ return 0;
+}
+
+const RegisterInfo *
+RegisterContextFreeBSD_powerpc::GetRegisterInfo() const
+{
+ //assert (m_target_arch.GetCore() == ArchSpec::eCore_powerpc);
+ llvm_unreachable("Abstract class!");
+ return NULL;
+}
+
+uint32_t
+RegisterContextFreeBSD_powerpc::GetRegisterCount () const
+{
+ return 0;
+}
+
+RegisterContextFreeBSD_powerpc32::RegisterContextFreeBSD_powerpc32(const ArchSpec &target_arch) :
+ RegisterContextFreeBSD_powerpc(target_arch)
+{
+}
+
+RegisterContextFreeBSD_powerpc32::~RegisterContextFreeBSD_powerpc32()
+{
+}
+
+size_t
+RegisterContextFreeBSD_powerpc32::GetGPRSize() const
+{
+ return sizeof(GPR32);
+}
+
+const RegisterInfo *
+RegisterContextFreeBSD_powerpc32::GetRegisterInfo() const
+{
+ //assert (m_target_arch.GetCore() == ArchSpec::eCore_powerpc);
+ return g_register_infos_powerpc32;
+}
+
+uint32_t
+RegisterContextFreeBSD_powerpc32::GetRegisterCount () const
+{
+ return static_cast<uint32_t> (sizeof (g_register_infos_powerpc32) / sizeof (g_register_infos_powerpc32 [0]));
+}
+
+RegisterContextFreeBSD_powerpc64::RegisterContextFreeBSD_powerpc64(const ArchSpec &target_arch) :
+ RegisterContextFreeBSD_powerpc(target_arch)
+{
+}
+
+RegisterContextFreeBSD_powerpc64::~RegisterContextFreeBSD_powerpc64()
+{
+}
+
+size_t
+RegisterContextFreeBSD_powerpc64::GetGPRSize() const
+{
+ return sizeof(GPR64);
+}
+
+const RegisterInfo *
+RegisterContextFreeBSD_powerpc64::GetRegisterInfo() const
+{
+ //assert (m_target_arch.GetCore() == ArchSpec::eCore_powerpc);
+ if (m_target_arch.GetMachine() == llvm::Triple::ppc)
+ return g_register_infos_powerpc64_32;
+ return g_register_infos_powerpc64;
+}
+
+uint32_t
+RegisterContextFreeBSD_powerpc64::GetRegisterCount () const
+{
+ return static_cast<uint32_t> (sizeof (g_register_infos_powerpc64) / sizeof (g_register_infos_powerpc64 [0]));
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h
new file mode 100644
index 0000000..b907fe9
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h
@@ -0,0 +1,66 @@
+//===-- RegisterContextFreeBSD_powerpc.h -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextFreeBSD_powerpc_H_
+#define liblldb_RegisterContextFreeBSD_powerpc_H_
+
+#include "RegisterContextPOSIX.h"
+
+class RegisterContextFreeBSD_powerpc:
+ public lldb_private::RegisterInfoInterface
+{
+public:
+ RegisterContextFreeBSD_powerpc(const lldb_private::ArchSpec &target_arch);
+ virtual ~RegisterContextFreeBSD_powerpc();
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount() const override;
+};
+
+class RegisterContextFreeBSD_powerpc32:
+ public RegisterContextFreeBSD_powerpc
+{
+public:
+ RegisterContextFreeBSD_powerpc32(const lldb_private::ArchSpec &target_arch);
+ virtual ~RegisterContextFreeBSD_powerpc32();
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount() const override;
+};
+
+class RegisterContextFreeBSD_powerpc64:
+ public RegisterContextFreeBSD_powerpc
+{
+public:
+ RegisterContextFreeBSD_powerpc64(const lldb_private::ArchSpec &target_arch);
+ virtual ~RegisterContextFreeBSD_powerpc64();
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount() const override;
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
new file mode 100644
index 0000000..34f2d18
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp
@@ -0,0 +1,164 @@
+//===-- RegisterContextFreeBSD_x86_64.cpp ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include <vector>
+#include "RegisterContextPOSIX_x86.h"
+#include "RegisterContextFreeBSD_i386.h"
+#include "RegisterContextFreeBSD_x86_64.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// http://svnweb.freebsd.org/base/head/sys/x86/include/reg.h
+typedef struct _GPR
+{
+ uint64_t r15;
+ uint64_t r14;
+ uint64_t r13;
+ uint64_t r12;
+ uint64_t r11;
+ uint64_t r10;
+ uint64_t r9;
+ uint64_t r8;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rbx;
+ uint64_t rdx;
+ uint64_t rcx;
+ uint64_t rax;
+ uint32_t trapno;
+ uint16_t fs;
+ uint16_t gs;
+ uint32_t err;
+ uint16_t es;
+ uint16_t ds;
+ uint64_t rip;
+ uint64_t cs;
+ uint64_t rflags;
+ uint64_t rsp;
+ uint64_t ss;
+} GPR;
+
+struct DBG {
+ uint64_t dr[16]; /* debug registers */
+ /* Index 0-3: debug address registers */
+ /* Index 4-5: reserved */
+ /* Index 6: debug status */
+ /* Index 7: debug control */
+ /* Index 8-15: reserved */
+};
+
+struct UserArea
+{
+ GPR gpr;
+ FPR fpr;
+ DBG dbg;
+};
+
+#define DR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(DBG, dr[reg_index]))
+
+//---------------------------------------------------------------------------
+// Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64 structure.
+//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_X86_64_STRUCT
+#include "RegisterInfos_x86_64.h"
+#undef DECLARE_REGISTER_INFOS_X86_64_STRUCT
+
+static std::vector<lldb_private::RegisterInfo>&
+GetSharedRegisterInfoVector ()
+{
+ static std::vector<lldb_private::RegisterInfo> register_infos;
+ return register_infos;
+}
+
+static const RegisterInfo *
+GetRegisterInfo_i386(const lldb_private::ArchSpec& arch)
+{
+ static std::vector<lldb_private::RegisterInfo> g_register_infos (GetSharedRegisterInfoVector ());
+
+ // Allocate RegisterInfo only once
+ if (g_register_infos.empty())
+ {
+ // Copy the register information from base class
+ std::unique_ptr<RegisterContextFreeBSD_i386> reg_interface(new RegisterContextFreeBSD_i386 (arch));
+ const RegisterInfo *base_info = reg_interface->GetRegisterInfo();
+ g_register_infos.insert(g_register_infos.end(), &base_info[0], &base_info[k_num_registers_i386]);
+
+ //---------------------------------------------------------------------------
+ // Include RegisterInfos_x86_64 to update the g_register_infos structure
+ // with x86_64 offsets.
+ //---------------------------------------------------------------------------
+ #define UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+ #include "RegisterInfos_x86_64.h"
+ #undef UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+ }
+
+ return &g_register_infos[0];
+}
+
+static const RegisterInfo *
+PrivateGetRegisterInfoPtr (const lldb_private::ArchSpec& target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ return GetRegisterInfo_i386 (target_arch);
+ case llvm::Triple::x86_64:
+ return g_register_infos_x86_64;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+static uint32_t
+PrivateGetRegisterCount (const lldb_private::ArchSpec& target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ // This vector should have already been filled.
+ assert (!GetSharedRegisterInfoVector ().empty () && "i386 register info vector not filled.");
+ return static_cast<uint32_t> (GetSharedRegisterInfoVector().size ());
+ case llvm::Triple::x86_64:
+ return static_cast<uint32_t> (sizeof (g_register_infos_x86_64) / sizeof (g_register_infos_x86_64 [0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(const ArchSpec &target_arch) :
+ lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p (PrivateGetRegisterInfoPtr (target_arch)),
+ m_register_count (PrivateGetRegisterCount (target_arch))
+{
+}
+
+size_t
+RegisterContextFreeBSD_x86_64::GetGPRSize() const
+{
+ return sizeof(GPR);
+}
+
+const RegisterInfo *
+RegisterContextFreeBSD_x86_64::GetRegisterInfo() const
+{
+ return m_register_info_p;
+}
+
+uint32_t
+RegisterContextFreeBSD_x86_64::GetRegisterCount () const
+{
+ return m_register_count;
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h
new file mode 100644
index 0000000..21fbdb4
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h
@@ -0,0 +1,35 @@
+//===-- RegisterContextFreeBSD_x86_64.h -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextFreeBSD_x86_64_H_
+#define liblldb_RegisterContextFreeBSD_x86_64_H_
+
+#include "RegisterContextPOSIX.h"
+
+class RegisterContextFreeBSD_x86_64:
+ public lldb_private::RegisterInfoInterface
+{
+public:
+ RegisterContextFreeBSD_x86_64(const lldb_private::ArchSpec &target_arch);
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ const uint32_t m_register_count;
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp
new file mode 100644
index 0000000..3c37010
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.cpp
@@ -0,0 +1,138 @@
+//===-- RegisterContextHistory.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "RegisterContextHistory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextHistory::RegisterContextHistory (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size, addr_t pc_value) :
+RegisterContext (thread, concrete_frame_idx),
+ m_pc_value (pc_value)
+{
+ m_reg_set0.name = "General Purpose Registers";
+ m_reg_set0.short_name = "GPR";
+ m_reg_set0.num_registers = 1;
+ m_reg_set0.registers = new uint32_t(0);
+
+ m_pc_reg_info.name = "pc";
+ m_pc_reg_info.alt_name = "pc";
+ m_pc_reg_info.byte_offset = 0;
+ m_pc_reg_info.byte_size = address_byte_size;
+ m_pc_reg_info.encoding = eEncodingUint;
+ m_pc_reg_info.format = eFormatPointer;
+ m_pc_reg_info.invalidate_regs = NULL;
+ m_pc_reg_info.value_regs = NULL;
+ m_pc_reg_info.kinds[eRegisterKindGCC] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindDWARF] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ m_pc_reg_info.kinds[eRegisterKindGDB] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindLLDB] = LLDB_INVALID_REGNUM;
+}
+
+RegisterContextHistory::~RegisterContextHistory ()
+{
+ delete m_reg_set0.registers;
+ delete m_pc_reg_info.invalidate_regs;
+ delete m_pc_reg_info.value_regs;
+}
+
+void
+RegisterContextHistory::InvalidateAllRegisters () {}
+
+size_t
+RegisterContextHistory::GetRegisterCount ()
+{
+ return 1;
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextHistory::GetRegisterInfoAtIndex (size_t reg)
+{
+ if (reg)
+ return NULL;
+ return &m_pc_reg_info;
+}
+
+size_t
+RegisterContextHistory::GetRegisterSetCount ()
+{
+ return 1;
+}
+
+const lldb_private::RegisterSet *
+RegisterContextHistory::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set)
+ return NULL;
+ return &m_reg_set0;
+}
+
+bool
+RegisterContextHistory::ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+ uint32_t reg_number = reg_info->kinds[eRegisterKindGeneric];
+ if (reg_number == LLDB_REGNUM_GENERIC_PC)
+ {
+ value.SetUInt(m_pc_value, reg_info->byte_size);
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextHistory::WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextHistory::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextHistory::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+uint32_t
+RegisterContextHistory::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num)
+{
+ if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC)
+ return 0;
+ return LLDB_INVALID_REGNUM;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h
new file mode 100644
index 0000000..04842c6
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextHistory.h
@@ -0,0 +1,79 @@
+//===-- RegisterContextHistory.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextHistory_h_
+#define lldb_RegisterContextHistory_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+namespace lldb_private {
+
+class RegisterContextHistory : public lldb_private::RegisterContext
+{
+public:
+ typedef std::shared_ptr<RegisterContextHistory> SharedPtr;
+
+ RegisterContextHistory (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size, lldb::addr_t pc_value);
+
+ ///
+ // pure virtual functions from the base class that we must implement
+ ///
+
+ virtual
+ ~RegisterContextHistory ();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
+
+private:
+ //------------------------------------------------------------------
+ // For RegisterContextLLDB only
+ //------------------------------------------------------------------
+
+ lldb_private::RegisterSet m_reg_set0; // register set 0 (PC only)
+ lldb_private::RegisterInfo m_pc_reg_info;
+
+ lldb::addr_t m_pc_value;
+
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextHistory);
+};
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextHistory_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
new file mode 100644
index 0000000..37b007c
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -0,0 +1,2084 @@
+//===-- RegisterContextLLDB.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/SectionLoadList.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "RegisterContextLLDB.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static ConstString GetSymbolOrFunctionName(const SymbolContext &sym_ctx)
+{
+ if (sym_ctx.symbol)
+ return sym_ctx.symbol->GetName();
+ else if (sym_ctx.function)
+ return sym_ctx.function->GetName();
+ return ConstString();
+}
+
+RegisterContextLLDB::RegisterContextLLDB
+(
+ Thread& thread,
+ const SharedPtr &next_frame,
+ SymbolContext& sym_ctx,
+ uint32_t frame_number,
+ UnwindLLDB& unwind_lldb
+) :
+ RegisterContext (thread, frame_number),
+ m_thread(thread),
+ m_fast_unwind_plan_sp (),
+ m_full_unwind_plan_sp (),
+ m_fallback_unwind_plan_sp (),
+ m_all_registers_available(false),
+ m_frame_type (-1),
+ m_cfa (LLDB_INVALID_ADDRESS),
+ m_start_pc (),
+ m_current_pc (),
+ m_current_offset (0),
+ m_current_offset_backed_up_one (0),
+ m_sym_ctx(sym_ctx),
+ m_sym_ctx_valid (false),
+ m_frame_number (frame_number),
+ m_registers(),
+ m_parent_unwind (unwind_lldb)
+{
+ m_sym_ctx.Clear(false);
+ m_sym_ctx_valid = false;
+
+ if (IsFrameZero ())
+ {
+ InitializeZerothFrame ();
+ }
+ else
+ {
+ InitializeNonZerothFrame ();
+ }
+
+ // This same code exists over in the GetFullUnwindPlanForFrame() but it may not have been executed yet
+ if (IsFrameZero()
+ || next_frame->m_frame_type == eTrapHandlerFrame
+ || next_frame->m_frame_type == eDebuggerFrame)
+ {
+ m_all_registers_available = true;
+ }
+}
+
+bool
+RegisterContextLLDB::IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset)
+{
+ if (!unwind_plan_sp)
+ return false;
+
+ // check if m_current_pc is valid
+ if (unwind_plan_sp->PlanValidAtAddress(m_current_pc))
+ {
+ // yes - current offset can be used as is
+ valid_pc_offset = m_current_offset;
+ return true;
+ }
+
+ // if m_current_offset <= 0, we've got nothing else to try
+ if (m_current_offset <= 0)
+ return false;
+
+ // check pc - 1 to see if it's valid
+ Address pc_minus_one (m_current_pc);
+ pc_minus_one.SetOffset(m_current_pc.GetOffset() - 1);
+ if (unwind_plan_sp->PlanValidAtAddress(pc_minus_one))
+ {
+ // *valid_pc_offset = m_current_offset - 1;
+ valid_pc_offset = m_current_pc.GetOffset() - 1;
+ return true;
+ }
+
+ return false;
+}
+
+// Initialize a RegisterContextLLDB which is the first frame of a stack -- the zeroth frame or currently
+// executing frame.
+
+void
+RegisterContextLLDB::InitializeZerothFrame()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ RegisterContextSP reg_ctx_sp = m_thread.GetRegisterContext();
+
+ if (reg_ctx_sp.get() == NULL)
+ {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("frame does not have a register context");
+ return;
+ }
+
+ addr_t current_pc = reg_ctx_sp->GetPC();
+
+ if (current_pc == LLDB_INVALID_ADDRESS)
+ {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("frame does not have a pc");
+ return;
+ }
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
+ // this will strip bit zero in case we read a PC from memory or from the LR.
+ // (which would be a no-op in frame 0 where we get it from the register set,
+ // but still a good idea to make the call here for other ABIs that may exist.)
+ ABI *abi = process->GetABI().get();
+ if (abi)
+ current_pc = abi->FixCodeAddress(current_pc);
+
+ // Initialize m_current_pc, an Address object, based on current_pc, an addr_t.
+ m_current_pc.SetLoadAddress (current_pc, &process->GetTarget());
+
+ // If we don't have a Module for some reason, we're not going to find symbol/function information - just
+ // stick in some reasonable defaults and hope we can unwind past this frame.
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp)
+ {
+ UnwindLogMsg ("using architectural default unwind method");
+ }
+
+ // We require either a symbol or function in the symbols context to be successfully
+ // filled in or this context is of no use to us.
+ const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
+ if (pc_module_sp.get()
+ && (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, resolve_scope, m_sym_ctx) & resolve_scope))
+ {
+ m_sym_ctx_valid = true;
+ }
+
+ if (m_sym_ctx.symbol)
+ {
+ UnwindLogMsg ("with pc value of 0x%" PRIx64 ", symbol name is '%s'",
+ current_pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ }
+ else if (m_sym_ctx.function)
+ {
+ UnwindLogMsg ("with pc value of 0x%" PRIx64 ", function name is '%s'",
+ current_pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ }
+ else
+ {
+ UnwindLogMsg ("with pc value of 0x%" PRIx64 ", no symbol/function name is known.", current_pc);
+ }
+
+ AddressRange addr_range;
+ m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range);
+
+ if (IsTrapHandlerSymbol (process, m_sym_ctx))
+ {
+ m_frame_type = eTrapHandlerFrame;
+ }
+ else
+ {
+ // FIXME: Detect eDebuggerFrame here.
+ m_frame_type = eNormalFrame;
+ }
+
+ // If we were able to find a symbol/function, set addr_range to the bounds of that symbol/function.
+ // else treat the current pc value as the start_pc and record no offset.
+ if (addr_range.GetBaseAddress().IsValid())
+ {
+ m_start_pc = addr_range.GetBaseAddress();
+ if (m_current_pc.GetSection() == m_start_pc.GetSection())
+ {
+ m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
+ }
+ else if (m_current_pc.GetModule() == m_start_pc.GetModule())
+ {
+ // This means that whatever symbol we kicked up isn't really correct
+ // --- we should not cross section boundaries ... We really should NULL out
+ // the function/symbol in this case unless there is a bad assumption
+ // here due to inlined functions?
+ m_current_offset = m_current_pc.GetFileAddress() - m_start_pc.GetFileAddress();
+ }
+ m_current_offset_backed_up_one = m_current_offset;
+ }
+ else
+ {
+ m_start_pc = m_current_pc;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ }
+
+ // We've set m_frame_type and m_sym_ctx before these calls.
+
+ m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
+
+ UnwindPlan::RowSP active_row;
+ lldb::RegisterKind row_register_kind = eRegisterKindGeneric;
+ if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ if (active_row.get() && log)
+ {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg ("%s", active_row_strm.GetString().c_str());
+ }
+ }
+
+ if (!active_row.get())
+ {
+ UnwindLogMsg ("could not find an unwindplan row for this frame's pc");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+
+ if (!ReadCFAValueForRow (row_register_kind, active_row, m_cfa))
+ {
+ UnwindLogMsg ("could not read CFA register for this frame.");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64 " using %s UnwindPlan",
+ (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()),
+ (uint64_t) m_cfa,
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+}
+
+// Initialize a RegisterContextLLDB for the non-zeroth frame -- rely on the RegisterContextLLDB "below" it
+// to provide things like its current pc value.
+
+void
+RegisterContextLLDB::InitializeNonZerothFrame()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (IsFrameZero ())
+ {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("non-zeroth frame tests positive for IsFrameZero -- that shouldn't happen.");
+ return;
+ }
+
+ if (!GetNextFrame().get() || !GetNextFrame()->IsValid())
+ {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("Could not get next frame, marking this frame as invalid.");
+ return;
+ }
+ if (!m_thread.GetRegisterContext())
+ {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("Could not get register context for this thread, marking this frame as invalid.");
+ return;
+ }
+
+ addr_t pc;
+ if (!ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc))
+ {
+ UnwindLogMsg ("could not get pc value");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ if (log)
+ {
+ UnwindLogMsg ("pc = 0x%" PRIx64, pc);
+ addr_t reg_val;
+ if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val))
+ UnwindLogMsg ("fp = 0x%" PRIx64, reg_val);
+ if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val))
+ UnwindLogMsg ("sp = 0x%" PRIx64, reg_val);
+ }
+
+ // A pc of 0x0 means it's the end of the stack crawl unless we're above a trap handler function
+ bool above_trap_handler = false;
+ if (GetNextFrame().get() && GetNextFrame()->IsValid() && GetNextFrame()->IsTrapHandlerFrame())
+ above_trap_handler = true;
+
+ if (pc == 0 || pc == 0x1)
+ {
+ if (above_trap_handler == false)
+ {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("this frame has a pc of 0x0");
+ return;
+ }
+ }
+
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
+ // this will strip bit zero in case we read a PC from memory or from the LR.
+ ABI *abi = process->GetABI().get();
+ if (abi)
+ pc = abi->FixCodeAddress(pc);
+
+ m_current_pc.SetLoadAddress (pc, &process->GetTarget());
+
+ // If we don't have a Module for some reason, we're not going to find symbol/function information - just
+ // stick in some reasonable defaults and hope we can unwind past this frame.
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp)
+ {
+ UnwindLogMsg ("using architectural default unwind method");
+
+ // Test the pc value to see if we know it's in an unmapped/non-executable region of memory.
+ uint32_t permissions;
+ if (process->GetLoadAddressPermissions(pc, permissions)
+ && (permissions & ePermissionsExecutable) == 0)
+ {
+ // If this is the second frame off the stack, we may have unwound the first frame
+ // incorrectly. But using the architecture default unwind plan may get us back on
+ // track -- albeit possibly skipping a real frame. Give this frame a clearly-invalid
+ // pc and see if we can get any further.
+ if (GetNextFrame().get() && GetNextFrame()->IsValid() && GetNextFrame()->IsFrameZero())
+ {
+ UnwindLogMsg ("had a pc of 0x%" PRIx64 " which is not in executable memory but on frame 1 -- allowing it once.",
+ (uint64_t) pc);
+ m_frame_type = eSkipFrame;
+ }
+ else
+ {
+ // anywhere other than the second frame, a non-executable pc means we're off in the weeds -- stop now.
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("pc is in a non-executable section of memory and this isn't the 2nd frame in the stack walk.");
+ return;
+ }
+ }
+
+ if (abi)
+ {
+ m_fast_unwind_plan_sp.reset ();
+ m_full_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateDefaultUnwindPlan(*m_full_unwind_plan_sp);
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ m_all_registers_available = false;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ RegisterKind row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0);
+ if (row.get())
+ {
+ if (!ReadCFAValueForRow (row_register_kind, row, m_cfa))
+ {
+ UnwindLogMsg ("failed to get cfa value");
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNotAValidFrame;
+ }
+ return;
+ }
+
+ // A couple of sanity checks..
+ if (m_cfa == LLDB_INVALID_ADDRESS || m_cfa == 0 || m_cfa == 1)
+ {
+ UnwindLogMsg ("could not find a valid cfa address");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ // m_cfa should point into the stack memory; if we can query memory region permissions,
+ // see if the memory is allocated & readable.
+ if (process->GetLoadAddressPermissions(m_cfa, permissions)
+ && (permissions & ePermissionsReadable) == 0)
+ {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("the CFA points to a region of memory that is not readable");
+ return;
+ }
+ }
+ else
+ {
+ UnwindLogMsg ("could not find a row for function offset zero");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ if (CheckIfLoopingStack ())
+ {
+ TryFallbackUnwindPlan();
+ if (CheckIfLoopingStack ())
+ {
+ UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+
+ UnwindLogMsg ("initialized frame cfa is 0x%" PRIx64, (uint64_t) m_cfa);
+ return;
+ }
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("could not find any symbol for this pc, or a default unwind plan, to continue unwind.");
+ return;
+ }
+
+ bool resolve_tail_call_address = true; // m_current_pc can be one past the address range of the function...
+ // This will handle the case where the saved pc does not point to
+ // a function/symbol because it is beyond the bounds of the correct
+ // function and there's no symbol there. ResolveSymbolContextForAddress
+ // will fail to find a symbol, back up the pc by 1 and re-search.
+ const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
+ uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress (m_current_pc,
+ resolve_scope,
+ m_sym_ctx, resolve_tail_call_address);
+
+ // We require either a symbol or function in the symbols context to be successfully
+ // filled in or this context is of no use to us.
+ if (resolve_scope & resolved_scope)
+ {
+ m_sym_ctx_valid = true;
+ }
+
+ if (m_sym_ctx.symbol)
+ {
+ UnwindLogMsg ("with pc value of 0x%" PRIx64 ", symbol name is '%s'",
+ pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ }
+ else if (m_sym_ctx.function)
+ {
+ UnwindLogMsg ("with pc value of 0x%" PRIx64 ", function name is '%s'",
+ pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ }
+ else
+ {
+ UnwindLogMsg ("with pc value of 0x%" PRIx64 ", no symbol/function name is known.", pc);
+ }
+
+ AddressRange addr_range;
+ if (!m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range))
+ {
+ m_sym_ctx_valid = false;
+ }
+
+ bool decr_pc_and_recompute_addr_range = false;
+
+ // If the symbol lookup failed...
+ if (m_sym_ctx_valid == false)
+ decr_pc_and_recompute_addr_range = true;
+
+ // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp),
+ // and our "current" pc is the start of a function...
+ if (m_sym_ctx_valid
+ && GetNextFrame()->m_frame_type != eTrapHandlerFrame
+ && GetNextFrame()->m_frame_type != eDebuggerFrame
+ && addr_range.GetBaseAddress().IsValid()
+ && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()
+ && addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset())
+ {
+ decr_pc_and_recompute_addr_range = true;
+ }
+
+ // We need to back up the pc by 1 byte and re-search for the Symbol to handle the case where the "saved pc"
+ // value is pointing to the next function, e.g. if a function ends with a CALL instruction.
+ // FIXME this may need to be an architectural-dependent behavior; if so we'll need to add a member function
+ // to the ABI plugin and consult that.
+ if (decr_pc_and_recompute_addr_range)
+ {
+ UnwindLogMsg ("Backing up the pc value of 0x%" PRIx64 " by 1 and re-doing symbol lookup; old symbol was %s",
+ pc, GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ Address temporary_pc;
+ temporary_pc.SetLoadAddress (pc - 1, &process->GetTarget());
+ m_sym_ctx.Clear (false);
+ m_sym_ctx_valid = false;
+ uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
+
+ ModuleSP temporary_module_sp = temporary_pc.GetModule();
+ if (temporary_module_sp &&
+ temporary_module_sp->ResolveSymbolContextForAddress (temporary_pc, resolve_scope, m_sym_ctx) & resolve_scope)
+ {
+ if (m_sym_ctx.GetAddressRange (resolve_scope, 0, false, addr_range))
+ m_sym_ctx_valid = true;
+ }
+ UnwindLogMsg ("Symbol is now %s", GetSymbolOrFunctionName(m_sym_ctx).AsCString(""));
+ }
+
+ // If we were able to find a symbol/function, set addr_range_ptr to the bounds of that symbol/function.
+ // else treat the current pc value as the start_pc and record no offset.
+ if (addr_range.GetBaseAddress().IsValid())
+ {
+ m_start_pc = addr_range.GetBaseAddress();
+ m_current_offset = pc - m_start_pc.GetLoadAddress (&process->GetTarget());
+ m_current_offset_backed_up_one = m_current_offset;
+ if (decr_pc_and_recompute_addr_range && m_current_offset_backed_up_one > 0)
+ {
+ m_current_offset_backed_up_one--;
+ if (m_sym_ctx_valid)
+ {
+ m_current_pc.SetLoadAddress (pc - 1, &process->GetTarget());
+ }
+ }
+ }
+ else
+ {
+ m_start_pc = m_current_pc;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ }
+
+ if (IsTrapHandlerSymbol (process, m_sym_ctx))
+ {
+ m_frame_type = eTrapHandlerFrame;
+ }
+ else
+ {
+ // FIXME: Detect eDebuggerFrame here.
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ }
+
+ // We've set m_frame_type and m_sym_ctx before this call.
+ m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
+
+ UnwindPlan::RowSP active_row;
+ RegisterKind row_register_kind = eRegisterKindGeneric;
+
+ // Try to get by with just the fast UnwindPlan if possible - the full UnwindPlan may be expensive to get
+ // (e.g. if we have to parse the entire eh_frame section of an ObjectFile for the first time.)
+
+ if (m_fast_unwind_plan_sp && m_fast_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ row_register_kind = m_fast_unwind_plan_sp->GetRegisterKind ();
+ if (active_row.get() && log)
+ {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_fast_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str());
+ }
+ }
+ else
+ {
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
+ int valid_offset = -1;
+ if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp, valid_offset))
+ {
+ active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (valid_offset);
+ row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ if (active_row.get() && log)
+ {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str());
+ }
+ }
+ }
+
+ if (!active_row.get())
+ {
+ m_frame_type = eNotAValidFrame;
+ UnwindLogMsg ("could not find unwind row for this pc");
+ return;
+ }
+
+ if (!ReadCFAValueForRow (row_register_kind, active_row, m_cfa))
+ {
+ UnwindLogMsg ("failed to get cfa");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ UnwindLogMsg ("m_cfa = 0x%" PRIx64, m_cfa);
+
+ if (CheckIfLoopingStack ())
+ {
+ TryFallbackUnwindPlan();
+ if (CheckIfLoopingStack ())
+ {
+ UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+
+ UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64,
+ (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()), (uint64_t) m_cfa);
+}
+
+bool
+RegisterContextLLDB::CheckIfLoopingStack ()
+{
+ // If we have a bad stack setup, we can get the same CFA value multiple times -- or even
+ // more devious, we can actually oscillate between two CFA values. Detect that here and
+ // break out to avoid a possible infinite loop in lldb trying to unwind the stack.
+ addr_t next_frame_cfa;
+ addr_t next_next_frame_cfa = LLDB_INVALID_ADDRESS;
+ if (GetNextFrame().get() && GetNextFrame()->GetCFA(next_frame_cfa))
+ {
+ if (next_frame_cfa == m_cfa)
+ {
+ // We have a loop in the stack unwind
+ return true;
+ }
+ if (GetNextFrame()->GetNextFrame().get() && GetNextFrame()->GetNextFrame()->GetCFA(next_next_frame_cfa)
+ && next_next_frame_cfa == m_cfa)
+ {
+ // We have a loop in the stack unwind
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+RegisterContextLLDB::IsFrameZero () const
+{
+ return m_frame_number == 0;
+}
+
+
+// Find a fast unwind plan for this frame, if possible.
+//
+// On entry to this method,
+//
+// 1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame if either of those are correct,
+// 2. m_sym_ctx should already be filled in, and
+// 3. m_current_pc should have the current pc value for this frame
+// 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
+
+UnwindPlanSP
+RegisterContextLLDB::GetFastUnwindPlanForFrame ()
+{
+ UnwindPlanSP unwind_plan_sp;
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+
+ if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL)
+ return unwind_plan_sp;
+
+ if (IsFrameZero ())
+ return unwind_plan_sp;
+
+ FuncUnwindersSP func_unwinders_sp (pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx));
+ if (!func_unwinders_sp)
+ return unwind_plan_sp;
+
+ // If we're in _sigtramp(), unwinding past this frame requires special knowledge.
+ if (m_frame_type == eTrapHandlerFrame || m_frame_type == eDebuggerFrame)
+ return unwind_plan_sp;
+
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (*m_thread.CalculateTarget(), m_thread);
+ if (unwind_plan_sp)
+ {
+ if (unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log && log->GetVerbose())
+ {
+ if (m_fast_unwind_plan_sp)
+ UnwindLogMsgVerbose ("frame, and has a fast UnwindPlan");
+ else
+ UnwindLogMsgVerbose ("frame");
+ }
+ m_frame_type = eNormalFrame;
+ return unwind_plan_sp;
+ }
+ else
+ {
+ unwind_plan_sp.reset();
+ }
+ }
+ return unwind_plan_sp;
+}
+
+// On entry to this method,
+//
+// 1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame if either of those are correct,
+// 2. m_sym_ctx should already be filled in, and
+// 3. m_current_pc should have the current pc value for this frame
+// 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
+
+UnwindPlanSP
+RegisterContextLLDB::GetFullUnwindPlanForFrame ()
+{
+ UnwindPlanSP unwind_plan_sp;
+ UnwindPlanSP arch_default_unwind_plan_sp;
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ ABI *abi = process ? process->GetABI().get() : NULL;
+ if (abi)
+ {
+ arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp);
+ }
+ else
+ {
+ UnwindLogMsg ("unable to get architectural default UnwindPlan from ABI plugin");
+ }
+
+ bool behaves_like_zeroth_frame = false;
+ if (IsFrameZero ()
+ || GetNextFrame()->m_frame_type == eTrapHandlerFrame
+ || GetNextFrame()->m_frame_type == eDebuggerFrame)
+ {
+ behaves_like_zeroth_frame = true;
+ // If this frame behaves like a 0th frame (currently executing or
+ // interrupted asynchronously), all registers can be retrieved.
+ m_all_registers_available = true;
+ }
+
+ // If we've done a jmp 0x0 / bl 0x0 (called through a null function pointer) so the pc is 0x0
+ // in the zeroth frame, we need to use the "unwind at first instruction" arch default UnwindPlan
+ // Also, if this Process can report on memory region attributes, any non-executable region means
+ // we jumped through a bad function pointer - handle the same way as 0x0.
+ // Note, if we have a symbol context & a symbol, we don't want to follow this code path. This is
+ // for jumping to memory regions without any information available.
+
+ if ((!m_sym_ctx_valid || (m_sym_ctx.function == NULL && m_sym_ctx.symbol == NULL)) && behaves_like_zeroth_frame && m_current_pc.IsValid())
+ {
+ uint32_t permissions;
+ addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr());
+ if (current_pc_addr == 0
+ || (process &&
+ process->GetLoadAddressPermissions (current_pc_addr, permissions)
+ && (permissions & ePermissionsExecutable) == 0))
+ {
+ if (abi)
+ {
+ unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp);
+ m_frame_type = eNormalFrame;
+ return unwind_plan_sp;
+ }
+ }
+ }
+
+ // No Module for the current pc, try using the architecture default unwind.
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL)
+ {
+ m_frame_type = eNormalFrame;
+ return arch_default_unwind_plan_sp;
+ }
+
+ FuncUnwindersSP func_unwinders_sp;
+ if (m_sym_ctx_valid)
+ {
+ func_unwinders_sp = pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
+ }
+
+ // No FuncUnwinders available for this pc (i.e. a stripped function symbol and -fomit-frame-pointer).
+ // Try using the eh_frame information relative to the current PC,
+ // and finally fall back on the architectural default unwind.
+ if (!func_unwinders_sp)
+ {
+ DWARFCallFrameInfo *eh_frame = pc_module_sp && pc_module_sp->GetObjectFile() ?
+ pc_module_sp->GetObjectFile()->GetUnwindTable().GetEHFrameInfo() : nullptr;
+
+ m_frame_type = eNormalFrame;
+ if (eh_frame && m_current_pc.IsValid())
+ {
+ unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ // Even with -fomit-frame-pointer, we can try eh_frame to get back on track.
+ if (eh_frame->GetUnwindPlan (m_current_pc, *unwind_plan_sp))
+ return unwind_plan_sp;
+ else
+ unwind_plan_sp.reset();
+ }
+ return arch_default_unwind_plan_sp;
+ }
+
+ // If we're in _sigtramp(), unwinding past this frame requires special knowledge. On Mac OS X this knowledge
+ // is properly encoded in the eh_frame section, so prefer that if available.
+ // On other platforms we may need to provide a platform-specific UnwindPlan which encodes the details of
+ // how to unwind out of sigtramp.
+ if (m_frame_type == eTrapHandlerFrame && process)
+ {
+ m_fast_unwind_plan_sp.reset();
+ unwind_plan_sp = func_unwinders_sp->GetEHFrameUnwindPlan (process->GetTarget(), m_current_offset_backed_up_one);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc) && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes)
+ {
+ return unwind_plan_sp;
+ }
+ }
+
+ // Ask the DynamicLoader if the eh_frame CFI should be trusted in this frame even when it's frame zero
+ // This comes up if we have hand-written functions in a Module and hand-written eh_frame. The assembly
+ // instruction inspection may fail and the eh_frame CFI were probably written with some care to do the
+ // right thing. It'd be nice if there was a way to ask the eh_frame directly if it is asynchronous
+ // (can be trusted at every instruction point) or synchronous (the normal case - only at call sites).
+ // But there is not.
+ if (process && process->GetDynamicLoader() && process->GetDynamicLoader()->AlwaysRelyOnEHUnwindInfo (m_sym_ctx))
+ {
+ // We must specifically call the GetEHFrameUnwindPlan() method here -- normally we would
+ // call GetUnwindPlanAtCallSite() -- because CallSite may return an unwind plan sourced from
+ // either eh_frame (that's what we intend) or compact unwind (this won't work)
+ unwind_plan_sp = func_unwinders_sp->GetEHFrameUnwindPlan (process->GetTarget(), m_current_offset_backed_up_one);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan because the DynamicLoader suggested we prefer it",
+ unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+ }
+
+ // Typically the NonCallSite UnwindPlan is the unwind created by inspecting the assembly language instructions
+ if (behaves_like_zeroth_frame && process)
+ {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (process->GetTarget(), m_thread, m_current_offset_backed_up_one);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo)
+ {
+ // We probably have an UnwindPlan created by inspecting assembly instructions. The
+ // assembly profilers work really well with compiler-generated functions but hand-
+ // written assembly can be problematic. We set the eh_frame based unwind plan as our
+ // fallback unwind plan if instruction emulation doesn't work out even for non call
+ // sites if it is available and use the architecture default unwind plan if it is
+ // not available. The eh_frame unwind plan is more reliable even on non call sites
+ // then the architecture default plan and for hand written assembly code it is often
+ // written in a way that it valid at all location what helps in the most common
+ // cases when the instruction emulation fails.
+ UnwindPlanSP eh_frame_unwind_plan = func_unwinders_sp->GetEHFrameUnwindPlan (process->GetTarget(), m_current_offset_backed_up_one);
+ if (eh_frame_unwind_plan &&
+ eh_frame_unwind_plan.get() != unwind_plan_sp.get() &&
+ eh_frame_unwind_plan->GetSourceName() != unwind_plan_sp->GetSourceName())
+ {
+ m_fallback_unwind_plan_sp = eh_frame_unwind_plan;
+ }
+ else
+ {
+ m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp;
+ }
+ }
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+ }
+
+ // Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites
+ if (process)
+ {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (process->GetTarget(), m_current_offset_backed_up_one);
+ }
+ int valid_offset = -1;
+ if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+
+ // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've
+ // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible.
+ if (process)
+ {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (process->GetTarget(), m_thread, m_current_offset_backed_up_one);
+ }
+ if (unwind_plan_sp && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo)
+ {
+ // We probably have an UnwindPlan created by inspecting assembly instructions. The assembly
+ // profilers work really well with compiler-generated functions but hand- written assembly
+ // can be problematic. We set the eh_frame based unwind plan as our fallback unwind plan if
+ // instruction emulation doesn't work out even for non call sites if it is available and use
+ // the architecture default unwind plan if it is not available. The eh_frame unwind plan is
+ // more reliable even on non call sites then the architecture default plan and for hand
+ // written assembly code it is often written in a way that it valid at all location what
+ // helps in the most common cases when the instruction emulation fails.
+ UnwindPlanSP eh_frame_unwind_plan = func_unwinders_sp->GetEHFrameUnwindPlan (process->GetTarget(), m_current_offset_backed_up_one);
+ if (eh_frame_unwind_plan &&
+ eh_frame_unwind_plan.get() != unwind_plan_sp.get() &&
+ eh_frame_unwind_plan->GetSourceName() != unwind_plan_sp->GetSourceName())
+ {
+ m_fallback_unwind_plan_sp = eh_frame_unwind_plan;
+ }
+ else
+ {
+ m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp;
+ }
+ }
+
+ if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+
+ // If we're on the first instruction of a function, and we have an architectural default UnwindPlan
+ // for the initial instruction of a function, use that.
+ if (m_current_offset_backed_up_one == 0)
+ {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanArchitectureDefaultAtFunctionEntry (m_thread);
+ if (unwind_plan_sp)
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+ }
+
+ // If nothing else, use the architectural default UnwindPlan and hope that does the job.
+ if (arch_default_unwind_plan_sp)
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", arch_default_unwind_plan_sp->GetSourceName().GetCString());
+ else
+ UnwindLogMsg ("Unable to find any UnwindPlan for full unwind of this frame.");
+
+ return arch_default_unwind_plan_sp;
+}
+
+
+void
+RegisterContextLLDB::InvalidateAllRegisters ()
+{
+ m_frame_type = eNotAValidFrame;
+}
+
+size_t
+RegisterContextLLDB::GetRegisterCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterCount();
+}
+
+const RegisterInfo *
+RegisterContextLLDB::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex (reg);
+}
+
+size_t
+RegisterContextLLDB::GetRegisterSetCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterSetCount ();
+}
+
+const RegisterSet *
+RegisterContextLLDB::GetRegisterSet (size_t reg_set)
+{
+ return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
+}
+
+uint32_t
+RegisterContextLLDB::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num)
+{
+ return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
+bool
+RegisterContextLLDB::ReadRegisterValueFromRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+ bool success = false;
+
+ switch (regloc.type)
+ {
+ case UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext:
+ {
+ const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
+
+ if (!other_reg_info)
+ return false;
+
+ success = m_thread.GetRegisterContext()->ReadRegister (other_reg_info, value);
+ }
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterInRegister:
+ {
+ const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
+
+ if (!other_reg_info)
+ return false;
+
+ if (IsFrameZero ())
+ {
+ success = m_thread.GetRegisterContext()->ReadRegister (other_reg_info, value);
+ }
+ else
+ {
+ success = GetNextFrame()->ReadRegister (other_reg_info, value);
+ }
+ }
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
+ success = value.SetUInt (regloc.location.inferred_value, reg_info->byte_size);
+ break;
+
+ case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
+ assert ("FIXME debugger inferior function call unwind");
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation:
+ {
+ Error error (ReadRegisterValueFromMemory(reg_info,
+ regloc.location.target_memory_location,
+ reg_info->byte_size,
+ value));
+ success = error.Success();
+ }
+ break;
+ default:
+ assert ("Unknown RegisterLocation type.");
+ break;
+ }
+ return success;
+}
+
+bool
+RegisterContextLLDB::WriteRegisterValueToRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+
+ bool success = false;
+
+ switch (regloc.type)
+ {
+ case UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext:
+ {
+ const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
+ success = m_thread.GetRegisterContext()->WriteRegister (other_reg_info, value);
+ }
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterInRegister:
+ {
+ const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
+ if (IsFrameZero ())
+ {
+ success = m_thread.GetRegisterContext()->WriteRegister (other_reg_info, value);
+ }
+ else
+ {
+ success = GetNextFrame()->WriteRegister (other_reg_info, value);
+ }
+ }
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
+ case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
+ assert ("FIXME debugger inferior function call unwind");
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation:
+ {
+ Error error (WriteRegisterValueToMemory (reg_info,
+ regloc.location.target_memory_location,
+ reg_info->byte_size,
+ value));
+ success = error.Success();
+ }
+ break;
+ default:
+ assert ("Unknown RegisterLocation type.");
+ break;
+ }
+ return success;
+}
+
+
+bool
+RegisterContextLLDB::IsValid () const
+{
+ return m_frame_type != eNotAValidFrame;
+}
+
+// After the final stack frame in a stack walk we'll get one invalid (eNotAValidFrame) stack frame --
+// one past the end of the stack walk. But higher-level code will need to tell the differnece between
+// "the unwind plan below this frame failed" versus "we successfully completed the stack walk" so
+// this method helps to disambiguate that.
+
+bool
+RegisterContextLLDB::IsTrapHandlerFrame () const
+{
+ return m_frame_type == eTrapHandlerFrame;
+}
+
+// A skip frame is a bogus frame on the stack -- but one where we're likely to find a real frame farther
+// up the stack if we keep looking. It's always the second frame in an unwind (i.e. the first frame after
+// frame zero) where unwinding can be the trickiest. Ideally we'll mark up this frame in some way so the
+// user knows we're displaying bad data and we may have skipped one frame of their real program in the
+// process of getting back on track.
+
+bool
+RegisterContextLLDB::IsSkipFrame () const
+{
+ return m_frame_type == eSkipFrame;
+}
+
+bool
+RegisterContextLLDB::IsTrapHandlerSymbol (lldb_private::Process *process, const lldb_private::SymbolContext &m_sym_ctx) const
+{
+ PlatformSP platform_sp (process->GetTarget().GetPlatform());
+ if (platform_sp)
+ {
+ const std::vector<ConstString> trap_handler_names (platform_sp->GetTrapHandlerSymbolNames());
+ for (ConstString name : trap_handler_names)
+ {
+ if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) ||
+ (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name))
+ {
+ return true;
+ }
+ }
+ }
+ const std::vector<ConstString> user_specified_trap_handler_names (m_parent_unwind.GetUserSpecifiedTrapHandlerFunctionNames());
+ for (ConstString name : user_specified_trap_handler_names)
+ {
+ if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) ||
+ (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Answer the question: Where did THIS frame save the CALLER frame ("previous" frame)'s register value?
+
+enum UnwindLLDB::RegisterSearchResult
+RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc)
+{
+ RegisterNumber regnum (m_thread, eRegisterKindLLDB, lldb_regnum);
+
+ // Have we already found this register location?
+ if (!m_registers.empty())
+ {
+ std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation>::const_iterator iterator;
+ iterator = m_registers.find (regnum.GetAsKind (eRegisterKindLLDB));
+ if (iterator != m_registers.end())
+ {
+ regloc = iterator->second;
+ UnwindLogMsg ("supplying caller's saved %s (%d)'s location, cached",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+
+ // Look through the available UnwindPlans for the register location.
+
+ UnwindPlan::Row::RegisterLocation unwindplan_regloc;
+ bool have_unwindplan_regloc = false;
+ RegisterKind unwindplan_registerkind = kNumRegisterKinds;
+
+ if (m_fast_unwind_plan_sp)
+ {
+ UnwindPlan::RowSP active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind ();
+ if (regnum.GetAsKind (unwindplan_registerkind) == LLDB_INVALID_REGNUM)
+ {
+ UnwindLogMsg ("could not convert lldb regnum %s (%d) into %d RegisterKind reg numbering scheme",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB), (int) unwindplan_registerkind);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ if (active_row->GetRegisterInfo (regnum.GetAsKind (unwindplan_registerkind), unwindplan_regloc))
+ {
+ UnwindLogMsg ("supplying caller's saved %s (%d)'s location using FastUnwindPlan",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+ have_unwindplan_regloc = true;
+ }
+ }
+
+ if (!have_unwindplan_regloc)
+ {
+ // m_full_unwind_plan_sp being NULL means that we haven't tried to find a full UnwindPlan yet
+ if (!m_full_unwind_plan_sp)
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
+
+ if (m_full_unwind_plan_sp)
+ {
+ RegisterNumber pc_regnum (m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+
+ UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind ();
+
+ RegisterNumber return_address_reg;
+
+ // If we're fetching the saved pc and this UnwindPlan defines a ReturnAddress register (e.g. lr on arm),
+ // look for the return address register number in the UnwindPlan's row.
+ if (pc_regnum.IsValid()
+ && pc_regnum == regnum
+ && m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM)
+ {
+
+ return_address_reg.init (m_thread, m_full_unwind_plan_sp->GetRegisterKind(), m_full_unwind_plan_sp->GetReturnAddressRegister());
+ regnum = return_address_reg;
+ UnwindLogMsg ("requested caller's saved PC but this UnwindPlan uses a RA reg; getting %s (%d) instead",
+ return_address_reg.GetName(), return_address_reg.GetAsKind (eRegisterKindLLDB));
+ }
+ else
+ {
+ if (regnum.GetAsKind (unwindplan_registerkind) == LLDB_INVALID_REGNUM)
+ {
+ if (unwindplan_registerkind == eRegisterKindGeneric)
+ {
+ UnwindLogMsg ("could not convert lldb regnum %s (%d) into eRegisterKindGeneric reg numbering scheme",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+ }
+ else
+ {
+ UnwindLogMsg ("could not convert lldb regnum %s (%d) into %d RegisterKind reg numbering scheme",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB), (int) unwindplan_registerkind);
+ }
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ }
+
+ if (regnum.IsValid()
+ && active_row->GetRegisterInfo (regnum.GetAsKind (unwindplan_registerkind), unwindplan_regloc))
+ {
+ have_unwindplan_regloc = true;
+ UnwindLogMsg ("supplying caller's saved %s (%d)'s location using %s UnwindPlan",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB),
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+ }
+
+ // This is frame 0 and we're retrieving the PC and it's saved in a Return Address register and
+ // it hasn't been saved anywhere yet -- that is, it's still live in the actual register.
+ // Handle this specially.
+
+ if (have_unwindplan_regloc == false
+ && return_address_reg.IsValid()
+ && IsFrameZero())
+ {
+ if (return_address_reg.GetAsKind (eRegisterKindLLDB) != LLDB_INVALID_REGNUM)
+ {
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext;
+ new_regloc.location.register_number = return_address_reg.GetAsKind (eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = new_regloc;
+ regloc = new_regloc;
+ UnwindLogMsg ("supplying caller's register %s (%d) from the live RegisterContext at frame 0, saved in %d",
+ return_address_reg.GetName(), return_address_reg.GetAsKind (eRegisterKindLLDB),
+ return_address_reg.GetAsKind (eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+
+ // If this architecture stores the return address in a register (it defines a Return Address register)
+ // and we're on a non-zero stack frame and the Full UnwindPlan says that the pc is stored in the
+ // RA registers (e.g. lr on arm), then we know that the full unwindplan is not trustworthy -- this
+ // is an impossible situation and the instruction emulation code has likely been misled.
+ // If this stack frame meets those criteria, we need to throw away the Full UnwindPlan that the
+ // instruction emulation came up with and fall back to the architecture's Default UnwindPlan so
+ // the stack walk can get past this point.
+
+ // Special note: If the Full UnwindPlan was generated from the compiler, don't second-guess it
+ // when we're at a call site location.
+
+ // arch_default_ra_regnum is the return address register # in the Full UnwindPlan register numbering
+ RegisterNumber arch_default_ra_regnum (m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
+
+ if (arch_default_ra_regnum.GetAsKind (unwindplan_registerkind) != LLDB_INVALID_REGNUM
+ && pc_regnum == regnum
+ && unwindplan_regloc.IsInOtherRegister()
+ && unwindplan_regloc.GetRegisterNumber() == arch_default_ra_regnum.GetAsKind (unwindplan_registerkind)
+ && m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes
+ && !m_all_registers_available)
+ {
+ UnwindLogMsg ("%s UnwindPlan tried to restore the pc from the link register but this is a non-zero frame",
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+
+ // Throw away the full unwindplan; install the arch default unwindplan
+ if (ForceSwitchToFallbackUnwindPlan())
+ {
+ // Update for the possibly new unwind plan
+ unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind ();
+ UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+
+ // Sanity check: Verify that we can fetch a pc value and CFA value with this unwind plan
+
+ RegisterNumber arch_default_pc_reg (m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ bool can_fetch_pc_value = false;
+ bool can_fetch_cfa = false;
+ addr_t cfa_value;
+ if (active_row)
+ {
+ if (arch_default_pc_reg.GetAsKind (unwindplan_registerkind) != LLDB_INVALID_REGNUM
+ && active_row->GetRegisterInfo (arch_default_pc_reg.GetAsKind (unwindplan_registerkind), unwindplan_regloc))
+ {
+ can_fetch_pc_value = true;
+ }
+ if (ReadCFAValueForRow (unwindplan_registerkind, active_row, cfa_value))
+ {
+ can_fetch_cfa = true;
+ }
+ }
+
+ if (can_fetch_pc_value && can_fetch_cfa)
+ {
+ have_unwindplan_regloc = true;
+ }
+ else
+ {
+ have_unwindplan_regloc = false;
+ }
+ }
+ else
+ {
+ // We were unable to fall back to another unwind plan
+ have_unwindplan_regloc = false;
+ }
+ }
+ }
+ }
+
+ if (have_unwindplan_regloc == false)
+ {
+ // Did the UnwindPlan fail to give us the caller's stack pointer?
+ // The stack pointer is defined to be the same as THIS frame's CFA, so return the CFA value as
+ // the caller's stack pointer. This is true on x86-32/x86-64 at least.
+
+ RegisterNumber sp_regnum (m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ if (sp_regnum.GetAsKind (eRegisterKindLLDB) != LLDB_INVALID_REGNUM
+ && sp_regnum.GetAsKind (eRegisterKindLLDB) == regnum.GetAsKind (eRegisterKindLLDB))
+ {
+ // make sure we won't lose precision copying an addr_t (m_cfa) into a uint64_t (.inferred_value)
+ assert (sizeof (addr_t) <= sizeof (uint64_t));
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = m_cfa;
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg ("supplying caller's stack pointer %s (%d) value, computed from CFA",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (have_unwindplan_regloc == false)
+ {
+ // If a volatile register is being requested, we don't want to forward the next frame's register contents
+ // up the stack -- the register is not retrievable at this frame.
+ ABI *abi = process ? process->GetABI().get() : NULL;
+ if (abi)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(regnum.GetAsKind (eRegisterKindLLDB));
+ if (reg_info && abi->RegisterIsVolatile (reg_info))
+ {
+ UnwindLogMsg ("did not supply reg location for %s (%d) because it is volatile",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile;
+ }
+ }
+
+ if (IsFrameZero ())
+ {
+ // This is frame 0 - we should return the actual live register context value
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext;
+ new_regloc.location.register_number = regnum.GetAsKind (eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = new_regloc;
+ regloc = new_regloc;
+ UnwindLogMsg ("supplying caller's register %s (%d) from the live RegisterContext at frame 0",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ else
+ {
+ std::string unwindplan_name ("");
+ if (m_full_unwind_plan_sp)
+ {
+ unwindplan_name += "via '";
+ unwindplan_name += m_full_unwind_plan_sp->GetSourceName().AsCString();
+ unwindplan_name += "'";
+ }
+ UnwindLogMsg ("no save location for %s (%d) %s",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB),
+ unwindplan_name.c_str());
+ }
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ // unwindplan_regloc has valid contents about where to retrieve the register
+ if (unwindplan_regloc.IsUnspecified())
+ {
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterNotSaved;
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = new_regloc;
+ UnwindLogMsg ("save location for %s (%d) is unspecified, continue searching",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ if (unwindplan_regloc.IsSame())
+ {
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ regloc.location.register_number = regnum.GetAsKind (eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg ("supplying caller's register %s (%d), saved in register %s (%d)",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB),
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsCFAPlusOffset())
+ {
+ int offset = unwindplan_regloc.GetOffset();
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = m_cfa + offset;
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg ("supplying caller's register %s (%d), value is CFA plus offset %d [value is 0x%" PRIx64 "]",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB),
+ offset, regloc.location.inferred_value);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsAtCFAPlusOffset())
+ {
+ int offset = unwindplan_regloc.GetOffset();
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
+ regloc.location.target_memory_location = m_cfa + offset;
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg ("supplying caller's register %s (%d) from the stack, saved at CFA plus offset %d [saved at 0x%" PRIx64 "]",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB),
+ offset, regloc.location.target_memory_location);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsInOtherRegister())
+ {
+ uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber();
+ RegisterNumber row_regnum (m_thread, unwindplan_registerkind, unwindplan_regnum);
+ if (row_regnum.GetAsKind (eRegisterKindLLDB) == LLDB_INVALID_REGNUM)
+ {
+ UnwindLogMsg ("could not supply caller's %s (%d) location - was saved in another reg but couldn't convert that regnum",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ regloc.location.register_number = row_regnum.GetAsKind (eRegisterKindLLDB);
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg ("supplying caller's register %s (%d), saved in register %s (%d)",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB),
+ row_regnum.GetName(), row_regnum.GetAsKind (eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsDWARFExpression() || unwindplan_regloc.IsAtDWARFExpression())
+ {
+ DataExtractor dwarfdata (unwindplan_regloc.GetDWARFExpressionBytes(),
+ unwindplan_regloc.GetDWARFExpressionLength(),
+ process->GetByteOrder(), process->GetAddressByteSize());
+ ModuleSP opcode_ctx;
+ DWARFExpression dwarfexpr (opcode_ctx, dwarfdata, 0, unwindplan_regloc.GetDWARFExpressionLength());
+ dwarfexpr.SetRegisterKind (unwindplan_registerkind);
+ Value result;
+ Error error;
+ if (dwarfexpr.Evaluate (&exe_ctx, NULL, NULL, this, 0, NULL, result, &error))
+ {
+ addr_t val;
+ val = result.GetScalar().ULongLong();
+ if (unwindplan_regloc.IsDWARFExpression())
+ {
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = val;
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg ("supplying caller's register %s (%d) via DWARF expression (IsDWARFExpression)",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ else
+ {
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
+ regloc.location.target_memory_location = val;
+ m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc;
+ UnwindLogMsg ("supplying caller's register %s (%d) via DWARF expression (IsAtDWARFExpression)",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+ UnwindLogMsg ("tried to use IsDWARFExpression or IsAtDWARFExpression for %s (%d) but failed",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ UnwindLogMsg ("no save location for %s (%d) in this stack frame",
+ regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
+
+ // FIXME UnwindPlan::Row types atDWARFExpression and isDWARFExpression are unsupported.
+
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+}
+
+// TryFallbackUnwindPlan() -- this method is a little tricky.
+//
+// When this is called, the frame above -- the caller frame, the "previous" frame --
+// is invalid or bad.
+//
+// Instead of stopping the stack walk here, we'll try a different UnwindPlan and see
+// if we can get a valid frame above us.
+//
+// This most often happens when an unwind plan based on assembly instruction inspection
+// is not correct -- mostly with hand-written assembly functions or functions where the
+// stack frame is set up "out of band", e.g. the kernel saved the register context and
+// then called an asynchronous trap handler like _sigtramp.
+//
+// Often in these cases, if we just do a dumb stack walk we'll get past this tricky
+// frame and our usual techniques can continue to be used.
+
+bool
+RegisterContextLLDB::TryFallbackUnwindPlan ()
+{
+ if (m_fallback_unwind_plan_sp.get() == nullptr)
+ return false;
+
+ if (m_full_unwind_plan_sp.get() == nullptr)
+ return false;
+
+ if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get()
+ || m_full_unwind_plan_sp->GetSourceName() == m_fallback_unwind_plan_sp->GetSourceName())
+ {
+ return false;
+ }
+
+ // If a compiler generated unwind plan failed, trying the arch default unwindplan
+ // isn't going to do any better.
+ if (m_full_unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes)
+ return false;
+
+
+ // Get the caller's pc value and our own CFA value.
+ // Swap in the fallback unwind plan, re-fetch the caller's pc value and CFA value.
+ // If they're the same, then the fallback unwind plan provides no benefit.
+
+ RegisterNumber pc_regnum (m_thread, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+
+ addr_t old_caller_pc_value = LLDB_INVALID_ADDRESS;
+ addr_t new_caller_pc_value = LLDB_INVALID_ADDRESS;
+ addr_t old_this_frame_cfa_value = m_cfa;
+ UnwindLLDB::RegisterLocation regloc;
+ if (SavedLocationForRegister (pc_regnum.GetAsKind (eRegisterKindLLDB), regloc) == UnwindLLDB::RegisterSearchResult::eRegisterFound)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(pc_regnum.GetAsKind (eRegisterKindLLDB));
+ if (reg_info)
+ {
+ RegisterValue reg_value;
+ if (ReadRegisterValueFromRegisterLocation (regloc, reg_info, reg_value))
+ {
+ old_caller_pc_value = reg_value.GetAsUInt64();
+ }
+ }
+ }
+
+ // This is a tricky wrinkle! If SavedLocationForRegister() detects a really impossible
+ // register location for the full unwind plan, it may call ForceSwitchToFallbackUnwindPlan()
+ // which in turn replaces the full unwindplan with the fallback... in short, we're done,
+ // we're using the fallback UnwindPlan.
+ // We checked if m_fallback_unwind_plan_sp was nullptr at the top -- the only way it
+ // became nullptr since then is via SavedLocationForRegister().
+ if (m_fallback_unwind_plan_sp.get() == nullptr)
+ return true;
+
+
+ // Switch the full UnwindPlan to be the fallback UnwindPlan. If we decide this isn't
+ // working, we need to restore.
+ // We'll also need to save & restore the value of the m_cfa ivar. Save is down below a bit in 'old_cfa'.
+ UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp;
+ addr_t old_cfa = m_cfa;
+
+ m_registers.clear();
+
+ m_full_unwind_plan_sp = m_fallback_unwind_plan_sp;
+
+ UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+
+ if (active_row && active_row->GetCFAValue().GetValueType() != UnwindPlan::Row::CFAValue::unspecified)
+ {
+ addr_t new_cfa;
+ if (!ReadCFAValueForRow (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row, new_cfa)
+ || new_cfa == 0 || new_cfa == 1 || new_cfa == LLDB_INVALID_ADDRESS)
+ {
+ UnwindLogMsg ("failed to get cfa with fallback unwindplan");
+ m_fallback_unwind_plan_sp.reset();
+ m_full_unwind_plan_sp = original_full_unwind_plan_sp;
+ m_cfa = old_cfa;
+ return false;
+ }
+ m_cfa = new_cfa;
+
+ if (SavedLocationForRegister (pc_regnum.GetAsKind (eRegisterKindLLDB), regloc) == UnwindLLDB::RegisterSearchResult::eRegisterFound)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(pc_regnum.GetAsKind (eRegisterKindLLDB));
+ if (reg_info)
+ {
+ RegisterValue reg_value;
+ if (ReadRegisterValueFromRegisterLocation (regloc, reg_info, reg_value))
+ {
+ new_caller_pc_value = reg_value.GetAsUInt64();
+ }
+ }
+ }
+
+
+ if (new_caller_pc_value == LLDB_INVALID_ADDRESS)
+ {
+ UnwindLogMsg ("failed to get a pc value for the caller frame with the fallback unwind plan");
+ m_fallback_unwind_plan_sp.reset();
+ m_full_unwind_plan_sp = original_full_unwind_plan_sp;
+ m_cfa = old_cfa;
+ return false;
+ }
+
+ if (old_caller_pc_value != LLDB_INVALID_ADDRESS)
+ {
+ if (old_caller_pc_value == new_caller_pc_value && new_cfa == old_this_frame_cfa_value)
+ {
+ UnwindLogMsg ("fallback unwind plan got the same values for this frame CFA and caller frame pc, not using");
+ m_fallback_unwind_plan_sp.reset();
+ m_full_unwind_plan_sp = original_full_unwind_plan_sp;
+ m_cfa = old_cfa;
+ return false;
+ }
+ }
+
+ UnwindLogMsg ("trying to unwind from this function with the UnwindPlan '%s' because UnwindPlan '%s' failed.",
+ m_fallback_unwind_plan_sp->GetSourceName().GetCString(),
+ original_full_unwind_plan_sp->GetSourceName().GetCString());
+
+ // We've copied the fallback unwind plan into the full - now clear the fallback.
+ m_fallback_unwind_plan_sp.reset();
+ }
+
+ return true;
+}
+
+bool
+RegisterContextLLDB::ForceSwitchToFallbackUnwindPlan ()
+{
+ if (m_fallback_unwind_plan_sp.get() == NULL)
+ return false;
+
+ if (m_full_unwind_plan_sp.get() == NULL)
+ return false;
+
+ if (m_full_unwind_plan_sp.get() == m_fallback_unwind_plan_sp.get()
+ || m_full_unwind_plan_sp->GetSourceName() == m_fallback_unwind_plan_sp->GetSourceName())
+ {
+ return false;
+ }
+
+ UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+
+ if (active_row && active_row->GetCFAValue().GetValueType() != UnwindPlan::Row::CFAValue::unspecified)
+ {
+ addr_t new_cfa;
+ if (!ReadCFAValueForRow (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row, new_cfa)
+ || new_cfa == 0 || new_cfa == 1 || new_cfa == LLDB_INVALID_ADDRESS)
+ {
+ UnwindLogMsg ("failed to get cfa with fallback unwindplan");
+ m_fallback_unwind_plan_sp.reset();
+ return false;
+ }
+
+ m_full_unwind_plan_sp = m_fallback_unwind_plan_sp;
+ m_fallback_unwind_plan_sp.reset();
+
+ m_registers.clear();
+
+ m_cfa = new_cfa;
+
+ UnwindLogMsg ("switched unconditionally to the fallback unwindplan %s", m_full_unwind_plan_sp->GetSourceName().GetCString());
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextLLDB::ReadCFAValueForRow (lldb::RegisterKind row_register_kind,
+ const UnwindPlan::RowSP &row,
+ addr_t &cfa_value)
+{
+ RegisterValue reg_value;
+
+ cfa_value = LLDB_INVALID_ADDRESS;
+ addr_t cfa_reg_contents;
+
+ switch (row->GetCFAValue().GetValueType())
+ {
+ case UnwindPlan::Row::CFAValue::isRegisterDereferenced:
+ {
+ RegisterNumber cfa_reg (m_thread, row_register_kind, row->GetCFAValue().GetRegisterNumber());
+ if (ReadGPRValue (cfa_reg, cfa_reg_contents))
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (cfa_reg.GetAsKind (eRegisterKindLLDB));
+ RegisterValue reg_value;
+ if (reg_info)
+ {
+ Error error = ReadRegisterValueFromMemory(reg_info,
+ cfa_reg_contents,
+ reg_info->byte_size,
+ reg_value);
+ if (error.Success ())
+ {
+ cfa_value = reg_value.GetAsUInt64();
+ UnwindLogMsg ("CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64 ", CFA value is 0x%" PRIx64,
+ cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB),
+ cfa_reg_contents, cfa_value);
+ return true;
+ }
+ else
+ {
+ UnwindLogMsg ("Tried to deref reg %s (%d) [0x%" PRIx64 "] but memory read failed.",
+ cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB),
+ cfa_reg_contents);
+ }
+ }
+ }
+ break;
+ }
+ case UnwindPlan::Row::CFAValue::isRegisterPlusOffset:
+ {
+ RegisterNumber cfa_reg (m_thread, row_register_kind, row->GetCFAValue().GetRegisterNumber());
+ if (ReadGPRValue (cfa_reg, cfa_reg_contents))
+ {
+ if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 || cfa_reg_contents == 1)
+ {
+ UnwindLogMsg ("Got an invalid CFA register value - reg %s (%d), value 0x%" PRIx64,
+ cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB),
+ cfa_reg_contents);
+ cfa_reg_contents = LLDB_INVALID_ADDRESS;
+ return false;
+ }
+ cfa_value = cfa_reg_contents + row->GetCFAValue().GetOffset();
+ UnwindLogMsg ("CFA is 0x%" PRIx64 ": Register %s (%d) contents are 0x%" PRIx64 ", offset is %d",
+ cfa_value,
+ cfa_reg.GetName(), cfa_reg.GetAsKind (eRegisterKindLLDB),
+ cfa_reg_contents, row->GetCFAValue().GetOffset());
+ return true;
+ }
+ break;
+ }
+ case UnwindPlan::Row::CFAValue::isDWARFExpression:
+ {
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ DataExtractor dwarfdata (row->GetCFAValue().GetDWARFExpressionBytes(),
+ row->GetCFAValue().GetDWARFExpressionLength(),
+ process->GetByteOrder(), process->GetAddressByteSize());
+ ModuleSP opcode_ctx;
+ DWARFExpression dwarfexpr (opcode_ctx, dwarfdata, 0, row->GetCFAValue().GetDWARFExpressionLength());
+ dwarfexpr.SetRegisterKind (row_register_kind);
+ Value result;
+ Error error;
+ if (dwarfexpr.Evaluate (&exe_ctx, NULL, NULL, this, 0, NULL, result, &error))
+ {
+ cfa_value = result.GetScalar().ULongLong();
+
+ UnwindLogMsg ("CFA value set by DWARF expression is 0x%" PRIx64, cfa_value);
+ return true;
+ }
+ UnwindLogMsg ("Failed to set CFA value via DWARF expression: %s", error.AsCString());
+ break;
+ }
+ default:
+ return false;
+ }
+ return false;
+}
+
+// Retrieve a general purpose register value for THIS frame, as saved by the NEXT frame, i.e. the frame that
+// this frame called. e.g.
+//
+// foo () { }
+// bar () { foo (); }
+// main () { bar (); }
+//
+// stopped in foo() so
+// frame 0 - foo
+// frame 1 - bar
+// frame 2 - main
+// and this RegisterContext is for frame 1 (bar) - if we want to get the pc value for frame 1, we need to ask
+// where frame 0 (the "next" frame) saved that and retrieve the value.
+
+bool
+RegisterContextLLDB::ReadGPRValue (lldb::RegisterKind register_kind, uint32_t regnum, addr_t &value)
+{
+ if (!IsValid())
+ return false;
+
+ uint32_t lldb_regnum;
+ if (register_kind == eRegisterKindLLDB)
+ {
+ lldb_regnum = regnum;
+ }
+ else if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindLLDB, lldb_regnum))
+ {
+ return false;
+ }
+
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
+ RegisterValue reg_value;
+ // if this is frame 0 (currently executing frame), get the requested reg contents from the actual thread registers
+ if (IsFrameZero ())
+ {
+ if (m_thread.GetRegisterContext()->ReadRegister (reg_info, reg_value))
+ {
+ value = reg_value.GetAsUInt64();
+ return true;
+ }
+ return false;
+ }
+
+ bool pc_register = false;
+ uint32_t generic_regnum;
+ if (register_kind == eRegisterKindGeneric && regnum == LLDB_REGNUM_GENERIC_PC)
+ {
+ pc_register = true;
+ }
+ else if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindGeneric, generic_regnum)
+ && generic_regnum == LLDB_REGNUM_GENERIC_PC)
+ {
+ pc_register = true;
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, pc_register))
+ {
+ return false;
+ }
+ if (ReadRegisterValueFromRegisterLocation (regloc, reg_info, reg_value))
+ {
+ value = reg_value.GetAsUInt64();
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextLLDB::ReadGPRValue (const RegisterNumber &regnum, addr_t &value)
+{
+ return ReadGPRValue (regnum.GetRegisterKind(), regnum.GetRegisterNumber(), value);
+}
+
+// Find the value of a register in THIS frame
+
+bool
+RegisterContextLLDB::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+
+ const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
+ UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum);
+
+ // If this is the 0th frame, hand this over to the live register context
+ if (IsFrameZero ())
+ {
+ UnwindLogMsgVerbose ("passing along to the live register context for reg %d", lldb_regnum);
+ return m_thread.GetRegisterContext()->ReadRegister (reg_info, value);
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ // Find out where the NEXT frame saved THIS frame's register contents
+ if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, false))
+ return false;
+
+ return ReadRegisterValueFromRegisterLocation (regloc, reg_info, value);
+}
+
+bool
+RegisterContextLLDB::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+
+ const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
+ UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum);
+
+ // If this is the 0th frame, hand this over to the live register context
+ if (IsFrameZero ())
+ {
+ UnwindLogMsgVerbose ("passing along to the live register context for reg %d", lldb_regnum);
+ return m_thread.GetRegisterContext()->WriteRegister (reg_info, value);
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ // Find out where the NEXT frame saved THIS frame's register contents
+ if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, false))
+ return false;
+
+ return WriteRegisterValueToRegisterLocation (regloc, reg_info, value);
+}
+
+// Don't need to implement this one
+bool
+RegisterContextLLDB::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+// Don't need to implement this one
+bool
+RegisterContextLLDB::WriteAllRegisterValues (const lldb::DataBufferSP& data_sp)
+{
+ return false;
+}
+
+// Retrieve the pc value for THIS from
+
+bool
+RegisterContextLLDB::GetCFA (addr_t& cfa)
+{
+ if (!IsValid())
+ {
+ return false;
+ }
+ if (m_cfa == LLDB_INVALID_ADDRESS)
+ {
+ return false;
+ }
+ cfa = m_cfa;
+ return true;
+}
+
+
+RegisterContextLLDB::SharedPtr
+RegisterContextLLDB::GetNextFrame () const
+{
+ RegisterContextLLDB::SharedPtr regctx;
+ if (m_frame_number == 0)
+ return regctx;
+ return m_parent_unwind.GetRegisterContextForFrameNum (m_frame_number - 1);
+}
+
+RegisterContextLLDB::SharedPtr
+RegisterContextLLDB::GetPrevFrame () const
+{
+ RegisterContextLLDB::SharedPtr regctx;
+ return m_parent_unwind.GetRegisterContextForFrameNum (m_frame_number + 1);
+}
+
+// Retrieve the address of the start of the function of THIS frame
+
+bool
+RegisterContextLLDB::GetStartPC (addr_t& start_pc)
+{
+ if (!IsValid())
+ return false;
+
+ if (!m_start_pc.IsValid())
+ {
+ return ReadPC (start_pc);
+ }
+ start_pc = m_start_pc.GetLoadAddress (CalculateTarget().get());
+ return true;
+}
+
+// Retrieve the current pc value for THIS frame, as saved by the NEXT frame.
+
+bool
+RegisterContextLLDB::ReadPC (addr_t& pc)
+{
+ if (!IsValid())
+ return false;
+
+ bool above_trap_handler = false;
+ if (GetNextFrame().get() && GetNextFrame()->IsValid() && GetNextFrame()->IsTrapHandlerFrame())
+ above_trap_handler = true;
+
+ if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc))
+ {
+ // A pc value of 0 or 1 is impossible in the middle of the stack -- it indicates the end of a stack walk.
+ // On the currently executing frame (or such a frame interrupted asynchronously by sigtramp et al) this may
+ // occur if code has jumped through a NULL pointer -- we want to be able to unwind past that frame to help
+ // find the bug.
+
+ if (m_all_registers_available == false
+ && above_trap_handler == false
+ && (pc == 0 || pc == 1))
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+void
+RegisterContextLLDB::UnwindLogMsg (const char *fmt, ...)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log)
+ {
+ va_list args;
+ va_start (args, fmt);
+
+ char *logmsg;
+ if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL)
+ {
+ if (logmsg)
+ free (logmsg);
+ va_end (args);
+ return;
+ }
+ va_end (args);
+
+ log->Printf ("%*sth%d/fr%u %s",
+ m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number,
+ logmsg);
+ free (logmsg);
+ }
+}
+
+void
+RegisterContextLLDB::UnwindLogMsgVerbose (const char *fmt, ...)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log && log->GetVerbose())
+ {
+ va_list args;
+ va_start (args, fmt);
+
+ char *logmsg;
+ if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL)
+ {
+ if (logmsg)
+ free (logmsg);
+ va_end (args);
+ return;
+ }
+ va_end (args);
+
+ log->Printf ("%*sth%d/fr%u %s",
+ m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number,
+ logmsg);
+ free (logmsg);
+ }
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h
new file mode 100644
index 0000000..5f94a97
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h
@@ -0,0 +1,272 @@
+//===-- RegisterContextLLDB.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextLLDB_h_
+#define lldb_RegisterContextLLDB_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Utility/RegisterNumber.h"
+#include "UnwindLLDB.h"
+
+namespace lldb_private {
+
+class UnwindLLDB;
+
+class RegisterContextLLDB : public lldb_private::RegisterContext
+{
+public:
+ typedef std::shared_ptr<RegisterContextLLDB> SharedPtr;
+
+ RegisterContextLLDB (lldb_private::Thread &thread,
+ const SharedPtr& next_frame,
+ lldb_private::SymbolContext& sym_ctx,
+ uint32_t frame_number, lldb_private::UnwindLLDB& unwind_lldb);
+
+ ///
+ // pure virtual functions from the base class that we must implement
+ ///
+
+ virtual
+ ~RegisterContextLLDB () { }
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
+
+ bool
+ IsValid () const;
+
+ bool
+ IsTrapHandlerFrame () const;
+
+ bool
+ GetCFA (lldb::addr_t& cfa);
+
+ bool
+ GetStartPC (lldb::addr_t& start_pc);
+
+ bool
+ ReadPC (lldb::addr_t& start_pc);
+
+private:
+
+ enum FrameType
+ {
+ eNormalFrame,
+ eTrapHandlerFrame,
+ eDebuggerFrame, // a debugger inferior function call frame; we get caller's registers from debugger
+ eSkipFrame, // The unwind resulted in a bogus frame but may get back on track so we don't want to give up yet
+ eNotAValidFrame // this frame is invalid for some reason - most likely it is past the top (end) of the stack
+ };
+
+ // UnwindLLDB needs to pass around references to RegisterLocations
+ friend class UnwindLLDB;
+
+
+ // Returns true if we have an unwind loop -- the same stack frame unwinding
+ // multiple times.
+ bool
+ CheckIfLoopingStack ();
+
+ // Indicates whether this frame is frame zero -- the currently
+ // executing frame -- or not.
+ bool
+ IsFrameZero () const;
+
+ void
+ InitializeZerothFrame ();
+
+ void
+ InitializeNonZerothFrame();
+
+ SharedPtr
+ GetNextFrame () const;
+
+ SharedPtr
+ GetPrevFrame () const;
+
+ // A SkipFrame occurs when the unwind out of frame 0 didn't go right -- we've got one bogus frame at frame #1.
+ // There is a good chance we'll get back on track if we follow the frame pointer chain (or whatever is appropriate
+ // on this ABI) so we allow one invalid frame to be in the stack. Ideally we'll mark this frame specially at some
+ // point and indicate to the user that the unwinder had a hiccup. Often when this happens we will miss a frame of
+ // the program's actual stack in the unwind and we want to flag that for the user somehow.
+ bool
+ IsSkipFrame () const;
+
+
+ //------------------------------------------------------------------
+ /// Determines if a SymbolContext is a trap handler or not
+ ///
+ /// Given a SymbolContext, determines if this is a trap handler function
+ /// aka asynchronous signal handler.
+ ///
+ /// @return
+ /// Returns true if the SymbolContext is a trap handler.
+ //------------------------------------------------------------------
+ bool
+ IsTrapHandlerSymbol (lldb_private::Process *process, const lldb_private::SymbolContext &m_sym_ctx) const;
+
+ // Provide a location for where THIS function saved the CALLER's register value
+ // Or a frame "below" this one saved it, i.e. a function called by this one, preserved a register that this
+ // function didn't modify/use.
+ //
+ // The RegisterLocation type may be set to eRegisterNotAvailable -- this will happen for a volatile register
+ // being queried mid-stack. Instead of floating frame 0's contents of that register up the stack (which may
+ // or may not be the value of that reg when the function was executing), we won't return any value.
+ //
+ // If a non-volatile register (a "preserved" register) is requested mid-stack and no frames "below" the requested
+ // stack have saved the register anywhere, it is safe to assume that frame 0's register values are still the same
+ // as the requesting frame's.
+ lldb_private::UnwindLLDB::RegisterSearchResult
+ SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc);
+
+ bool
+ ReadRegisterValueFromRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegisterValueToRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value);
+
+ //------------------------------------------------------------------
+ /// If the unwind has to the caller frame has failed, try something else
+ ///
+ /// If lldb is using an assembly language based UnwindPlan for a frame and
+ /// the unwind to the caller frame fails, try falling back to a generic
+ /// UnwindPlan (architecture default unwindplan) to see if that might work
+ /// better. This is mostly helping to work around problems where the
+ /// assembly language inspection fails on hand-written assembly code.
+ ///
+ /// @return
+ /// Returns true if a fallback unwindplan was found & was installed.
+ //------------------------------------------------------------------
+ bool
+ TryFallbackUnwindPlan ();
+
+ //------------------------------------------------------------------
+ /// Switch to the fallback unwind plan unconditionally without any safety
+ /// checks that it is providing better results than the normal unwind plan.
+ ///
+ /// The only time it is valid to call this method is if the full unwindplan is
+ /// found to be fundamentally incorrect/impossible.
+ ///
+ /// Returns true if it was able to install the fallback unwind plan.
+ //------------------------------------------------------------------
+ bool
+ ForceSwitchToFallbackUnwindPlan ();
+
+ // Get the contents of a general purpose (address-size) register for this frame
+ // (usually retrieved from the next frame)
+ bool
+ ReadGPRValue (lldb::RegisterKind register_kind, uint32_t regnum, lldb::addr_t &value);
+
+ bool
+ ReadGPRValue (const RegisterNumber &reg_num, lldb::addr_t &value);
+
+ // Get the CFA register for a given frame.
+ bool
+ ReadCFAValueForRow (lldb::RegisterKind register_kind, const UnwindPlan::RowSP &row, lldb::addr_t &value);
+
+ lldb::UnwindPlanSP
+ GetFastUnwindPlanForFrame ();
+
+ lldb::UnwindPlanSP
+ GetFullUnwindPlanForFrame ();
+
+ void
+ UnwindLogMsg (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ UnwindLogMsgVerbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ bool
+ IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset);
+
+
+ lldb_private::Thread& m_thread;
+
+ ///
+ // The following tell us how to retrieve the CALLER's register values (ie the "previous" frame, aka the frame above)
+ // i.e. where THIS frame saved them
+ ///
+
+ lldb::UnwindPlanSP m_fast_unwind_plan_sp; // may be NULL
+ lldb::UnwindPlanSP m_full_unwind_plan_sp;
+ lldb::UnwindPlanSP m_fallback_unwind_plan_sp; // may be NULL
+
+ bool m_all_registers_available; // Can we retrieve all regs or just nonvolatile regs?
+ int m_frame_type; // enum FrameType
+
+ lldb::addr_t m_cfa;
+ lldb_private::Address m_start_pc;
+ lldb_private::Address m_current_pc;
+
+ int m_current_offset; // how far into the function we've executed; -1 if unknown
+ // 0 if no instructions have been executed yet.
+
+ int m_current_offset_backed_up_one; // how far into the function we've executed; -1 if unknown
+ // 0 if no instructions have been executed yet.
+ // On architectures where the return address on the stack points
+ // to the instruction after the CALL, this value will have 1
+ // subtracted from it. Else a function that ends in a CALL will
+ // have an offset pointing into the next function's address range.
+ // m_current_pc has the actual address of the "current" pc.
+
+ lldb_private::SymbolContext& m_sym_ctx;
+ bool m_sym_ctx_valid; // if ResolveSymbolContextForAddress fails, don't try to use m_sym_ctx
+
+ uint32_t m_frame_number; // What stack frame this RegisterContext is
+
+ std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation> m_registers; // where to find reg values for this frame
+
+ lldb_private::UnwindLLDB& m_parent_unwind; // The UnwindLLDB that is creating this RegisterContextLLDB
+
+ //------------------------------------------------------------------
+ // For RegisterContextLLDB only
+ //------------------------------------------------------------------
+
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextLLDB);
+};
+
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextLLDB_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp
new file mode 100644
index 0000000..e7784b1
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp
@@ -0,0 +1,87 @@
+//===-- RegisterContextLinux_arm.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include <stddef.h>
+#include <vector>
+#include <cassert>
+
+#include "llvm/Support/Compiler.h"
+#include "lldb/lldb-defines.h"
+
+#include "RegisterContextLinux_arm.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Based on RegisterContextDarwin_arm.cpp
+#define GPR_OFFSET(idx) ((idx) * 4)
+#define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextLinux_arm::GPR))
+#define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU))
+#define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextLinux_arm::DBG, reg) + sizeof (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU) + sizeof (RegisterContextLinux_arm::EXC)))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextLinux_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU) + sizeof (RegisterContextLinux_arm::EXC))
+
+//-----------------------------------------------------------------------------
+// Include RegisterInfos_arm to declare our g_register_infos_arm structure.
+//-----------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_ARM_STRUCT
+#include "RegisterInfos_arm.h"
+#undef DECLARE_REGISTER_INFOS_ARM_STRUCT
+
+static const lldb_private::RegisterInfo *
+GetRegisterInfoPtr (const lldb_private::ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ return g_register_infos_arm;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return NULL;
+ }
+}
+
+static uint32_t
+GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ return static_cast<uint32_t>(sizeof(g_register_infos_arm) / sizeof(g_register_infos_arm[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextLinux_arm::RegisterContextLinux_arm(const lldb_private::ArchSpec &target_arch) :
+ lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p(GetRegisterInfoPtr(target_arch)),
+ m_register_info_count(GetRegisterInfoCount(target_arch))
+{
+}
+
+size_t
+RegisterContextLinux_arm::GetGPRSize() const
+{
+ return sizeof(struct RegisterContextLinux_arm::GPR);
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextLinux_arm::GetRegisterInfo() const
+{
+ return m_register_info_p;
+}
+
+uint32_t
+RegisterContextLinux_arm::GetRegisterCount() const
+{
+ return m_register_info_count;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm.h
new file mode 100644
index 0000000..7087eb4
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm.h
@@ -0,0 +1,76 @@
+//===-- RegisterContextLinux_arm.h -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextLinux_arm_h_
+#define liblldb_RegisterContextLinux_arm_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "RegisterContextPOSIX.h"
+#include "RegisterInfoInterface.h"
+
+class RegisterContextLinux_arm
+ : public lldb_private::RegisterInfoInterface
+{
+public:
+
+ struct GPR
+ {
+ uint32_t r[16]; // R0-R15
+ uint32_t cpsr; // CPSR
+ };
+
+
+ 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;
+ };
+ struct EXC
+ {
+ uint32_t exception;
+ uint32_t fsr; /* Fault status */
+ uint32_t far; /* Virtual Fault Address */
+ };
+
+ struct DBG
+ {
+ uint32_t bvr[16];
+ uint32_t bcr[16];
+ uint32_t wvr[16];
+ uint32_t wcr[16];
+ };
+
+ RegisterContextLinux_arm(const lldb_private::ArchSpec &target_arch);
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
+};
+
+#endif // liblldb_RegisterContextLinux_arm_h_
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp
new file mode 100644
index 0000000..8c23e39
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp
@@ -0,0 +1,89 @@
+//===-- RegisterContextLinux_arm64.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include <stddef.h>
+#include <vector>
+#include <cassert>
+
+#include "llvm/Support/Compiler.h"
+#include "lldb/lldb-defines.h"
+
+#include "RegisterContextLinux_arm64.h"
+
+// Based on RegisterContextDarwin_arm64.cpp
+#define GPR_OFFSET(idx) ((idx) * 8)
+#define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::GPR, reg))
+
+#define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextLinux_arm64::GPR))
+#define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::FPU, reg))
+
+#define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::EXC, reg) + sizeof (RegisterContextLinux_arm64::GPR) + sizeof (RegisterContextLinux_arm64::FPU))
+#define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::DBG, reg) + sizeof (RegisterContextLinux_arm64::GPR) + sizeof (RegisterContextLinux_arm64::FPU) + sizeof (RegisterContextLinux_arm64::EXC))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextLinux_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextLinux_arm64::GPR) + sizeof (RegisterContextLinux_arm64::FPU) + sizeof (RegisterContextLinux_arm64::EXC))
+
+
+//-----------------------------------------------------------------------------
+// Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure.
+//-----------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_ARM64_STRUCT
+#include "RegisterInfos_arm64.h"
+#undef DECLARE_REGISTER_INFOS_ARM64_STRUCT
+
+static const lldb_private::RegisterInfo *
+GetRegisterInfoPtr (const lldb_private::ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ return g_register_infos_arm64;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return NULL;
+ }
+}
+
+static uint32_t
+GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ return static_cast<uint32_t>(sizeof(g_register_infos_arm64) / sizeof(g_register_infos_arm64[0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextLinux_arm64::RegisterContextLinux_arm64(const lldb_private::ArchSpec &target_arch) :
+ lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p(GetRegisterInfoPtr(target_arch)),
+ m_register_info_count(GetRegisterInfoCount(target_arch))
+{
+}
+
+size_t
+RegisterContextLinux_arm64::GetGPRSize() const
+{
+ return sizeof(struct RegisterContextLinux_arm64::GPR);
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextLinux_arm64::GetRegisterInfo() const
+{
+ return m_register_info_p;
+}
+
+uint32_t
+RegisterContextLinux_arm64::GetRegisterCount() const
+{
+ return m_register_info_count;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm64.h
new file mode 100644
index 0000000..a9a5a09
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_arm64.h
@@ -0,0 +1,81 @@
+//===-- RegisterContextLinux_arm64.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextLinux_arm64_H_
+#define liblldb_RegisterContextLinux_arm64_H_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "RegisterContextPOSIX.h"
+#include "RegisterInfoInterface.h"
+
+class RegisterContextLinux_arm64
+ : public lldb_private::RegisterInfoInterface
+{
+public:
+ // based on RegisterContextDarwin_arm64.h
+ struct GPR
+ {
+ uint64_t x[29]; // x0-x28
+ uint64_t fp; // x29
+ uint64_t lr; // x30
+ uint64_t sp; // x31
+ uint64_t pc; // pc
+ uint32_t cpsr; // cpsr
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct VReg
+ {
+ uint8_t bytes[16];
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct FPU
+ {
+ VReg v[32];
+ uint32_t fpsr;
+ uint32_t fpcr;
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct EXC
+ {
+ uint64_t far; // Virtual Fault Address
+ uint32_t esr; // Exception syndrome
+ uint32_t exception; // number of arm exception token
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct DBG
+ {
+ uint64_t bvr[16];
+ uint64_t bcr[16];
+ uint64_t wvr[16];
+ uint64_t wcr[16];
+ uint64_t mdscr_el1;
+ };
+
+ RegisterContextLinux_arm64(const lldb_private::ArchSpec &target_arch);
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
new file mode 100644
index 0000000..4f6bbc8
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.cpp
@@ -0,0 +1,133 @@
+//===-- RegisterContextLinux_i386.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "RegisterContextPOSIX_x86.h"
+#include "RegisterContextLinux_i386.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+struct GPR
+{
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t ebp;
+ uint32_t eax;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+ uint32_t orig_ax;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t eflags;
+ uint32_t esp;
+ uint32_t ss;
+};
+
+struct FPR_i386
+{
+ uint16_t fctrl; // FPU Control Word (fcw)
+ uint16_t fstat; // FPU Status Word (fsw)
+ uint16_t ftag; // FPU Tag Word (ftw)
+ uint16_t fop; // Last Instruction Opcode (fop)
+ union
+ {
+ struct
+ {
+ uint64_t fip; // Instruction Pointer
+ uint64_t fdp; // Data Pointer
+ } x86_64;
+ struct
+ {
+ uint32_t fioff; // FPU IP Offset (fip)
+ uint32_t fiseg; // FPU IP Selector (fcs)
+ uint32_t fooff; // FPU Operand Pointer Offset (foo)
+ uint32_t foseg; // FPU Operand Pointer Selector (fos)
+ } i386_;// Added _ in the end to avoid error with gcc defining i386 in some cases
+ } ptr;
+ uint32_t mxcsr; // MXCSR Register State
+ uint32_t mxcsrmask; // MXCSR Mask
+ MMSReg stmm[8]; // 8*16 bytes for each FP-reg = 128 bytes
+ XMMReg xmm[8]; // 8*16 bytes for each XMM-reg = 128 bytes
+ uint32_t padding[56];
+};
+
+struct UserArea
+{
+ GPR regs; // General purpose registers.
+ int32_t fpvalid; // True if FPU is being used.
+ FPR_i386 i387; // FPU registers.
+ uint32_t tsize; // Text segment size.
+ uint32_t dsize; // Data segment size.
+ uint32_t ssize; // Stack segment size.
+ uint32_t start_code; // VM address of text.
+ uint32_t start_stack; // VM address of stack bottom (top in rsp).
+ int32_t signal; // Signal causing core dump.
+ int32_t reserved; // Unused.
+ uint32_t ar0; // Location of GPR's.
+ uint32_t fpstate; // Location of FPR's. Should be a FXSTATE *, but this
+ // has to be 32-bits even on 64-bit systems.
+ uint32_t magic; // Identifier for core dumps.
+ char u_comm[32]; // Command causing core dump.
+ uint32_t u_debugreg[8]; // Debug registers (DR0 - DR7).
+};
+
+#define DR_SIZE sizeof(((UserArea*)NULL)->u_debugreg[0])
+#define DR_0_OFFSET 0xFC
+#define DR_OFFSET(reg_index) \
+ (DR_0_OFFSET + (reg_index * 4))
+#define FPR_SIZE(reg) sizeof(((FPR_i386*)NULL)->reg)
+
+//---------------------------------------------------------------------------
+// Include RegisterInfos_i386 to declare our g_register_infos_i386 structure.
+//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_I386_STRUCT
+#include "RegisterInfos_i386.h"
+#undef DECLARE_REGISTER_INFOS_I386_STRUCT
+
+RegisterContextLinux_i386::RegisterContextLinux_i386(const ArchSpec &target_arch) :
+ RegisterInfoInterface(target_arch)
+{
+}
+
+size_t
+RegisterContextLinux_i386::GetGPRSize() const
+{
+ return sizeof(GPR);
+}
+
+const RegisterInfo *
+RegisterContextLinux_i386::GetRegisterInfo() const
+{
+ switch (m_target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ return g_register_infos_i386;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return NULL;
+ }
+}
+
+uint32_t
+RegisterContextLinux_i386::GetRegisterCount () const
+{
+ return static_cast<uint32_t> (sizeof (g_register_infos_i386) / sizeof (g_register_infos_i386 [0]));
+}
+
+uint32_t
+RegisterContextLinux_i386::GetUserRegisterCount () const
+{
+ return static_cast<uint32_t> (k_num_user_registers_i386);
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.h
new file mode 100644
index 0000000..cb71d79
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_i386.h
@@ -0,0 +1,34 @@
+//===-- RegisterContextLinux_i386.h -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextLinux_i386_H_
+#define liblldb_RegisterContextLinux_i386_H_
+
+#include "RegisterContextPOSIX.h"
+
+class RegisterContextLinux_i386
+ : public lldb_private::RegisterInfoInterface
+{
+public:
+ RegisterContextLinux_i386(const lldb_private::ArchSpec &target_arch);
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+
+ uint32_t
+ GetUserRegisterCount () const override;
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp
new file mode 100644
index 0000000..4d58b85
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.cpp
@@ -0,0 +1,67 @@
+//===-- RegisterContextLinux_mips.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include <vector>
+#include <stddef.h>
+
+// For GDB, GCC and DWARF Register numbers
+#include "RegisterContextLinux_mips.h"
+
+// Internal codes for mips registers
+#include "lldb-mips-linux-register-enums.h"
+
+// For GP and FP buffers
+#include "RegisterContext_mips.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+//---------------------------------------------------------------------------
+// Include RegisterInfos_mips to declare our g_register_infos_mips structure.
+//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_MIPS_STRUCT
+#include "RegisterInfos_mips.h"
+#undef DECLARE_REGISTER_INFOS_MIPS_STRUCT
+
+RegisterContextLinux_mips::RegisterContextLinux_mips(const ArchSpec &target_arch) :
+ RegisterInfoInterface(target_arch)
+{
+}
+
+size_t
+RegisterContextLinux_mips::GetGPRSize() const
+{
+ return sizeof(GPR_linux_mips);
+}
+
+const RegisterInfo *
+RegisterContextLinux_mips::GetRegisterInfo() const
+{
+ switch (m_target_arch.GetMachine())
+ {
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ return g_register_infos_mips;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return NULL;
+ }
+}
+
+uint32_t
+RegisterContextLinux_mips::GetRegisterCount () const
+{
+ return static_cast<uint32_t> (sizeof (g_register_infos_mips) / sizeof (g_register_infos_mips [0]));
+}
+
+uint32_t
+RegisterContextLinux_mips::GetUserRegisterCount () const
+{
+ return static_cast<uint32_t> (k_num_user_registers_mips);
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.h
new file mode 100644
index 0000000..bcc2d00
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips.h
@@ -0,0 +1,35 @@
+//===-- RegisterContextLinux_mips.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextLinux_mips_H_
+#define liblldb_RegisterContextLinux_mips_H_
+
+#include "lldb/lldb-private.h"
+#include "RegisterInfoInterface.h"
+
+class RegisterContextLinux_mips
+ : public lldb_private::RegisterInfoInterface
+{
+public:
+ RegisterContextLinux_mips(const lldb_private::ArchSpec &target_arch);
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+
+ uint32_t
+ GetUserRegisterCount () const override;
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp
new file mode 100644
index 0000000..7f512f8
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.cpp
@@ -0,0 +1,126 @@
+//===-- RegisterContextLinux_mips64.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#if defined (__mips__)
+
+#include <vector>
+#include <stddef.h>
+
+// For GDB, GCC and DWARF Register numbers
+#include "RegisterContextLinux_mips64.h"
+
+// For GP and FP buffers
+#include "RegisterContext_mips.h"
+
+// Internal codes for all mips32 and mips64 registers
+#include "lldb-mips-linux-register-enums.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//---------------------------------------------------------------------------
+// Include RegisterInfos_mips64 to declare our g_register_infos_mips64 structure.
+//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_MIPS64_STRUCT
+#define LINUX_MIPS64
+#include "RegisterInfos_mips64.h"
+#undef LINUX_MIPS64
+#undef DECLARE_REGISTER_INFOS_MIPS64_STRUCT
+
+//---------------------------------------------------------------------------
+// Include RegisterInfos_mips to declare our g_register_infos_mips structure.
+//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_MIPS_STRUCT
+#include "RegisterInfos_mips.h"
+#undef DECLARE_REGISTER_INFOS_MIPS_STRUCT
+
+static const RegisterInfo *
+GetRegisterInfoPtr (const ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ return g_register_infos_mips64;
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ return g_register_infos_mips;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+static uint32_t
+GetRegisterInfoCount (const ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ return static_cast<uint32_t> (sizeof (g_register_infos_mips64) / sizeof (g_register_infos_mips64 [0]));
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ return static_cast<uint32_t> (sizeof (g_register_infos_mips) / sizeof (g_register_infos_mips [0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+uint32_t
+GetUserRegisterInfoCount (const ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ return static_cast<uint32_t> (k_num_user_registers_mips);
+ case llvm::Triple::mips64el:
+ case llvm::Triple::mips64:
+ return static_cast<uint32_t> (k_num_user_registers_mips64);
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextLinux_mips64::RegisterContextLinux_mips64(const ArchSpec &target_arch) :
+ lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p (GetRegisterInfoPtr (target_arch)),
+ m_register_info_count (GetRegisterInfoCount (target_arch)),
+ m_user_register_count (GetUserRegisterInfoCount (target_arch))
+{
+}
+
+size_t
+RegisterContextLinux_mips64::GetGPRSize() const
+{
+ return sizeof(GPR_linux_mips);
+}
+
+const RegisterInfo *
+RegisterContextLinux_mips64::GetRegisterInfo() const
+{
+ return m_register_info_p;
+}
+
+uint32_t
+RegisterContextLinux_mips64::GetRegisterCount () const
+{
+ return m_register_info_count;
+}
+
+uint32_t
+RegisterContextLinux_mips64::GetUserRegisterCount () const
+{
+ return m_user_register_count;
+}
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h
new file mode 100644
index 0000000..86c662c
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_mips64.h
@@ -0,0 +1,44 @@
+//===-- RegisterContextLinux_mips64.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined (__mips__)
+
+#ifndef liblldb_RegisterContextLinux_mips64_H_
+#define liblldb_RegisterContextLinux_mips64_H_
+
+#include "lldb/lldb-private.h"
+#include "RegisterInfoInterface.h"
+
+class RegisterContextLinux_mips64
+ : public lldb_private::RegisterInfoInterface
+{
+public:
+ RegisterContextLinux_mips64(const lldb_private::ArchSpec &target_arch);
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+
+ uint32_t
+ GetUserRegisterCount () const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
+ uint32_t m_user_register_count;
+};
+
+#endif
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp
new file mode 100644
index 0000000..c0993b4
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.cpp
@@ -0,0 +1,198 @@
+//===-- RegisterContextLinux_x86_64.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include <vector>
+#include "RegisterContextPOSIX_x86.h"
+#include "RegisterContextLinux_i386.h"
+#include "RegisterContextLinux_x86_64.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+typedef struct _GPR
+{
+ uint64_t r15;
+ uint64_t r14;
+ uint64_t r13;
+ uint64_t r12;
+ uint64_t rbp;
+ uint64_t rbx;
+ uint64_t r11;
+ uint64_t r10;
+ uint64_t r9;
+ uint64_t r8;
+ uint64_t rax;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rsi;
+ uint64_t rdi;
+ uint64_t orig_ax;
+ uint64_t rip;
+ uint64_t cs;
+ uint64_t rflags;
+ uint64_t rsp;
+ uint64_t ss;
+ uint64_t fs_base;
+ uint64_t gs_base;
+ uint64_t ds;
+ uint64_t es;
+ uint64_t fs;
+ uint64_t gs;
+} GPR;
+
+struct DBG {
+ uint64_t dr[8];
+};
+
+struct UserArea
+{
+ GPR gpr; // General purpose registers.
+ int32_t fpvalid; // True if FPU is being used.
+ int32_t pad0;
+ FXSAVE fpr; // General purpose floating point registers (see FPR for extended register sets).
+ uint64_t tsize; // Text segment size.
+ uint64_t dsize; // Data segment size.
+ uint64_t ssize; // Stack segment size.
+ uint64_t start_code; // VM address of text.
+ uint64_t start_stack; // VM address of stack bottom (top in rsp).
+ int64_t signal; // Signal causing core dump.
+ int32_t reserved; // Unused.
+ int32_t pad1;
+ uint64_t ar0; // Location of GPR's.
+ FXSAVE* fpstate; // Location of FPR's.
+ uint64_t magic; // Identifier for core dumps.
+ char u_comm[32]; // Command causing core dump.
+ DBG dbg; // Debug registers.
+ uint64_t error_code; // CPU error code.
+ uint64_t fault_address; // Control register CR3.
+};
+
+
+#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.
+//---------------------------------------------------------------------------
+#define DECLARE_REGISTER_INFOS_X86_64_STRUCT
+#include "RegisterInfos_x86_64.h"
+#undef DECLARE_REGISTER_INFOS_X86_64_STRUCT
+
+static std::vector<lldb_private::RegisterInfo>&
+GetPrivateRegisterInfoVector ()
+{
+ static std::vector<lldb_private::RegisterInfo> g_register_infos;
+ return g_register_infos;
+}
+
+static const RegisterInfo *
+GetRegisterInfo_i386(const lldb_private::ArchSpec &arch)
+{
+ std::vector<lldb_private::RegisterInfo> &g_register_infos = GetPrivateRegisterInfoVector ();
+
+ // Allocate RegisterInfo only once
+ if (g_register_infos.empty())
+ {
+ // Copy the register information from base class
+ std::unique_ptr<RegisterContextLinux_i386> reg_interface(new RegisterContextLinux_i386 (arch));
+ const RegisterInfo *base_info = reg_interface->GetRegisterInfo();
+ g_register_infos.insert(g_register_infos.end(), &base_info[0], &base_info[k_num_registers_i386]);
+
+ //---------------------------------------------------------------------------
+ // Include RegisterInfos_x86_64 to update the g_register_infos structure
+ // with x86_64 offsets.
+ //---------------------------------------------------------------------------
+ #define UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+ #include "RegisterInfos_x86_64.h"
+ #undef UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+ }
+
+ return &g_register_infos[0];
+}
+
+static const RegisterInfo *
+GetRegisterInfoPtr (const ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ return GetRegisterInfo_i386 (target_arch);
+ case llvm::Triple::x86_64:
+ return g_register_infos_x86_64;
+ default:
+ assert(false && "Unhandled target architecture.");
+ return nullptr;
+ }
+}
+
+static uint32_t
+GetRegisterInfoCount (const ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ {
+ assert (!GetPrivateRegisterInfoVector ().empty () && "i386 register info not yet filled.");
+ return static_cast<uint32_t> (GetPrivateRegisterInfoVector ().size ());
+ }
+ case llvm::Triple::x86_64:
+ return static_cast<uint32_t> (sizeof (g_register_infos_x86_64) / sizeof (g_register_infos_x86_64 [0]));
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+static uint32_t
+GetUserRegisterInfoCount (const ArchSpec &target_arch)
+{
+ switch (target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ return static_cast<uint32_t> (k_num_user_registers_i386);
+ case llvm::Triple::x86_64:
+ return static_cast<uint32_t> (k_num_user_registers_x86_64);
+ default:
+ assert(false && "Unhandled target architecture.");
+ return 0;
+ }
+}
+
+RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(const ArchSpec &target_arch) :
+ lldb_private::RegisterInfoInterface(target_arch),
+ m_register_info_p (GetRegisterInfoPtr (target_arch)),
+ m_register_info_count (GetRegisterInfoCount (target_arch)),
+ m_user_register_count (GetUserRegisterInfoCount (target_arch))
+{
+}
+
+size_t
+RegisterContextLinux_x86_64::GetGPRSize() const
+{
+ return sizeof(GPR);
+}
+
+const RegisterInfo *
+RegisterContextLinux_x86_64::GetRegisterInfo() const
+{
+ return m_register_info_p;
+}
+
+uint32_t
+RegisterContextLinux_x86_64::GetRegisterCount () const
+{
+ return m_register_info_count;
+}
+
+uint32_t
+RegisterContextLinux_x86_64::GetUserRegisterCount () const
+{
+ return m_user_register_count;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h
new file mode 100644
index 0000000..0cdfae9
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLinux_x86_64.h
@@ -0,0 +1,39 @@
+//===-- RegisterContextLinux_x86_64.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextLinux_x86_64_H_
+#define liblldb_RegisterContextLinux_x86_64_H_
+
+#include "RegisterContextPOSIX.h"
+
+class RegisterContextLinux_x86_64
+ : public lldb_private::RegisterInfoInterface
+{
+public:
+ RegisterContextLinux_x86_64(const lldb_private::ArchSpec &target_arch);
+
+ size_t
+ GetGPRSize() const override;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfo() const override;
+
+ uint32_t
+ GetRegisterCount () const override;
+
+ uint32_t
+ GetUserRegisterCount () const override;
+
+private:
+ const lldb_private::RegisterInfo *m_register_info_p;
+ uint32_t m_register_info_count;
+ uint32_t m_user_register_count;
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
new file mode 100644
index 0000000..a2ab674
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
@@ -0,0 +1,207 @@
+//===-- RegisterContextMacOSXFrameBackchain.cpp -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMacOSXFrameBackchain.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Thread.h"
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RegisterContextMacOSXFrameBackchain constructor
+//----------------------------------------------------------------------
+RegisterContextMacOSXFrameBackchain::RegisterContextMacOSXFrameBackchain
+(
+ Thread &thread,
+ uint32_t concrete_frame_idx,
+ const UnwindMacOSXFrameBackchain::Cursor &cursor
+) :
+ RegisterContext (thread, concrete_frame_idx),
+ m_cursor (cursor),
+ m_cursor_is_valid (true)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RegisterContextMacOSXFrameBackchain::~RegisterContextMacOSXFrameBackchain()
+{
+}
+
+void
+RegisterContextMacOSXFrameBackchain::InvalidateAllRegisters ()
+{
+ m_cursor_is_valid = false;
+}
+
+size_t
+RegisterContextMacOSXFrameBackchain::GetRegisterCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterCount();
+}
+
+const RegisterInfo *
+RegisterContextMacOSXFrameBackchain::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex(reg);
+}
+
+size_t
+RegisterContextMacOSXFrameBackchain::GetRegisterSetCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterSetCount();
+}
+
+
+
+const RegisterSet *
+RegisterContextMacOSXFrameBackchain::GetRegisterSet (size_t reg_set)
+{
+ return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
+}
+
+
+
+bool
+RegisterContextMacOSXFrameBackchain::ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ if (!m_cursor_is_valid)
+ return false;
+
+ uint64_t reg_value = LLDB_INVALID_ADDRESS;
+
+ switch (reg_info->kinds[eRegisterKindGeneric])
+ {
+ case LLDB_REGNUM_GENERIC_PC:
+ if (m_cursor.pc == LLDB_INVALID_ADDRESS)
+ return false;
+ reg_value = m_cursor.pc;
+ break;
+
+ case LLDB_REGNUM_GENERIC_FP:
+ if (m_cursor.fp == LLDB_INVALID_ADDRESS)
+ return false;
+ reg_value = m_cursor.fp;
+ break;
+
+ default:
+ return false;
+ }
+
+ switch (reg_info->encoding)
+ {
+ case eEncodingInvalid:
+ case eEncodingVector:
+ break;
+
+ case eEncodingUint:
+ case eEncodingSint:
+ value.SetUInt(reg_value, reg_info->byte_size);
+ return true;
+
+ case eEncodingIEEE754:
+ switch (reg_info->byte_size)
+ {
+ case sizeof (float):
+ if (sizeof (float) == sizeof(uint32_t))
+ {
+ value.SetUInt32(reg_value, RegisterValue::eTypeFloat);
+ return true;
+ }
+ else if (sizeof (float) == sizeof(uint64_t))
+ {
+ value.SetUInt64(reg_value, RegisterValue::eTypeFloat);
+ return true;
+ }
+ break;
+
+ case sizeof (double):
+ if (sizeof (double) == sizeof(uint32_t))
+ {
+ value.SetUInt32(reg_value, RegisterValue::eTypeDouble);
+ return true;
+ }
+ else if (sizeof (double) == sizeof(uint64_t))
+ {
+ value.SetUInt64(reg_value, RegisterValue::eTypeDouble);
+ return true;
+ }
+ break;
+
+ // TOOD: need a better way to detect when "long double" types are
+ // the same bytes size as "double"
+#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) && !defined(_MSC_VER) && \
+ !defined(__mips__) && !defined(__powerpc__) && !defined(__ANDROID_NDK__)
+ case sizeof (long double):
+ if (sizeof (long double) == sizeof(uint32_t))
+ {
+ value.SetUInt32(reg_value, RegisterValue::eTypeLongDouble);
+ return true;
+ }
+ else if (sizeof (long double) == sizeof(uint64_t))
+ {
+ value.SetUInt64(reg_value, RegisterValue::eTypeLongDouble);
+ return true;
+ }
+ break;
+#endif
+ }
+ break;
+ }
+ return false;
+}
+
+bool
+RegisterContextMacOSXFrameBackchain::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ // Not supported yet. We could easily add support for this by remembering
+ // the address of each entry (it would need to be part of the cursor)
+ return false;
+}
+
+bool
+RegisterContextMacOSXFrameBackchain::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ // libunwind frames can't handle this it doesn't always have all register
+ // values. This call should only be called on frame zero anyway so there
+ // shouldn't be any problem
+ return false;
+}
+
+bool
+RegisterContextMacOSXFrameBackchain::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ // Since this class doesn't respond to "ReadAllRegisterValues()", it must
+ // not have been the one that saved all the register values. So we just let
+ // the thread's register context (the register context for frame zero) do
+ // the writing.
+ return m_thread.GetRegisterContext()->WriteAllRegisterValues(data_sp);
+}
+
+
+uint32_t
+RegisterContextMacOSXFrameBackchain::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num)
+{
+ return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
new file mode 100644
index 0000000..505b8d4
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
@@ -0,0 +1,77 @@
+//===-- RegisterContextMacOSXFrameBackchain.h -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextMacOSXFrameBackchain_h_
+#define lldb_RegisterContextMacOSXFrameBackchain_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "UnwindMacOSXFrameBackchain.h"
+
+class RegisterContextMacOSXFrameBackchain : public lldb_private::RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextMacOSXFrameBackchain (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ const UnwindMacOSXFrameBackchain::Cursor &cursor);
+
+ virtual
+ ~RegisterContextMacOSXFrameBackchain ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
+
+private:
+ UnwindMacOSXFrameBackchain::Cursor m_cursor;
+ bool m_cursor_is_valid;
+ //------------------------------------------------------------------
+ // For RegisterContextMacOSXFrameBackchain only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextMacOSXFrameBackchain);
+};
+
+#endif // lldb_RegisterContextMacOSXFrameBackchain_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp
new file mode 100644
index 0000000..7ceb536
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp
@@ -0,0 +1,87 @@
+//===-- RegisterContextMach_arm.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+#include "RegisterContextMach_arm.h"
+
+// C Includes
+#include <mach/mach_types.h>
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextMach_arm::RegisterContextMach_arm(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_arm (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextMach_arm::~RegisterContextMach_arm()
+{
+}
+
+int
+RegisterContextMach_arm::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextMach_arm::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextMach_arm::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextMach_arm::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg)
+{
+ mach_msg_type_number_t count = DBGWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&dbg, &count);
+}
+
+int
+RegisterContextMach_arm::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextMach_arm::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextMach_arm::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+int
+RegisterContextMach_arm::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&dbg, DBGWordCount);
+}
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h
new file mode 100644
index 0000000..e97a4bf
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h
@@ -0,0 +1,56 @@
+//===-- RegisterContextMach_arm.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextMach_arm_h_
+#define liblldb_RegisterContextMach_arm_h_
+
+// C Includes
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextDarwin_arm.h"
+
+class RegisterContextMach_arm : public RegisterContextDarwin_arm
+{
+public:
+
+ RegisterContextMach_arm(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextMach_arm();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+
+ int
+ DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg);
+};
+
+#endif // liblldb_RegisterContextMach_arm_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp
new file mode 100644
index 0000000..3d6c9a6
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp
@@ -0,0 +1,72 @@
+//===-- RegisterContextMach_i386.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+// C Includes
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextMach_i386.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextMach_i386::RegisterContextMach_i386(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_i386 (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextMach_i386::~RegisterContextMach_i386()
+{
+}
+
+int
+RegisterContextMach_i386::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextMach_i386::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextMach_i386::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextMach_i386::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextMach_i386::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextMach_i386::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h
new file mode 100644
index 0000000..ad0f69d
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h
@@ -0,0 +1,49 @@
+//===-- RegisterContextMach_i386.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextMach_i386_h_
+#define liblldb_RegisterContextMach_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextDarwin_i386.h"
+
+class RegisterContextMach_i386 : public RegisterContextDarwin_i386
+{
+public:
+
+ RegisterContextMach_i386(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextMach_i386();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+};
+
+#endif // liblldb_RegisterContextMach_i386_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp
new file mode 100644
index 0000000..f03685e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp
@@ -0,0 +1,72 @@
+//===-- RegisterContextMach_x86_64.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+// C Includes
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextMach_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextMach_x86_64::RegisterContextMach_x86_64(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_x86_64 (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextMach_x86_64::~RegisterContextMach_x86_64()
+{
+}
+
+int
+RegisterContextMach_x86_64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextMach_x86_64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextMach_x86_64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextMach_x86_64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextMach_x86_64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextMach_x86_64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h
new file mode 100644
index 0000000..9e6dfa3
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h
@@ -0,0 +1,49 @@
+//===-- RegisterContextMach_x86_64.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextMach_x86_64_h_
+#define liblldb_RegisterContextMach_x86_64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextDarwin_x86_64.h"
+
+class RegisterContextMach_x86_64 : public RegisterContextDarwin_x86_64
+{
+public:
+
+ RegisterContextMach_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextMach_x86_64();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+};
+
+#endif // liblldb_RegisterContextMach_x86_64_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp
new file mode 100644
index 0000000..40d00b1
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp
@@ -0,0 +1,174 @@
+//===-- RegisterContextMemory.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMemory.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "DynamicRegisterInfo.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RegisterContextMemory constructor
+//----------------------------------------------------------------------
+RegisterContextMemory::RegisterContextMemory
+(
+ Thread &thread,
+ uint32_t concrete_frame_idx,
+ DynamicRegisterInfo &reg_infos,
+ addr_t reg_data_addr
+) :
+ RegisterContext (thread, concrete_frame_idx),
+ m_reg_infos (reg_infos),
+ m_reg_valid (),
+ m_reg_data (),
+ m_reg_data_addr (reg_data_addr)
+{
+ // 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.
+ const size_t num_regs = reg_infos.GetNumRegisters();
+ assert (num_regs > 0);
+ m_reg_valid.resize (num_regs);
+
+ // Make a heap based buffer that is big enough to store all registers
+ DataBufferSP reg_data_sp(new DataBufferHeap (reg_infos.GetRegisterDataByteSize(), 0));
+ m_reg_data.SetData (reg_data_sp);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RegisterContextMemory::~RegisterContextMemory()
+{
+}
+
+void
+RegisterContextMemory::InvalidateAllRegisters ()
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ SetAllRegisterValid (false);
+}
+
+void
+RegisterContextMemory::SetAllRegisterValid (bool b)
+{
+ std::vector<bool>::iterator pos, end = m_reg_valid.end();
+ for (pos = m_reg_valid.begin(); pos != end; ++pos)
+ *pos = b;
+}
+
+size_t
+RegisterContextMemory::GetRegisterCount ()
+{
+ return m_reg_infos.GetNumRegisters ();
+}
+
+const RegisterInfo *
+RegisterContextMemory::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_reg_infos.GetRegisterInfoAtIndex (reg);
+}
+
+size_t
+RegisterContextMemory::GetRegisterSetCount ()
+{
+ return m_reg_infos.GetNumRegisterSets ();
+}
+
+const RegisterSet *
+RegisterContextMemory::GetRegisterSet (size_t reg_set)
+{
+ return m_reg_infos.GetRegisterSet (reg_set);
+}
+
+uint32_t
+RegisterContextMemory::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num)
+{
+ return m_reg_infos.ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
+bool
+RegisterContextMemory::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB];
+ if (!m_reg_valid[reg_num])
+ {
+ if (!ReadAllRegisterValues(m_reg_data.GetSharedDataBuffer ()))
+ return false;
+ }
+ const bool partial_data_ok = false;
+ return reg_value.SetValueFromData(reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok).Success();
+}
+
+bool
+RegisterContextMemory::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB];
+ addr_t reg_addr = m_reg_data_addr + reg_info->byte_offset;
+ Error error (WriteRegisterValueToMemory(reg_info, reg_addr, reg_info->byte_size, reg_value));
+ m_reg_valid[reg_num] = false;
+ return error.Success();
+ }
+ return false;
+}
+
+bool
+RegisterContextMemory::ReadAllRegisterValues (DataBufferSP &data_sp)
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (process_sp->ReadMemory(m_reg_data_addr, data_sp->GetBytes(), data_sp->GetByteSize(), error) == data_sp->GetByteSize())
+ {
+ SetAllRegisterValid (true);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+RegisterContextMemory::WriteAllRegisterValues (const DataBufferSP &data_sp)
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ SetAllRegisterValid (false);
+ if (process_sp->WriteMemory(m_reg_data_addr, data_sp->GetBytes(), data_sp->GetByteSize(), error) == data_sp->GetByteSize())
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+RegisterContextMemory::SetAllRegisterData (const lldb::DataBufferSP &data_sp)
+{
+ m_reg_data.SetData(data_sp);
+ SetAllRegisterValid (true);
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h
new file mode 100644
index 0000000..9d97dfa
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextMemory.h
@@ -0,0 +1,102 @@
+//===-- RegisterContextMemory.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextMemory_h_
+#define lldb_RegisterContextMemory_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/RegisterContext.h"
+
+class DynamicRegisterInfo;
+
+class RegisterContextMemory : public lldb_private::RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextMemory (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ DynamicRegisterInfo &reg_info,
+ lldb::addr_t reg_data_addr);
+
+ virtual
+ ~RegisterContextMemory ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
+
+
+ //------------------------------------------------------------------
+ // If all of the thread register are in a contiguous buffer in
+ // memory, then the default ReadRegister/WriteRegister and
+ // ReadAllRegisterValues/WriteAllRegisterValues will work. If thread
+ // registers are not contiguous, clients will want to subclass this
+ // class and modify the read/write functions as needed.
+ //------------------------------------------------------------------
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ void
+ SetAllRegisterData (const lldb::DataBufferSP &data_sp);
+protected:
+
+ void
+ SetAllRegisterValid (bool b);
+
+ DynamicRegisterInfo &m_reg_infos;
+ std::vector<bool> m_reg_valid;
+ lldb_private::DataExtractor m_reg_data;
+ lldb::addr_t m_reg_data_addr; // If this is valid, then we have a register context that is stored in memmory
+
+private:
+ //------------------------------------------------------------------
+ // For RegisterContextMemory only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextMemory);
+};
+
+#endif // lldb_RegisterContextMemory_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX.h
new file mode 100644
index 0000000..6ddd9cf
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX.h
@@ -0,0 +1,79 @@
+//===-- RegisterContextPOSIX.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextPOSIX_H_
+#define liblldb_RegisterContextPOSIX_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Target/RegisterContext.h"
+#include "RegisterInfoInterface.h"
+
+//------------------------------------------------------------------------------
+/// @class POSIXBreakpointProtocol
+///
+/// @brief Extends RegisterClass with a few virtual operations useful on POSIX.
+class POSIXBreakpointProtocol
+{
+public:
+ POSIXBreakpointProtocol()
+ { m_watchpoints_initialized = false; }
+ virtual ~POSIXBreakpointProtocol() {}
+
+ /// Updates the register state of the associated thread after hitting a
+ /// breakpoint (if that make sense for the architecture). Default
+ /// implementation simply returns true for architectures which do not
+ /// require any update.
+ ///
+ /// @return
+ /// True if the operation succeeded and false otherwise.
+ virtual bool UpdateAfterBreakpoint() = 0;
+
+ /// Determines the index in lldb's register file given a kernel byte offset.
+ virtual unsigned
+ GetRegisterIndexFromOffset(unsigned offset) = 0;
+
+ // Checks to see if a watchpoint specified by hw_index caused the inferior
+ // to stop.
+ virtual bool
+ IsWatchpointHit (uint32_t hw_index) = 0;
+
+ // Resets any watchpoints that have been hit.
+ virtual bool
+ ClearWatchpointHits () = 0;
+
+ // Returns the watchpoint address associated with a watchpoint hardware
+ // index.
+ virtual lldb::addr_t
+ GetWatchpointAddress (uint32_t hw_index) = 0;
+
+ virtual bool
+ IsWatchpointVacant (uint32_t hw_index) = 0;
+
+ virtual bool
+ SetHardwareWatchpointWithIndex (lldb::addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index) = 0;
+
+ // From lldb_private::RegisterContext
+ virtual uint32_t
+ NumSupportedHardwareWatchpoints () = 0;
+
+ // Force m_watchpoints_initialized to TRUE
+ void
+ ForceWatchpointsInitialized () {m_watchpoints_initialized = true;}
+
+protected:
+ bool m_watchpoints_initialized;
+};
+
+#endif // #ifndef liblldb_RegisterContextPOSIX_H_
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp
new file mode 100644
index 0000000..d306f86
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp
@@ -0,0 +1,287 @@
+//===-- RegisterContextPOSIX_arm.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstring>
+#include <errno.h>
+#include <stdint.h>
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContextPOSIX_arm.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+
+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,
+ 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.
+}
+
+bool RegisterContextPOSIX_arm::IsFPR(unsigned reg)
+{
+ return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
+}
+
+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_ap.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);
+
+ // elf-core yet to support ReadFPR()
+ lldb::ProcessSP base = CalculateProcess();
+ if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
+ return;
+}
+
+RegisterContextPOSIX_arm::~RegisterContextPOSIX_arm()
+{
+}
+
+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;
+}
+
+unsigned
+RegisterContextPOSIX_arm::GetRegisterSize(unsigned reg)
+{
+ assert(reg < m_reg_info.num_registers && "Invalid register number.");
+ return 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;
+}
+
+size_t
+RegisterContextPOSIX_arm::GetGPRSize()
+{
+ return m_register_info_ap->GetGPRSize ();
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_arm::GetRegisterInfo()
+{
+ // Commonly, this method is overridden and g_register_infos is copied and specialized.
+ // So, use GetRegisterInfo() rather than g_register_infos in this scope.
+ return m_register_info_ap->GetRegisterInfo ();
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_arm::GetRegisterInfoAtIndex(size_t reg)
+{
+ if (reg < m_reg_info.num_registers)
+ return &GetRegisterInfo()[reg];
+ else
+ return NULL;
+}
+
+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;
+}
+
+const lldb_private::RegisterSet *
+RegisterContextPOSIX_arm::GetRegisterSet(size_t set)
+{
+ if (IsRegisterSetAvailable(set))
+ {
+ switch (m_register_info_ap->m_target_arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ return &g_reg_sets_arm[set];
+ default:
+ assert(false && "Unhandled target architecture.");
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+const char *
+RegisterContextPOSIX_arm::GetRegisterName(unsigned reg)
+{
+ assert(reg < m_reg_info.num_registers && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+lldb::ByteOrder
+RegisterContextPOSIX_arm::GetByteOrder()
+{
+ // Get the target process whose privileged thread was used for the register read.
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
+ lldb_private::Process *process = CalculateProcess().get();
+
+ if (process)
+ byte_order = process->GetByteOrder();
+ return byte_order;
+}
+
+bool
+RegisterContextPOSIX_arm::IsRegisterSetAvailable(size_t set_index)
+{
+ return set_index < k_num_register_sets;
+}
+
+
+// Used when parsing DWARF and EH frame information and any other
+// object file sections that contain register numbers in them.
+uint32_t
+RegisterContextPOSIX_arm::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num)
+{
+ const uint32_t num_regs = GetRegisterCount();
+
+ assert (kind < lldb::kNumRegisterKinds);
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+ {
+ const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx);
+
+ if (reg_info->kinds[kind] == num)
+ return reg_idx;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h
new file mode 100644
index 0000000..a3a2926
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h
@@ -0,0 +1,121 @@
+//===-- RegisterContextPOSIX_arm.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextPOSIX_arm_H_
+#define liblldb_RegisterContextPOSIX_arm_H_
+
+#include "lldb/Core/Log.h"
+#include "lldb-arm-register-enums.h"
+#include "RegisterContextPOSIX.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();
+
+ void
+ Invalidate();
+
+ void
+ InvalidateAllRegisters();
+
+ size_t
+ GetRegisterCount();
+
+ virtual size_t
+ GetGPRSize();
+
+ virtual unsigned
+ GetRegisterSize(unsigned reg);
+
+ virtual unsigned
+ GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex(size_t reg);
+
+ size_t
+ GetRegisterSetCount();
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t set);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num);
+
+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_ap; // 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);
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo();
+
+ bool
+ IsGPR(unsigned reg);
+
+ bool
+ IsFPR(unsigned reg);
+
+ lldb::ByteOrder GetByteOrder();
+
+ virtual bool ReadGPR() = 0;
+ virtual bool ReadFPR() = 0;
+ virtual bool WriteGPR() = 0;
+ virtual bool WriteFPR() = 0;
+};
+
+#endif // #ifndef liblldb_RegisterContextPOSIX_arm_H_
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
new file mode 100644
index 0000000..96508ea
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp
@@ -0,0 +1,302 @@
+//===-- RegisterContextPOSIX_arm64.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstring>
+#include <errno.h>
+#include <stdint.h>
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContextPOSIX_arm64.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// ARM64 general purpose registers.
+const uint32_t g_gpr_regnums_arm64[] =
+{
+ gpr_x0_arm64,
+ gpr_x1_arm64,
+ gpr_x2_arm64,
+ gpr_x3_arm64,
+ gpr_x4_arm64,
+ gpr_x5_arm64,
+ gpr_x6_arm64,
+ gpr_x7_arm64,
+ gpr_x8_arm64,
+ gpr_x9_arm64,
+ gpr_x10_arm64,
+ gpr_x11_arm64,
+ gpr_x12_arm64,
+ gpr_x13_arm64,
+ gpr_x14_arm64,
+ gpr_x15_arm64,
+ gpr_x16_arm64,
+ gpr_x17_arm64,
+ gpr_x18_arm64,
+ gpr_x19_arm64,
+ gpr_x20_arm64,
+ gpr_x21_arm64,
+ gpr_x22_arm64,
+ gpr_x23_arm64,
+ gpr_x24_arm64,
+ gpr_x25_arm64,
+ gpr_x26_arm64,
+ gpr_x27_arm64,
+ gpr_x28_arm64,
+ gpr_fp_arm64,
+ gpr_lr_arm64,
+ gpr_sp_arm64,
+ gpr_pc_arm64,
+ gpr_cpsr_arm64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 1) == k_num_gpr_registers_arm64, \
+ "g_gpr_regnums_arm64 has wrong number of register infos");
+
+// ARM64 floating point registers.
+static const uint32_t g_fpu_regnums_arm64[] =
+{
+ fpu_v0_arm64,
+ fpu_v1_arm64,
+ fpu_v2_arm64,
+ fpu_v3_arm64,
+ fpu_v4_arm64,
+ fpu_v5_arm64,
+ fpu_v6_arm64,
+ fpu_v7_arm64,
+ fpu_v8_arm64,
+ fpu_v9_arm64,
+ fpu_v10_arm64,
+ fpu_v11_arm64,
+ fpu_v12_arm64,
+ fpu_v13_arm64,
+ fpu_v14_arm64,
+ fpu_v15_arm64,
+ fpu_v16_arm64,
+ fpu_v17_arm64,
+ fpu_v18_arm64,
+ fpu_v19_arm64,
+ fpu_v20_arm64,
+ fpu_v21_arm64,
+ fpu_v22_arm64,
+ fpu_v23_arm64,
+ fpu_v24_arm64,
+ fpu_v25_arm64,
+ fpu_v26_arm64,
+ fpu_v27_arm64,
+ fpu_v28_arm64,
+ fpu_v29_arm64,
+ fpu_v30_arm64,
+ fpu_v31_arm64,
+ fpu_fpsr_arm64,
+ fpu_fpcr_arm64,
+ LLDB_INVALID_REGNUM // register sets need to end with this flag
+};
+static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers_arm64, \
+ "g_fpu_regnums_arm64 has wrong number of register infos");
+
+// Number of register sets provided by this context.
+enum
+{
+ k_num_register_sets = 2
+};
+
+// 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_arm64, g_gpr_regnums_arm64 },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64 }
+};
+
+bool RegisterContextPOSIX_arm64::IsGPR(unsigned reg)
+{
+ return reg <= m_reg_info.last_gpr; // GPR's come first.
+}
+
+bool RegisterContextPOSIX_arm64::IsFPR(unsigned reg)
+{
+ return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
+}
+
+RegisterContextPOSIX_arm64::RegisterContextPOSIX_arm64(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info)
+ : lldb_private::RegisterContext(thread, concrete_frame_idx)
+{
+ m_register_info_ap.reset(register_info);
+
+ switch (register_info->m_target_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ m_reg_info.num_registers = k_num_registers_arm64;
+ m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64;
+ m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64;
+ m_reg_info.last_gpr = k_last_gpr_arm64;
+ m_reg_info.first_fpr = k_first_fpr_arm64;
+ m_reg_info.last_fpr = k_last_fpr_arm64;
+ m_reg_info.first_fpr_v = fpu_v0_arm64;
+ m_reg_info.last_fpr_v = fpu_v31_arm64;
+ m_reg_info.gpr_flags = gpr_cpsr_arm64;
+ break;
+ default:
+ assert(false && "Unhandled target architecture.");
+ break;
+ }
+
+ ::memset(&m_fpr, 0, sizeof m_fpr);
+
+ // elf-core yet to support ReadFPR()
+ lldb::ProcessSP base = CalculateProcess();
+ if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
+ return;
+}
+
+RegisterContextPOSIX_arm64::~RegisterContextPOSIX_arm64()
+{
+}
+
+void
+RegisterContextPOSIX_arm64::Invalidate()
+{
+}
+
+void
+RegisterContextPOSIX_arm64::InvalidateAllRegisters()
+{
+}
+
+unsigned
+RegisterContextPOSIX_arm64::GetRegisterOffset(unsigned reg)
+{
+ assert(reg < m_reg_info.num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned
+RegisterContextPOSIX_arm64::GetRegisterSize(unsigned reg)
+{
+ assert(reg < m_reg_info.num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_size;
+}
+
+size_t
+RegisterContextPOSIX_arm64::GetRegisterCount()
+{
+ size_t num_registers = m_reg_info.num_gpr_registers + m_reg_info.num_fpr_registers;
+ return num_registers;
+}
+
+size_t
+RegisterContextPOSIX_arm64::GetGPRSize()
+{
+ return m_register_info_ap->GetGPRSize ();
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_arm64::GetRegisterInfo()
+{
+ // Commonly, this method is overridden and g_register_infos is copied and specialized.
+ // So, use GetRegisterInfo() rather than g_register_infos in this scope.
+ return m_register_info_ap->GetRegisterInfo ();
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_arm64::GetRegisterInfoAtIndex(size_t reg)
+{
+ if (reg < m_reg_info.num_registers)
+ return &GetRegisterInfo()[reg];
+ else
+ return NULL;
+}
+
+size_t
+RegisterContextPOSIX_arm64::GetRegisterSetCount()
+{
+ size_t sets = 0;
+ for (size_t set = 0; set < k_num_register_sets; ++set)
+ {
+ if (IsRegisterSetAvailable(set))
+ ++sets;
+ }
+
+ return sets;
+}
+
+const lldb_private::RegisterSet *
+RegisterContextPOSIX_arm64::GetRegisterSet(size_t set)
+{
+ if (IsRegisterSetAvailable(set))
+ {
+ switch (m_register_info_ap->m_target_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ return &g_reg_sets_arm64[set];
+ default:
+ assert(false && "Unhandled target architecture.");
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+const char *
+RegisterContextPOSIX_arm64::GetRegisterName(unsigned reg)
+{
+ assert(reg < m_reg_info.num_registers && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+lldb::ByteOrder
+RegisterContextPOSIX_arm64::GetByteOrder()
+{
+ // Get the target process whose privileged thread was used for the register read.
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
+ lldb_private::Process *process = CalculateProcess().get();
+
+ if (process)
+ byte_order = process->GetByteOrder();
+ return byte_order;
+}
+
+bool
+RegisterContextPOSIX_arm64::IsRegisterSetAvailable(size_t set_index)
+{
+ return set_index < k_num_register_sets;
+}
+
+
+// Used when parsing DWARF and EH frame information and any other
+// object file sections that contain register numbers in them.
+uint32_t
+RegisterContextPOSIX_arm64::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num)
+{
+ const uint32_t num_regs = GetRegisterCount();
+
+ assert (kind < lldb::kNumRegisterKinds);
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+ {
+ const lldb_private::RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx);
+
+ if (reg_info->kinds[kind] == num)
+ return reg_idx;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
new file mode 100644
index 0000000..29e7a7d
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
@@ -0,0 +1,119 @@
+//===-- RegisterContextPOSIX_arm64.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextPOSIX_arm64_H_
+#define liblldb_RegisterContextPOSIX_arm64_H_
+
+#include "lldb/Core/Log.h"
+#include "lldb-arm64-register-enums.h"
+#include "RegisterContextPOSIX.h"
+
+class ProcessMonitor;
+
+class RegisterContextPOSIX_arm64
+ : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextPOSIX_arm64 (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+ ~RegisterContextPOSIX_arm64();
+
+ void
+ Invalidate();
+
+ void
+ InvalidateAllRegisters();
+
+ size_t
+ GetRegisterCount();
+
+ virtual size_t
+ GetGPRSize();
+
+ virtual unsigned
+ GetRegisterSize(unsigned reg);
+
+ virtual unsigned
+ GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex(size_t reg);
+
+ size_t
+ GetRegisterSetCount();
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t set);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num);
+
+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;
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct VReg
+ {
+ uint8_t bytes[16];
+ };
+
+ // based on RegisterContextDarwin_arm64.h
+ struct FPU
+ {
+ VReg v[32];
+ uint32_t fpsr;
+ uint32_t fpcr;
+ };
+
+ uint64_t m_gpr_arm64[lldb_private::k_num_gpr_registers_arm64]; // 64-bit general purpose registers.
+ RegInfo m_reg_info;
+ struct RegisterContextPOSIX_arm64::FPU m_fpr; // floating-point registers including extended register sets.
+ std::unique_ptr<lldb_private::RegisterInfoInterface> m_register_info_ap; // 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);
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo();
+
+ bool
+ IsGPR(unsigned reg);
+
+ bool
+ IsFPR(unsigned reg);
+
+ lldb::ByteOrder GetByteOrder();
+
+ virtual bool ReadGPR() = 0;
+ virtual bool ReadFPR() = 0;
+ virtual bool WriteGPR() = 0;
+ virtual bool WriteFPR() = 0;
+};
+
+#endif // #ifndef liblldb_RegisterContextPOSIX_arm64_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp
new file mode 100644
index 0000000..cefedae
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp
@@ -0,0 +1,237 @@
+//===-- RegisterContextPOSIX_mips64.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstring>
+#include <errno.h>
+#include <stdint.h>
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContextPOSIX_mips64.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+static const
+uint32_t g_gpr_regnums[] =
+{
+ gpr_zero_mips64,
+ gpr_r1_mips64,
+ gpr_r2_mips64,
+ gpr_r3_mips64,
+ gpr_r4_mips64,
+ gpr_r5_mips64,
+ gpr_r6_mips64,
+ gpr_r7_mips64,
+ gpr_r8_mips64,
+ gpr_r9_mips64,
+ gpr_r10_mips64,
+ gpr_r11_mips64,
+ gpr_r12_mips64,
+ gpr_r13_mips64,
+ gpr_r14_mips64,
+ gpr_r15_mips64,
+ gpr_r16_mips64,
+ gpr_r17_mips64,
+ gpr_r18_mips64,
+ gpr_r19_mips64,
+ gpr_r20_mips64,
+ gpr_r21_mips64,
+ gpr_r22_mips64,
+ gpr_r23_mips64,
+ gpr_r24_mips64,
+ gpr_r25_mips64,
+ gpr_r26_mips64,
+ gpr_r27_mips64,
+ gpr_gp_mips64,
+ gpr_sp_mips64,
+ gpr_r30_mips64,
+ gpr_ra_mips64,
+ gpr_sr_mips64,
+ gpr_mullo_mips64,
+ gpr_mulhi_mips64,
+ gpr_badvaddr_mips64,
+ gpr_cause_mips64,
+ gpr_pc_mips64,
+ gpr_ic_mips64,
+ gpr_dummy_mips64
+};
+
+// Number of register sets provided by this context.
+enum
+{
+ k_num_register_sets = 1
+};
+
+static const RegisterSet
+g_reg_sets_mips64[k_num_register_sets] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers_mips64, g_gpr_regnums },
+};
+
+bool RegisterContextPOSIX_mips64::IsGPR(unsigned reg)
+{
+ return reg <= k_num_gpr_registers_mips64; // GPR's come first.
+}
+
+bool
+RegisterContextPOSIX_mips64::IsFPR(unsigned reg)
+{
+ // XXX
+ return false;
+}
+
+RegisterContextPOSIX_mips64::RegisterContextPOSIX_mips64(Thread &thread,
+ uint32_t concrete_frame_idx,
+ RegisterInfoInterface *register_info)
+ : RegisterContext(thread, concrete_frame_idx)
+{
+ m_register_info_ap.reset(register_info);
+
+ // elf-core yet to support ReadFPR()
+ ProcessSP base = CalculateProcess();
+ if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
+ return;
+}
+
+RegisterContextPOSIX_mips64::~RegisterContextPOSIX_mips64()
+{
+}
+
+void
+RegisterContextPOSIX_mips64::Invalidate()
+{
+}
+
+void
+RegisterContextPOSIX_mips64::InvalidateAllRegisters()
+{
+}
+
+unsigned
+RegisterContextPOSIX_mips64::GetRegisterOffset(unsigned reg)
+{
+ assert(reg < k_num_registers_mips64 && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned
+RegisterContextPOSIX_mips64::GetRegisterSize(unsigned reg)
+{
+ assert(reg < k_num_registers_mips64 && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_size;
+}
+
+size_t
+RegisterContextPOSIX_mips64::GetRegisterCount()
+{
+ size_t num_registers = k_num_registers_mips64;
+ return num_registers;
+}
+
+size_t
+RegisterContextPOSIX_mips64::GetGPRSize()
+{
+ return m_register_info_ap->GetGPRSize();
+}
+
+const RegisterInfo *
+RegisterContextPOSIX_mips64::GetRegisterInfo()
+{
+ // Commonly, this method is overridden and g_register_infos is copied and specialized.
+ // So, use GetRegisterInfo() rather than g_register_infos in this scope.
+ return m_register_info_ap->GetRegisterInfo ();
+}
+
+const RegisterInfo *
+RegisterContextPOSIX_mips64::GetRegisterInfoAtIndex(size_t reg)
+{
+ if (reg < k_num_registers_mips64)
+ return &GetRegisterInfo()[reg];
+ else
+ return NULL;
+}
+
+size_t
+RegisterContextPOSIX_mips64::GetRegisterSetCount()
+{
+ size_t sets = 0;
+ for (size_t set = 0; set < k_num_register_sets; ++set)
+ {
+ if (IsRegisterSetAvailable(set))
+ ++sets;
+ }
+
+ return sets;
+}
+
+const RegisterSet *
+RegisterContextPOSIX_mips64::GetRegisterSet(size_t set)
+{
+ if (IsRegisterSetAvailable(set))
+ return &g_reg_sets_mips64[set];
+ else
+ return NULL;
+}
+
+const char *
+RegisterContextPOSIX_mips64::GetRegisterName(unsigned reg)
+{
+ assert(reg < k_num_registers_mips64 && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+lldb::ByteOrder
+RegisterContextPOSIX_mips64::GetByteOrder()
+{
+ // Get the target process whose privileged thread was used for the register read.
+ lldb::ByteOrder byte_order = eByteOrderInvalid;
+ Process *process = CalculateProcess().get();
+
+ if (process)
+ byte_order = process->GetByteOrder();
+ return byte_order;
+}
+
+bool
+RegisterContextPOSIX_mips64::IsRegisterSetAvailable(size_t set_index)
+{
+ size_t num_sets = k_num_register_sets;
+
+ return (set_index < num_sets);
+}
+
+// Used when parsing DWARF and EH frame information and any other
+// object file sections that contain register numbers in them.
+uint32_t
+RegisterContextPOSIX_mips64::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num)
+{
+ const uint32_t num_regs = GetRegisterCount();
+
+ assert (kind < kNumRegisterKinds);
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx);
+
+ if (reg_info->kinds[kind] == num)
+ return reg_idx;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h
new file mode 100644
index 0000000..612a034
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h
@@ -0,0 +1,90 @@
+//===-- RegisterContextPOSIX_mips64.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextPOSIX_mips64_H_
+#define liblldb_RegisterContextPOSIX_mips64_H_
+
+#include "lldb/Core/Log.h"
+#include "RegisterContextPOSIX.h"
+#include "RegisterContext_mips.h"
+#include "lldb-mips-freebsd-register-enums.h"
+
+using namespace lldb_private;
+
+class ProcessMonitor;
+
+class RegisterContextPOSIX_mips64
+ : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextPOSIX_mips64 (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+ ~RegisterContextPOSIX_mips64();
+
+ void
+ Invalidate();
+
+ void
+ InvalidateAllRegisters();
+
+ size_t
+ GetRegisterCount();
+
+ virtual size_t
+ GetGPRSize();
+
+ virtual unsigned
+ GetRegisterSize(unsigned reg);
+
+ virtual unsigned
+ GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex(size_t reg);
+
+ size_t
+ GetRegisterSetCount();
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t set);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num);
+
+protected:
+ uint64_t m_gpr_mips64[k_num_gpr_registers_mips64]; // general purpose registers.
+ std::unique_ptr<lldb_private::RegisterInfoInterface> m_register_info_ap; // 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);
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo();
+
+ bool
+ IsGPR(unsigned reg);
+
+ bool
+ IsFPR(unsigned reg);
+
+ lldb::ByteOrder GetByteOrder();
+
+ virtual bool ReadGPR() = 0;
+ virtual bool ReadFPR() = 0;
+ virtual bool WriteGPR() = 0;
+ virtual bool WriteFPR() = 0;
+};
+
+#endif // #ifndef liblldb_RegisterContextPOSIX_mips64_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp
new file mode 100644
index 0000000..e353e81
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp
@@ -0,0 +1,319 @@
+//===-- RegisterContextPOSIX_powerpc.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstring>
+#include <errno.h>
+#include <stdint.h>
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContextPOSIX_powerpc.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+static const
+uint32_t g_gpr_regnums[] =
+{
+ gpr_r0_powerpc,
+ gpr_r1_powerpc,
+ gpr_r2_powerpc,
+ gpr_r3_powerpc,
+ gpr_r4_powerpc,
+ gpr_r5_powerpc,
+ gpr_r6_powerpc,
+ gpr_r7_powerpc,
+ gpr_r8_powerpc,
+ gpr_r9_powerpc,
+ gpr_r10_powerpc,
+ gpr_r11_powerpc,
+ gpr_r12_powerpc,
+ gpr_r13_powerpc,
+ gpr_r14_powerpc,
+ gpr_r15_powerpc,
+ gpr_r16_powerpc,
+ gpr_r17_powerpc,
+ gpr_r18_powerpc,
+ gpr_r19_powerpc,
+ gpr_r20_powerpc,
+ gpr_r21_powerpc,
+ gpr_r22_powerpc,
+ gpr_r23_powerpc,
+ gpr_r24_powerpc,
+ gpr_r25_powerpc,
+ gpr_r26_powerpc,
+ gpr_r27_powerpc,
+ gpr_r28_powerpc,
+ gpr_r29_powerpc,
+ gpr_r30_powerpc,
+ gpr_r31_powerpc,
+ gpr_lr_powerpc,
+ gpr_cr_powerpc,
+ gpr_xer_powerpc,
+ gpr_ctr_powerpc,
+ gpr_pc_powerpc,
+};
+
+static const
+uint32_t g_fpr_regnums[] =
+{
+ fpr_f0_powerpc,
+ fpr_f1_powerpc,
+ fpr_f2_powerpc,
+ fpr_f3_powerpc,
+ fpr_f4_powerpc,
+ fpr_f5_powerpc,
+ fpr_f6_powerpc,
+ fpr_f7_powerpc,
+ fpr_f8_powerpc,
+ fpr_f9_powerpc,
+ fpr_f10_powerpc,
+ fpr_f11_powerpc,
+ fpr_f12_powerpc,
+ fpr_f13_powerpc,
+ fpr_f14_powerpc,
+ fpr_f15_powerpc,
+ fpr_f16_powerpc,
+ fpr_f17_powerpc,
+ fpr_f18_powerpc,
+ fpr_f19_powerpc,
+ fpr_f20_powerpc,
+ fpr_f21_powerpc,
+ fpr_f22_powerpc,
+ fpr_f23_powerpc,
+ fpr_f24_powerpc,
+ fpr_f25_powerpc,
+ fpr_f26_powerpc,
+ fpr_f27_powerpc,
+ fpr_f28_powerpc,
+ fpr_f29_powerpc,
+ fpr_f30_powerpc,
+ fpr_f31_powerpc,
+ fpr_fpscr_powerpc,
+};
+
+static const
+uint32_t g_vmx_regnums[] =
+{
+ vmx_v0_powerpc,
+ vmx_v1_powerpc,
+ vmx_v2_powerpc,
+ vmx_v3_powerpc,
+ vmx_v4_powerpc,
+ vmx_v5_powerpc,
+ vmx_v6_powerpc,
+ vmx_v7_powerpc,
+ vmx_v8_powerpc,
+ vmx_v9_powerpc,
+ vmx_v10_powerpc,
+ vmx_v11_powerpc,
+ vmx_v12_powerpc,
+ vmx_v13_powerpc,
+ vmx_v14_powerpc,
+ vmx_v15_powerpc,
+ vmx_v16_powerpc,
+ vmx_v17_powerpc,
+ vmx_v18_powerpc,
+ vmx_v19_powerpc,
+ vmx_v20_powerpc,
+ vmx_v21_powerpc,
+ vmx_v22_powerpc,
+ vmx_v23_powerpc,
+ vmx_v24_powerpc,
+ vmx_v25_powerpc,
+ vmx_v26_powerpc,
+ vmx_v27_powerpc,
+ vmx_v28_powerpc,
+ vmx_v29_powerpc,
+ vmx_v30_powerpc,
+ vmx_v31_powerpc,
+ vmx_vrsave_powerpc,
+ vmx_vscr_powerpc,
+};
+
+// Number of register sets provided by this context.
+enum
+{
+ k_num_register_sets = 3
+};
+
+static const RegisterSet
+g_reg_sets_powerpc[k_num_register_sets] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers_powerpc, g_gpr_regnums },
+ { "Floating Point Registers", "fpr", k_num_fpr_registers_powerpc, g_fpr_regnums },
+ { "Altivec/VMX Registers", "vmx", k_num_vmx_registers_powerpc, g_vmx_regnums },
+};
+
+static_assert(k_first_gpr_powerpc == 0, "GPRs must index starting at 0, or fix IsGPR()");
+bool RegisterContextPOSIX_powerpc::IsGPR(unsigned reg)
+{
+ return (reg <= k_last_gpr_powerpc); // GPR's come first.
+}
+
+bool
+RegisterContextPOSIX_powerpc::IsFPR(unsigned reg)
+{
+ return (reg >= k_first_fpr) && (reg <= k_last_fpr);
+}
+
+bool
+RegisterContextPOSIX_powerpc::IsVMX(unsigned reg)
+{
+ return (reg >= k_first_vmx) && (reg <= k_last_vmx);
+}
+
+RegisterContextPOSIX_powerpc::RegisterContextPOSIX_powerpc(Thread &thread,
+ uint32_t concrete_frame_idx,
+ RegisterInfoInterface *register_info)
+ : RegisterContext(thread, concrete_frame_idx)
+{
+ m_register_info_ap.reset(register_info);
+
+ // elf-core yet to support ReadFPR()
+ ProcessSP base = CalculateProcess();
+ if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
+ return;
+}
+
+RegisterContextPOSIX_powerpc::~RegisterContextPOSIX_powerpc()
+{
+}
+
+void
+RegisterContextPOSIX_powerpc::Invalidate()
+{
+}
+
+void
+RegisterContextPOSIX_powerpc::InvalidateAllRegisters()
+{
+}
+
+unsigned
+RegisterContextPOSIX_powerpc::GetRegisterOffset(unsigned reg)
+{
+ assert(reg < k_num_registers_powerpc && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned
+RegisterContextPOSIX_powerpc::GetRegisterSize(unsigned reg)
+{
+ assert(reg < k_num_registers_powerpc && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_size;
+}
+
+size_t
+RegisterContextPOSIX_powerpc::GetRegisterCount()
+{
+ size_t num_registers = k_num_registers_powerpc;
+ return num_registers;
+}
+
+size_t
+RegisterContextPOSIX_powerpc::GetGPRSize()
+{
+ return m_register_info_ap->GetGPRSize();
+}
+
+const RegisterInfo *
+RegisterContextPOSIX_powerpc::GetRegisterInfo()
+{
+ // Commonly, this method is overridden and g_register_infos is copied and specialized.
+ // So, use GetRegisterInfo() rather than g_register_infos in this scope.
+ return m_register_info_ap->GetRegisterInfo ();
+}
+
+const RegisterInfo *
+RegisterContextPOSIX_powerpc::GetRegisterInfoAtIndex(size_t reg)
+{
+ if (reg < k_num_registers_powerpc)
+ return &GetRegisterInfo()[reg];
+ else
+ return NULL;
+}
+
+size_t
+RegisterContextPOSIX_powerpc::GetRegisterSetCount()
+{
+ size_t sets = 0;
+ for (size_t set = 0; set < k_num_register_sets; ++set)
+ {
+ if (IsRegisterSetAvailable(set))
+ ++sets;
+ }
+
+ return sets;
+}
+
+const RegisterSet *
+RegisterContextPOSIX_powerpc::GetRegisterSet(size_t set)
+{
+ if (IsRegisterSetAvailable(set))
+ return &g_reg_sets_powerpc[set];
+ else
+ return NULL;
+}
+
+const char *
+RegisterContextPOSIX_powerpc::GetRegisterName(unsigned reg)
+{
+ assert(reg < k_num_registers_powerpc && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+lldb::ByteOrder
+RegisterContextPOSIX_powerpc::GetByteOrder()
+{
+ // Get the target process whose privileged thread was used for the register read.
+ lldb::ByteOrder byte_order = eByteOrderInvalid;
+ Process *process = CalculateProcess().get();
+
+ if (process)
+ byte_order = process->GetByteOrder();
+ return byte_order;
+}
+
+bool
+RegisterContextPOSIX_powerpc::IsRegisterSetAvailable(size_t set_index)
+{
+ size_t num_sets = k_num_register_sets;
+
+ return (set_index < num_sets);
+}
+
+// Used when parsing DWARF and EH frame information and any other
+// object file sections that contain register numbers in them.
+uint32_t
+RegisterContextPOSIX_powerpc::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num)
+{
+ const uint32_t num_regs = GetRegisterCount();
+
+ assert (kind < kNumRegisterKinds);
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx);
+
+ if (reg_info->kinds[kind] == num)
+ return reg_idx;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h
new file mode 100644
index 0000000..c7a2451
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h
@@ -0,0 +1,218 @@
+//===-- RegisterContextPOSIX_powerpc.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextPOSIX_powerpc_H_
+#define liblldb_RegisterContextPOSIX_powerpc_H_
+
+#include "lldb/Core/Log.h"
+#include "RegisterContextPOSIX.h"
+#include "RegisterContext_powerpc.h"
+
+class ProcessMonitor;
+
+// ---------------------------------------------------------------------------
+// Internal codes for all powerpc registers.
+// ---------------------------------------------------------------------------
+enum
+{
+ k_first_gpr_powerpc,
+ gpr_r0_powerpc = k_first_gpr_powerpc,
+ gpr_r1_powerpc,
+ gpr_r2_powerpc,
+ gpr_r3_powerpc,
+ gpr_r4_powerpc,
+ gpr_r5_powerpc,
+ gpr_r6_powerpc,
+ gpr_r7_powerpc,
+ gpr_r8_powerpc,
+ gpr_r9_powerpc,
+ gpr_r10_powerpc,
+ gpr_r11_powerpc,
+ gpr_r12_powerpc,
+ gpr_r13_powerpc,
+ gpr_r14_powerpc,
+ gpr_r15_powerpc,
+ gpr_r16_powerpc,
+ gpr_r17_powerpc,
+ gpr_r18_powerpc,
+ gpr_r19_powerpc,
+ gpr_r20_powerpc,
+ gpr_r21_powerpc,
+ gpr_r22_powerpc,
+ gpr_r23_powerpc,
+ gpr_r24_powerpc,
+ gpr_r25_powerpc,
+ gpr_r26_powerpc,
+ gpr_r27_powerpc,
+ gpr_r28_powerpc,
+ gpr_r29_powerpc,
+ gpr_r30_powerpc,
+ gpr_r31_powerpc,
+ gpr_lr_powerpc,
+ gpr_cr_powerpc,
+ gpr_xer_powerpc,
+ gpr_ctr_powerpc,
+ gpr_pc_powerpc,
+ k_last_gpr_powerpc = gpr_pc_powerpc,
+
+ k_first_fpr,
+ fpr_f0_powerpc = k_first_fpr,
+ fpr_f1_powerpc,
+ fpr_f2_powerpc,
+ fpr_f3_powerpc,
+ fpr_f4_powerpc,
+ fpr_f5_powerpc,
+ fpr_f6_powerpc,
+ fpr_f7_powerpc,
+ fpr_f8_powerpc,
+ fpr_f9_powerpc,
+ fpr_f10_powerpc,
+ fpr_f11_powerpc,
+ fpr_f12_powerpc,
+ fpr_f13_powerpc,
+ fpr_f14_powerpc,
+ fpr_f15_powerpc,
+ fpr_f16_powerpc,
+ fpr_f17_powerpc,
+ fpr_f18_powerpc,
+ fpr_f19_powerpc,
+ fpr_f20_powerpc,
+ fpr_f21_powerpc,
+ fpr_f22_powerpc,
+ fpr_f23_powerpc,
+ fpr_f24_powerpc,
+ fpr_f25_powerpc,
+ fpr_f26_powerpc,
+ fpr_f27_powerpc,
+ fpr_f28_powerpc,
+ fpr_f29_powerpc,
+ fpr_f30_powerpc,
+ fpr_f31_powerpc,
+ fpr_fpscr_powerpc,
+ k_last_fpr = fpr_fpscr_powerpc,
+
+ k_first_vmx,
+ vmx_v0_powerpc = k_first_vmx,
+ vmx_v1_powerpc,
+ vmx_v2_powerpc,
+ vmx_v3_powerpc,
+ vmx_v4_powerpc,
+ vmx_v5_powerpc,
+ vmx_v6_powerpc,
+ vmx_v7_powerpc,
+ vmx_v8_powerpc,
+ vmx_v9_powerpc,
+ vmx_v10_powerpc,
+ vmx_v11_powerpc,
+ vmx_v12_powerpc,
+ vmx_v13_powerpc,
+ vmx_v14_powerpc,
+ vmx_v15_powerpc,
+ vmx_v16_powerpc,
+ vmx_v17_powerpc,
+ vmx_v18_powerpc,
+ vmx_v19_powerpc,
+ vmx_v20_powerpc,
+ vmx_v21_powerpc,
+ vmx_v22_powerpc,
+ vmx_v23_powerpc,
+ vmx_v24_powerpc,
+ vmx_v25_powerpc,
+ vmx_v26_powerpc,
+ vmx_v27_powerpc,
+ vmx_v28_powerpc,
+ vmx_v29_powerpc,
+ vmx_v30_powerpc,
+ vmx_v31_powerpc,
+ vmx_vrsave_powerpc,
+ vmx_vscr_powerpc,
+ k_last_vmx = vmx_vscr_powerpc,
+
+ k_num_registers_powerpc,
+ k_num_gpr_registers_powerpc = k_last_gpr_powerpc - k_first_gpr_powerpc + 1,
+ k_num_fpr_registers_powerpc = k_last_fpr - k_first_fpr + 1,
+ k_num_vmx_registers_powerpc = k_last_vmx - k_first_vmx + 1,
+};
+
+class RegisterContextPOSIX_powerpc
+ : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextPOSIX_powerpc (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+ ~RegisterContextPOSIX_powerpc();
+
+ void
+ Invalidate();
+
+ void
+ InvalidateAllRegisters();
+
+ size_t
+ GetRegisterCount();
+
+ virtual size_t
+ GetGPRSize();
+
+ virtual unsigned
+ GetRegisterSize(unsigned reg);
+
+ virtual unsigned
+ GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex(size_t reg);
+
+ size_t
+ GetRegisterSetCount();
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t set);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num);
+
+protected:
+ uint64_t m_gpr_powerpc[k_num_gpr_registers_powerpc]; // general purpose registers.
+ uint64_t m_fpr_powerpc[k_num_fpr_registers_powerpc]; // floating point registers.
+ uint32_t m_vmx_powerpc[k_num_vmx_registers_powerpc][4];
+ std::unique_ptr<lldb_private::RegisterInfoInterface> m_register_info_ap; // 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);
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo();
+
+ bool
+ IsGPR(unsigned reg);
+
+ bool
+ IsFPR(unsigned reg);
+
+ bool
+ IsVMX(unsigned reg);
+
+ lldb::ByteOrder GetByteOrder();
+
+ virtual bool ReadGPR() = 0;
+ virtual bool ReadFPR() = 0;
+ virtual bool ReadVMX() = 0;
+ virtual bool WriteGPR() = 0;
+ virtual bool WriteFPR() = 0;
+ virtual bool WriteVMX() = 0;
+};
+
+#endif // #ifndef liblldb_RegisterContextPOSIX_powerpc_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp
new file mode 100644
index 0000000..77b6385
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp
@@ -0,0 +1,667 @@
+//===-- RegisterContextPOSIX_x86.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstring>
+#include <errno.h>
+#include <stdint.h>
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+#include "RegisterContext_x86.h"
+#include "RegisterContextPOSIX_x86.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+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 must be terminated with LLDB_INVALID_REGNUM.
+};
+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");
+
+const uint32_t
+g_lldb_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 must be terminated with LLDB_INVALID_REGNUM.
+};
+static_assert((sizeof(g_lldb_regnums_i386) / sizeof(g_lldb_regnums_i386[0])) - 1 == k_num_fpr_registers_i386,
+ "g_lldb_regnums_i386 has wrong number of register infos");
+
+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 must be terminated with LLDB_INVALID_REGNUM.
+};
+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_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 must be terminated with LLDB_INVALID_REGNUM.
+};
+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");
+
+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_INVALID_REGNUM // Register sets must be terminated with LLDB_INVALID_REGNUM.
+};
+static_assert((sizeof(g_lldb_regnums_x86_64) / sizeof(g_lldb_regnums_x86_64[0])) - 1 == k_num_fpr_registers_x86_64,
+ "g_lldb_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 must be terminated with LLDB_INVALID_REGNUM.
+};
+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");
+
+uint32_t RegisterContextPOSIX_x86::g_contained_eax[] = { lldb_eax_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_ebx[] = { lldb_ebx_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_ecx[] = { lldb_ecx_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_edx[] = { lldb_edx_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_edi[] = { lldb_edi_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_esi[] = { lldb_esi_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_ebp[] = { lldb_ebp_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_esp[] = { lldb_esp_i386, LLDB_INVALID_REGNUM };
+
+uint32_t RegisterContextPOSIX_x86::g_invalidate_eax[] = { lldb_eax_i386, lldb_ax_i386, lldb_ah_i386, lldb_al_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_ebx[] = { lldb_ebx_i386, lldb_bx_i386, lldb_bh_i386, lldb_bl_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_ecx[] = { lldb_ecx_i386, lldb_cx_i386, lldb_ch_i386, lldb_cl_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_edx[] = { lldb_edx_i386, lldb_dx_i386, lldb_dh_i386, lldb_dl_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_edi[] = { lldb_edi_i386, lldb_di_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_esi[] = { lldb_esi_i386, lldb_si_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_ebp[] = { lldb_ebp_i386, lldb_bp_i386, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_esp[] = { lldb_esp_i386, lldb_sp_i386, LLDB_INVALID_REGNUM };
+
+uint32_t RegisterContextPOSIX_x86::g_contained_rax[] = { lldb_rax_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_rbx[] = { lldb_rbx_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_rcx[] = { lldb_rcx_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_rdx[] = { lldb_rdx_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_rdi[] = { lldb_rdi_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_rsi[] = { lldb_rsi_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_rbp[] = { lldb_rbp_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_rsp[] = { lldb_rsp_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r8[] = { lldb_r8_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r9[] = { lldb_r9_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r10[] = { lldb_r10_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r11[] = { lldb_r11_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r12[] = { lldb_r12_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r13[] = { lldb_r13_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r14[] = { lldb_r14_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_contained_r15[] = { lldb_r15_x86_64, LLDB_INVALID_REGNUM };
+
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rax[] = { lldb_rax_x86_64, lldb_eax_x86_64, lldb_ax_x86_64, lldb_ah_x86_64, lldb_al_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rbx[] = { lldb_rbx_x86_64, lldb_ebx_x86_64, lldb_bx_x86_64, lldb_bh_x86_64, lldb_bl_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rcx[] = { lldb_rcx_x86_64, lldb_ecx_x86_64, lldb_cx_x86_64, lldb_ch_x86_64, lldb_cl_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rdx[] = { lldb_rdx_x86_64, lldb_edx_x86_64, lldb_dx_x86_64, lldb_dh_x86_64, lldb_dl_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rdi[] = { lldb_rdi_x86_64, lldb_edi_x86_64, lldb_di_x86_64, lldb_dil_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rsi[] = { lldb_rsi_x86_64, lldb_esi_x86_64, lldb_si_x86_64, lldb_sil_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rbp[] = { lldb_rbp_x86_64, lldb_ebp_x86_64, lldb_bp_x86_64, lldb_bpl_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_rsp[] = { lldb_rsp_x86_64, lldb_esp_x86_64, lldb_sp_x86_64, lldb_spl_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r8[] = { lldb_r8_x86_64, lldb_r8d_x86_64, lldb_r8w_x86_64, lldb_r8l_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r9[] = { lldb_r9_x86_64, lldb_r9d_x86_64, lldb_r9w_x86_64, lldb_r9l_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r10[] = { lldb_r10_x86_64, lldb_r10d_x86_64, lldb_r10w_x86_64, lldb_r10l_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r11[] = { lldb_r11_x86_64, lldb_r11d_x86_64, lldb_r11w_x86_64, lldb_r11l_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r12[] = { lldb_r12_x86_64, lldb_r12d_x86_64, lldb_r12w_x86_64, lldb_r12l_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r13[] = { lldb_r13_x86_64, lldb_r13d_x86_64, lldb_r13w_x86_64, lldb_r13l_x86_64, LLDB_INVALID_REGNUM };
+uint32_t RegisterContextPOSIX_x86::g_invalidate_r14[] = { lldb_r14_x86_64, lldb_r14d_x86_64, lldb_r14w_x86_64, lldb_r14l_x86_64, LLDB_INVALID_REGNUM };
+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 };
+
+// Number of register sets provided by this context.
+enum
+{
+ k_num_extended_register_sets = 1,
+ k_num_register_sets = 3
+};
+
+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_lldb_regnums_i386 },
+ { "Advanced Vector Extensions", "avx", k_num_avx_registers_i386, g_avx_regnums_i386 }
+};
+
+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_lldb_regnums_x86_64 },
+ { "Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, g_avx_regnums_x86_64 }
+};
+
+bool RegisterContextPOSIX_x86::IsGPR(unsigned reg)
+{
+ return reg <= m_reg_info.last_gpr; // GPR's come first.
+}
+
+bool RegisterContextPOSIX_x86::IsFPR(unsigned reg)
+{
+ return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr);
+}
+
+bool RegisterContextPOSIX_x86::IsAVX(unsigned reg)
+{
+ return (m_reg_info.first_ymm <= reg && reg <= m_reg_info.last_ymm);
+}
+
+bool RegisterContextPOSIX_x86::IsFPR(unsigned reg, FPRType fpr_type)
+{
+ bool generic_fpr = IsFPR(reg);
+
+ if (fpr_type == eXSAVE)
+ return generic_fpr || IsAVX(reg);
+ return generic_fpr;
+}
+
+RegisterContextPOSIX_x86::RegisterContextPOSIX_x86(Thread &thread,
+ uint32_t concrete_frame_idx,
+ RegisterInfoInterface *register_info)
+ : RegisterContext(thread, concrete_frame_idx)
+{
+ m_register_info_ap.reset(register_info);
+
+ switch (register_info->m_target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ m_reg_info.num_registers = k_num_registers_i386;
+ m_reg_info.num_gpr_registers = k_num_gpr_registers_i386;
+ m_reg_info.num_fpr_registers = k_num_fpr_registers_i386;
+ m_reg_info.num_avx_registers = k_num_avx_registers_i386;
+ m_reg_info.last_gpr = k_last_gpr_i386;
+ m_reg_info.first_fpr = k_first_fpr_i386;
+ m_reg_info.last_fpr = k_last_fpr_i386;
+ m_reg_info.first_st = lldb_st0_i386;
+ m_reg_info.last_st = lldb_st7_i386;
+ m_reg_info.first_mm = lldb_mm0_i386;
+ m_reg_info.last_mm = lldb_mm7_i386;
+ m_reg_info.first_xmm = lldb_xmm0_i386;
+ m_reg_info.last_xmm = lldb_xmm7_i386;
+ m_reg_info.first_ymm = lldb_ymm0_i386;
+ m_reg_info.last_ymm = lldb_ymm7_i386;
+ m_reg_info.first_dr = lldb_dr0_i386;
+ m_reg_info.gpr_flags = lldb_eflags_i386;
+ break;
+ case llvm::Triple::x86_64:
+ m_reg_info.num_registers = k_num_registers_x86_64;
+ m_reg_info.num_gpr_registers = k_num_gpr_registers_x86_64;
+ m_reg_info.num_fpr_registers = k_num_fpr_registers_x86_64;
+ m_reg_info.num_avx_registers = k_num_avx_registers_x86_64;
+ m_reg_info.last_gpr = k_last_gpr_x86_64;
+ m_reg_info.first_fpr = k_first_fpr_x86_64;
+ m_reg_info.last_fpr = k_last_fpr_x86_64;
+ m_reg_info.first_st = lldb_st0_x86_64;
+ m_reg_info.last_st = lldb_st7_x86_64;
+ m_reg_info.first_mm = lldb_mm0_x86_64;
+ m_reg_info.last_mm = lldb_mm7_x86_64;
+ m_reg_info.first_xmm = lldb_xmm0_x86_64;
+ m_reg_info.last_xmm = lldb_xmm15_x86_64;
+ m_reg_info.first_ymm = lldb_ymm0_x86_64;
+ m_reg_info.last_ymm = lldb_ymm15_x86_64;
+ m_reg_info.first_dr = lldb_dr0_x86_64;
+ m_reg_info.gpr_flags = lldb_rflags_x86_64;
+ break;
+ default:
+ assert(false && "Unhandled target architecture.");
+ break;
+ }
+
+ // Initialize m_iovec to point to the buffer and buffer size
+ // using the conventions of Berkeley style UIO structures, as required
+ // by PTRACE extensions.
+ m_iovec.iov_base = &m_fpr.xstate.xsave;
+ m_iovec.iov_len = sizeof(m_fpr.xstate.xsave);
+
+ ::memset(&m_fpr, 0, sizeof(FPR));
+
+ // elf-core yet to support ReadFPR()
+ ProcessSP base = CalculateProcess();
+ if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
+ return;
+
+ m_fpr_type = eNotValid;
+}
+
+RegisterContextPOSIX_x86::~RegisterContextPOSIX_x86()
+{
+}
+
+RegisterContextPOSIX_x86::FPRType RegisterContextPOSIX_x86::GetFPRType()
+{
+ if (m_fpr_type == eNotValid)
+ {
+ // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx
+ m_fpr_type = eXSAVE; // extended floating-point registers, if available
+ if (false == ReadFPR())
+ m_fpr_type = eFXSAVE; // assume generic floating-point registers
+ }
+ return m_fpr_type;
+}
+
+void
+RegisterContextPOSIX_x86::Invalidate()
+{
+}
+
+void
+RegisterContextPOSIX_x86::InvalidateAllRegisters()
+{
+}
+
+unsigned
+RegisterContextPOSIX_x86::GetRegisterOffset(unsigned reg)
+{
+ assert(reg < m_reg_info.num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned
+RegisterContextPOSIX_x86::GetRegisterSize(unsigned reg)
+{
+ assert(reg < m_reg_info.num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_size;
+}
+
+size_t
+RegisterContextPOSIX_x86::GetRegisterCount()
+{
+ size_t num_registers = m_reg_info.num_gpr_registers + m_reg_info.num_fpr_registers;
+ if (GetFPRType() == eXSAVE)
+ return num_registers + m_reg_info.num_avx_registers;
+ return num_registers;
+}
+
+size_t
+RegisterContextPOSIX_x86::GetGPRSize()
+{
+ return m_register_info_ap->GetGPRSize ();
+}
+
+const RegisterInfo *
+RegisterContextPOSIX_x86::GetRegisterInfo()
+{
+ // Commonly, this method is overridden and g_register_infos is copied and specialized.
+ // So, use GetRegisterInfo() rather than g_register_infos in this scope.
+ return m_register_info_ap->GetRegisterInfo ();
+}
+
+const RegisterInfo *
+RegisterContextPOSIX_x86::GetRegisterInfoAtIndex(size_t reg)
+{
+ if (reg < m_reg_info.num_registers)
+ return &GetRegisterInfo()[reg];
+ else
+ return NULL;
+}
+
+size_t
+RegisterContextPOSIX_x86::GetRegisterSetCount()
+{
+ size_t sets = 0;
+ for (size_t set = 0; set < k_num_register_sets; ++set)
+ {
+ if (IsRegisterSetAvailable(set))
+ ++sets;
+ }
+
+ return sets;
+}
+
+const RegisterSet *
+RegisterContextPOSIX_x86::GetRegisterSet(size_t set)
+{
+ if (IsRegisterSetAvailable(set))
+ {
+ switch (m_register_info_ap->m_target_arch.GetMachine())
+ {
+ case llvm::Triple::x86:
+ return &g_reg_sets_i386[set];
+ case llvm::Triple::x86_64:
+ return &g_reg_sets_x86_64[set];
+ default:
+ assert(false && "Unhandled target architecture.");
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+const char *
+RegisterContextPOSIX_x86::GetRegisterName(unsigned reg)
+{
+ assert(reg < m_reg_info.num_registers && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+lldb::ByteOrder
+RegisterContextPOSIX_x86::GetByteOrder()
+{
+ // Get the target process whose privileged thread was used for the register read.
+ lldb::ByteOrder byte_order = eByteOrderInvalid;
+ Process *process = CalculateProcess().get();
+
+ if (process)
+ byte_order = process->GetByteOrder();
+ return byte_order;
+}
+
+// Parse ymm registers and into xmm.bytes and ymmh.bytes.
+bool RegisterContextPOSIX_x86::CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order)
+{
+ if (!IsAVX(reg))
+ return false;
+
+ if (byte_order == eByteOrderLittle)
+ {
+ ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
+ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
+ sizeof(XMMReg));
+ ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
+ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
+ sizeof(YMMHReg));
+ return true;
+ }
+
+ if (byte_order == eByteOrderBig)
+ {
+ ::memcpy(m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
+ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
+ sizeof(XMMReg));
+ ::memcpy(m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
+ m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
+ sizeof(YMMHReg));
+ return true;
+ }
+ return false; // unsupported or invalid byte order
+}
+
+// Concatenate xmm.bytes with ymmh.bytes
+bool RegisterContextPOSIX_x86::CopyXSTATEtoYMM(uint32_t reg, lldb::ByteOrder byte_order)
+{
+ if (!IsAVX(reg))
+ return false;
+
+ if (byte_order == eByteOrderLittle)
+ {
+ ::memcpy(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
+ m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
+ sizeof(XMMReg));
+ ::memcpy(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
+ m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
+ sizeof(YMMHReg));
+ return true;
+ }
+
+ if (byte_order == eByteOrderBig)
+ {
+ ::memcpy(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes + sizeof(XMMReg),
+ m_fpr.xstate.fxsave.xmm[reg - m_reg_info.first_ymm].bytes,
+ sizeof(XMMReg));
+ ::memcpy(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
+ m_fpr.xstate.xsave.ymmh[reg - m_reg_info.first_ymm].bytes,
+ sizeof(YMMHReg));
+ return true;
+ }
+ return false; // unsupported or invalid byte order
+}
+
+bool
+RegisterContextPOSIX_x86::IsRegisterSetAvailable(size_t set_index)
+{
+ // Note: Extended register sets are assumed to be at the end of g_reg_sets...
+ size_t num_sets = k_num_register_sets - k_num_extended_register_sets;
+
+ if (GetFPRType() == eXSAVE) // ...and to start with AVX registers.
+ ++num_sets;
+ return (set_index < num_sets);
+}
+
+
+// Used when parsing DWARF and EH frame information and any other
+// object file sections that contain register numbers in them.
+uint32_t
+RegisterContextPOSIX_x86::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num)
+{
+ const uint32_t num_regs = GetRegisterCount();
+
+ assert (kind < kNumRegisterKinds);
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx);
+
+ if (reg_info->kinds[kind] == num)
+ return reg_idx;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h
new file mode 100644
index 0000000..0eec1d9
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h
@@ -0,0 +1,189 @@
+//===-- RegisterContextPOSIX_x86.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextPOSIX_x86_H_
+#define liblldb_RegisterContextPOSIX_x86_H_
+
+#include "lldb/Core/Log.h"
+#include "lldb-x86-register-enums.h"
+#include "RegisterContextPOSIX.h"
+#include "RegisterContext_x86.h"
+
+class ProcessMonitor;
+
+class RegisterContextPOSIX_x86
+ : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextPOSIX_x86 (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ lldb_private::RegisterInfoInterface *register_info);
+
+ ~RegisterContextPOSIX_x86();
+
+ void
+ Invalidate();
+
+ void
+ InvalidateAllRegisters();
+
+ size_t
+ GetRegisterCount();
+
+ virtual size_t
+ GetGPRSize();
+
+ virtual unsigned
+ GetRegisterSize(unsigned reg);
+
+ virtual unsigned
+ GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex(size_t reg);
+
+ size_t
+ GetRegisterSetCount();
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t set);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num);
+
+ //---------------------------------------------------------------------------
+ // Note: prefer kernel definitions over user-land
+ //---------------------------------------------------------------------------
+ enum FPRType
+ {
+ eNotValid = 0,
+ eFSAVE, // TODO
+ eFXSAVE,
+ eSOFT, // TODO
+ eXSAVE
+ };
+
+ static uint32_t g_contained_eax[];
+ static uint32_t g_contained_ebx[];
+ static uint32_t g_contained_ecx[];
+ static uint32_t g_contained_edx[];
+ static uint32_t g_contained_edi[];
+ static uint32_t g_contained_esi[];
+ static uint32_t g_contained_ebp[];
+ static uint32_t g_contained_esp[];
+
+ static uint32_t g_invalidate_eax[];
+ static uint32_t g_invalidate_ebx[];
+ static uint32_t g_invalidate_ecx[];
+ static uint32_t g_invalidate_edx[];
+ static uint32_t g_invalidate_edi[];
+ static uint32_t g_invalidate_esi[];
+ static uint32_t g_invalidate_ebp[];
+ static uint32_t g_invalidate_esp[];
+
+ static uint32_t g_contained_rax[];
+ static uint32_t g_contained_rbx[];
+ static uint32_t g_contained_rcx[];
+ static uint32_t g_contained_rdx[];
+ static uint32_t g_contained_rdi[];
+ static uint32_t g_contained_rsi[];
+ static uint32_t g_contained_rbp[];
+ static uint32_t g_contained_rsp[];
+ static uint32_t g_contained_r8[];
+ static uint32_t g_contained_r9[];
+ static uint32_t g_contained_r10[];
+ static uint32_t g_contained_r11[];
+ static uint32_t g_contained_r12[];
+ static uint32_t g_contained_r13[];
+ static uint32_t g_contained_r14[];
+ static uint32_t g_contained_r15[];
+
+ static uint32_t g_invalidate_rax[];
+ static uint32_t g_invalidate_rbx[];
+ static uint32_t g_invalidate_rcx[];
+ static uint32_t g_invalidate_rdx[];
+ static uint32_t g_invalidate_rdi[];
+ static uint32_t g_invalidate_rsi[];
+ static uint32_t g_invalidate_rbp[];
+ static uint32_t g_invalidate_rsp[];
+ static uint32_t g_invalidate_r8[];
+ static uint32_t g_invalidate_r9[];
+ static uint32_t g_invalidate_r10[];
+ static uint32_t g_invalidate_r11[];
+ static uint32_t g_invalidate_r12[];
+ static uint32_t g_invalidate_r13[];
+ static uint32_t g_invalidate_r14[];
+ static uint32_t g_invalidate_r15[];
+
+protected:
+ struct RegInfo
+ {
+ uint32_t num_registers;
+ uint32_t num_gpr_registers;
+ uint32_t num_fpr_registers;
+ uint32_t num_avx_registers;
+
+ uint32_t last_gpr;
+ uint32_t first_fpr;
+ uint32_t last_fpr;
+
+ uint32_t first_st;
+ uint32_t last_st;
+ uint32_t first_mm;
+ uint32_t last_mm;
+ uint32_t first_xmm;
+ uint32_t last_xmm;
+ uint32_t first_ymm;
+ uint32_t last_ymm;
+
+ uint32_t first_dr;
+ uint32_t gpr_flags;
+ };
+
+ uint64_t m_gpr_x86_64[lldb_private::k_num_gpr_registers_x86_64]; // 64-bit general purpose registers.
+ RegInfo m_reg_info;
+ FPRType m_fpr_type; // determines the type of data stored by union FPR, if any.
+ FPR m_fpr; // floating-point registers including extended register sets.
+ IOVEC m_iovec; // wrapper for xsave.
+ YMM m_ymm_set; // copy of ymmh and xmm register halves.
+ std::unique_ptr<lldb_private::RegisterInfoInterface> m_register_info_ap; // 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);
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo();
+
+ bool
+ IsGPR(unsigned reg);
+
+ bool
+ IsFPR(unsigned reg);
+
+ bool
+ IsAVX(unsigned reg);
+
+ lldb::ByteOrder GetByteOrder();
+
+ bool CopyXSTATEtoYMM(uint32_t reg, lldb::ByteOrder byte_order);
+ bool CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order);
+ bool IsFPR(unsigned reg, FPRType fpr_type);
+ FPRType GetFPRType();
+
+ virtual bool ReadGPR() = 0;
+ virtual bool ReadFPR() = 0;
+ virtual bool WriteGPR() = 0;
+ virtual bool WriteFPR() = 0;
+};
+
+#endif // #ifndef liblldb_RegisterContextPOSIX_x86_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
new file mode 100644
index 0000000..200ef4d
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
@@ -0,0 +1,261 @@
+//===-- RegisterContextThreadMemory.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+#include "RegisterContextThreadMemory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextThreadMemory::RegisterContextThreadMemory (Thread &thread,
+ lldb::addr_t register_data_addr) :
+ RegisterContext (thread, 0),
+ m_thread_wp (thread.shared_from_this()),
+ m_reg_ctx_sp (),
+ m_register_data_addr (register_data_addr),
+ m_stop_id(0)
+{
+}
+
+RegisterContextThreadMemory::~RegisterContextThreadMemory()
+{
+}
+
+void
+RegisterContextThreadMemory::UpdateRegisterContext ()
+{
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ {
+ ProcessSP process_sp (thread_sp->GetProcess());
+
+ if (process_sp)
+ {
+ const uint32_t stop_id = process_sp->GetModID().GetStopID();
+ if (m_stop_id != stop_id)
+ {
+ m_stop_id = stop_id;
+ m_reg_ctx_sp.reset();
+ }
+ if (!m_reg_ctx_sp)
+ {
+ ThreadSP backing_thread_sp (thread_sp->GetBackingThread());
+ if (backing_thread_sp)
+ {
+ m_reg_ctx_sp = backing_thread_sp->GetRegisterContext();
+ }
+ else
+ {
+ OperatingSystem *os = process_sp->GetOperatingSystem ();
+ if (os->IsOperatingSystemPluginThread (thread_sp))
+ m_reg_ctx_sp = os->CreateRegisterContextForThread (thread_sp.get(), m_register_data_addr);
+ }
+ }
+ }
+ else
+ {
+ m_reg_ctx_sp.reset();
+ }
+ }
+ else
+ {
+ m_reg_ctx_sp.reset();
+ }
+}
+
+//------------------------------------------------------------------
+// Subclasses must override these functions
+//------------------------------------------------------------------
+void
+RegisterContextThreadMemory::InvalidateAllRegisters ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ m_reg_ctx_sp->InvalidateAllRegisters();
+}
+
+size_t
+RegisterContextThreadMemory::GetRegisterCount ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterCount();
+ return 0;
+}
+
+const RegisterInfo *
+RegisterContextThreadMemory::GetRegisterInfoAtIndex (size_t reg)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterInfoAtIndex(reg);
+ return NULL;
+}
+
+size_t
+RegisterContextThreadMemory::GetRegisterSetCount ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterSetCount();
+ return 0;
+}
+
+const RegisterSet *
+RegisterContextThreadMemory::GetRegisterSet (size_t reg_set)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterSet(reg_set);
+ return NULL;
+}
+
+bool
+RegisterContextThreadMemory::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadRegister(reg_info, reg_value);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteRegister (reg_info, reg_value);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadAllRegisterValues(data_sp);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteAllRegisterValues (data_sp);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::CopyFromRegisterContext (lldb::RegisterContextSP reg_ctx_sp)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->CopyFromRegisterContext(reg_ctx_sp);
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ConvertRegisterKindToRegisterNumber(kind, num);
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::NumSupportedHardwareBreakpoints ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->NumSupportedHardwareBreakpoints();
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->SetHardwareBreakpoint(addr, size);
+ return 0;
+}
+
+bool
+RegisterContextThreadMemory::ClearHardwareBreakpoint (uint32_t hw_idx)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ClearHardwareBreakpoint (hw_idx);
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::NumSupportedHardwareWatchpoints ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->NumSupportedHardwareWatchpoints();
+ return 0;
+}
+
+uint32_t
+RegisterContextThreadMemory::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->SetHardwareWatchpoint(addr, size, read, write);
+ return 0;
+}
+
+bool
+RegisterContextThreadMemory::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ClearHardwareWatchpoint(hw_index);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::HardwareSingleStep (bool enable)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->HardwareSingleStep(enable);
+ return false;
+}
+
+Error
+RegisterContextThreadMemory::ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadRegisterValueFromMemory (reg_info, src_addr, src_len, reg_value);
+ Error error;
+ error.SetErrorString("invalid register context");
+ return error;
+}
+
+Error
+RegisterContextThreadMemory::WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteRegisterValueToMemory (reg_info, dst_addr, dst_len, reg_value);
+ Error error;
+ error.SetErrorString("invalid register context");
+ return error;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
new file mode 100644
index 0000000..161ef04
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
@@ -0,0 +1,114 @@
+//===-- RegisterContextThreadMemory.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextThreadMemory_h_
+#define lldb_RegisterContextThreadMemory_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+namespace lldb_private {
+
+class RegisterContextThreadMemory : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextThreadMemory (Thread &thread,
+ lldb::addr_t register_data_addr);
+
+ virtual ~RegisterContextThreadMemory();
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value);
+
+ // These two functions are used to implement "push" and "pop" of register states. They are used primarily
+ // for expression evaluation, where we need to push a new state (storing the old one in data_sp) and then
+ // restoring the original state by passing the data_sp we got from ReadAllRegisters to WriteAllRegisterValues.
+ // ReadAllRegisters will do what is necessary to return a coherent set of register values for this thread, which
+ // may mean e.g. interrupting a thread that is sitting in a kernel trap. That is a somewhat disruptive operation,
+ // so these API's should only be used when this behavior is needed.
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ bool
+ CopyFromRegisterContext (lldb::RegisterContextSP context);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num);
+
+ //------------------------------------------------------------------
+ // Subclasses can override these functions if desired
+ //------------------------------------------------------------------
+ virtual uint32_t
+ NumSupportedHardwareBreakpoints ();
+
+ virtual uint32_t
+ SetHardwareBreakpoint (lldb::addr_t addr, size_t size);
+
+ virtual bool
+ ClearHardwareBreakpoint (uint32_t hw_idx);
+
+ virtual uint32_t
+ NumSupportedHardwareWatchpoints ();
+
+ virtual uint32_t
+ SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write);
+
+ virtual bool
+ ClearHardwareWatchpoint (uint32_t hw_index);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ virtual Error
+ ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue &reg_value);
+
+ virtual Error
+ WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue &reg_value);
+
+protected:
+ void
+ UpdateRegisterContext ();
+
+ lldb::ThreadWP m_thread_wp;
+ lldb::RegisterContextSP m_reg_ctx_sp;
+ lldb::addr_t m_register_data_addr;
+ uint32_t m_stop_id;
+private:
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextThreadMemory);
+};
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextThreadMemory_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_mips.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_mips.h
new file mode 100644
index 0000000..de2b4d6
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_mips.h
@@ -0,0 +1,611 @@
+//===-- RegisterContext_mips.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContext_mips64_H_
+#define liblldb_RegisterContext_mips64_H_
+
+// eh_frame and DWARF Register numbers (eRegisterKindEHFrame & eRegisterKindDWARF)
+
+enum
+{
+ // GP Registers
+ gcc_dwarf_zero_mips = 0,
+ gcc_dwarf_r1_mips,
+ gcc_dwarf_r2_mips,
+ gcc_dwarf_r3_mips,
+ gcc_dwarf_r4_mips,
+ gcc_dwarf_r5_mips,
+ gcc_dwarf_r6_mips,
+ gcc_dwarf_r7_mips,
+ gcc_dwarf_r8_mips,
+ gcc_dwarf_r9_mips,
+ gcc_dwarf_r10_mips,
+ gcc_dwarf_r11_mips,
+ gcc_dwarf_r12_mips,
+ gcc_dwarf_r13_mips,
+ gcc_dwarf_r14_mips,
+ gcc_dwarf_r15_mips,
+ gcc_dwarf_r16_mips,
+ gcc_dwarf_r17_mips,
+ gcc_dwarf_r18_mips,
+ gcc_dwarf_r19_mips,
+ gcc_dwarf_r20_mips,
+ gcc_dwarf_r21_mips,
+ gcc_dwarf_r22_mips,
+ gcc_dwarf_r23_mips,
+ gcc_dwarf_r24_mips,
+ gcc_dwarf_r25_mips,
+ gcc_dwarf_r26_mips,
+ gcc_dwarf_r27_mips,
+ gcc_dwarf_gp_mips,
+ gcc_dwarf_sp_mips,
+ gcc_dwarf_r30_mips,
+ gcc_dwarf_ra_mips,
+ gcc_dwarf_sr_mips,
+ gcc_dwarf_lo_mips,
+ gcc_dwarf_hi_mips,
+ gcc_dwarf_bad_mips,
+ gcc_dwarf_cause_mips,
+ gcc_dwarf_pc_mips,
+ gcc_dwarf_f0_mips,
+ gcc_dwarf_f1_mips,
+ gcc_dwarf_f2_mips,
+ gcc_dwarf_f3_mips,
+ gcc_dwarf_f4_mips,
+ gcc_dwarf_f5_mips,
+ gcc_dwarf_f6_mips,
+ gcc_dwarf_f7_mips,
+ gcc_dwarf_f8_mips,
+ gcc_dwarf_f9_mips,
+ gcc_dwarf_f10_mips,
+ gcc_dwarf_f11_mips,
+ gcc_dwarf_f12_mips,
+ gcc_dwarf_f13_mips,
+ gcc_dwarf_f14_mips,
+ gcc_dwarf_f15_mips,
+ gcc_dwarf_f16_mips,
+ gcc_dwarf_f17_mips,
+ gcc_dwarf_f18_mips,
+ gcc_dwarf_f19_mips,
+ gcc_dwarf_f20_mips,
+ gcc_dwarf_f21_mips,
+ gcc_dwarf_f22_mips,
+ gcc_dwarf_f23_mips,
+ gcc_dwarf_f24_mips,
+ gcc_dwarf_f25_mips,
+ gcc_dwarf_f26_mips,
+ gcc_dwarf_f27_mips,
+ gcc_dwarf_f28_mips,
+ gcc_dwarf_f29_mips,
+ gcc_dwarf_f30_mips,
+ gcc_dwarf_f31_mips,
+ gcc_dwarf_fcsr_mips,
+ gcc_dwarf_fir_mips,
+ gcc_dwarf_w0_mips,
+ gcc_dwarf_w1_mips,
+ gcc_dwarf_w2_mips,
+ gcc_dwarf_w3_mips,
+ gcc_dwarf_w4_mips,
+ gcc_dwarf_w5_mips,
+ gcc_dwarf_w6_mips,
+ gcc_dwarf_w7_mips,
+ gcc_dwarf_w8_mips,
+ gcc_dwarf_w9_mips,
+ gcc_dwarf_w10_mips,
+ gcc_dwarf_w11_mips,
+ gcc_dwarf_w12_mips,
+ gcc_dwarf_w13_mips,
+ gcc_dwarf_w14_mips,
+ gcc_dwarf_w15_mips,
+ gcc_dwarf_w16_mips,
+ gcc_dwarf_w17_mips,
+ gcc_dwarf_w18_mips,
+ gcc_dwarf_w19_mips,
+ gcc_dwarf_w20_mips,
+ gcc_dwarf_w21_mips,
+ gcc_dwarf_w22_mips,
+ gcc_dwarf_w23_mips,
+ gcc_dwarf_w24_mips,
+ gcc_dwarf_w25_mips,
+ gcc_dwarf_w26_mips,
+ gcc_dwarf_w27_mips,
+ gcc_dwarf_w28_mips,
+ gcc_dwarf_w29_mips,
+ gcc_dwarf_w30_mips,
+ gcc_dwarf_w31_mips,
+ gcc_dwarf_mcsr_mips,
+ gcc_dwarf_mir_mips,
+ gcc_dwarf_config5_mips,
+ gcc_dwarf_ic_mips,
+ gcc_dwarf_dummy_mips
+};
+
+enum
+{
+ gcc_dwarf_zero_mips64 = 0,
+ gcc_dwarf_r1_mips64,
+ gcc_dwarf_r2_mips64,
+ gcc_dwarf_r3_mips64,
+ gcc_dwarf_r4_mips64,
+ gcc_dwarf_r5_mips64,
+ gcc_dwarf_r6_mips64,
+ gcc_dwarf_r7_mips64,
+ gcc_dwarf_r8_mips64,
+ gcc_dwarf_r9_mips64,
+ gcc_dwarf_r10_mips64,
+ gcc_dwarf_r11_mips64,
+ gcc_dwarf_r12_mips64,
+ gcc_dwarf_r13_mips64,
+ gcc_dwarf_r14_mips64,
+ gcc_dwarf_r15_mips64,
+ gcc_dwarf_r16_mips64,
+ gcc_dwarf_r17_mips64,
+ gcc_dwarf_r18_mips64,
+ gcc_dwarf_r19_mips64,
+ gcc_dwarf_r20_mips64,
+ gcc_dwarf_r21_mips64,
+ gcc_dwarf_r22_mips64,
+ gcc_dwarf_r23_mips64,
+ gcc_dwarf_r24_mips64,
+ gcc_dwarf_r25_mips64,
+ gcc_dwarf_r26_mips64,
+ gcc_dwarf_r27_mips64,
+ gcc_dwarf_gp_mips64,
+ gcc_dwarf_sp_mips64,
+ gcc_dwarf_r30_mips64,
+ gcc_dwarf_ra_mips64,
+ gcc_dwarf_sr_mips64,
+ gcc_dwarf_lo_mips64,
+ gcc_dwarf_hi_mips64,
+ gcc_dwarf_bad_mips64,
+ gcc_dwarf_cause_mips64,
+ gcc_dwarf_pc_mips64,
+ gcc_dwarf_f0_mips64,
+ gcc_dwarf_f1_mips64,
+ gcc_dwarf_f2_mips64,
+ gcc_dwarf_f3_mips64,
+ gcc_dwarf_f4_mips64,
+ gcc_dwarf_f5_mips64,
+ gcc_dwarf_f6_mips64,
+ gcc_dwarf_f7_mips64,
+ gcc_dwarf_f8_mips64,
+ gcc_dwarf_f9_mips64,
+ gcc_dwarf_f10_mips64,
+ gcc_dwarf_f11_mips64,
+ gcc_dwarf_f12_mips64,
+ gcc_dwarf_f13_mips64,
+ gcc_dwarf_f14_mips64,
+ gcc_dwarf_f15_mips64,
+ gcc_dwarf_f16_mips64,
+ gcc_dwarf_f17_mips64,
+ gcc_dwarf_f18_mips64,
+ gcc_dwarf_f19_mips64,
+ gcc_dwarf_f20_mips64,
+ gcc_dwarf_f21_mips64,
+ gcc_dwarf_f22_mips64,
+ gcc_dwarf_f23_mips64,
+ gcc_dwarf_f24_mips64,
+ gcc_dwarf_f25_mips64,
+ gcc_dwarf_f26_mips64,
+ gcc_dwarf_f27_mips64,
+ gcc_dwarf_f28_mips64,
+ gcc_dwarf_f29_mips64,
+ gcc_dwarf_f30_mips64,
+ gcc_dwarf_f31_mips64,
+ gcc_dwarf_fcsr_mips64,
+ gcc_dwarf_fir_mips64,
+ gcc_dwarf_ic_mips64,
+ gcc_dwarf_dummy_mips64,
+ gcc_dwarf_w0_mips64,
+ gcc_dwarf_w1_mips64,
+ gcc_dwarf_w2_mips64,
+ gcc_dwarf_w3_mips64,
+ gcc_dwarf_w4_mips64,
+ gcc_dwarf_w5_mips64,
+ gcc_dwarf_w6_mips64,
+ gcc_dwarf_w7_mips64,
+ gcc_dwarf_w8_mips64,
+ gcc_dwarf_w9_mips64,
+ gcc_dwarf_w10_mips64,
+ gcc_dwarf_w11_mips64,
+ gcc_dwarf_w12_mips64,
+ gcc_dwarf_w13_mips64,
+ gcc_dwarf_w14_mips64,
+ gcc_dwarf_w15_mips64,
+ gcc_dwarf_w16_mips64,
+ gcc_dwarf_w17_mips64,
+ gcc_dwarf_w18_mips64,
+ gcc_dwarf_w19_mips64,
+ gcc_dwarf_w20_mips64,
+ gcc_dwarf_w21_mips64,
+ gcc_dwarf_w22_mips64,
+ gcc_dwarf_w23_mips64,
+ gcc_dwarf_w24_mips64,
+ gcc_dwarf_w25_mips64,
+ gcc_dwarf_w26_mips64,
+ gcc_dwarf_w27_mips64,
+ gcc_dwarf_w28_mips64,
+ gcc_dwarf_w29_mips64,
+ gcc_dwarf_w30_mips64,
+ gcc_dwarf_w31_mips64,
+ gcc_dwarf_mcsr_mips64,
+ gcc_dwarf_mir_mips64,
+ gcc_dwarf_config5_mips64,
+};
+
+// GDB Register numbers (eRegisterKindGDB)
+enum
+{
+ gdb_zero_mips = 0,
+ gdb_r1_mips,
+ gdb_r2_mips,
+ gdb_r3_mips,
+ gdb_r4_mips,
+ gdb_r5_mips,
+ gdb_r6_mips,
+ gdb_r7_mips,
+ gdb_r8_mips,
+ gdb_r9_mips,
+ gdb_r10_mips,
+ gdb_r11_mips,
+ gdb_r12_mips,
+ gdb_r13_mips,
+ gdb_r14_mips,
+ gdb_r15_mips,
+ gdb_r16_mips,
+ gdb_r17_mips,
+ gdb_r18_mips,
+ gdb_r19_mips,
+ gdb_r20_mips,
+ gdb_r21_mips,
+ gdb_r22_mips,
+ gdb_r23_mips,
+ gdb_r24_mips,
+ gdb_r25_mips,
+ gdb_r26_mips,
+ gdb_r27_mips,
+ gdb_gp_mips,
+ gdb_sp_mips,
+ gdb_r30_mips,
+ gdb_ra_mips,
+ gdb_sr_mips,
+ gdb_lo_mips,
+ gdb_hi_mips,
+ gdb_bad_mips,
+ gdb_cause_mips,
+ gdb_pc_mips,
+ gdb_f0_mips,
+ gdb_f1_mips,
+ gdb_f2_mips,
+ gdb_f3_mips,
+ gdb_f4_mips,
+ gdb_f5_mips,
+ gdb_f6_mips,
+ gdb_f7_mips,
+ gdb_f8_mips,
+ gdb_f9_mips,
+ gdb_f10_mips,
+ gdb_f11_mips,
+ gdb_f12_mips,
+ gdb_f13_mips,
+ gdb_f14_mips,
+ gdb_f15_mips,
+ gdb_f16_mips,
+ gdb_f17_mips,
+ gdb_f18_mips,
+ gdb_f19_mips,
+ gdb_f20_mips,
+ gdb_f21_mips,
+ gdb_f22_mips,
+ gdb_f23_mips,
+ gdb_f24_mips,
+ gdb_f25_mips,
+ gdb_f26_mips,
+ gdb_f27_mips,
+ gdb_f28_mips,
+ gdb_f29_mips,
+ gdb_f30_mips,
+ gdb_f31_mips,
+ gdb_fcsr_mips,
+ gdb_fir_mips,
+ gdb_w0_mips,
+ gdb_w1_mips,
+ gdb_w2_mips,
+ gdb_w3_mips,
+ gdb_w4_mips,
+ gdb_w5_mips,
+ gdb_w6_mips,
+ gdb_w7_mips,
+ gdb_w8_mips,
+ gdb_w9_mips,
+ gdb_w10_mips,
+ gdb_w11_mips,
+ gdb_w12_mips,
+ gdb_w13_mips,
+ gdb_w14_mips,
+ gdb_w15_mips,
+ gdb_w16_mips,
+ gdb_w17_mips,
+ gdb_w18_mips,
+ gdb_w19_mips,
+ gdb_w20_mips,
+ gdb_w21_mips,
+ gdb_w22_mips,
+ gdb_w23_mips,
+ gdb_w24_mips,
+ gdb_w25_mips,
+ gdb_w26_mips,
+ gdb_w27_mips,
+ gdb_w28_mips,
+ gdb_w29_mips,
+ gdb_w30_mips,
+ gdb_w31_mips,
+ gdb_mcsr_mips,
+ gdb_mir_mips,
+ gdb_config5_mips,
+ gdb_ic_mips,
+ gdb_dummy_mips
+};
+
+enum
+{
+ gdb_zero_mips64 = 0,
+ gdb_r1_mips64,
+ gdb_r2_mips64,
+ gdb_r3_mips64,
+ gdb_r4_mips64,
+ gdb_r5_mips64,
+ gdb_r6_mips64,
+ gdb_r7_mips64,
+ gdb_r8_mips64,
+ gdb_r9_mips64,
+ gdb_r10_mips64,
+ gdb_r11_mips64,
+ gdb_r12_mips64,
+ gdb_r13_mips64,
+ gdb_r14_mips64,
+ gdb_r15_mips64,
+ gdb_r16_mips64,
+ gdb_r17_mips64,
+ gdb_r18_mips64,
+ gdb_r19_mips64,
+ gdb_r20_mips64,
+ gdb_r21_mips64,
+ gdb_r22_mips64,
+ gdb_r23_mips64,
+ gdb_r24_mips64,
+ gdb_r25_mips64,
+ gdb_r26_mips64,
+ gdb_r27_mips64,
+ gdb_gp_mips64,
+ gdb_sp_mips64,
+ gdb_r30_mips64,
+ gdb_ra_mips64,
+ gdb_sr_mips64,
+ gdb_lo_mips64,
+ gdb_hi_mips64,
+ gdb_bad_mips64,
+ gdb_cause_mips64,
+ gdb_pc_mips64,
+ gdb_f0_mips64,
+ gdb_f1_mips64,
+ gdb_f2_mips64,
+ gdb_f3_mips64,
+ gdb_f4_mips64,
+ gdb_f5_mips64,
+ gdb_f6_mips64,
+ gdb_f7_mips64,
+ gdb_f8_mips64,
+ gdb_f9_mips64,
+ gdb_f10_mips64,
+ gdb_f11_mips64,
+ gdb_f12_mips64,
+ gdb_f13_mips64,
+ gdb_f14_mips64,
+ gdb_f15_mips64,
+ gdb_f16_mips64,
+ gdb_f17_mips64,
+ gdb_f18_mips64,
+ gdb_f19_mips64,
+ gdb_f20_mips64,
+ gdb_f21_mips64,
+ gdb_f22_mips64,
+ gdb_f23_mips64,
+ gdb_f24_mips64,
+ gdb_f25_mips64,
+ gdb_f26_mips64,
+ gdb_f27_mips64,
+ gdb_f28_mips64,
+ gdb_f29_mips64,
+ gdb_f30_mips64,
+ gdb_f31_mips64,
+ gdb_fcsr_mips64,
+ gdb_fir_mips64,
+ gdb_ic_mips64,
+ gdb_dummy_mips64,
+ gdb_w0_mips64,
+ gdb_w1_mips64,
+ gdb_w2_mips64,
+ gdb_w3_mips64,
+ gdb_w4_mips64,
+ gdb_w5_mips64,
+ gdb_w6_mips64,
+ gdb_w7_mips64,
+ gdb_w8_mips64,
+ gdb_w9_mips64,
+ gdb_w10_mips64,
+ gdb_w11_mips64,
+ gdb_w12_mips64,
+ gdb_w13_mips64,
+ gdb_w14_mips64,
+ gdb_w15_mips64,
+ gdb_w16_mips64,
+ gdb_w17_mips64,
+ gdb_w18_mips64,
+ gdb_w19_mips64,
+ gdb_w20_mips64,
+ gdb_w21_mips64,
+ gdb_w22_mips64,
+ gdb_w23_mips64,
+ gdb_w24_mips64,
+ gdb_w25_mips64,
+ gdb_w26_mips64,
+ gdb_w27_mips64,
+ gdb_w28_mips64,
+ gdb_w29_mips64,
+ gdb_w30_mips64,
+ gdb_w31_mips64,
+ gdb_mcsr_mips64,
+ gdb_mir_mips64,
+ gdb_config5_mips64,
+};
+
+struct IOVEC_mips
+{
+ void *iov_base;
+ size_t iov_len;
+};
+
+// GP registers
+struct GPR_linux_mips
+{
+ uint64_t zero;
+ uint64_t r1;
+ uint64_t r2;
+ uint64_t r3;
+ uint64_t r4;
+ uint64_t r5;
+ uint64_t r6;
+ uint64_t r7;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t r16;
+ uint64_t r17;
+ uint64_t r18;
+ uint64_t r19;
+ uint64_t r20;
+ uint64_t r21;
+ uint64_t r22;
+ uint64_t r23;
+ uint64_t r24;
+ uint64_t r25;
+ uint64_t r26;
+ uint64_t r27;
+ uint64_t gp;
+ uint64_t sp;
+ uint64_t r30;
+ uint64_t ra;
+ uint64_t mullo;
+ uint64_t mulhi;
+ uint64_t pc;
+ uint64_t badvaddr;
+ uint64_t sr;
+ uint64_t cause;
+ uint64_t config5;
+};
+
+struct FPR_linux_mips
+{
+ uint64_t f0;
+ uint64_t f1;
+ uint64_t f2;
+ uint64_t f3;
+ uint64_t f4;
+ uint64_t f5;
+ uint64_t f6;
+ uint64_t f7;
+ uint64_t f8;
+ uint64_t f9;
+ uint64_t f10;
+ uint64_t f11;
+ uint64_t f12;
+ uint64_t f13;
+ uint64_t f14;
+ uint64_t f15;
+ uint64_t f16;
+ uint64_t f17;
+ uint64_t f18;
+ uint64_t f19;
+ uint64_t f20;
+ uint64_t f21;
+ uint64_t f22;
+ uint64_t f23;
+ uint64_t f24;
+ uint64_t f25;
+ uint64_t f26;
+ uint64_t f27;
+ uint64_t f28;
+ uint64_t f29;
+ uint64_t f30;
+ uint64_t f31;
+ uint32_t fcsr;
+ uint32_t fir;
+ uint32_t config5;
+};
+
+struct MSAReg
+{
+ uint8_t byte[16];
+};
+
+struct MSA_linux_mips
+{
+ MSAReg w0;
+ MSAReg w1;
+ MSAReg w2;
+ MSAReg w3;
+ MSAReg w4;
+ MSAReg w5;
+ MSAReg w6;
+ MSAReg w7;
+ MSAReg w8;
+ MSAReg w9;
+ MSAReg w10;
+ MSAReg w11;
+ MSAReg w12;
+ MSAReg w13;
+ MSAReg w14;
+ MSAReg w15;
+ MSAReg w16;
+ MSAReg w17;
+ MSAReg w18;
+ MSAReg w19;
+ MSAReg w20;
+ MSAReg w21;
+ MSAReg w22;
+ MSAReg w23;
+ MSAReg w24;
+ MSAReg w25;
+ MSAReg w26;
+ MSAReg w27;
+ MSAReg w28;
+ MSAReg w29;
+ MSAReg w30;
+ MSAReg w31;
+ uint32_t fcsr; /* FPU control status register */
+ uint32_t fir; /* FPU implementaion revision */
+ uint32_t mcsr; /* MSA control status register */
+ uint32_t mir; /* MSA implementation revision */
+ uint32_t config5; /* Config5 register */
+};
+
+struct UserArea
+{
+ GPR_linux_mips gpr; // General purpose registers.
+ FPR_linux_mips fpr; // Floating point registers.
+ MSA_linux_mips msa; // MSA registers.
+};
+
+#endif // liblldb_RegisterContext_mips64_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h
new file mode 100644
index 0000000..7438b88
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_powerpc.h
@@ -0,0 +1,232 @@
+//===-- RegisterContext_powerpc.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContext_powerpc_H_
+#define liblldb_RegisterContext_powerpc_H_
+
+// GCC and DWARF Register numbers (eRegisterKindGCC & eRegisterKindDWARF)
+enum
+{
+ gcc_dwarf_r0_powerpc = 0,
+ gcc_dwarf_r1_powerpc,
+ gcc_dwarf_r2_powerpc,
+ gcc_dwarf_r3_powerpc,
+ gcc_dwarf_r4_powerpc,
+ gcc_dwarf_r5_powerpc,
+ gcc_dwarf_r6_powerpc,
+ gcc_dwarf_r7_powerpc,
+ gcc_dwarf_r8_powerpc,
+ gcc_dwarf_r9_powerpc,
+ gcc_dwarf_r10_powerpc,
+ gcc_dwarf_r11_powerpc,
+ gcc_dwarf_r12_powerpc,
+ gcc_dwarf_r13_powerpc,
+ gcc_dwarf_r14_powerpc,
+ gcc_dwarf_r15_powerpc,
+ gcc_dwarf_r16_powerpc,
+ gcc_dwarf_r17_powerpc,
+ gcc_dwarf_r18_powerpc,
+ gcc_dwarf_r19_powerpc,
+ gcc_dwarf_r20_powerpc,
+ gcc_dwarf_r21_powerpc,
+ gcc_dwarf_r22_powerpc,
+ gcc_dwarf_r23_powerpc,
+ gcc_dwarf_r24_powerpc,
+ gcc_dwarf_r25_powerpc,
+ gcc_dwarf_r26_powerpc,
+ gcc_dwarf_r27_powerpc,
+ gcc_dwarf_r28_powerpc,
+ gcc_dwarf_r29_powerpc,
+ gcc_dwarf_r30_powerpc,
+ gcc_dwarf_r31_powerpc,
+ gcc_dwarf_f0_powerpc,
+ gcc_dwarf_f1_powerpc,
+ gcc_dwarf_f2_powerpc,
+ gcc_dwarf_f3_powerpc,
+ gcc_dwarf_f4_powerpc,
+ gcc_dwarf_f5_powerpc,
+ gcc_dwarf_f6_powerpc,
+ gcc_dwarf_f7_powerpc,
+ gcc_dwarf_f8_powerpc,
+ gcc_dwarf_f9_powerpc,
+ gcc_dwarf_f10_powerpc,
+ gcc_dwarf_f11_powerpc,
+ gcc_dwarf_f12_powerpc,
+ gcc_dwarf_f13_powerpc,
+ gcc_dwarf_f14_powerpc,
+ gcc_dwarf_f15_powerpc,
+ gcc_dwarf_f16_powerpc,
+ gcc_dwarf_f17_powerpc,
+ gcc_dwarf_f18_powerpc,
+ gcc_dwarf_f19_powerpc,
+ gcc_dwarf_f20_powerpc,
+ gcc_dwarf_f21_powerpc,
+ gcc_dwarf_f22_powerpc,
+ gcc_dwarf_f23_powerpc,
+ gcc_dwarf_f24_powerpc,
+ gcc_dwarf_f25_powerpc,
+ gcc_dwarf_f26_powerpc,
+ gcc_dwarf_f27_powerpc,
+ gcc_dwarf_f28_powerpc,
+ gcc_dwarf_f29_powerpc,
+ gcc_dwarf_f30_powerpc,
+ gcc_dwarf_f31_powerpc,
+ gcc_dwarf_cr_powerpc,
+ gcc_dwarf_fpscr_powerpc,
+ gcc_dwarf_msr_powerpc,
+ gcc_dwarf_vscr_powerpc,
+ gcc_dwarf_xer_powerpc = 101,
+ gcc_dwarf_lr_powerpc = 108,
+ gcc_dwarf_ctr_powerpc,
+ gcc_dwarf_pc_powerpc,
+ gcc_dwarf_vrsave_powerpc = 356,
+ gcc_dwarf_v0_powerpc = 1124,
+ gcc_dwarf_v1_powerpc,
+ gcc_dwarf_v2_powerpc,
+ gcc_dwarf_v3_powerpc,
+ gcc_dwarf_v4_powerpc,
+ gcc_dwarf_v5_powerpc,
+ gcc_dwarf_v6_powerpc,
+ gcc_dwarf_v7_powerpc,
+ gcc_dwarf_v8_powerpc,
+ gcc_dwarf_v9_powerpc,
+ gcc_dwarf_v10_powerpc,
+ gcc_dwarf_v11_powerpc,
+ gcc_dwarf_v12_powerpc,
+ gcc_dwarf_v13_powerpc,
+ gcc_dwarf_v14_powerpc,
+ gcc_dwarf_v15_powerpc,
+ gcc_dwarf_v16_powerpc,
+ gcc_dwarf_v17_powerpc,
+ gcc_dwarf_v18_powerpc,
+ gcc_dwarf_v19_powerpc,
+ gcc_dwarf_v20_powerpc,
+ gcc_dwarf_v21_powerpc,
+ gcc_dwarf_v22_powerpc,
+ gcc_dwarf_v23_powerpc,
+ gcc_dwarf_v24_powerpc,
+ gcc_dwarf_v25_powerpc,
+ gcc_dwarf_v26_powerpc,
+ gcc_dwarf_v27_powerpc,
+ gcc_dwarf_v28_powerpc,
+ gcc_dwarf_v29_powerpc,
+ gcc_dwarf_v30_powerpc,
+ gcc_dwarf_v31_powerpc,
+};
+
+// GDB Register numbers (eRegisterKindGDB)
+enum
+{
+ gdb_r0_powerpc = 0,
+ gdb_r1_powerpc,
+ gdb_r2_powerpc,
+ gdb_r3_powerpc,
+ gdb_r4_powerpc,
+ gdb_r5_powerpc,
+ gdb_r6_powerpc,
+ gdb_r7_powerpc,
+ gdb_r8_powerpc,
+ gdb_r9_powerpc,
+ gdb_r10_powerpc,
+ gdb_r11_powerpc,
+ gdb_r12_powerpc,
+ gdb_r13_powerpc,
+ gdb_r14_powerpc,
+ gdb_r15_powerpc,
+ gdb_r16_powerpc,
+ gdb_r17_powerpc,
+ gdb_r18_powerpc,
+ gdb_r19_powerpc,
+ gdb_r20_powerpc,
+ gdb_r21_powerpc,
+ gdb_r22_powerpc,
+ gdb_r23_powerpc,
+ gdb_r24_powerpc,
+ gdb_r25_powerpc,
+ gdb_r26_powerpc,
+ gdb_r27_powerpc,
+ gdb_r28_powerpc,
+ gdb_r29_powerpc,
+ gdb_r30_powerpc,
+ gdb_r31_powerpc,
+ gdb_f0_powerpc,
+ gdb_f1_powerpc,
+ gdb_f2_powerpc,
+ gdb_f3_powerpc,
+ gdb_f4_powerpc,
+ gdb_f5_powerpc,
+ gdb_f6_powerpc,
+ gdb_f7_powerpc,
+ gdb_f8_powerpc,
+ gdb_f9_powerpc,
+ gdb_f10_powerpc,
+ gdb_f11_powerpc,
+ gdb_f12_powerpc,
+ gdb_f13_powerpc,
+ gdb_f14_powerpc,
+ gdb_f15_powerpc,
+ gdb_f16_powerpc,
+ gdb_f17_powerpc,
+ gdb_f18_powerpc,
+ gdb_f19_powerpc,
+ gdb_f20_powerpc,
+ gdb_f21_powerpc,
+ gdb_f22_powerpc,
+ gdb_f23_powerpc,
+ gdb_f24_powerpc,
+ gdb_f25_powerpc,
+ gdb_f26_powerpc,
+ gdb_f27_powerpc,
+ gdb_f28_powerpc,
+ gdb_f29_powerpc,
+ gdb_f30_powerpc,
+ gdb_f31_powerpc,
+ gdb_pc_powerpc,
+ gdb_cr_powerpc = 66,
+ gdb_lr_powerpc,
+ gdb_ctr_powerpc,
+ gdb_xer_powerpc,
+ gdb_fpscr_powerpc,
+ gdb_v0_powerpc = 106,
+ gdb_v1_powerpc,
+ gdb_v2_powerpc,
+ gdb_v3_powerpc,
+ gdb_v4_powerpc,
+ gdb_v5_powerpc,
+ gdb_v6_powerpc,
+ gdb_v7_powerpc,
+ gdb_v8_powerpc,
+ gdb_v9_powerpc,
+ gdb_v10_powerpc,
+ gdb_v11_powerpc,
+ gdb_v12_powerpc,
+ gdb_v13_powerpc,
+ gdb_v14_powerpc,
+ gdb_v15_powerpc,
+ gdb_v16_powerpc,
+ gdb_v17_powerpc,
+ gdb_v18_powerpc,
+ gdb_v19_powerpc,
+ gdb_v20_powerpc,
+ gdb_v21_powerpc,
+ gdb_v22_powerpc,
+ gdb_v23_powerpc,
+ gdb_v24_powerpc,
+ gdb_v25_powerpc,
+ gdb_v26_powerpc,
+ gdb_v27_powerpc,
+ gdb_v28_powerpc,
+ gdb_v29_powerpc,
+ gdb_v30_powerpc,
+ gdb_v31_powerpc,
+ gdb_vscr_powerpc,
+ gdb_vrsave_powerpc,
+};
+
+#endif // liblldb_RegisterContext_powerpc_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h
new file mode 100644
index 0000000..6b3f6fb
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h
@@ -0,0 +1,487 @@
+//===-- RegisterContext_x86.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContext_x86_H_
+#define liblldb_RegisterContext_x86_H_
+
+//---------------------------------------------------------------------------
+// i386 gcc, dwarf, gdb enums
+//---------------------------------------------------------------------------
+
+// Register numbers seen in eh_frame (eRegisterKindGCC)
+//
+// From Jason Molenda: "gcc registers" is the register numbering used in the eh_frame
+// CFI. The only registers that are described in eh_frame CFI are those that are
+// preserved across function calls aka callee-saved aka non-volatile. And none
+// of the floating point registers on x86 are preserved across function calls.
+//
+// The only reason there is a "gcc register" and a "dwarf register" is because of a
+// mistake years and years ago with i386 where they got esp and ebp
+// backwards when they emitted the eh_frame instructions. Once there were
+// binaries In The Wild using the reversed numbering, we had to stick with it
+// forever.
+enum
+{
+ // 2nd parameter in DwarfRegNum() is regnum for exception handling on x86-32.
+ // See http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register
+ gcc_eax_i386 = 0,
+ gcc_ecx_i386,
+ gcc_edx_i386,
+ gcc_ebx_i386,
+
+ // on Darwin esp & ebp are reversed in the eh_frame section for i386 (versus dwarf's reg numbering).
+ // To be specific:
+ // i386+darwin eh_frame: 4 is ebp, 5 is esp
+ // i386+everyone else eh_frame: 4 is esp, 5 is ebp
+ // i386 dwarf: 4 is esp, 5 is ebp
+ // lldb will get the darwin-specific eh_frame reg numberings from debugserver instead of here so we
+ // only encode the 4 == esp, 5 == ebp numbers in this generic header.
+ gcc_esp_i386,
+ gcc_ebp_i386,
+ gcc_esi_i386,
+ gcc_edi_i386,
+ gcc_eip_i386,
+ gcc_eflags_i386,
+ gcc_st0_i386 = 12,
+ gcc_st1_i386,
+ gcc_st2_i386,
+ gcc_st3_i386,
+ gcc_st4_i386,
+ gcc_st5_i386,
+ gcc_st6_i386,
+ gcc_st7_i386,
+ gcc_xmm0_i386 = 21,
+ gcc_xmm1_i386,
+ gcc_xmm2_i386,
+ gcc_xmm3_i386,
+ gcc_xmm4_i386,
+ gcc_xmm5_i386,
+ gcc_xmm6_i386,
+ gcc_xmm7_i386,
+ gcc_mm0_i386 = 29,
+ gcc_mm1_i386,
+ gcc_mm2_i386,
+ gcc_mm3_i386,
+ gcc_mm4_i386,
+ gcc_mm5_i386,
+ gcc_mm6_i386,
+ gcc_mm7_i386,
+};
+
+// DWARF register numbers (eRegisterKindDWARF)
+// Intel's x86 or IA-32
+enum
+{
+ // General Purpose Registers.
+ dwarf_eax_i386 = 0,
+ dwarf_ecx_i386,
+ dwarf_edx_i386,
+ dwarf_ebx_i386,
+ dwarf_esp_i386,
+ dwarf_ebp_i386,
+ dwarf_esi_i386,
+ dwarf_edi_i386,
+ dwarf_eip_i386,
+ dwarf_eflags_i386,
+ // Floating Point Registers
+ dwarf_st0_i386 = 11,
+ dwarf_st1_i386,
+ dwarf_st2_i386,
+ dwarf_st3_i386,
+ dwarf_st4_i386,
+ dwarf_st5_i386,
+ dwarf_st6_i386,
+ dwarf_st7_i386,
+ // SSE Registers
+ dwarf_xmm0_i386 = 21,
+ dwarf_xmm1_i386,
+ dwarf_xmm2_i386,
+ dwarf_xmm3_i386,
+ dwarf_xmm4_i386,
+ dwarf_xmm5_i386,
+ dwarf_xmm6_i386,
+ dwarf_xmm7_i386,
+ // MMX Registers
+ dwarf_mm0_i386 = 29,
+ dwarf_mm1_i386,
+ dwarf_mm2_i386,
+ dwarf_mm3_i386,
+ dwarf_mm4_i386,
+ dwarf_mm5_i386,
+ dwarf_mm6_i386,
+ dwarf_mm7_i386,
+ dwarf_fctrl_i386 = 37, // x87 control word
+ dwarf_fstat_i386 = 38, // x87 status word
+ dwarf_mxcsr_i386 = 39,
+ dwarf_es_i386 = 40,
+ dwarf_cs_i386 = 41,
+ dwarf_ss_i386 = 42,
+ dwarf_ds_i386 = 43,
+ dwarf_fs_i386 = 44,
+ dwarf_gs_i386 = 45
+
+ // I believe the ymm registers use the dwarf_xmm%_i386 register numbers and
+ // then differentiate based on size of the register.
+};
+
+// Register numbers GDB uses (eRegisterKindGDB)
+//
+// From Jason Molenda: The "gdb numbers" are what you would see in the stabs debug format.
+enum
+{
+ gdb_eax_i386,
+ gdb_ecx_i386,
+ gdb_edx_i386,
+ gdb_ebx_i386,
+ gdb_esp_i386,
+ gdb_ebp_i386,
+ gdb_esi_i386,
+ gdb_edi_i386,
+ gdb_eip_i386,
+ gdb_eflags_i386,
+ gdb_cs_i386,
+ gdb_ss_i386,
+ gdb_ds_i386,
+ gdb_es_i386,
+ gdb_fs_i386,
+ gdb_gs_i386,
+ gdb_st0_i386 = 16,
+ gdb_st1_i386,
+ gdb_st2_i386,
+ gdb_st3_i386,
+ gdb_st4_i386,
+ gdb_st5_i386,
+ gdb_st6_i386,
+ gdb_st7_i386,
+ gdb_fctrl_i386, // FPU Control Word
+ gdb_fstat_i386, // FPU Status Word
+ gdb_ftag_i386, // FPU Tag Word
+ gdb_fiseg_i386, // FPU IP Selector
+ gdb_fioff_i386, // FPU IP Offset
+ gdb_foseg_i386, // FPU Operand Pointer Selector
+ gdb_fooff_i386, // FPU Operand Pointer Offset
+ gdb_fop_i386, // Last Instruction Opcode
+ gdb_xmm0_i386 = 32,
+ gdb_xmm1_i386,
+ gdb_xmm2_i386,
+ gdb_xmm3_i386,
+ gdb_xmm4_i386,
+ gdb_xmm5_i386,
+ gdb_xmm6_i386,
+ gdb_xmm7_i386,
+ gdb_mxcsr_i386 = 40,
+ gdb_ymm0h_i386,
+ gdb_ymm1h_i386,
+ gdb_ymm2h_i386,
+ gdb_ymm3h_i386,
+ gdb_ymm4h_i386,
+ gdb_ymm5h_i386,
+ gdb_ymm6h_i386,
+ gdb_ymm7h_i386,
+ gdb_mm0_i386,
+ gdb_mm1_i386,
+ gdb_mm2_i386,
+ gdb_mm3_i386,
+ gdb_mm4_i386,
+ gdb_mm5_i386,
+ gdb_mm6_i386,
+ gdb_mm7_i386,
+};
+
+//---------------------------------------------------------------------------
+// AMD x86_64, AMD64, Intel EM64T, or Intel 64 gcc, dwarf, gdb enums
+//---------------------------------------------------------------------------
+
+// GCC and DWARF Register numbers (eRegisterKindGCC & eRegisterKindDWARF)
+// This is the spec I used (as opposed to x86-64-abi-0.99.pdf):
+// http://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf
+enum
+{
+ // GP Registers
+ gcc_dwarf_rax_x86_64 = 0,
+ gcc_dwarf_rdx_x86_64,
+ gcc_dwarf_rcx_x86_64,
+ gcc_dwarf_rbx_x86_64,
+ gcc_dwarf_rsi_x86_64,
+ gcc_dwarf_rdi_x86_64,
+ gcc_dwarf_rbp_x86_64,
+ gcc_dwarf_rsp_x86_64,
+ // Extended GP Registers
+ gcc_dwarf_r8_x86_64 = 8,
+ gcc_dwarf_r9_x86_64,
+ gcc_dwarf_r10_x86_64,
+ gcc_dwarf_r11_x86_64,
+ gcc_dwarf_r12_x86_64,
+ gcc_dwarf_r13_x86_64,
+ gcc_dwarf_r14_x86_64,
+ gcc_dwarf_r15_x86_64,
+ // Return Address (RA) mapped to RIP
+ gcc_dwarf_rip_x86_64 = 16,
+ // SSE Vector Registers
+ gcc_dwarf_xmm0_x86_64 = 17,
+ gcc_dwarf_xmm1_x86_64,
+ gcc_dwarf_xmm2_x86_64,
+ gcc_dwarf_xmm3_x86_64,
+ gcc_dwarf_xmm4_x86_64,
+ gcc_dwarf_xmm5_x86_64,
+ gcc_dwarf_xmm6_x86_64,
+ gcc_dwarf_xmm7_x86_64,
+ gcc_dwarf_xmm8_x86_64,
+ gcc_dwarf_xmm9_x86_64,
+ gcc_dwarf_xmm10_x86_64,
+ gcc_dwarf_xmm11_x86_64,
+ gcc_dwarf_xmm12_x86_64,
+ gcc_dwarf_xmm13_x86_64,
+ gcc_dwarf_xmm14_x86_64,
+ gcc_dwarf_xmm15_x86_64,
+ // Floating Point Registers
+ gcc_dwarf_st0_x86_64 = 33,
+ gcc_dwarf_st1_x86_64,
+ gcc_dwarf_st2_x86_64,
+ gcc_dwarf_st3_x86_64,
+ gcc_dwarf_st4_x86_64,
+ gcc_dwarf_st5_x86_64,
+ gcc_dwarf_st6_x86_64,
+ gcc_dwarf_st7_x86_64,
+ // MMX Registers
+ gcc_dwarf_mm0_x86_64 = 41,
+ gcc_dwarf_mm1_x86_64,
+ gcc_dwarf_mm2_x86_64,
+ gcc_dwarf_mm3_x86_64,
+ gcc_dwarf_mm4_x86_64,
+ gcc_dwarf_mm5_x86_64,
+ gcc_dwarf_mm6_x86_64,
+ gcc_dwarf_mm7_x86_64,
+ // Control and Status Flags Register
+ gcc_dwarf_rflags_x86_64 = 49,
+ // selector registers
+ gcc_dwarf_es_x86_64 = 50,
+ gcc_dwarf_cs_x86_64,
+ gcc_dwarf_ss_x86_64,
+ gcc_dwarf_ds_x86_64,
+ gcc_dwarf_fs_x86_64,
+ gcc_dwarf_gs_x86_64,
+ // Floating point control registers
+ gcc_dwarf_mxcsr_x86_64 = 64, // Media Control and Status
+ gcc_dwarf_fctrl_x86_64, // x87 control word
+ gcc_dwarf_fstat_x86_64, // x87 status word
+ // Upper Vector Registers
+ gcc_dwarf_ymm0h_x86_64 = 67,
+ gcc_dwarf_ymm1h_x86_64,
+ gcc_dwarf_ymm2h_x86_64,
+ gcc_dwarf_ymm3h_x86_64,
+ gcc_dwarf_ymm4h_x86_64,
+ gcc_dwarf_ymm5h_x86_64,
+ gcc_dwarf_ymm6h_x86_64,
+ gcc_dwarf_ymm7h_x86_64,
+ gcc_dwarf_ymm8h_x86_64,
+ gcc_dwarf_ymm9h_x86_64,
+ gcc_dwarf_ymm10h_x86_64,
+ gcc_dwarf_ymm11h_x86_64,
+ gcc_dwarf_ymm12h_x86_64,
+ gcc_dwarf_ymm13h_x86_64,
+ gcc_dwarf_ymm14h_x86_64,
+ gcc_dwarf_ymm15h_x86_64,
+ // AVX2 Vector Mask Registers
+ // gcc_dwarf_k0_x86_64 = 118,
+ // gcc_dwarf_k1_x86_64,
+ // gcc_dwarf_k2_x86_64,
+ // gcc_dwarf_k3_x86_64,
+ // gcc_dwarf_k4_x86_64,
+ // gcc_dwarf_k5_x86_64,
+ // gcc_dwarf_k6_x86_64,
+ // gcc_dwarf_k7_x86_64,
+};
+
+// GDB Register numbers (eRegisterKindGDB)
+enum
+{
+ // GP Registers
+ gdb_rax_x86_64 = 0,
+ gdb_rbx_x86_64,
+ gdb_rcx_x86_64,
+ gdb_rdx_x86_64,
+ gdb_rsi_x86_64,
+ gdb_rdi_x86_64,
+ gdb_rbp_x86_64,
+ gdb_rsp_x86_64,
+ // Extended GP Registers
+ gdb_r8_x86_64,
+ gdb_r9_x86_64,
+ gdb_r10_x86_64,
+ gdb_r11_x86_64,
+ gdb_r12_x86_64,
+ gdb_r13_x86_64,
+ gdb_r14_x86_64,
+ gdb_r15_x86_64,
+ // Return Address (RA) mapped to RIP
+ gdb_rip_x86_64,
+ // Control and Status Flags Register
+ gdb_rflags_x86_64,
+ gdb_cs_x86_64,
+ gdb_ss_x86_64,
+ gdb_ds_x86_64,
+ gdb_es_x86_64,
+ gdb_fs_x86_64,
+ gdb_gs_x86_64,
+ // Floating Point Registers
+ gdb_st0_x86_64,
+ gdb_st1_x86_64,
+ gdb_st2_x86_64,
+ gdb_st3_x86_64,
+ gdb_st4_x86_64,
+ gdb_st5_x86_64,
+ gdb_st6_x86_64,
+ gdb_st7_x86_64,
+ gdb_fctrl_x86_64,
+ gdb_fstat_x86_64,
+ gdb_ftag_x86_64,
+ gdb_fiseg_x86_64,
+ gdb_fioff_x86_64,
+ gdb_foseg_x86_64,
+ gdb_fooff_x86_64,
+ gdb_fop_x86_64,
+ // SSE Vector Registers
+ gdb_xmm0_x86_64 = 40,
+ gdb_xmm1_x86_64,
+ gdb_xmm2_x86_64,
+ gdb_xmm3_x86_64,
+ gdb_xmm4_x86_64,
+ gdb_xmm5_x86_64,
+ gdb_xmm6_x86_64,
+ gdb_xmm7_x86_64,
+ gdb_xmm8_x86_64,
+ gdb_xmm9_x86_64,
+ gdb_xmm10_x86_64,
+ gdb_xmm11_x86_64,
+ gdb_xmm12_x86_64,
+ gdb_xmm13_x86_64,
+ gdb_xmm14_x86_64,
+ gdb_xmm15_x86_64,
+ // Floating point control registers
+ gdb_mxcsr_x86_64 = 56,
+ gdb_ymm0h_x86_64,
+ gdb_ymm1h_x86_64,
+ gdb_ymm2h_x86_64,
+ gdb_ymm3h_x86_64,
+ gdb_ymm4h_x86_64,
+ gdb_ymm5h_x86_64,
+ gdb_ymm6h_x86_64,
+ gdb_ymm7h_x86_64,
+ gdb_ymm8h_x86_64,
+ gdb_ymm9h_x86_64,
+ gdb_ymm10h_x86_64,
+ gdb_ymm11h_x86_64,
+ gdb_ymm12h_x86_64,
+ gdb_ymm13h_x86_64,
+ gdb_ymm14h_x86_64,
+ gdb_ymm15h_x86_64
+};
+
+//---------------------------------------------------------------------------
+// Generic floating-point registers
+//---------------------------------------------------------------------------
+
+struct MMSReg
+{
+ uint8_t bytes[10];
+ uint8_t pad[6];
+};
+
+struct XMMReg
+{
+ uint8_t bytes[16]; // 128-bits for each XMM register
+};
+
+// i387_fxsave_struct
+struct FXSAVE
+{
+ uint16_t fctrl; // FPU Control Word (fcw)
+ uint16_t fstat; // FPU Status Word (fsw)
+ uint16_t ftag; // FPU Tag Word (ftw)
+ uint16_t fop; // Last Instruction Opcode (fop)
+ union
+ {
+ struct
+ {
+ uint64_t fip; // Instruction Pointer
+ uint64_t fdp; // Data Pointer
+ } x86_64;
+ struct
+ {
+ uint32_t fioff; // FPU IP Offset (fip)
+ uint32_t fiseg; // FPU IP Selector (fcs)
+ uint32_t fooff; // FPU Operand Pointer Offset (foo)
+ uint32_t foseg; // FPU Operand Pointer Selector (fos)
+ } i386_;// Added _ in the end to avoid error with gcc defining i386 in some cases
+ } ptr;
+ uint32_t mxcsr; // MXCSR Register State
+ uint32_t mxcsrmask; // MXCSR Mask
+ MMSReg stmm[8]; // 8*16 bytes for each FP-reg = 128 bytes
+ XMMReg xmm[16]; // 16*16 bytes for each XMM-reg = 256 bytes
+ uint32_t padding[24];
+};
+
+//---------------------------------------------------------------------------
+// Extended floating-point registers
+//---------------------------------------------------------------------------
+
+struct YMMHReg
+{
+ uint8_t bytes[16]; // 16 * 8 bits for the high bytes of each YMM register
+};
+
+struct YMMReg
+{
+ uint8_t bytes[32]; // 16 * 16 bits for each YMM register
+};
+
+struct YMM
+{
+ YMMReg ymm[16]; // assembled from ymmh and xmm registers
+};
+
+struct XSAVE_HDR
+{
+ uint64_t xstate_bv; // OS enabled xstate mask to determine the extended states supported by the processor
+ uint64_t reserved1[2];
+ uint64_t reserved2[5];
+} __attribute__((packed));
+
+// x86 extensions to FXSAVE (i.e. for AVX processors)
+struct XSAVE
+{
+ FXSAVE i387; // floating point registers typical in i387_fxsave_struct
+ XSAVE_HDR header; // The xsave_hdr_struct can be used to determine if the following extensions are usable
+ YMMHReg ymmh[16]; // High 16 bytes of each of 16 YMM registers (the low bytes are in FXSAVE.xmm for compatibility with SSE)
+ // Slot any extensions to the register file here
+} __attribute__((packed, aligned (64)));
+
+// Floating-point registers
+struct FPR
+{
+ // Thread state for the floating-point unit of the processor read by ptrace.
+ union XSTATE
+ {
+ FXSAVE fxsave; // Generic floating-point registers.
+ XSAVE xsave; // x86 extended processor state.
+ } xstate;
+};
+
+//---------------------------------------------------------------------------
+// ptrace PTRACE_GETREGSET, PTRACE_SETREGSET structure
+//---------------------------------------------------------------------------
+
+struct IOVEC
+{
+ void *iov_base; // pointer to XSAVE
+ size_t iov_len; // sizeof(XSAVE)
+};
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h
new file mode 100644
index 0000000..94cb5cc
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h
@@ -0,0 +1,60 @@
+//===-- RegisterInfoInterface.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterInfoInterface_h
+#define lldb_RegisterInfoInterface_h
+
+#include "lldb/Core/ArchSpec.h"
+
+namespace lldb_private
+{
+
+ ///------------------------------------------------------------------------------
+ /// @class RegisterInfoInterface
+ ///
+ /// @brief RegisterInfo interface to patch RegisterInfo structure for archs.
+ ///------------------------------------------------------------------------------
+ class RegisterInfoInterface
+ {
+ public:
+ RegisterInfoInterface(const lldb_private::ArchSpec& target_arch) : m_target_arch(target_arch) {}
+ virtual ~RegisterInfoInterface () {}
+
+ virtual size_t
+ GetGPRSize () const = 0;
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo () const = 0;
+
+ // Returns the number of registers including the user registers and the
+ // lldb internal registers also
+ virtual uint32_t
+ GetRegisterCount () const = 0;
+
+ // Returns the number of the user registers (excluding the registers
+ // kept for lldb internal use only). Subclasses should override it if
+ // they belongs to an architecture with lldb internal registers.
+ virtual uint32_t
+ GetUserRegisterCount () const
+ {
+ return GetRegisterCount();
+ }
+
+ const lldb_private::ArchSpec&
+ GetTargetArchitecture() const
+ { return m_target_arch; }
+
+ public:
+ // FIXME make private.
+ lldb_private::ArchSpec m_target_arch;
+ };
+
+}
+
+#endif
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h
new file mode 100644
index 0000000..3d144d6
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h
@@ -0,0 +1,303 @@
+//===-- RegisterInfos_arm.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifdef DECLARE_REGISTER_INFOS_ARM_STRUCT
+
+#include <stddef.h>
+
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "Utility/ARM_GCC_Registers.h"
+#include "Utility/ARM_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#ifndef GPR_OFFSET
+#error GPR_OFFSET must be defined before including this header file
+#endif
+
+
+#ifndef FPU_OFFSET
+#error FPU_OFFSET must be defined before including this header file
+#endif
+
+#ifndef EXC_OFFSET
+#error EXC_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef DBG_OFFSET
+#error DBG_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef DEFINE_DBG
+#error DEFINE_DBG must be defined before including this header file
+#endif
+
+enum
+{
+ gpr_r0 = 0,
+ 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_r13, gpr_sp = gpr_r13,
+ gpr_r14, gpr_lr = gpr_r14,
+ gpr_r15, gpr_pc = gpr_r15,
+ gpr_cpsr,
+
+ 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,
+
+ exc_exception,
+ exc_fsr,
+ exc_far,
+
+ dbg_bvr0,
+ dbg_bvr1,
+ dbg_bvr2,
+ dbg_bvr3,
+ dbg_bvr4,
+ dbg_bvr5,
+ dbg_bvr6,
+ dbg_bvr7,
+ dbg_bvr8,
+ dbg_bvr9,
+ dbg_bvr10,
+ dbg_bvr11,
+ dbg_bvr12,
+ dbg_bvr13,
+ dbg_bvr14,
+ dbg_bvr15,
+
+ dbg_bcr0,
+ dbg_bcr1,
+ dbg_bcr2,
+ dbg_bcr3,
+ dbg_bcr4,
+ dbg_bcr5,
+ dbg_bcr6,
+ dbg_bcr7,
+ dbg_bcr8,
+ dbg_bcr9,
+ dbg_bcr10,
+ dbg_bcr11,
+ dbg_bcr12,
+ dbg_bcr13,
+ dbg_bcr14,
+ dbg_bcr15,
+
+ dbg_wvr0,
+ dbg_wvr1,
+ dbg_wvr2,
+ dbg_wvr3,
+ dbg_wvr4,
+ dbg_wvr5,
+ dbg_wvr6,
+ dbg_wvr7,
+ dbg_wvr8,
+ dbg_wvr9,
+ dbg_wvr10,
+ dbg_wvr11,
+ dbg_wvr12,
+ dbg_wvr13,
+ dbg_wvr14,
+ dbg_wvr15,
+
+ dbg_wcr0,
+ dbg_wcr1,
+ dbg_wcr2,
+ dbg_wcr3,
+ dbg_wcr4,
+ dbg_wcr5,
+ dbg_wcr6,
+ dbg_wcr7,
+ dbg_wcr8,
+ dbg_wcr9,
+ dbg_wcr10,
+ dbg_wcr11,
+ dbg_wcr12,
+ dbg_wcr13,
+ dbg_wcr14,
+ dbg_wcr15,
+
+ k_num_registers
+};
+
+static RegisterInfo g_register_infos_arm[] = {
+// General purpose registers
+// NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== ===============
+{ "r0", NULL, 4, GPR_OFFSET(0), eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1, gdb_arm_r0, gpr_r0 }, NULL, NULL},
+{ "r1", NULL, 4, GPR_OFFSET(1), eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2, gdb_arm_r1, gpr_r1 }, NULL, NULL},
+{ "r2", NULL, 4, GPR_OFFSET(2), eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3, gdb_arm_r2, gpr_r2 }, NULL, NULL},
+{ "r3", NULL, 4, GPR_OFFSET(3), eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4, gdb_arm_r3, gpr_r3 }, NULL, NULL},
+{ "r4", NULL, 4, GPR_OFFSET(4), eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, gdb_arm_r4, gpr_r4 }, NULL, NULL},
+{ "r5", NULL, 4, GPR_OFFSET(5), eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, gdb_arm_r5, gpr_r5 }, NULL, NULL},
+{ "r6", NULL, 4, GPR_OFFSET(6), eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, gdb_arm_r6, gpr_r6 }, NULL, NULL},
+{ "r7", NULL, 4, GPR_OFFSET(7), eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_INVALID_REGNUM, gdb_arm_r7, gpr_r7 }, NULL, NULL},
+{ "r8", NULL, 4, GPR_OFFSET(8), eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, gdb_arm_r8, gpr_r8 }, NULL, NULL},
+{ "r9", NULL, 4, GPR_OFFSET(9), eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, gdb_arm_r9, gpr_r9 }, NULL, NULL},
+{ "r10", NULL, 4, GPR_OFFSET(10), eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, gdb_arm_r10, gpr_r10 }, NULL, NULL},
+{ "r11", NULL, 4, GPR_OFFSET(11), eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_REGNUM_GENERIC_FP, gdb_arm_r11, gpr_r11 }, NULL, NULL},
+{ "r12", NULL, 4, GPR_OFFSET(12), eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, gdb_arm_r12, gpr_r12 }, NULL, NULL},
+{ "sp", "r13", 4, GPR_OFFSET(13), eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, gdb_arm_sp, gpr_sp }, NULL, NULL},
+{ "lr", "r14", 4, GPR_OFFSET(14), eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_arm_lr, gpr_lr }, NULL, NULL},
+{ "pc", "r15", 4, GPR_OFFSET(15), eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, gdb_arm_pc, gpr_pc }, NULL, NULL},
+{ "cpsr", "psr", 4, GPR_OFFSET(16), eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, gdb_arm_cpsr, gpr_cpsr }, NULL, NULL},
+
+{ "s0", NULL, 4, FPU_OFFSET(0), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, gdb_arm_s0, fpu_s0 }, NULL, NULL},
+{ "s1", NULL, 4, FPU_OFFSET(1), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, gdb_arm_s1, fpu_s1 }, NULL, NULL},
+{ "s2", NULL, 4, FPU_OFFSET(2), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, gdb_arm_s2, fpu_s2 }, NULL, NULL},
+{ "s3", NULL, 4, FPU_OFFSET(3), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, gdb_arm_s3, fpu_s3 }, NULL, NULL},
+{ "s4", NULL, 4, FPU_OFFSET(4), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, gdb_arm_s4, fpu_s4 }, NULL, NULL},
+{ "s5", NULL, 4, FPU_OFFSET(5), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, gdb_arm_s5, fpu_s5 }, NULL, NULL},
+{ "s6", NULL, 4, FPU_OFFSET(6), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, gdb_arm_s6, fpu_s6 }, NULL, NULL},
+{ "s7", NULL, 4, FPU_OFFSET(7), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, gdb_arm_s7, fpu_s7 }, NULL, NULL},
+{ "s8", NULL, 4, FPU_OFFSET(8), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, gdb_arm_s8, fpu_s8 }, NULL, NULL},
+{ "s9", NULL, 4, FPU_OFFSET(9), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, gdb_arm_s9, fpu_s9 }, NULL, NULL},
+{ "s10", NULL, 4, FPU_OFFSET(10), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, gdb_arm_s10, fpu_s10 }, NULL, NULL},
+{ "s11", NULL, 4, FPU_OFFSET(11), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, gdb_arm_s11, fpu_s11 }, NULL, NULL},
+{ "s12", NULL, 4, FPU_OFFSET(12), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, gdb_arm_s12, fpu_s12 }, NULL, NULL},
+{ "s13", NULL, 4, FPU_OFFSET(13), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, gdb_arm_s13, fpu_s13 }, NULL, NULL},
+{ "s14", NULL, 4, FPU_OFFSET(14), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, gdb_arm_s14, fpu_s14 }, NULL, NULL},
+{ "s15", NULL, 4, FPU_OFFSET(15), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, gdb_arm_s15, fpu_s15 }, NULL, NULL},
+{ "s16", NULL, 4, FPU_OFFSET(16), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, gdb_arm_s16, fpu_s16 }, NULL, NULL},
+{ "s17", NULL, 4, FPU_OFFSET(17), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, gdb_arm_s17, fpu_s17 }, NULL, NULL},
+{ "s18", NULL, 4, FPU_OFFSET(18), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, gdb_arm_s18, fpu_s18 }, NULL, NULL},
+{ "s19", NULL, 4, FPU_OFFSET(19), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, gdb_arm_s19, fpu_s19 }, NULL, NULL},
+{ "s20", NULL, 4, FPU_OFFSET(20), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, gdb_arm_s20, fpu_s20 }, NULL, NULL},
+{ "s21", NULL, 4, FPU_OFFSET(21), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, gdb_arm_s21, fpu_s21 }, NULL, NULL},
+{ "s22", NULL, 4, FPU_OFFSET(22), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, gdb_arm_s22, fpu_s22 }, NULL, NULL},
+{ "s23", NULL, 4, FPU_OFFSET(23), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, gdb_arm_s23, fpu_s23 }, NULL, NULL},
+{ "s24", NULL, 4, FPU_OFFSET(24), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, gdb_arm_s24, fpu_s24 }, NULL, NULL},
+{ "s25", NULL, 4, FPU_OFFSET(25), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, gdb_arm_s25, fpu_s25 }, NULL, NULL},
+{ "s26", NULL, 4, FPU_OFFSET(26), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, gdb_arm_s26, fpu_s26 }, NULL, NULL},
+{ "s27", NULL, 4, FPU_OFFSET(27), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, gdb_arm_s27, fpu_s27 }, NULL, NULL},
+{ "s28", NULL, 4, FPU_OFFSET(28), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, gdb_arm_s28, fpu_s28 }, NULL, NULL},
+{ "s29", NULL, 4, FPU_OFFSET(29), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, gdb_arm_s29, fpu_s29 }, NULL, NULL},
+{ "s30", NULL, 4, FPU_OFFSET(30), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, gdb_arm_s30, fpu_s30 }, NULL, NULL},
+{ "s31", NULL, 4, FPU_OFFSET(31), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, gdb_arm_s31, fpu_s31 }, NULL, NULL},
+{ "fpscr", NULL, 4, FPU_OFFSET(32), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, gdb_arm_fpscr, fpu_fpscr }, NULL, NULL},
+
+{ "exception",NULL, 4, EXC_OFFSET(0), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL},
+{ "fsr", NULL, 4, EXC_OFFSET(1), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_fsr }, NULL, NULL},
+{ "far", NULL, 4, EXC_OFFSET(2), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, NULL, NULL},
+
+{ DEFINE_DBG (bvr, 0) },
+{ DEFINE_DBG (bvr, 1) },
+{ DEFINE_DBG (bvr, 2) },
+{ DEFINE_DBG (bvr, 3) },
+{ DEFINE_DBG (bvr, 4) },
+{ DEFINE_DBG (bvr, 5) },
+{ DEFINE_DBG (bvr, 6) },
+{ DEFINE_DBG (bvr, 7) },
+{ DEFINE_DBG (bvr, 8) },
+{ DEFINE_DBG (bvr, 9) },
+{ DEFINE_DBG (bvr, 10) },
+{ DEFINE_DBG (bvr, 11) },
+{ DEFINE_DBG (bvr, 12) },
+{ DEFINE_DBG (bvr, 13) },
+{ DEFINE_DBG (bvr, 14) },
+{ DEFINE_DBG (bvr, 15) },
+
+{ DEFINE_DBG (bcr, 0) },
+{ DEFINE_DBG (bcr, 1) },
+{ DEFINE_DBG (bcr, 2) },
+{ DEFINE_DBG (bcr, 3) },
+{ DEFINE_DBG (bcr, 4) },
+{ DEFINE_DBG (bcr, 5) },
+{ DEFINE_DBG (bcr, 6) },
+{ DEFINE_DBG (bcr, 7) },
+{ DEFINE_DBG (bcr, 8) },
+{ DEFINE_DBG (bcr, 9) },
+{ DEFINE_DBG (bcr, 10) },
+{ DEFINE_DBG (bcr, 11) },
+{ DEFINE_DBG (bcr, 12) },
+{ DEFINE_DBG (bcr, 13) },
+{ DEFINE_DBG (bcr, 14) },
+{ DEFINE_DBG (bcr, 15) },
+
+{ DEFINE_DBG (wvr, 0) },
+{ DEFINE_DBG (wvr, 1) },
+{ DEFINE_DBG (wvr, 2) },
+{ DEFINE_DBG (wvr, 3) },
+{ DEFINE_DBG (wvr, 4) },
+{ DEFINE_DBG (wvr, 5) },
+{ DEFINE_DBG (wvr, 6) },
+{ DEFINE_DBG (wvr, 7) },
+{ DEFINE_DBG (wvr, 8) },
+{ DEFINE_DBG (wvr, 9) },
+{ DEFINE_DBG (wvr, 10) },
+{ DEFINE_DBG (wvr, 11) },
+{ DEFINE_DBG (wvr, 12) },
+{ DEFINE_DBG (wvr, 13) },
+{ DEFINE_DBG (wvr, 14) },
+{ DEFINE_DBG (wvr, 15) },
+
+{ DEFINE_DBG (wcr, 0) },
+{ DEFINE_DBG (wcr, 1) },
+{ DEFINE_DBG (wcr, 2) },
+{ DEFINE_DBG (wcr, 3) },
+{ DEFINE_DBG (wcr, 4) },
+{ DEFINE_DBG (wcr, 5) },
+{ DEFINE_DBG (wcr, 6) },
+{ DEFINE_DBG (wcr, 7) },
+{ DEFINE_DBG (wcr, 8) },
+{ DEFINE_DBG (wcr, 9) },
+{ DEFINE_DBG (wcr, 10) },
+{ DEFINE_DBG (wcr, 11) },
+{ DEFINE_DBG (wcr, 12) },
+{ DEFINE_DBG (wcr, 13) },
+{ DEFINE_DBG (wcr, 14) },
+{ DEFINE_DBG (wcr, 15) }
+};
+
+#endif // DECLARE_REGISTER_INFOS_ARM_STRUCT
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h
new file mode 100644
index 0000000..0255a3b
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h
@@ -0,0 +1,347 @@
+//===-- RegisterInfos_arm64.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifdef DECLARE_REGISTER_INFOS_ARM64_STRUCT
+
+#include <stddef.h>
+
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "Utility/ARM64_GCC_Registers.h"
+#include "Utility/ARM64_DWARF_Registers.h"
+
+#ifndef GPR_OFFSET
+#error GPR_OFFSET must be defined before including this header file
+#endif
+
+#ifndef GPR_OFFSET_NAME
+#error GPR_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef FPU_OFFSET
+#error FPU_OFFSET must be defined before including this header file
+#endif
+
+#ifndef FPU_OFFSET_NAME
+#error FPU_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef EXC_OFFSET_NAME
+#error EXC_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef DBG_OFFSET_NAME
+#error DBG_OFFSET_NAME must be defined before including this header file
+#endif
+
+#ifndef DEFINE_DBG
+#error DEFINE_DBG must be defined before including this header file
+#endif
+
+enum
+{
+ gpr_x0 = 0,
+ gpr_x1,
+ gpr_x2,
+ gpr_x3,
+ gpr_x4,
+ gpr_x5,
+ gpr_x6,
+ gpr_x7,
+ gpr_x8,
+ gpr_x9,
+ gpr_x10,
+ gpr_x11,
+ gpr_x12,
+ gpr_x13,
+ gpr_x14,
+ gpr_x15,
+ gpr_x16,
+ gpr_x17,
+ gpr_x18,
+ gpr_x19,
+ gpr_x20,
+ gpr_x21,
+ gpr_x22,
+ gpr_x23,
+ gpr_x24,
+ gpr_x25,
+ gpr_x26,
+ gpr_x27,
+ gpr_x28,
+ gpr_x29 = 29, gpr_fp = gpr_x29,
+ gpr_x30 = 30, gpr_lr = gpr_x30, gpr_ra = gpr_x30,
+ gpr_x31 = 31, gpr_sp = gpr_x31,
+ gpr_pc = 32,
+ gpr_cpsr,
+
+ fpu_v0,
+ fpu_v1,
+ fpu_v2,
+ fpu_v3,
+ fpu_v4,
+ fpu_v5,
+ fpu_v6,
+ fpu_v7,
+ fpu_v8,
+ fpu_v9,
+ fpu_v10,
+ fpu_v11,
+ fpu_v12,
+ fpu_v13,
+ fpu_v14,
+ fpu_v15,
+ fpu_v16,
+ fpu_v17,
+ fpu_v18,
+ fpu_v19,
+ fpu_v20,
+ fpu_v21,
+ fpu_v22,
+ fpu_v23,
+ fpu_v24,
+ fpu_v25,
+ fpu_v26,
+ fpu_v27,
+ fpu_v28,
+ fpu_v29,
+ fpu_v30,
+ fpu_v31,
+
+ fpu_fpsr,
+ fpu_fpcr,
+
+ exc_far,
+ exc_esr,
+ exc_exception,
+
+ dbg_bvr0,
+ dbg_bvr1,
+ dbg_bvr2,
+ dbg_bvr3,
+ dbg_bvr4,
+ dbg_bvr5,
+ dbg_bvr6,
+ dbg_bvr7,
+ dbg_bvr8,
+ dbg_bvr9,
+ dbg_bvr10,
+ dbg_bvr11,
+ dbg_bvr12,
+ dbg_bvr13,
+ dbg_bvr14,
+ dbg_bvr15,
+
+ dbg_bcr0,
+ dbg_bcr1,
+ dbg_bcr2,
+ dbg_bcr3,
+ dbg_bcr4,
+ dbg_bcr5,
+ dbg_bcr6,
+ dbg_bcr7,
+ dbg_bcr8,
+ dbg_bcr9,
+ dbg_bcr10,
+ dbg_bcr11,
+ dbg_bcr12,
+ dbg_bcr13,
+ dbg_bcr14,
+ dbg_bcr15,
+
+ dbg_wvr0,
+ dbg_wvr1,
+ dbg_wvr2,
+ dbg_wvr3,
+ dbg_wvr4,
+ dbg_wvr5,
+ dbg_wvr6,
+ dbg_wvr7,
+ dbg_wvr8,
+ dbg_wvr9,
+ dbg_wvr10,
+ dbg_wvr11,
+ dbg_wvr12,
+ dbg_wvr13,
+ dbg_wvr14,
+ dbg_wvr15,
+
+ dbg_wcr0,
+ dbg_wcr1,
+ dbg_wcr2,
+ dbg_wcr3,
+ dbg_wcr4,
+ dbg_wcr5,
+ dbg_wcr6,
+ dbg_wcr7,
+ dbg_wcr8,
+ dbg_wcr9,
+ dbg_wcr10,
+ dbg_wcr11,
+ dbg_wcr12,
+ dbg_wcr13,
+ dbg_wcr14,
+ dbg_wcr15,
+
+ k_num_registers
+};
+
+static lldb_private::RegisterInfo g_register_infos_arm64[] = {
+// General purpose registers
+// NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== ===============
+{ "x0", NULL, 8, GPR_OFFSET(0), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x0, arm64_dwarf::x0, LLDB_REGNUM_GENERIC_ARG1, arm64_gcc::x0, gpr_x0 }, NULL, NULL},
+{ "x1", NULL, 8, GPR_OFFSET(1), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x1, arm64_dwarf::x1, LLDB_REGNUM_GENERIC_ARG2, arm64_gcc::x1, gpr_x1 }, NULL, NULL},
+{ "x2", NULL, 8, GPR_OFFSET(2), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x2, arm64_dwarf::x2, LLDB_REGNUM_GENERIC_ARG3, arm64_gcc::x2, gpr_x2 }, NULL, NULL},
+{ "x3", NULL, 8, GPR_OFFSET(3), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x3, arm64_dwarf::x3, LLDB_REGNUM_GENERIC_ARG4, arm64_gcc::x3, gpr_x3 }, NULL, NULL},
+{ "x4", NULL, 8, GPR_OFFSET(4), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x4, arm64_dwarf::x4, LLDB_REGNUM_GENERIC_ARG5, arm64_gcc::x4, gpr_x4 }, NULL, NULL},
+{ "x5", NULL, 8, GPR_OFFSET(5), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x5, arm64_dwarf::x5, LLDB_REGNUM_GENERIC_ARG6, arm64_gcc::x5, gpr_x5 }, NULL, NULL},
+{ "x6", NULL, 8, GPR_OFFSET(6), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x6, arm64_dwarf::x6, LLDB_REGNUM_GENERIC_ARG7, arm64_gcc::x6, gpr_x6 }, NULL, NULL},
+{ "x7", NULL, 8, GPR_OFFSET(7), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x7, arm64_dwarf::x7, LLDB_REGNUM_GENERIC_ARG8, arm64_gcc::x7, gpr_x7 }, NULL, NULL},
+{ "x8", NULL, 8, GPR_OFFSET(8), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x8, arm64_dwarf::x8, LLDB_INVALID_REGNUM, arm64_gcc::x8, gpr_x8 }, NULL, NULL},
+{ "x9", NULL, 8, GPR_OFFSET(9), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x9, arm64_dwarf::x9, LLDB_INVALID_REGNUM, arm64_gcc::x9, gpr_x9 }, NULL, NULL},
+{ "x10", NULL, 8, GPR_OFFSET(10), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x10, arm64_dwarf::x10, LLDB_INVALID_REGNUM, arm64_gcc::x10, gpr_x10 }, NULL, NULL},
+{ "x11", NULL, 8, GPR_OFFSET(11), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x11, arm64_dwarf::x11, LLDB_INVALID_REGNUM, arm64_gcc::x11, gpr_x11 }, NULL, NULL},
+{ "x12", NULL, 8, GPR_OFFSET(12), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x12, arm64_dwarf::x12, LLDB_INVALID_REGNUM, arm64_gcc::x12, gpr_x12 }, NULL, NULL},
+{ "x13", NULL, 8, GPR_OFFSET(13), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x13, arm64_dwarf::x13, LLDB_INVALID_REGNUM, arm64_gcc::x13, gpr_x13 }, NULL, NULL},
+{ "x14", NULL, 8, GPR_OFFSET(14), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x14, arm64_dwarf::x14, LLDB_INVALID_REGNUM, arm64_gcc::x14, gpr_x14 }, NULL, NULL},
+{ "x15", NULL, 8, GPR_OFFSET(15), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x15, arm64_dwarf::x15, LLDB_INVALID_REGNUM, arm64_gcc::x15, gpr_x15 }, NULL, NULL},
+{ "x16", NULL, 8, GPR_OFFSET(16), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x16, arm64_dwarf::x16, LLDB_INVALID_REGNUM, arm64_gcc::x16, gpr_x16 }, NULL, NULL},
+{ "x17", NULL, 8, GPR_OFFSET(17), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x17, arm64_dwarf::x17, LLDB_INVALID_REGNUM, arm64_gcc::x17, gpr_x17 }, NULL, NULL},
+{ "x18", NULL, 8, GPR_OFFSET(18), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x18, arm64_dwarf::x18, LLDB_INVALID_REGNUM, arm64_gcc::x18, gpr_x18 }, NULL, NULL},
+{ "x19", NULL, 8, GPR_OFFSET(19), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x19, arm64_dwarf::x19, LLDB_INVALID_REGNUM, arm64_gcc::x19, gpr_x19 }, NULL, NULL},
+{ "x20", NULL, 8, GPR_OFFSET(20), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x20, arm64_dwarf::x20, LLDB_INVALID_REGNUM, arm64_gcc::x20, gpr_x20 }, NULL, NULL},
+{ "x21", NULL, 8, GPR_OFFSET(21), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x21, arm64_dwarf::x21, LLDB_INVALID_REGNUM, arm64_gcc::x21, gpr_x21 }, NULL, NULL},
+{ "x22", NULL, 8, GPR_OFFSET(22), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x22, arm64_dwarf::x22, LLDB_INVALID_REGNUM, arm64_gcc::x22, gpr_x22 }, NULL, NULL},
+{ "x23", NULL, 8, GPR_OFFSET(23), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x23, arm64_dwarf::x23, LLDB_INVALID_REGNUM, arm64_gcc::x23, gpr_x23 }, NULL, NULL},
+{ "x24", NULL, 8, GPR_OFFSET(24), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x24, arm64_dwarf::x24, LLDB_INVALID_REGNUM, arm64_gcc::x24, gpr_x24 }, NULL, NULL},
+{ "x25", NULL, 8, GPR_OFFSET(25), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x25, arm64_dwarf::x25, LLDB_INVALID_REGNUM, arm64_gcc::x25, gpr_x25 }, NULL, NULL},
+{ "x26", NULL, 8, GPR_OFFSET(26), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x26, arm64_dwarf::x26, LLDB_INVALID_REGNUM, arm64_gcc::x26, gpr_x26 }, NULL, NULL},
+{ "x27", NULL, 8, GPR_OFFSET(27), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x27, arm64_dwarf::x27, LLDB_INVALID_REGNUM, arm64_gcc::x27, gpr_x27 }, NULL, NULL},
+{ "x28", NULL, 8, GPR_OFFSET(28), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::x28, arm64_dwarf::x28, LLDB_INVALID_REGNUM, arm64_gcc::x28, gpr_x28 }, NULL, NULL},
+
+{ "fp", "x29", 8, GPR_OFFSET(29), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::fp, arm64_dwarf::fp, LLDB_REGNUM_GENERIC_FP, arm64_gcc::fp, gpr_fp }, NULL, NULL},
+{ "lr", "x30", 8, GPR_OFFSET(30), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::lr, arm64_dwarf::lr, LLDB_REGNUM_GENERIC_RA, arm64_gcc::lr, gpr_lr }, NULL, NULL},
+{ "sp", "x31", 8, GPR_OFFSET(31), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::sp, arm64_dwarf::sp, LLDB_REGNUM_GENERIC_SP, arm64_gcc::sp, gpr_sp }, NULL, NULL},
+{ "pc", NULL, 8, GPR_OFFSET(32), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::pc, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, arm64_gcc::pc, gpr_pc }, NULL, NULL},
+
+{ "cpsr", NULL, 4, GPR_OFFSET_NAME(cpsr), lldb::eEncodingUint, lldb::eFormatHex, { arm64_gcc::cpsr, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, arm64_gcc::cpsr, gpr_cpsr }, NULL, NULL},
+
+{ "v0", NULL, 16, FPU_OFFSET(0), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v0, LLDB_INVALID_REGNUM, arm64_gcc::v0, fpu_v0 }, NULL, NULL},
+{ "v1", NULL, 16, FPU_OFFSET(1), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v1, LLDB_INVALID_REGNUM, arm64_gcc::v1, fpu_v1 }, NULL, NULL},
+{ "v2", NULL, 16, FPU_OFFSET(2), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v2, LLDB_INVALID_REGNUM, arm64_gcc::v2, fpu_v2 }, NULL, NULL},
+{ "v3", NULL, 16, FPU_OFFSET(3), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v3, LLDB_INVALID_REGNUM, arm64_gcc::v3, fpu_v3 }, NULL, NULL},
+{ "v4", NULL, 16, FPU_OFFSET(4), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v4, LLDB_INVALID_REGNUM, arm64_gcc::v4, fpu_v4 }, NULL, NULL},
+{ "v5", NULL, 16, FPU_OFFSET(5), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v5, LLDB_INVALID_REGNUM, arm64_gcc::v5, fpu_v5 }, NULL, NULL},
+{ "v6", NULL, 16, FPU_OFFSET(6), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v6, LLDB_INVALID_REGNUM, arm64_gcc::v6, fpu_v6 }, NULL, NULL},
+{ "v7", NULL, 16, FPU_OFFSET(7), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v7, LLDB_INVALID_REGNUM, arm64_gcc::v7, fpu_v7 }, NULL, NULL},
+{ "v8", NULL, 16, FPU_OFFSET(8), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v8, LLDB_INVALID_REGNUM, arm64_gcc::v8, fpu_v8 }, NULL, NULL},
+{ "v9", NULL, 16, FPU_OFFSET(9), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v9, LLDB_INVALID_REGNUM, arm64_gcc::v9, fpu_v9 }, NULL, NULL},
+{ "v10", NULL, 16, FPU_OFFSET(10), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v10, LLDB_INVALID_REGNUM, arm64_gcc::v10, fpu_v10 }, NULL, NULL},
+{ "v11", NULL, 16, FPU_OFFSET(11), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v11, LLDB_INVALID_REGNUM, arm64_gcc::v11, fpu_v11 }, NULL, NULL},
+{ "v12", NULL, 16, FPU_OFFSET(12), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v12, LLDB_INVALID_REGNUM, arm64_gcc::v12, fpu_v12 }, NULL, NULL},
+{ "v13", NULL, 16, FPU_OFFSET(13), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v13, LLDB_INVALID_REGNUM, arm64_gcc::v13, fpu_v13 }, NULL, NULL},
+{ "v14", NULL, 16, FPU_OFFSET(14), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v14, LLDB_INVALID_REGNUM, arm64_gcc::v14, fpu_v14 }, NULL, NULL},
+{ "v15", NULL, 16, FPU_OFFSET(15), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v15, LLDB_INVALID_REGNUM, arm64_gcc::v15, fpu_v15 }, NULL, NULL},
+{ "v16", NULL, 16, FPU_OFFSET(16), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v16, LLDB_INVALID_REGNUM, arm64_gcc::v16, fpu_v16 }, NULL, NULL},
+{ "v17", NULL, 16, FPU_OFFSET(17), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v17, LLDB_INVALID_REGNUM, arm64_gcc::v17, fpu_v17 }, NULL, NULL},
+{ "v18", NULL, 16, FPU_OFFSET(18), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v18, LLDB_INVALID_REGNUM, arm64_gcc::v18, fpu_v18 }, NULL, NULL},
+{ "v19", NULL, 16, FPU_OFFSET(19), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v19, LLDB_INVALID_REGNUM, arm64_gcc::v19, fpu_v19 }, NULL, NULL},
+{ "v20", NULL, 16, FPU_OFFSET(20), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v20, LLDB_INVALID_REGNUM, arm64_gcc::v20, fpu_v20 }, NULL, NULL},
+{ "v21", NULL, 16, FPU_OFFSET(21), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v21, LLDB_INVALID_REGNUM, arm64_gcc::v21, fpu_v21 }, NULL, NULL},
+{ "v22", NULL, 16, FPU_OFFSET(22), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v22, LLDB_INVALID_REGNUM, arm64_gcc::v22, fpu_v22 }, NULL, NULL},
+{ "v23", NULL, 16, FPU_OFFSET(23), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v23, LLDB_INVALID_REGNUM, arm64_gcc::v23, fpu_v23 }, NULL, NULL},
+{ "v24", NULL, 16, FPU_OFFSET(24), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v24, LLDB_INVALID_REGNUM, arm64_gcc::v24, fpu_v24 }, NULL, NULL},
+{ "v25", NULL, 16, FPU_OFFSET(25), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v25, LLDB_INVALID_REGNUM, arm64_gcc::v25, fpu_v25 }, NULL, NULL},
+{ "v26", NULL, 16, FPU_OFFSET(26), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v26, LLDB_INVALID_REGNUM, arm64_gcc::v26, fpu_v26 }, NULL, NULL},
+{ "v27", NULL, 16, FPU_OFFSET(27), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v27, LLDB_INVALID_REGNUM, arm64_gcc::v27, fpu_v27 }, NULL, NULL},
+{ "v28", NULL, 16, FPU_OFFSET(28), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v28, LLDB_INVALID_REGNUM, arm64_gcc::v28, fpu_v28 }, NULL, NULL},
+{ "v29", NULL, 16, FPU_OFFSET(29), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v29, LLDB_INVALID_REGNUM, arm64_gcc::v29, fpu_v29 }, NULL, NULL},
+{ "v30", NULL, 16, FPU_OFFSET(30), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v30, LLDB_INVALID_REGNUM, arm64_gcc::v30, fpu_v30 }, NULL, NULL},
+{ "v31", NULL, 16, FPU_OFFSET(31), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v31, LLDB_INVALID_REGNUM, arm64_gcc::v31, fpu_v31 }, NULL, NULL},
+
+{ "fpsr", NULL, 4, FPU_OFFSET_NAME(fpsr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpsr }, NULL, NULL},
+{ "fpcr", NULL, 4, FPU_OFFSET_NAME(fpcr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpcr }, NULL, NULL},
+
+{ "far", NULL, 8, EXC_OFFSET_NAME(far), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, NULL, NULL},
+{ "esr", NULL, 4, EXC_OFFSET_NAME(esr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_esr }, NULL, NULL},
+{ "exception",NULL, 4, EXC_OFFSET_NAME(exception), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL},
+
+{ DEFINE_DBG (bvr, 0) },
+{ DEFINE_DBG (bvr, 1) },
+{ DEFINE_DBG (bvr, 2) },
+{ DEFINE_DBG (bvr, 3) },
+{ DEFINE_DBG (bvr, 4) },
+{ DEFINE_DBG (bvr, 5) },
+{ DEFINE_DBG (bvr, 6) },
+{ DEFINE_DBG (bvr, 7) },
+{ DEFINE_DBG (bvr, 8) },
+{ DEFINE_DBG (bvr, 9) },
+{ DEFINE_DBG (bvr, 10) },
+{ DEFINE_DBG (bvr, 11) },
+{ DEFINE_DBG (bvr, 12) },
+{ DEFINE_DBG (bvr, 13) },
+{ DEFINE_DBG (bvr, 14) },
+{ DEFINE_DBG (bvr, 15) },
+
+{ DEFINE_DBG (bcr, 0) },
+{ DEFINE_DBG (bcr, 1) },
+{ DEFINE_DBG (bcr, 2) },
+{ DEFINE_DBG (bcr, 3) },
+{ DEFINE_DBG (bcr, 4) },
+{ DEFINE_DBG (bcr, 5) },
+{ DEFINE_DBG (bcr, 6) },
+{ DEFINE_DBG (bcr, 7) },
+{ DEFINE_DBG (bcr, 8) },
+{ DEFINE_DBG (bcr, 9) },
+{ DEFINE_DBG (bcr, 10) },
+{ DEFINE_DBG (bcr, 11) },
+{ DEFINE_DBG (bcr, 12) },
+{ DEFINE_DBG (bcr, 13) },
+{ DEFINE_DBG (bcr, 14) },
+{ DEFINE_DBG (bcr, 15) },
+
+{ DEFINE_DBG (wvr, 0) },
+{ DEFINE_DBG (wvr, 1) },
+{ DEFINE_DBG (wvr, 2) },
+{ DEFINE_DBG (wvr, 3) },
+{ DEFINE_DBG (wvr, 4) },
+{ DEFINE_DBG (wvr, 5) },
+{ DEFINE_DBG (wvr, 6) },
+{ DEFINE_DBG (wvr, 7) },
+{ DEFINE_DBG (wvr, 8) },
+{ DEFINE_DBG (wvr, 9) },
+{ DEFINE_DBG (wvr, 10) },
+{ DEFINE_DBG (wvr, 11) },
+{ DEFINE_DBG (wvr, 12) },
+{ DEFINE_DBG (wvr, 13) },
+{ DEFINE_DBG (wvr, 14) },
+{ DEFINE_DBG (wvr, 15) },
+
+{ DEFINE_DBG (wcr, 0) },
+{ DEFINE_DBG (wcr, 1) },
+{ DEFINE_DBG (wcr, 2) },
+{ DEFINE_DBG (wcr, 3) },
+{ DEFINE_DBG (wcr, 4) },
+{ DEFINE_DBG (wcr, 5) },
+{ DEFINE_DBG (wcr, 6) },
+{ DEFINE_DBG (wcr, 7) },
+{ DEFINE_DBG (wcr, 8) },
+{ DEFINE_DBG (wcr, 9) },
+{ DEFINE_DBG (wcr, 10) },
+{ DEFINE_DBG (wcr, 11) },
+{ DEFINE_DBG (wcr, 12) },
+{ DEFINE_DBG (wcr, 13) },
+{ DEFINE_DBG (wcr, 14) },
+{ DEFINE_DBG (wcr, 15) }
+};
+
+#endif // DECLARE_REGISTER_INFOS_ARM64_STRUCT
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h
new file mode 100644
index 0000000..6982536
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h
@@ -0,0 +1,215 @@
+//===-- RegisterInfos_i386.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+#include "llvm/Support/Compiler.h"
+
+#include <stddef.h>
+
+#ifdef DECLARE_REGISTER_INFOS_I386_STRUCT
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(GPR, regname))
+
+// Computes the offset of the given FPR in the extended data area.
+#define FPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(UserArea, i387) + \
+ LLVM_EXTENSION offsetof(FPR_i386, regname))
+
+// Computes the offset of the YMM register assembled from register halves.
+// Based on DNBArchImplI386.cpp from debugserver
+#define YMM_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, i387) + \
+ LLVM_EXTENSION offsetof(FPR, xstate) + \
+ LLVM_EXTENSION offsetof(FXSAVE, xmm[7]) + \
+ sizeof(XMMReg) + (32 * reg_index))
+
+// Number of bytes needed to represent a FPR.
+#if !defined(FPR_SIZE)
+#define FPR_SIZE(reg) sizeof(((FXSAVE*)NULL)->reg)
+#endif
+
+// Number of bytes needed to represent the i'th FP register.
+#define FP_SIZE sizeof(((MMSReg*)NULL)->bytes)
+
+// Number of bytes needed to represent an XMM register.
+#define XMM_SIZE sizeof(XMMReg)
+
+// Number of bytes needed to represent a YMM register.
+#define YMM_SIZE sizeof(YMMReg)
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, lldb_##reg##_i386 }, NULL, NULL }
+
+#define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \
+ { #name, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, lldb_##name##_i386 }, NULL, NULL }
+
+// RegisterKind: GCC, DWARF, Generic, GDB, LLDB
+
+#define DEFINE_FP_ST(reg, i) \
+ { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(stmm[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { gcc_st##i##_i386, dwarf_st##i##_i386, LLDB_INVALID_REGNUM, gdb_st##i##_i386, lldb_st##i##_i386 }, \
+ NULL, NULL }
+
+#define DEFINE_FP_MM(reg, i) \
+ { #reg#i, NULL, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \
+ eEncodingUint, eFormatHex, \
+ { gcc_mm##i##_i386, dwarf_mm##i##_i386, LLDB_INVALID_REGNUM, gdb_mm##i##_i386, lldb_mm##i##_i386 }, \
+ NULL, NULL }
+
+#define DEFINE_XMM(reg, i) \
+ { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { gcc_##reg##i##_i386, dwarf_##reg##i##_i386, LLDB_INVALID_REGNUM, gdb_##reg##i##_i386, lldb_##reg##i##_i386}, \
+ NULL, NULL }
+
+// I believe the YMM registers use dwarf_xmm_%_i386 register numbers and then differentiate based on register size.
+#define DEFINE_YMM(reg, i) \
+ { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(i), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { LLDB_INVALID_REGNUM, dwarf_xmm##i##_i386, LLDB_INVALID_REGNUM, gdb_##reg##i##h_i386, lldb_##reg##i##_i386 }, \
+ NULL, NULL }
+
+#define DEFINE_DR(reg, i) \
+ { #reg#i, NULL, DR_SIZE, DR_OFFSET(i), eEncodingUint, eFormatHex, \
+ { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }
+
+#define DEFINE_GPR_PSEUDO_16(reg16, reg32) \
+ { #reg16, NULL, 2, GPR_OFFSET(reg32), eEncodingUint, \
+ eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg16##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 }
+#define DEFINE_GPR_PSEUDO_8H(reg8, reg32) \
+ { #reg8, NULL, 1, GPR_OFFSET(reg32)+1, eEncodingUint, \
+ eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 }
+#define DEFINE_GPR_PSEUDO_8L(reg8, reg32) \
+ { #reg8, NULL, 1, GPR_OFFSET(reg32), eEncodingUint, \
+ eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 }
+
+static RegisterInfo
+g_register_infos_i386[] =
+{
+ // General purpose registers.
+ DEFINE_GPR(eax, NULL, gcc_eax_i386, dwarf_eax_i386, LLDB_INVALID_REGNUM, gdb_eax_i386),
+ DEFINE_GPR(ebx, NULL, gcc_ebx_i386, dwarf_ebx_i386, LLDB_INVALID_REGNUM, gdb_ebx_i386),
+ DEFINE_GPR(ecx, NULL, gcc_ecx_i386, dwarf_ecx_i386, LLDB_INVALID_REGNUM, gdb_ecx_i386),
+ DEFINE_GPR(edx, NULL, gcc_edx_i386, dwarf_edx_i386, LLDB_INVALID_REGNUM, gdb_edx_i386),
+ DEFINE_GPR(edi, NULL, gcc_edi_i386, dwarf_edi_i386, LLDB_INVALID_REGNUM, gdb_edi_i386),
+ DEFINE_GPR(esi, NULL, gcc_esi_i386, dwarf_esi_i386, LLDB_INVALID_REGNUM, gdb_esi_i386),
+ DEFINE_GPR(ebp, "fp", gcc_ebp_i386, dwarf_ebp_i386, LLDB_REGNUM_GENERIC_FP, gdb_ebp_i386),
+ DEFINE_GPR(esp, "sp", gcc_esp_i386, dwarf_esp_i386, LLDB_REGNUM_GENERIC_SP, gdb_esp_i386),
+ DEFINE_GPR(eip, "pc", gcc_eip_i386, dwarf_eip_i386, LLDB_REGNUM_GENERIC_PC, gdb_eip_i386),
+ DEFINE_GPR(eflags, "flags", gcc_eflags_i386, dwarf_eflags_i386, LLDB_REGNUM_GENERIC_FLAGS, gdb_eflags_i386),
+ DEFINE_GPR(cs, NULL, LLDB_INVALID_REGNUM, dwarf_cs_i386, LLDB_INVALID_REGNUM, gdb_cs_i386),
+ DEFINE_GPR(fs, NULL, LLDB_INVALID_REGNUM, dwarf_fs_i386, LLDB_INVALID_REGNUM, gdb_fs_i386),
+ DEFINE_GPR(gs, NULL, LLDB_INVALID_REGNUM, dwarf_gs_i386, LLDB_INVALID_REGNUM, gdb_gs_i386),
+ DEFINE_GPR(ss, NULL, LLDB_INVALID_REGNUM, dwarf_ss_i386, LLDB_INVALID_REGNUM, gdb_ss_i386),
+ DEFINE_GPR(ds, NULL, LLDB_INVALID_REGNUM, dwarf_ds_i386, LLDB_INVALID_REGNUM, gdb_ds_i386),
+ DEFINE_GPR(es, NULL, LLDB_INVALID_REGNUM, dwarf_es_i386, LLDB_INVALID_REGNUM, gdb_es_i386),
+
+ DEFINE_GPR_PSEUDO_16(ax, eax),
+ DEFINE_GPR_PSEUDO_16(bx, ebx),
+ DEFINE_GPR_PSEUDO_16(cx, ecx),
+ DEFINE_GPR_PSEUDO_16(dx, edx),
+ DEFINE_GPR_PSEUDO_16(di, edi),
+ DEFINE_GPR_PSEUDO_16(si, esi),
+ DEFINE_GPR_PSEUDO_16(bp, ebp),
+ DEFINE_GPR_PSEUDO_16(sp, esp),
+ DEFINE_GPR_PSEUDO_8H(ah, eax),
+ DEFINE_GPR_PSEUDO_8H(bh, ebx),
+ DEFINE_GPR_PSEUDO_8H(ch, ecx),
+ DEFINE_GPR_PSEUDO_8H(dh, edx),
+ DEFINE_GPR_PSEUDO_8L(al, eax),
+ DEFINE_GPR_PSEUDO_8L(bl, ebx),
+ DEFINE_GPR_PSEUDO_8L(cl, ecx),
+ DEFINE_GPR_PSEUDO_8L(dl, edx),
+
+ // i387 Floating point registers.
+ DEFINE_FPR(fctrl, fctrl, LLDB_INVALID_REGNUM, dwarf_fctrl_i386, LLDB_INVALID_REGNUM, gdb_fctrl_i386),
+ DEFINE_FPR(fstat, fstat, LLDB_INVALID_REGNUM, dwarf_fstat_i386, LLDB_INVALID_REGNUM, gdb_fstat_i386),
+ DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftag_i386),
+ DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop_i386),
+ DEFINE_FPR(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_i386),
+ DEFINE_FPR(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_i386),
+ DEFINE_FPR(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_i386),
+ DEFINE_FPR(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_i386),
+ DEFINE_FPR(mxcsr, mxcsr, LLDB_INVALID_REGNUM, dwarf_mxcsr_i386, LLDB_INVALID_REGNUM, gdb_mxcsr_i386),
+ 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),
+
+ // XMM registers
+ DEFINE_XMM(xmm, 0),
+ DEFINE_XMM(xmm, 1),
+ DEFINE_XMM(xmm, 2),
+ DEFINE_XMM(xmm, 3),
+ DEFINE_XMM(xmm, 4),
+ DEFINE_XMM(xmm, 5),
+ DEFINE_XMM(xmm, 6),
+ DEFINE_XMM(xmm, 7),
+
+ // Copy of YMM registers assembled from xmm and ymmh
+ DEFINE_YMM(ymm, 0),
+ DEFINE_YMM(ymm, 1),
+ DEFINE_YMM(ymm, 2),
+ DEFINE_YMM(ymm, 3),
+ DEFINE_YMM(ymm, 4),
+ DEFINE_YMM(ymm, 5),
+ DEFINE_YMM(ymm, 6),
+ DEFINE_YMM(ymm, 7),
+
+ // Debug registers for lldb internal use
+ DEFINE_DR(dr, 0),
+ DEFINE_DR(dr, 1),
+ DEFINE_DR(dr, 2),
+ DEFINE_DR(dr, 3),
+ DEFINE_DR(dr, 4),
+ DEFINE_DR(dr, 5),
+ DEFINE_DR(dr, 6),
+ DEFINE_DR(dr, 7)
+};
+static_assert((sizeof(g_register_infos_i386) / sizeof(g_register_infos_i386[0])) == k_num_registers_i386,
+ "g_register_infos_x86_64 has wrong number of register infos");
+
+#undef GPR_OFFSET
+#undef FPR_OFFSET
+#undef YMM_OFFSET
+#undef FPR_SIZE
+#undef FP_SIZE
+#undef XMM_SIZE
+#undef YMM_SIZE
+#undef DEFINE_GPR
+#undef DEFINE_FPR
+#undef DEFINE_FP
+#undef DEFINE_XMM
+#undef DEFINE_YMM
+#undef DEFINE_DR
+#undef DEFINE_GPR_PSEUDO_16
+#undef DEFINE_GPR_PSEUDO_8H
+#undef DEFINE_GPR_PSEUDO_8L
+
+#endif // DECLARE_REGISTER_INFOS_I386_STRUCT
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_mips.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_mips.h
new file mode 100644
index 0000000..83ce6f0
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_mips.h
@@ -0,0 +1,175 @@
+//===-- RegisterInfos_mips.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+#include "llvm/Support/Compiler.h"
+
+#include <stddef.h>
+
+#ifdef DECLARE_REGISTER_INFOS_MIPS_STRUCT
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(UserArea, gpr) + \
+ LLVM_EXTENSION offsetof(GPR_linux_mips, regname))
+
+// Computes the offset of the given FPR in the extended data area.
+#define FPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(UserArea, fpr) + \
+ LLVM_EXTENSION offsetof(FPR_linux_mips, regname))
+
+// Computes the offset of the given MSA in the extended data area.
+#define MSA_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(UserArea, msa) + \
+ LLVM_EXTENSION offsetof(MSA_linux_mips, regname))
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((GPR_linux_mips*)NULL)->reg) / 2, GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips }, NULL, NULL }
+
+#define DEFINE_FPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((FPR_linux_mips*)NULL)->reg), FPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, fpr_##reg##_mips }, NULL, NULL }
+
+#define DEFINE_MSA(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((MSA_linux_mips*)0)->reg), MSA_OFFSET(reg), eEncodingVector, \
+ eFormatVectorOfUInt8, { kind1, kind2, kind3, kind4, msa_##reg##_mips }, NULL, NULL }
+
+#define DEFINE_MSA_INFO(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((MSA_linux_mips*)0)->reg), MSA_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, msa_##reg##_mips }, NULL, NULL }
+
+// RegisterKind: GCC, DWARF, Generic, GDB, LLDB
+
+static RegisterInfo
+g_register_infos_mips[] =
+{
+ DEFINE_GPR (zero, "zero", gcc_dwarf_zero_mips, gcc_dwarf_zero_mips, LLDB_INVALID_REGNUM, gdb_zero_mips),
+ DEFINE_GPR (r1, "at", gcc_dwarf_r1_mips, gcc_dwarf_r1_mips, LLDB_INVALID_REGNUM, gdb_r1_mips),
+ DEFINE_GPR (r2, NULL, gcc_dwarf_r2_mips, gcc_dwarf_r2_mips, LLDB_INVALID_REGNUM, gdb_r2_mips),
+ DEFINE_GPR (r3, NULL, gcc_dwarf_r3_mips, gcc_dwarf_r3_mips, LLDB_INVALID_REGNUM, gdb_r3_mips),
+ DEFINE_GPR (r4, NULL, gcc_dwarf_r4_mips, gcc_dwarf_r4_mips, LLDB_REGNUM_GENERIC_ARG1, gdb_r4_mips),
+ DEFINE_GPR (r5, NULL, gcc_dwarf_r5_mips, gcc_dwarf_r5_mips, LLDB_REGNUM_GENERIC_ARG2, gdb_r5_mips),
+ DEFINE_GPR (r6, NULL, gcc_dwarf_r6_mips, gcc_dwarf_r6_mips, LLDB_REGNUM_GENERIC_ARG3, gdb_r6_mips),
+ DEFINE_GPR (r7, NULL, gcc_dwarf_r7_mips, gcc_dwarf_r7_mips, LLDB_REGNUM_GENERIC_ARG4, gdb_r7_mips),
+ DEFINE_GPR (r8, NULL, gcc_dwarf_r8_mips, gcc_dwarf_r8_mips, LLDB_INVALID_REGNUM, gdb_r8_mips),
+ DEFINE_GPR (r9, NULL, gcc_dwarf_r9_mips, gcc_dwarf_r9_mips, LLDB_INVALID_REGNUM, gdb_r9_mips),
+ DEFINE_GPR (r10, NULL, gcc_dwarf_r10_mips, gcc_dwarf_r10_mips, LLDB_INVALID_REGNUM, gdb_r10_mips),
+ DEFINE_GPR (r11, NULL, gcc_dwarf_r11_mips, gcc_dwarf_r11_mips, LLDB_INVALID_REGNUM, gdb_r11_mips),
+ DEFINE_GPR (r12, NULL, gcc_dwarf_r12_mips, gcc_dwarf_r12_mips, LLDB_INVALID_REGNUM, gdb_r12_mips),
+ DEFINE_GPR (r13, NULL, gcc_dwarf_r13_mips, gcc_dwarf_r13_mips, LLDB_INVALID_REGNUM, gdb_r13_mips),
+ DEFINE_GPR (r14, NULL, gcc_dwarf_r14_mips, gcc_dwarf_r14_mips, LLDB_INVALID_REGNUM, gdb_r14_mips),
+ DEFINE_GPR (r15, NULL, gcc_dwarf_r15_mips, gcc_dwarf_r15_mips, LLDB_INVALID_REGNUM, gdb_r15_mips),
+ DEFINE_GPR (r16, NULL, gcc_dwarf_r16_mips, gcc_dwarf_r16_mips, LLDB_INVALID_REGNUM, gdb_r16_mips),
+ DEFINE_GPR (r17, NULL, gcc_dwarf_r17_mips, gcc_dwarf_r17_mips, LLDB_INVALID_REGNUM, gdb_r17_mips),
+ DEFINE_GPR (r18, NULL, gcc_dwarf_r18_mips, gcc_dwarf_r18_mips, LLDB_INVALID_REGNUM, gdb_r18_mips),
+ DEFINE_GPR (r19, NULL, gcc_dwarf_r19_mips, gcc_dwarf_r19_mips, LLDB_INVALID_REGNUM, gdb_r19_mips),
+ DEFINE_GPR (r20, NULL, gcc_dwarf_r20_mips, gcc_dwarf_r20_mips, LLDB_INVALID_REGNUM, gdb_r20_mips),
+ DEFINE_GPR (r21, NULL, gcc_dwarf_r21_mips, gcc_dwarf_r21_mips, LLDB_INVALID_REGNUM, gdb_r21_mips),
+ DEFINE_GPR (r22, NULL, gcc_dwarf_r22_mips, gcc_dwarf_r22_mips, LLDB_INVALID_REGNUM, gdb_r22_mips),
+ DEFINE_GPR (r23, NULL, gcc_dwarf_r23_mips, gcc_dwarf_r23_mips, LLDB_INVALID_REGNUM, gdb_r23_mips),
+ DEFINE_GPR (r24, NULL, gcc_dwarf_r24_mips, gcc_dwarf_r24_mips, LLDB_INVALID_REGNUM, gdb_r24_mips),
+ DEFINE_GPR (r25, NULL, gcc_dwarf_r25_mips, gcc_dwarf_r25_mips, LLDB_INVALID_REGNUM, gdb_r25_mips),
+ DEFINE_GPR (r26, NULL, gcc_dwarf_r26_mips, gcc_dwarf_r26_mips, LLDB_INVALID_REGNUM, gdb_r26_mips),
+ DEFINE_GPR (r27, NULL, gcc_dwarf_r27_mips, gcc_dwarf_r27_mips, LLDB_INVALID_REGNUM, gdb_r27_mips),
+ DEFINE_GPR (gp, "gp", gcc_dwarf_gp_mips, gcc_dwarf_gp_mips, LLDB_INVALID_REGNUM, gdb_gp_mips),
+ DEFINE_GPR (sp, "sp", gcc_dwarf_sp_mips, gcc_dwarf_sp_mips, LLDB_REGNUM_GENERIC_SP, gdb_sp_mips),
+ DEFINE_GPR (r30, "fp", gcc_dwarf_r30_mips, gcc_dwarf_r30_mips, LLDB_REGNUM_GENERIC_FP, gdb_r30_mips),
+ DEFINE_GPR (ra, "ra", gcc_dwarf_ra_mips, gcc_dwarf_ra_mips, LLDB_REGNUM_GENERIC_RA, gdb_ra_mips),
+ DEFINE_GPR (sr, "status", gcc_dwarf_sr_mips, gcc_dwarf_sr_mips, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM),
+ DEFINE_GPR (mullo, NULL, gcc_dwarf_lo_mips, gcc_dwarf_lo_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR (mulhi, NULL, gcc_dwarf_hi_mips, gcc_dwarf_hi_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR (badvaddr, NULL, gcc_dwarf_bad_mips, gcc_dwarf_bad_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR (cause, NULL, gcc_dwarf_cause_mips, gcc_dwarf_cause_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR (pc, NULL, gcc_dwarf_pc_mips, gcc_dwarf_pc_mips, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM),
+ DEFINE_GPR (config5, NULL, gcc_dwarf_config5_mips, gcc_dwarf_config5_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR (f0, NULL, gcc_dwarf_f0_mips, gcc_dwarf_f0_mips, LLDB_INVALID_REGNUM, gdb_f0_mips),
+ DEFINE_FPR (f1, NULL, gcc_dwarf_f1_mips, gcc_dwarf_f1_mips, LLDB_INVALID_REGNUM, gdb_f1_mips),
+ DEFINE_FPR (f2, NULL, gcc_dwarf_f2_mips, gcc_dwarf_f2_mips, LLDB_INVALID_REGNUM, gdb_f2_mips),
+ DEFINE_FPR (f3, NULL, gcc_dwarf_f3_mips, gcc_dwarf_f3_mips, LLDB_INVALID_REGNUM, gdb_f3_mips),
+ DEFINE_FPR (f4, NULL, gcc_dwarf_f4_mips, gcc_dwarf_f4_mips, LLDB_INVALID_REGNUM, gdb_f4_mips),
+ DEFINE_FPR (f5, NULL, gcc_dwarf_f5_mips, gcc_dwarf_f5_mips, LLDB_INVALID_REGNUM, gdb_f5_mips),
+ DEFINE_FPR (f6, NULL, gcc_dwarf_f6_mips, gcc_dwarf_f6_mips, LLDB_INVALID_REGNUM, gdb_f6_mips),
+ DEFINE_FPR (f7, NULL, gcc_dwarf_f7_mips, gcc_dwarf_f7_mips, LLDB_INVALID_REGNUM, gdb_f7_mips),
+ DEFINE_FPR (f8, NULL, gcc_dwarf_f8_mips, gcc_dwarf_f8_mips, LLDB_INVALID_REGNUM, gdb_f8_mips),
+ DEFINE_FPR (f9, NULL, gcc_dwarf_f9_mips, gcc_dwarf_f9_mips, LLDB_INVALID_REGNUM, gdb_f9_mips),
+ DEFINE_FPR (f10, NULL, gcc_dwarf_f10_mips, gcc_dwarf_f10_mips, LLDB_INVALID_REGNUM, gdb_f10_mips),
+ DEFINE_FPR (f11, NULL, gcc_dwarf_f11_mips, gcc_dwarf_f11_mips, LLDB_INVALID_REGNUM, gdb_f11_mips),
+ DEFINE_FPR (f12, NULL, gcc_dwarf_f12_mips, gcc_dwarf_f12_mips, LLDB_INVALID_REGNUM, gdb_f12_mips),
+ DEFINE_FPR (f13, NULL, gcc_dwarf_f13_mips, gcc_dwarf_f13_mips, LLDB_INVALID_REGNUM, gdb_f13_mips),
+ DEFINE_FPR (f14, NULL, gcc_dwarf_f14_mips, gcc_dwarf_f14_mips, LLDB_INVALID_REGNUM, gdb_f14_mips),
+ DEFINE_FPR (f15, NULL, gcc_dwarf_f15_mips, gcc_dwarf_f15_mips, LLDB_INVALID_REGNUM, gdb_f15_mips),
+ DEFINE_FPR (f16, NULL, gcc_dwarf_f16_mips, gcc_dwarf_f16_mips, LLDB_INVALID_REGNUM, gdb_f16_mips),
+ DEFINE_FPR (f17, NULL, gcc_dwarf_f17_mips, gcc_dwarf_f17_mips, LLDB_INVALID_REGNUM, gdb_f17_mips),
+ DEFINE_FPR (f18, NULL, gcc_dwarf_f18_mips, gcc_dwarf_f18_mips, LLDB_INVALID_REGNUM, gdb_f18_mips),
+ DEFINE_FPR (f19, NULL, gcc_dwarf_f19_mips, gcc_dwarf_f19_mips, LLDB_INVALID_REGNUM, gdb_f19_mips),
+ DEFINE_FPR (f20, NULL, gcc_dwarf_f20_mips, gcc_dwarf_f20_mips, LLDB_INVALID_REGNUM, gdb_f20_mips),
+ DEFINE_FPR (f21, NULL, gcc_dwarf_f21_mips, gcc_dwarf_f21_mips, LLDB_INVALID_REGNUM, gdb_f21_mips),
+ DEFINE_FPR (f22, NULL, gcc_dwarf_f22_mips, gcc_dwarf_f22_mips, LLDB_INVALID_REGNUM, gdb_f22_mips),
+ DEFINE_FPR (f23, NULL, gcc_dwarf_f23_mips, gcc_dwarf_f23_mips, LLDB_INVALID_REGNUM, gdb_f23_mips),
+ DEFINE_FPR (f24, NULL, gcc_dwarf_f24_mips, gcc_dwarf_f24_mips, LLDB_INVALID_REGNUM, gdb_f24_mips),
+ DEFINE_FPR (f25, NULL, gcc_dwarf_f25_mips, gcc_dwarf_f25_mips, LLDB_INVALID_REGNUM, gdb_f25_mips),
+ DEFINE_FPR (f26, NULL, gcc_dwarf_f26_mips, gcc_dwarf_f26_mips, LLDB_INVALID_REGNUM, gdb_f26_mips),
+ DEFINE_FPR (f27, NULL, gcc_dwarf_f27_mips, gcc_dwarf_f27_mips, LLDB_INVALID_REGNUM, gdb_f27_mips),
+ DEFINE_FPR (f28, NULL, gcc_dwarf_f28_mips, gcc_dwarf_f28_mips, LLDB_INVALID_REGNUM, gdb_f28_mips),
+ DEFINE_FPR (f29, NULL, gcc_dwarf_f29_mips, gcc_dwarf_f29_mips, LLDB_INVALID_REGNUM, gdb_f29_mips),
+ DEFINE_FPR (f30, NULL, gcc_dwarf_f30_mips, gcc_dwarf_f30_mips, LLDB_INVALID_REGNUM, gdb_f30_mips),
+ DEFINE_FPR (f31, NULL, gcc_dwarf_f31_mips, gcc_dwarf_f31_mips, LLDB_INVALID_REGNUM, gdb_f31_mips),
+ DEFINE_FPR (fcsr, NULL, gcc_dwarf_fcsr_mips, gcc_dwarf_fcsr_mips, LLDB_INVALID_REGNUM, gdb_fcsr_mips),
+ DEFINE_FPR (fir, NULL, gcc_dwarf_fir_mips, gcc_dwarf_fir_mips, LLDB_INVALID_REGNUM, gdb_fir_mips),
+ DEFINE_FPR (config5, NULL, gcc_dwarf_config5_mips, gcc_dwarf_config5_mips, LLDB_INVALID_REGNUM, gdb_config5_mips),
+ DEFINE_MSA (w0, NULL, gcc_dwarf_w0_mips, gcc_dwarf_w0_mips, LLDB_INVALID_REGNUM, gdb_w0_mips),
+ DEFINE_MSA (w1, NULL, gcc_dwarf_w1_mips, gcc_dwarf_w1_mips, LLDB_INVALID_REGNUM, gdb_w1_mips),
+ DEFINE_MSA (w2, NULL, gcc_dwarf_w2_mips, gcc_dwarf_w2_mips, LLDB_INVALID_REGNUM, gdb_w2_mips),
+ DEFINE_MSA (w3, NULL, gcc_dwarf_w3_mips, gcc_dwarf_w3_mips, LLDB_INVALID_REGNUM, gdb_w3_mips),
+ DEFINE_MSA (w4, NULL, gcc_dwarf_w4_mips, gcc_dwarf_w4_mips, LLDB_INVALID_REGNUM, gdb_w4_mips),
+ DEFINE_MSA (w5, NULL, gcc_dwarf_w5_mips, gcc_dwarf_w5_mips, LLDB_INVALID_REGNUM, gdb_w5_mips),
+ DEFINE_MSA (w6, NULL, gcc_dwarf_w6_mips, gcc_dwarf_w6_mips, LLDB_INVALID_REGNUM, gdb_w6_mips),
+ DEFINE_MSA (w7, NULL, gcc_dwarf_w7_mips, gcc_dwarf_w7_mips, LLDB_INVALID_REGNUM, gdb_w7_mips),
+ DEFINE_MSA (w8, NULL, gcc_dwarf_w8_mips, gcc_dwarf_w8_mips, LLDB_INVALID_REGNUM, gdb_w8_mips),
+ DEFINE_MSA (w9, NULL, gcc_dwarf_w9_mips, gcc_dwarf_w9_mips, LLDB_INVALID_REGNUM, gdb_w9_mips),
+ DEFINE_MSA (w10, NULL, gcc_dwarf_w10_mips, gcc_dwarf_w10_mips, LLDB_INVALID_REGNUM, gdb_w10_mips),
+ DEFINE_MSA (w11, NULL, gcc_dwarf_w11_mips, gcc_dwarf_w11_mips, LLDB_INVALID_REGNUM, gdb_w11_mips),
+ DEFINE_MSA (w12, NULL, gcc_dwarf_w12_mips, gcc_dwarf_w12_mips, LLDB_INVALID_REGNUM, gdb_w12_mips),
+ DEFINE_MSA (w13, NULL, gcc_dwarf_w13_mips, gcc_dwarf_w13_mips, LLDB_INVALID_REGNUM, gdb_w13_mips),
+ DEFINE_MSA (w14, NULL, gcc_dwarf_w14_mips, gcc_dwarf_w14_mips, LLDB_INVALID_REGNUM, gdb_w14_mips),
+ DEFINE_MSA (w15, NULL, gcc_dwarf_w15_mips, gcc_dwarf_w15_mips, LLDB_INVALID_REGNUM, gdb_w15_mips),
+ DEFINE_MSA (w16, NULL, gcc_dwarf_w16_mips, gcc_dwarf_w16_mips, LLDB_INVALID_REGNUM, gdb_w16_mips),
+ DEFINE_MSA (w17, NULL, gcc_dwarf_w17_mips, gcc_dwarf_w17_mips, LLDB_INVALID_REGNUM, gdb_w17_mips),
+ DEFINE_MSA (w18, NULL, gcc_dwarf_w18_mips, gcc_dwarf_w18_mips, LLDB_INVALID_REGNUM, gdb_w18_mips),
+ DEFINE_MSA (w19, NULL, gcc_dwarf_w19_mips, gcc_dwarf_w19_mips, LLDB_INVALID_REGNUM, gdb_w19_mips),
+ DEFINE_MSA (w20, NULL, gcc_dwarf_w10_mips, gcc_dwarf_w20_mips, LLDB_INVALID_REGNUM, gdb_w20_mips),
+ DEFINE_MSA (w21, NULL, gcc_dwarf_w21_mips, gcc_dwarf_w21_mips, LLDB_INVALID_REGNUM, gdb_w21_mips),
+ DEFINE_MSA (w22, NULL, gcc_dwarf_w22_mips, gcc_dwarf_w22_mips, LLDB_INVALID_REGNUM, gdb_w22_mips),
+ DEFINE_MSA (w23, NULL, gcc_dwarf_w23_mips, gcc_dwarf_w23_mips, LLDB_INVALID_REGNUM, gdb_w23_mips),
+ DEFINE_MSA (w24, NULL, gcc_dwarf_w24_mips, gcc_dwarf_w24_mips, LLDB_INVALID_REGNUM, gdb_w24_mips),
+ DEFINE_MSA (w25, NULL, gcc_dwarf_w25_mips, gcc_dwarf_w25_mips, LLDB_INVALID_REGNUM, gdb_w25_mips),
+ DEFINE_MSA (w26, NULL, gcc_dwarf_w26_mips, gcc_dwarf_w26_mips, LLDB_INVALID_REGNUM, gdb_w26_mips),
+ DEFINE_MSA (w27, NULL, gcc_dwarf_w27_mips, gcc_dwarf_w27_mips, LLDB_INVALID_REGNUM, gdb_w27_mips),
+ DEFINE_MSA (w28, NULL, gcc_dwarf_w28_mips, gcc_dwarf_w28_mips, LLDB_INVALID_REGNUM, gdb_w28_mips),
+ DEFINE_MSA (w29, NULL, gcc_dwarf_w29_mips, gcc_dwarf_w29_mips, LLDB_INVALID_REGNUM, gdb_w29_mips),
+ DEFINE_MSA (w30, NULL, gcc_dwarf_w30_mips, gcc_dwarf_w30_mips, LLDB_INVALID_REGNUM, gdb_w30_mips),
+ DEFINE_MSA (w31, NULL, gcc_dwarf_w31_mips, gcc_dwarf_w31_mips, LLDB_INVALID_REGNUM, gdb_w31_mips),
+ DEFINE_MSA_INFO (mcsr, NULL, gcc_dwarf_mcsr_mips, gcc_dwarf_mcsr_mips, LLDB_INVALID_REGNUM, gdb_mcsr_mips),
+ DEFINE_MSA_INFO (mir, NULL, gcc_dwarf_mir_mips, gcc_dwarf_mir_mips, LLDB_INVALID_REGNUM, gdb_mir_mips),
+ DEFINE_MSA_INFO (fcsr, NULL, gcc_dwarf_fcsr_mips, gcc_dwarf_fcsr_mips, LLDB_INVALID_REGNUM, gdb_fcsr_mips),
+ DEFINE_MSA_INFO (fir, NULL, gcc_dwarf_fir_mips, gcc_dwarf_fir_mips, LLDB_INVALID_REGNUM, gdb_fir_mips),
+ DEFINE_MSA_INFO (config5, NULL, gcc_dwarf_config5_mips, gcc_dwarf_config5_mips, LLDB_INVALID_REGNUM, gdb_config5_mips)
+};
+static_assert((sizeof(g_register_infos_mips) / sizeof(g_register_infos_mips[0])) == k_num_registers_mips,
+ "g_register_infos_mips has wrong number of register infos");
+
+#undef GPR_OFFSET
+#undef FPR_OFFSET
+#undef MSA_OFFSET
+#undef DEFINE_GPR
+#undef DEFINE_FPR
+#undef DEFINE_MSA
+#undef DEFINE_MSA_INFO
+
+#endif // DECLARE_REGISTER_INFOS_MIPS_STRUCT
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h
new file mode 100644
index 0000000..101842e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h
@@ -0,0 +1,237 @@
+//===-- RegisterInfos_mips64.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+#include "llvm/Support/Compiler.h"
+
+#include <stddef.h>
+
+#ifdef DECLARE_REGISTER_INFOS_MIPS64_STRUCT
+
+// Computes the offset of the given GPR in the user data area.
+#ifdef LINUX_MIPS64
+ #define GPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(UserArea, gpr) + \
+ LLVM_EXTENSION offsetof(GPR_linux_mips, regname))
+#else
+ #define GPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(GPR_freebsd_mips, regname))
+#endif
+
+// Computes the offset of the given FPR in the extended data area.
+#define FPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(UserArea, fpr) + \
+ LLVM_EXTENSION offsetof(FPR_linux_mips, regname))
+
+// Computes the offset of the given MSA in the extended data area.
+#define MSA_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(UserArea, msa) + \
+ LLVM_EXTENSION offsetof(MSA_linux_mips, regname))
+
+// RegisterKind: GCC, DWARF, Generic, GDB, LLDB
+
+// Note that the size and offset will be updated by platform-specific classes.
+#ifdef LINUX_MIPS64
+ #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((GPR_linux_mips*)0)->reg), GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL }
+#else
+ #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((GPR_freebsd_mips*)0)->reg), GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL }
+#endif
+
+#define DEFINE_GPR_INFO(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((GPR_linux_mips*)0)->reg) / 2, GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL }
+
+#define DEFINE_FPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((FPR_linux_mips*)0)->reg), FPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, fpr_##reg##_mips64 }, NULL, NULL }
+
+#define DEFINE_MSA(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((MSA_linux_mips*)0)->reg), MSA_OFFSET(reg), eEncodingVector, \
+ eFormatVectorOfUInt8, { kind1, kind2, kind3, kind4, msa_##reg##_mips64 }, NULL, NULL }
+
+#define DEFINE_MSA_INFO(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((MSA_linux_mips*)0)->reg), MSA_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, msa_##reg##_mips64 }, NULL, NULL }
+
+static RegisterInfo
+g_register_infos_mips64[] =
+{
+ // General purpose registers. GCC, DWARF, Generic, GDB
+#ifndef LINUX_MIPS64
+ DEFINE_GPR(zero, "r0", gcc_dwarf_zero_mips64, gcc_dwarf_zero_mips64, LLDB_INVALID_REGNUM, gdb_zero_mips64),
+ DEFINE_GPR(r1, NULL, gcc_dwarf_r1_mips64, gcc_dwarf_r1_mips64, LLDB_INVALID_REGNUM, gdb_r1_mips64),
+ DEFINE_GPR(r2, NULL, gcc_dwarf_r2_mips64, gcc_dwarf_r2_mips64, LLDB_INVALID_REGNUM, gdb_r2_mips64),
+ DEFINE_GPR(r3, NULL, gcc_dwarf_r3_mips64, gcc_dwarf_r3_mips64, LLDB_INVALID_REGNUM, gdb_r3_mips64),
+ DEFINE_GPR(r4, NULL, gcc_dwarf_r4_mips64, gcc_dwarf_r4_mips64, LLDB_REGNUM_GENERIC_ARG1, gdb_r4_mips64),
+ DEFINE_GPR(r5, NULL, gcc_dwarf_r5_mips64, gcc_dwarf_r5_mips64, LLDB_REGNUM_GENERIC_ARG2, gdb_r5_mips64),
+ DEFINE_GPR(r6, NULL, gcc_dwarf_r6_mips64, gcc_dwarf_r6_mips64, LLDB_REGNUM_GENERIC_ARG3, gdb_r6_mips64),
+ DEFINE_GPR(r7, NULL, gcc_dwarf_r7_mips64, gcc_dwarf_r7_mips64, LLDB_REGNUM_GENERIC_ARG4, gdb_r7_mips64),
+ DEFINE_GPR(r8, NULL, gcc_dwarf_r8_mips64, gcc_dwarf_r8_mips64, LLDB_REGNUM_GENERIC_ARG5, gdb_r8_mips64),
+ DEFINE_GPR(r9, NULL, gcc_dwarf_r9_mips64, gcc_dwarf_r9_mips64, LLDB_REGNUM_GENERIC_ARG6, gdb_r9_mips64),
+ DEFINE_GPR(r10, NULL, gcc_dwarf_r10_mips64, gcc_dwarf_r10_mips64, LLDB_REGNUM_GENERIC_ARG7, gdb_r10_mips64),
+ DEFINE_GPR(r11, NULL, gcc_dwarf_r11_mips64, gcc_dwarf_r11_mips64, LLDB_REGNUM_GENERIC_ARG8, gdb_r11_mips64),
+ DEFINE_GPR(r12, NULL, gcc_dwarf_r12_mips64, gcc_dwarf_r12_mips64, LLDB_INVALID_REGNUM, gdb_r12_mips64),
+ DEFINE_GPR(r13, NULL, gcc_dwarf_r13_mips64, gcc_dwarf_r13_mips64, LLDB_INVALID_REGNUM, gdb_r13_mips64),
+ DEFINE_GPR(r14, NULL, gcc_dwarf_r14_mips64, gcc_dwarf_r14_mips64, LLDB_INVALID_REGNUM, gdb_r14_mips64),
+ DEFINE_GPR(r15, NULL, gcc_dwarf_r15_mips64, gcc_dwarf_r15_mips64, LLDB_INVALID_REGNUM, gdb_r15_mips64),
+ DEFINE_GPR(r16, NULL, gcc_dwarf_r16_mips64, gcc_dwarf_r16_mips64, LLDB_INVALID_REGNUM, gdb_r16_mips64),
+ DEFINE_GPR(r17, NULL, gcc_dwarf_r17_mips64, gcc_dwarf_r17_mips64, LLDB_INVALID_REGNUM, gdb_r17_mips64),
+ DEFINE_GPR(r18, NULL, gcc_dwarf_r18_mips64, gcc_dwarf_r18_mips64, LLDB_INVALID_REGNUM, gdb_r18_mips64),
+ DEFINE_GPR(r19, NULL, gcc_dwarf_r19_mips64, gcc_dwarf_r19_mips64, LLDB_INVALID_REGNUM, gdb_r19_mips64),
+ DEFINE_GPR(r20, NULL, gcc_dwarf_r20_mips64, gcc_dwarf_r20_mips64, LLDB_INVALID_REGNUM, gdb_r20_mips64),
+ DEFINE_GPR(r21, NULL, gcc_dwarf_r21_mips64, gcc_dwarf_r21_mips64, LLDB_INVALID_REGNUM, gdb_r21_mips64),
+ DEFINE_GPR(r22, NULL, gcc_dwarf_r22_mips64, gcc_dwarf_r22_mips64, LLDB_INVALID_REGNUM, gdb_r22_mips64),
+ DEFINE_GPR(r23, NULL, gcc_dwarf_r23_mips64, gcc_dwarf_r23_mips64, LLDB_INVALID_REGNUM, gdb_r23_mips64),
+ DEFINE_GPR(r24, NULL, gcc_dwarf_r24_mips64, gcc_dwarf_r24_mips64, LLDB_INVALID_REGNUM, gdb_r24_mips64),
+ DEFINE_GPR(r25, NULL, gcc_dwarf_r25_mips64, gcc_dwarf_r25_mips64, LLDB_INVALID_REGNUM, gdb_r25_mips64),
+ DEFINE_GPR(r26, NULL, gcc_dwarf_r26_mips64, gcc_dwarf_r26_mips64, LLDB_INVALID_REGNUM, gdb_r26_mips64),
+ DEFINE_GPR(r27, NULL, gcc_dwarf_r27_mips64, gcc_dwarf_r27_mips64, LLDB_INVALID_REGNUM, gdb_r27_mips64),
+ DEFINE_GPR(gp, "r28", gcc_dwarf_gp_mips64, gcc_dwarf_gp_mips64, LLDB_INVALID_REGNUM, gdb_gp_mips64),
+ DEFINE_GPR(sp, "r29", gcc_dwarf_sp_mips64, gcc_dwarf_sp_mips64, LLDB_REGNUM_GENERIC_SP, gdb_sp_mips64),
+ DEFINE_GPR(r30, NULL, gcc_dwarf_r30_mips64, gcc_dwarf_r30_mips64, LLDB_REGNUM_GENERIC_FP, gdb_r30_mips64),
+ DEFINE_GPR(ra, "r31", gcc_dwarf_ra_mips64, gcc_dwarf_ra_mips64, LLDB_REGNUM_GENERIC_RA, gdb_ra_mips64),
+ DEFINE_GPR(sr, NULL, gcc_dwarf_sr_mips64, gcc_dwarf_sr_mips64, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(mullo, NULL, gcc_dwarf_lo_mips64, gcc_dwarf_lo_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(mulhi, NULL, gcc_dwarf_hi_mips64, gcc_dwarf_hi_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(badvaddr, NULL, gcc_dwarf_bad_mips64, gcc_dwarf_bad_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(cause, NULL, gcc_dwarf_cause_mips64, gcc_dwarf_cause_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(pc, "pc", gcc_dwarf_pc_mips64, gcc_dwarf_pc_mips64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(ic, NULL, gcc_dwarf_ic_mips64, gcc_dwarf_ic_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(dummy, NULL, gcc_dwarf_dummy_mips64, gcc_dwarf_dummy_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+#else
+
+ DEFINE_GPR(zero, "r0", gcc_dwarf_zero_mips64, gcc_dwarf_zero_mips64, LLDB_INVALID_REGNUM, gdb_zero_mips64),
+ DEFINE_GPR(r1, NULL, gcc_dwarf_r1_mips64, gcc_dwarf_r1_mips64, LLDB_INVALID_REGNUM, gdb_r1_mips64),
+ DEFINE_GPR(r2, NULL, gcc_dwarf_r2_mips64, gcc_dwarf_r2_mips64, LLDB_INVALID_REGNUM, gdb_r2_mips64),
+ DEFINE_GPR(r3, NULL, gcc_dwarf_r3_mips64, gcc_dwarf_r3_mips64, LLDB_INVALID_REGNUM, gdb_r3_mips64),
+ DEFINE_GPR(r4, NULL, gcc_dwarf_r4_mips64, gcc_dwarf_r4_mips64, LLDB_REGNUM_GENERIC_ARG1, gdb_r4_mips64),
+ DEFINE_GPR(r5, NULL, gcc_dwarf_r5_mips64, gcc_dwarf_r5_mips64, LLDB_REGNUM_GENERIC_ARG2, gdb_r5_mips64),
+ DEFINE_GPR(r6, NULL, gcc_dwarf_r6_mips64, gcc_dwarf_r6_mips64, LLDB_REGNUM_GENERIC_ARG3, gdb_r6_mips64),
+ DEFINE_GPR(r7, NULL, gcc_dwarf_r7_mips64, gcc_dwarf_r7_mips64, LLDB_REGNUM_GENERIC_ARG4, gdb_r7_mips64),
+ DEFINE_GPR(r8, NULL, gcc_dwarf_r8_mips64, gcc_dwarf_r8_mips64, LLDB_REGNUM_GENERIC_ARG5, gdb_r8_mips64),
+ DEFINE_GPR(r9, NULL, gcc_dwarf_r9_mips64, gcc_dwarf_r9_mips64, LLDB_REGNUM_GENERIC_ARG6, gdb_r9_mips64),
+ DEFINE_GPR(r10, NULL, gcc_dwarf_r10_mips64, gcc_dwarf_r10_mips64, LLDB_REGNUM_GENERIC_ARG7, gdb_r10_mips64),
+ DEFINE_GPR(r11, NULL, gcc_dwarf_r11_mips64, gcc_dwarf_r11_mips64, LLDB_REGNUM_GENERIC_ARG8, gdb_r11_mips64),
+ DEFINE_GPR(r12, NULL, gcc_dwarf_r12_mips64, gcc_dwarf_r12_mips64, LLDB_INVALID_REGNUM, gdb_r12_mips64),
+ DEFINE_GPR(r13, NULL, gcc_dwarf_r13_mips64, gcc_dwarf_r13_mips64, LLDB_INVALID_REGNUM, gdb_r13_mips64),
+ DEFINE_GPR(r14, NULL, gcc_dwarf_r14_mips64, gcc_dwarf_r14_mips64, LLDB_INVALID_REGNUM, gdb_r14_mips64),
+ DEFINE_GPR(r15, NULL, gcc_dwarf_r15_mips64, gcc_dwarf_r15_mips64, LLDB_INVALID_REGNUM, gdb_r15_mips64),
+ DEFINE_GPR(r16, NULL, gcc_dwarf_r16_mips64, gcc_dwarf_r16_mips64, LLDB_INVALID_REGNUM, gdb_r16_mips64),
+ DEFINE_GPR(r17, NULL, gcc_dwarf_r17_mips64, gcc_dwarf_r17_mips64, LLDB_INVALID_REGNUM, gdb_r17_mips64),
+ DEFINE_GPR(r18, NULL, gcc_dwarf_r18_mips64, gcc_dwarf_r18_mips64, LLDB_INVALID_REGNUM, gdb_r18_mips64),
+ DEFINE_GPR(r19, NULL, gcc_dwarf_r19_mips64, gcc_dwarf_r19_mips64, LLDB_INVALID_REGNUM, gdb_r19_mips64),
+ DEFINE_GPR(r20, NULL, gcc_dwarf_r20_mips64, gcc_dwarf_r20_mips64, LLDB_INVALID_REGNUM, gdb_r20_mips64),
+ DEFINE_GPR(r21, NULL, gcc_dwarf_r21_mips64, gcc_dwarf_r21_mips64, LLDB_INVALID_REGNUM, gdb_r21_mips64),
+ DEFINE_GPR(r22, NULL, gcc_dwarf_r22_mips64, gcc_dwarf_r22_mips64, LLDB_INVALID_REGNUM, gdb_r22_mips64),
+ DEFINE_GPR(r23, NULL, gcc_dwarf_r23_mips64, gcc_dwarf_r23_mips64, LLDB_INVALID_REGNUM, gdb_r23_mips64),
+ DEFINE_GPR(r24, NULL, gcc_dwarf_r24_mips64, gcc_dwarf_r24_mips64, LLDB_INVALID_REGNUM, gdb_r24_mips64),
+ DEFINE_GPR(r25, NULL, gcc_dwarf_r25_mips64, gcc_dwarf_r25_mips64, LLDB_INVALID_REGNUM, gdb_r25_mips64),
+ DEFINE_GPR(r26, NULL, gcc_dwarf_r26_mips64, gcc_dwarf_r26_mips64, LLDB_INVALID_REGNUM, gdb_r26_mips64),
+ DEFINE_GPR(r27, NULL, gcc_dwarf_r27_mips64, gcc_dwarf_r27_mips64, LLDB_INVALID_REGNUM, gdb_r27_mips64),
+ DEFINE_GPR(gp, "r28", gcc_dwarf_gp_mips64, gcc_dwarf_gp_mips64, LLDB_INVALID_REGNUM, gdb_gp_mips64),
+ DEFINE_GPR(sp, "r29", gcc_dwarf_sp_mips64, gcc_dwarf_sp_mips64, LLDB_REGNUM_GENERIC_SP, gdb_sp_mips64),
+ DEFINE_GPR(r30, NULL, gcc_dwarf_r30_mips64, gcc_dwarf_r30_mips64, LLDB_REGNUM_GENERIC_FP, gdb_r30_mips64),
+ DEFINE_GPR(ra, "r31", gcc_dwarf_ra_mips64, gcc_dwarf_ra_mips64, LLDB_REGNUM_GENERIC_RA, gdb_ra_mips64),
+ DEFINE_GPR_INFO(sr, NULL, gcc_dwarf_sr_mips64, gcc_dwarf_sr_mips64, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(mullo, NULL, gcc_dwarf_lo_mips64, gcc_dwarf_lo_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(mulhi, NULL, gcc_dwarf_hi_mips64, gcc_dwarf_hi_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(badvaddr, NULL, gcc_dwarf_bad_mips64, gcc_dwarf_bad_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR_INFO(cause, NULL, gcc_dwarf_cause_mips64, gcc_dwarf_cause_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_GPR(pc, "pc", gcc_dwarf_pc_mips64, gcc_dwarf_pc_mips64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM),
+ DEFINE_GPR_INFO(config5, NULL, gcc_dwarf_config5_mips64, gcc_dwarf_config5_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+ DEFINE_FPR (f0, NULL, gcc_dwarf_f0_mips64, gcc_dwarf_f0_mips64, LLDB_INVALID_REGNUM, gdb_f0_mips64),
+ DEFINE_FPR (f1, NULL, gcc_dwarf_f1_mips64, gcc_dwarf_f1_mips64, LLDB_INVALID_REGNUM, gdb_f1_mips64),
+ DEFINE_FPR (f2, NULL, gcc_dwarf_f2_mips64, gcc_dwarf_f2_mips64, LLDB_INVALID_REGNUM, gdb_f2_mips64),
+ DEFINE_FPR (f3, NULL, gcc_dwarf_f3_mips64, gcc_dwarf_f3_mips64, LLDB_INVALID_REGNUM, gdb_f3_mips64),
+ DEFINE_FPR (f4, NULL, gcc_dwarf_f4_mips64, gcc_dwarf_f4_mips64, LLDB_INVALID_REGNUM, gdb_f4_mips64),
+ DEFINE_FPR (f5, NULL, gcc_dwarf_f5_mips64, gcc_dwarf_f5_mips64, LLDB_INVALID_REGNUM, gdb_f5_mips64),
+ DEFINE_FPR (f6, NULL, gcc_dwarf_f6_mips64, gcc_dwarf_f6_mips64, LLDB_INVALID_REGNUM, gdb_f6_mips64),
+ DEFINE_FPR (f7, NULL, gcc_dwarf_f7_mips64, gcc_dwarf_f7_mips64, LLDB_INVALID_REGNUM, gdb_f7_mips64),
+ DEFINE_FPR (f8, NULL, gcc_dwarf_f8_mips64, gcc_dwarf_f8_mips64, LLDB_INVALID_REGNUM, gdb_f8_mips64),
+ DEFINE_FPR (f9, NULL, gcc_dwarf_f9_mips64, gcc_dwarf_f9_mips64, LLDB_INVALID_REGNUM, gdb_f9_mips64),
+ DEFINE_FPR (f10, NULL, gcc_dwarf_f10_mips64, gcc_dwarf_f10_mips64, LLDB_INVALID_REGNUM, gdb_f10_mips64),
+ DEFINE_FPR (f11, NULL, gcc_dwarf_f11_mips64, gcc_dwarf_f11_mips64, LLDB_INVALID_REGNUM, gdb_f11_mips64),
+ DEFINE_FPR (f12, NULL, gcc_dwarf_f12_mips64, gcc_dwarf_f12_mips64, LLDB_INVALID_REGNUM, gdb_f12_mips64),
+ DEFINE_FPR (f13, NULL, gcc_dwarf_f13_mips64, gcc_dwarf_f13_mips64, LLDB_INVALID_REGNUM, gdb_f13_mips64),
+ DEFINE_FPR (f14, NULL, gcc_dwarf_f14_mips64, gcc_dwarf_f14_mips64, LLDB_INVALID_REGNUM, gdb_f14_mips64),
+ DEFINE_FPR (f15, NULL, gcc_dwarf_f15_mips64, gcc_dwarf_f15_mips64, LLDB_INVALID_REGNUM, gdb_f15_mips64),
+ DEFINE_FPR (f16, NULL, gcc_dwarf_f16_mips64, gcc_dwarf_f16_mips64, LLDB_INVALID_REGNUM, gdb_f16_mips64),
+ DEFINE_FPR (f17, NULL, gcc_dwarf_f17_mips64, gcc_dwarf_f17_mips64, LLDB_INVALID_REGNUM, gdb_f17_mips64),
+ DEFINE_FPR (f18, NULL, gcc_dwarf_f18_mips64, gcc_dwarf_f18_mips64, LLDB_INVALID_REGNUM, gdb_f18_mips64),
+ DEFINE_FPR (f19, NULL, gcc_dwarf_f19_mips64, gcc_dwarf_f19_mips64, LLDB_INVALID_REGNUM, gdb_f19_mips64),
+ DEFINE_FPR (f20, NULL, gcc_dwarf_f20_mips64, gcc_dwarf_f20_mips64, LLDB_INVALID_REGNUM, gdb_f20_mips64),
+ DEFINE_FPR (f21, NULL, gcc_dwarf_f21_mips64, gcc_dwarf_f21_mips64, LLDB_INVALID_REGNUM, gdb_f21_mips64),
+ DEFINE_FPR (f22, NULL, gcc_dwarf_f22_mips64, gcc_dwarf_f22_mips64, LLDB_INVALID_REGNUM, gdb_f22_mips64),
+ DEFINE_FPR (f23, NULL, gcc_dwarf_f23_mips64, gcc_dwarf_f23_mips64, LLDB_INVALID_REGNUM, gdb_f23_mips64),
+ DEFINE_FPR (f24, NULL, gcc_dwarf_f24_mips64, gcc_dwarf_f24_mips64, LLDB_INVALID_REGNUM, gdb_f24_mips64),
+ DEFINE_FPR (f25, NULL, gcc_dwarf_f25_mips64, gcc_dwarf_f25_mips64, LLDB_INVALID_REGNUM, gdb_f25_mips64),
+ DEFINE_FPR (f26, NULL, gcc_dwarf_f26_mips64, gcc_dwarf_f26_mips64, LLDB_INVALID_REGNUM, gdb_f26_mips64),
+ DEFINE_FPR (f27, NULL, gcc_dwarf_f27_mips64, gcc_dwarf_f27_mips64, LLDB_INVALID_REGNUM, gdb_f27_mips64),
+ DEFINE_FPR (f28, NULL, gcc_dwarf_f28_mips64, gcc_dwarf_f28_mips64, LLDB_INVALID_REGNUM, gdb_f28_mips64),
+ DEFINE_FPR (f29, NULL, gcc_dwarf_f29_mips64, gcc_dwarf_f29_mips64, LLDB_INVALID_REGNUM, gdb_f29_mips64),
+ DEFINE_FPR (f30, NULL, gcc_dwarf_f30_mips64, gcc_dwarf_f30_mips64, LLDB_INVALID_REGNUM, gdb_f30_mips64),
+ DEFINE_FPR (f31, NULL, gcc_dwarf_f31_mips64, gcc_dwarf_f31_mips64, LLDB_INVALID_REGNUM, gdb_f31_mips64),
+ DEFINE_FPR (fcsr, NULL, gcc_dwarf_fcsr_mips64, gcc_dwarf_fcsr_mips64, LLDB_INVALID_REGNUM, gdb_fcsr_mips64),
+ DEFINE_FPR (fir, NULL, gcc_dwarf_fir_mips64, gcc_dwarf_fir_mips64, LLDB_INVALID_REGNUM, gdb_fir_mips64),
+ DEFINE_FPR (config5, NULL, gcc_dwarf_config5_mips64, gcc_dwarf_config5_mips64, LLDB_INVALID_REGNUM, gdb_config5_mips64),
+ DEFINE_MSA (w0, NULL, gcc_dwarf_w0_mips64, gcc_dwarf_w0_mips64, LLDB_INVALID_REGNUM, gdb_w0_mips64),
+ DEFINE_MSA (w1, NULL, gcc_dwarf_w1_mips64, gcc_dwarf_w1_mips64, LLDB_INVALID_REGNUM, gdb_w1_mips64),
+ DEFINE_MSA (w2, NULL, gcc_dwarf_w2_mips64, gcc_dwarf_w2_mips64, LLDB_INVALID_REGNUM, gdb_w2_mips64),
+ DEFINE_MSA (w3, NULL, gcc_dwarf_w3_mips64, gcc_dwarf_w3_mips64, LLDB_INVALID_REGNUM, gdb_w3_mips64),
+ DEFINE_MSA (w4, NULL, gcc_dwarf_w4_mips64, gcc_dwarf_w4_mips64, LLDB_INVALID_REGNUM, gdb_w4_mips64),
+ DEFINE_MSA (w5, NULL, gcc_dwarf_w5_mips64, gcc_dwarf_w5_mips64, LLDB_INVALID_REGNUM, gdb_w5_mips64),
+ DEFINE_MSA (w6, NULL, gcc_dwarf_w6_mips64, gcc_dwarf_w6_mips64, LLDB_INVALID_REGNUM, gdb_w6_mips64),
+ DEFINE_MSA (w7, NULL, gcc_dwarf_w7_mips64, gcc_dwarf_w7_mips64, LLDB_INVALID_REGNUM, gdb_w7_mips64),
+ DEFINE_MSA (w8, NULL, gcc_dwarf_w8_mips64, gcc_dwarf_w8_mips64, LLDB_INVALID_REGNUM, gdb_w8_mips64),
+ DEFINE_MSA (w9, NULL, gcc_dwarf_w9_mips64, gcc_dwarf_w9_mips64, LLDB_INVALID_REGNUM, gdb_w9_mips64),
+ DEFINE_MSA (w10, NULL, gcc_dwarf_w10_mips64, gcc_dwarf_w10_mips64, LLDB_INVALID_REGNUM, gdb_w10_mips64),
+ DEFINE_MSA (w11, NULL, gcc_dwarf_w11_mips64, gcc_dwarf_w11_mips64, LLDB_INVALID_REGNUM, gdb_w11_mips64),
+ DEFINE_MSA (w12, NULL, gcc_dwarf_w12_mips64, gcc_dwarf_w12_mips64, LLDB_INVALID_REGNUM, gdb_w12_mips64),
+ DEFINE_MSA (w13, NULL, gcc_dwarf_w13_mips64, gcc_dwarf_w13_mips64, LLDB_INVALID_REGNUM, gdb_w13_mips64),
+ DEFINE_MSA (w14, NULL, gcc_dwarf_w14_mips64, gcc_dwarf_w14_mips64, LLDB_INVALID_REGNUM, gdb_w14_mips64),
+ DEFINE_MSA (w15, NULL, gcc_dwarf_w15_mips64, gcc_dwarf_w15_mips64, LLDB_INVALID_REGNUM, gdb_w15_mips64),
+ DEFINE_MSA (w16, NULL, gcc_dwarf_w16_mips64, gcc_dwarf_w16_mips64, LLDB_INVALID_REGNUM, gdb_w16_mips64),
+ DEFINE_MSA (w17, NULL, gcc_dwarf_w17_mips64, gcc_dwarf_w17_mips64, LLDB_INVALID_REGNUM, gdb_w17_mips64),
+ DEFINE_MSA (w18, NULL, gcc_dwarf_w18_mips64, gcc_dwarf_w18_mips64, LLDB_INVALID_REGNUM, gdb_w18_mips64),
+ DEFINE_MSA (w19, NULL, gcc_dwarf_w19_mips64, gcc_dwarf_w19_mips64, LLDB_INVALID_REGNUM, gdb_w19_mips64),
+ DEFINE_MSA (w20, NULL, gcc_dwarf_w10_mips64, gcc_dwarf_w20_mips64, LLDB_INVALID_REGNUM, gdb_w20_mips64),
+ DEFINE_MSA (w21, NULL, gcc_dwarf_w21_mips64, gcc_dwarf_w21_mips64, LLDB_INVALID_REGNUM, gdb_w21_mips64),
+ DEFINE_MSA (w22, NULL, gcc_dwarf_w22_mips64, gcc_dwarf_w22_mips64, LLDB_INVALID_REGNUM, gdb_w22_mips64),
+ DEFINE_MSA (w23, NULL, gcc_dwarf_w23_mips64, gcc_dwarf_w23_mips64, LLDB_INVALID_REGNUM, gdb_w23_mips64),
+ DEFINE_MSA (w24, NULL, gcc_dwarf_w24_mips64, gcc_dwarf_w24_mips64, LLDB_INVALID_REGNUM, gdb_w24_mips64),
+ DEFINE_MSA (w25, NULL, gcc_dwarf_w25_mips64, gcc_dwarf_w25_mips64, LLDB_INVALID_REGNUM, gdb_w25_mips64),
+ DEFINE_MSA (w26, NULL, gcc_dwarf_w26_mips64, gcc_dwarf_w26_mips64, LLDB_INVALID_REGNUM, gdb_w26_mips64),
+ DEFINE_MSA (w27, NULL, gcc_dwarf_w27_mips64, gcc_dwarf_w27_mips64, LLDB_INVALID_REGNUM, gdb_w27_mips64),
+ DEFINE_MSA (w28, NULL, gcc_dwarf_w28_mips64, gcc_dwarf_w28_mips64, LLDB_INVALID_REGNUM, gdb_w28_mips64),
+ DEFINE_MSA (w29, NULL, gcc_dwarf_w29_mips64, gcc_dwarf_w29_mips64, LLDB_INVALID_REGNUM, gdb_w29_mips64),
+ DEFINE_MSA (w30, NULL, gcc_dwarf_w30_mips64, gcc_dwarf_w30_mips64, LLDB_INVALID_REGNUM, gdb_w30_mips64),
+ DEFINE_MSA (w31, NULL, gcc_dwarf_w31_mips64, gcc_dwarf_w31_mips64, LLDB_INVALID_REGNUM, gdb_w31_mips64),
+ DEFINE_MSA_INFO (mcsr, NULL, gcc_dwarf_mcsr_mips64, gcc_dwarf_mcsr_mips64, LLDB_INVALID_REGNUM, gdb_mcsr_mips64),
+ DEFINE_MSA_INFO (mir, NULL, gcc_dwarf_mir_mips64, gcc_dwarf_mir_mips64, LLDB_INVALID_REGNUM, gdb_mir_mips64),
+ DEFINE_MSA_INFO (fcsr, NULL, gcc_dwarf_fcsr_mips64, gcc_dwarf_fcsr_mips64, LLDB_INVALID_REGNUM, gdb_fcsr_mips64),
+ DEFINE_MSA_INFO (fir, NULL, gcc_dwarf_fir_mips64, gcc_dwarf_fir_mips64, LLDB_INVALID_REGNUM, gdb_fir_mips64),
+ DEFINE_MSA_INFO (config5, NULL, gcc_dwarf_config5_mips64, gcc_dwarf_config5_mips64, LLDB_INVALID_REGNUM, gdb_config5_mips64)
+#endif
+};
+
+static_assert((sizeof(g_register_infos_mips64) / sizeof(g_register_infos_mips64[0])) == k_num_registers_mips64,
+ "g_register_infos_mips64 has wrong number of register infos");
+
+#undef DEFINE_GPR
+#undef DEFINE_GPR_INFO
+#undef DEFINE_FPR
+#undef DEFINE_MSA
+#undef DEFINE_MSA_INFO
+#undef GPR_OFFSET
+#undef FPR_OFFSET
+#undef MSA_OFFSET
+
+#endif // DECLARE_REGISTER_INFOS_MIPS64_STRUCT
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h
new file mode 100644
index 0000000..fe145e9
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h
@@ -0,0 +1,184 @@
+//===-- RegisterInfos_powerpc.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include <stddef.h>
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (offsetof(GPR, regname))
+#define FPR_OFFSET(regname) \
+ (offsetof(FPR, regname))
+#define VMX_OFFSET(regname) \
+ (offsetof(VMX, regname))
+#define GPR_SIZE(regname) \
+ (sizeof(((GPR*)NULL)->regname))
+
+#ifdef DECLARE_REGISTER_INFOS_POWERPC_STRUCT
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, lldb_kind) \
+ { #reg, alt, GPR_SIZE(reg), GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { gcc_dwarf_##reg##_powerpc, gcc_dwarf_##reg##_powerpc, lldb_kind, gdb_##reg##_powerpc, gpr_##reg##_powerpc }, NULL, NULL }
+#define DEFINE_FPR(reg, lldb_kind) \
+ { #reg, NULL, 8, FPR_OFFSET(reg), eEncodingIEEE754, \
+ eFormatFloat, { gcc_dwarf_##reg##_powerpc, gcc_dwarf_##reg##_powerpc, lldb_kind, gdb_##reg##_powerpc, fpr_##reg##_powerpc }, NULL, NULL }
+#define DEFINE_VMX(reg, lldb_kind) \
+ { #reg, NULL, 16, VMX_OFFSET(reg), eEncodingVector, \
+ eFormatVectorOfUInt32, { gcc_dwarf_##reg##_powerpc, gcc_dwarf_##reg##_powerpc, lldb_kind, gdb_##reg##_powerpc, vmx_##reg##_powerpc }, NULL, NULL }
+
+ // General purpose registers. GCC, DWARF, Generic, GDB
+#define POWERPC_REGS \
+ DEFINE_GPR(r0, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r1, "sp", LLDB_REGNUM_GENERIC_SP), \
+ DEFINE_GPR(r2, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r3, "arg1",LLDB_REGNUM_GENERIC_ARG1), \
+ DEFINE_GPR(r4, "arg2",LLDB_REGNUM_GENERIC_ARG2), \
+ DEFINE_GPR(r5, "arg3",LLDB_REGNUM_GENERIC_ARG3), \
+ DEFINE_GPR(r6, "arg4",LLDB_REGNUM_GENERIC_ARG4), \
+ DEFINE_GPR(r7, "arg5",LLDB_REGNUM_GENERIC_ARG5), \
+ DEFINE_GPR(r8, "arg6",LLDB_REGNUM_GENERIC_ARG6), \
+ DEFINE_GPR(r9, "arg7",LLDB_REGNUM_GENERIC_ARG7), \
+ DEFINE_GPR(r10, "arg8",LLDB_REGNUM_GENERIC_ARG8), \
+ DEFINE_GPR(r11, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r12, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r13, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r14, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r15, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r16, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r17, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r18, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r19, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r20, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r21, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r22, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r23, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r24, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r25, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r26, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r27, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r28, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r29, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r30, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(r31, NULL, LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(lr, "lr", LLDB_REGNUM_GENERIC_RA), \
+ DEFINE_GPR(cr, "cr", LLDB_REGNUM_GENERIC_FLAGS), \
+ DEFINE_GPR(xer, "xer", LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(ctr, "ctr", LLDB_INVALID_REGNUM), \
+ DEFINE_GPR(pc, "pc", LLDB_REGNUM_GENERIC_PC), \
+ DEFINE_FPR(f0, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f1, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f2, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f3, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f4, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f5, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f6, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f7, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f8, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f9, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f10, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f11, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f12, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f13, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f14, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f15, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f16, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f17, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f18, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f19, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f20, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f21, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f22, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f23, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f24, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f25, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f26, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f27, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f28, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f29, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f30, LLDB_INVALID_REGNUM), \
+ DEFINE_FPR(f31, LLDB_INVALID_REGNUM), \
+ { "fpscr", NULL, 8, FPR_OFFSET(fpscr), eEncodingUint, eFormatHex, { gcc_dwarf_fpscr_powerpc, gcc_dwarf_fpscr_powerpc, LLDB_INVALID_REGNUM, gdb_fpscr_powerpc, fpr_fpscr_powerpc }, NULL, NULL }, \
+ DEFINE_VMX(v0, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v1, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v2, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v3, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v4, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v5, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v6, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v7, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v8, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v9, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v10, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v11, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v12, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v13, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v14, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v15, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v16, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v17, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v18, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v19, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v20, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v21, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v22, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v23, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v24, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v25, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v26, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v27, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v28, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v29, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v30, LLDB_INVALID_REGNUM), \
+ DEFINE_VMX(v31, LLDB_INVALID_REGNUM), \
+ { "vrsave", NULL, 4, VMX_OFFSET(vrsave), eEncodingUint, eFormatHex, { gcc_dwarf_vrsave_powerpc, gcc_dwarf_vrsave_powerpc, LLDB_INVALID_REGNUM, gdb_vrsave_powerpc, vmx_vrsave_powerpc }, NULL, NULL }, \
+ { "vscr", NULL, 4, VMX_OFFSET(vscr), eEncodingUint, eFormatHex, { gcc_dwarf_vscr_powerpc, gcc_dwarf_vscr_powerpc, LLDB_INVALID_REGNUM, gdb_vscr_powerpc, vmx_vscr_powerpc }, NULL, NULL },
+
+static RegisterInfo
+g_register_infos_powerpc64[] =
+{
+#define GPR GPR64
+ POWERPC_REGS
+#undef GPR
+};
+
+static RegisterInfo
+g_register_infos_powerpc32[] =
+{
+#define GPR GPR32
+ POWERPC_REGS
+#undef GPR
+};
+
+static RegisterInfo
+g_register_infos_powerpc64_32[] =
+{
+#define GPR GPR64
+#undef GPR_SIZE
+#define GPR_SIZE(reg) (sizeof(uint32_t))
+#undef GPR_OFFSET
+#define GPR_OFFSET(regname) \
+ (offsetof(GPR, regname) + (sizeof(((GPR *)NULL)->regname) - GPR_SIZE(reg)))
+ POWERPC_REGS
+#undef GPR
+};
+
+static_assert((sizeof(g_register_infos_powerpc32) / sizeof(g_register_infos_powerpc32[0])) == k_num_registers_powerpc,
+ "g_register_infos_powerpc32 has wrong number of register infos");
+static_assert((sizeof(g_register_infos_powerpc64) / sizeof(g_register_infos_powerpc64[0])) == k_num_registers_powerpc,
+ "g_register_infos_powerpc64 has wrong number of register infos");
+static_assert(sizeof(g_register_infos_powerpc64_32) == sizeof(g_register_infos_powerpc64),
+ "g_register_infos_powerpc64_32 doesn't match size of g_register_infos_powerpc64");
+
+#undef DEFINE_FPR
+#undef DEFINE_GPR
+
+#endif // DECLARE_REGISTER_INFOS_POWERPC_STRUCT
+
+#undef GPR_OFFSET
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
new file mode 100644
index 0000000..5da74ff
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h
@@ -0,0 +1,418 @@
+//===-- RegisterInfos_x86_64.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+#include "llvm/Support/Compiler.h"
+
+#include <stddef.h>
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(GPR, regname))
+
+// Computes the offset of the given FPR in the extended data area.
+#define FPR_OFFSET(regname) \
+ (LLVM_EXTENSION offsetof(UserArea, fpr) + \
+ LLVM_EXTENSION offsetof(FPR, xstate) + \
+ LLVM_EXTENSION offsetof(FXSAVE, regname))
+
+// Computes the offset of the YMM register assembled from register halves.
+// Based on DNBArchImplX86_64.cpp from debugserver
+#define YMM_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, fpr) + \
+ LLVM_EXTENSION offsetof(FPR, xstate) + \
+ LLVM_EXTENSION offsetof(XSAVE, ymmh[0]) + \
+ (32 * reg_index))
+
+#ifdef DECLARE_REGISTER_INFOS_X86_64_STRUCT
+
+// Number of bytes needed to represent a FPR.
+#define FPR_SIZE(reg) sizeof(((FXSAVE*)NULL)->reg)
+
+// Number of bytes needed to represent the i'th FP register.
+#define FP_SIZE sizeof(((MMSReg*)NULL)->bytes)
+
+// Number of bytes needed to represent an XMM register.
+#define XMM_SIZE sizeof(XMMReg)
+
+// Number of bytes needed to represent a YMM register.
+#define YMM_SIZE sizeof(YMMReg)
+
+#define DR_SIZE sizeof(((DBG*)NULL)->dr[0])
+
+// RegisterKind: GCC, DWARF, Generic, GDB, LLDB
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, lldb_##reg##_x86_64 }, NULL, NULL }
+
+#define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \
+ { #name, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, lldb_##name##_x86_64 }, NULL, NULL }
+
+#define DEFINE_FP_ST(reg, i) \
+ { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(stmm[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { gcc_dwarf_st##i##_x86_64, gcc_dwarf_st##i##_x86_64, LLDB_INVALID_REGNUM, gdb_st##i##_x86_64, lldb_st##i##_x86_64 }, \
+ NULL, NULL }
+
+#define DEFINE_FP_MM(reg, i) \
+ { #reg#i, NULL, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \
+ eEncodingUint, eFormatHex, \
+ { gcc_dwarf_mm##i##_x86_64, gcc_dwarf_mm##i##_x86_64, LLDB_INVALID_REGNUM, gdb_st##i##_x86_64, lldb_mm##i##_x86_64 }, \
+ NULL, NULL }
+
+#define DEFINE_XMM(reg, i) \
+ { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { gcc_dwarf_##reg##i##_x86_64, gcc_dwarf_##reg##i##_x86_64, LLDB_INVALID_REGNUM, gdb_##reg##i##_x86_64, lldb_##reg##i##_x86_64}, \
+ NULL, NULL }
+
+#define DEFINE_YMM(reg, i) \
+ { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(i), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { gcc_dwarf_##reg##i##h_x86_64, gcc_dwarf_##reg##i##h_x86_64, LLDB_INVALID_REGNUM, gdb_##reg##i##h_x86_64, lldb_##reg##i##_x86_64 }, \
+ NULL, NULL }
+
+#define DEFINE_DR(reg, i) \
+ { #reg#i, NULL, DR_SIZE, DR_OFFSET(i), eEncodingUint, eFormatHex, \
+ { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }
+
+#define DEFINE_GPR_PSEUDO_32(reg32, reg64) \
+ { #reg32, NULL, 4, GPR_OFFSET(reg64), eEncodingUint, \
+ eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg32##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 }
+#define DEFINE_GPR_PSEUDO_16(reg16, reg64) \
+ { #reg16, NULL, 2, GPR_OFFSET(reg64), eEncodingUint, \
+ eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg16##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 }
+#define DEFINE_GPR_PSEUDO_8H(reg8, reg64) \
+ { #reg8, NULL, 1, GPR_OFFSET(reg64)+1, eEncodingUint, \
+ eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 }
+#define DEFINE_GPR_PSEUDO_8L(reg8, reg64) \
+ { #reg8, NULL, 1, GPR_OFFSET(reg64), eEncodingUint, \
+ eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 }
+
+static RegisterInfo
+g_register_infos_x86_64[] =
+{
+ // General purpose registers. GCC, DWARF, Generic, GDB
+ DEFINE_GPR(rax, NULL, gcc_dwarf_rax_x86_64, gcc_dwarf_rax_x86_64, LLDB_INVALID_REGNUM, gdb_rax_x86_64),
+ DEFINE_GPR(rbx, NULL, gcc_dwarf_rbx_x86_64, gcc_dwarf_rbx_x86_64, LLDB_INVALID_REGNUM, gdb_rbx_x86_64),
+ DEFINE_GPR(rcx, "arg4", gcc_dwarf_rcx_x86_64, gcc_dwarf_rcx_x86_64, LLDB_REGNUM_GENERIC_ARG4, gdb_rcx_x86_64),
+ DEFINE_GPR(rdx, "arg3", gcc_dwarf_rdx_x86_64, gcc_dwarf_rdx_x86_64, LLDB_REGNUM_GENERIC_ARG3, gdb_rdx_x86_64),
+ DEFINE_GPR(rdi, "arg1", gcc_dwarf_rdi_x86_64, gcc_dwarf_rdi_x86_64, LLDB_REGNUM_GENERIC_ARG1, gdb_rdi_x86_64),
+ DEFINE_GPR(rsi, "arg2", gcc_dwarf_rsi_x86_64, gcc_dwarf_rsi_x86_64, LLDB_REGNUM_GENERIC_ARG2, gdb_rsi_x86_64),
+ DEFINE_GPR(rbp, "fp", gcc_dwarf_rbp_x86_64, gcc_dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP, gdb_rbp_x86_64),
+ DEFINE_GPR(rsp, "sp", gcc_dwarf_rsp_x86_64, gcc_dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP, gdb_rsp_x86_64),
+ DEFINE_GPR(r8, "arg5", gcc_dwarf_r8_x86_64, gcc_dwarf_r8_x86_64, LLDB_REGNUM_GENERIC_ARG5, gdb_r8_x86_64),
+ DEFINE_GPR(r9, "arg6", gcc_dwarf_r9_x86_64, gcc_dwarf_r9_x86_64, LLDB_REGNUM_GENERIC_ARG6, gdb_r9_x86_64),
+ DEFINE_GPR(r10, NULL, gcc_dwarf_r10_x86_64, gcc_dwarf_r10_x86_64, LLDB_INVALID_REGNUM, gdb_r10_x86_64),
+ DEFINE_GPR(r11, NULL, gcc_dwarf_r11_x86_64, gcc_dwarf_r11_x86_64, LLDB_INVALID_REGNUM, gdb_r11_x86_64),
+ DEFINE_GPR(r12, NULL, gcc_dwarf_r12_x86_64, gcc_dwarf_r12_x86_64, LLDB_INVALID_REGNUM, gdb_r12_x86_64),
+ DEFINE_GPR(r13, NULL, gcc_dwarf_r13_x86_64, gcc_dwarf_r13_x86_64, LLDB_INVALID_REGNUM, gdb_r13_x86_64),
+ DEFINE_GPR(r14, NULL, gcc_dwarf_r14_x86_64, gcc_dwarf_r14_x86_64, LLDB_INVALID_REGNUM, gdb_r14_x86_64),
+ DEFINE_GPR(r15, NULL, gcc_dwarf_r15_x86_64, gcc_dwarf_r15_x86_64, LLDB_INVALID_REGNUM, gdb_r15_x86_64),
+ DEFINE_GPR(rip, "pc", gcc_dwarf_rip_x86_64, gcc_dwarf_rip_x86_64, LLDB_REGNUM_GENERIC_PC, gdb_rip_x86_64),
+ DEFINE_GPR(rflags, "flags", gcc_dwarf_rflags_x86_64, gcc_dwarf_rflags_x86_64, LLDB_REGNUM_GENERIC_FLAGS, gdb_rflags_x86_64),
+ DEFINE_GPR(cs, NULL, gcc_dwarf_cs_x86_64, gcc_dwarf_cs_x86_64, LLDB_INVALID_REGNUM, gdb_cs_x86_64),
+ DEFINE_GPR(fs, NULL, gcc_dwarf_fs_x86_64, gcc_dwarf_fs_x86_64, LLDB_INVALID_REGNUM, gdb_fs_x86_64),
+ DEFINE_GPR(gs, NULL, gcc_dwarf_gs_x86_64, gcc_dwarf_gs_x86_64, LLDB_INVALID_REGNUM, gdb_gs_x86_64),
+ DEFINE_GPR(ss, NULL, gcc_dwarf_ss_x86_64, gcc_dwarf_ss_x86_64, LLDB_INVALID_REGNUM, gdb_ss_x86_64),
+ DEFINE_GPR(ds, NULL, gcc_dwarf_ds_x86_64, gcc_dwarf_ds_x86_64, LLDB_INVALID_REGNUM, gdb_ds_x86_64),
+ DEFINE_GPR(es, NULL, gcc_dwarf_es_x86_64, gcc_dwarf_es_x86_64, LLDB_INVALID_REGNUM, gdb_es_x86_64),
+
+ DEFINE_GPR_PSEUDO_32(eax, rax),
+ DEFINE_GPR_PSEUDO_32(ebx, rbx),
+ DEFINE_GPR_PSEUDO_32(ecx, rcx),
+ DEFINE_GPR_PSEUDO_32(edx, rdx),
+ DEFINE_GPR_PSEUDO_32(edi, rdi),
+ DEFINE_GPR_PSEUDO_32(esi, rsi),
+ DEFINE_GPR_PSEUDO_32(ebp, rbp),
+ DEFINE_GPR_PSEUDO_32(esp, rsp),
+ DEFINE_GPR_PSEUDO_32(r8d, r8),
+ DEFINE_GPR_PSEUDO_32(r9d, r9),
+ DEFINE_GPR_PSEUDO_32(r10d, r10),
+ DEFINE_GPR_PSEUDO_32(r11d, r11),
+ DEFINE_GPR_PSEUDO_32(r12d, r12),
+ DEFINE_GPR_PSEUDO_32(r13d, r13),
+ DEFINE_GPR_PSEUDO_32(r14d, r14),
+ DEFINE_GPR_PSEUDO_32(r15d, r15),
+ DEFINE_GPR_PSEUDO_16(ax, rax),
+ DEFINE_GPR_PSEUDO_16(bx, rbx),
+ DEFINE_GPR_PSEUDO_16(cx, rcx),
+ DEFINE_GPR_PSEUDO_16(dx, rdx),
+ DEFINE_GPR_PSEUDO_16(di, rdi),
+ DEFINE_GPR_PSEUDO_16(si, rsi),
+ DEFINE_GPR_PSEUDO_16(bp, rbp),
+ DEFINE_GPR_PSEUDO_16(sp, rsp),
+ DEFINE_GPR_PSEUDO_16(r8w, r8),
+ DEFINE_GPR_PSEUDO_16(r9w, r9),
+ DEFINE_GPR_PSEUDO_16(r10w, r10),
+ DEFINE_GPR_PSEUDO_16(r11w, r11),
+ DEFINE_GPR_PSEUDO_16(r12w, r12),
+ DEFINE_GPR_PSEUDO_16(r13w, r13),
+ DEFINE_GPR_PSEUDO_16(r14w, r14),
+ DEFINE_GPR_PSEUDO_16(r15w, r15),
+ DEFINE_GPR_PSEUDO_8H(ah, rax),
+ DEFINE_GPR_PSEUDO_8H(bh, rbx),
+ DEFINE_GPR_PSEUDO_8H(ch, rcx),
+ DEFINE_GPR_PSEUDO_8H(dh, rdx),
+ DEFINE_GPR_PSEUDO_8L(al, rax),
+ DEFINE_GPR_PSEUDO_8L(bl, rbx),
+ DEFINE_GPR_PSEUDO_8L(cl, rcx),
+ DEFINE_GPR_PSEUDO_8L(dl, rdx),
+ DEFINE_GPR_PSEUDO_8L(dil, rdi),
+ DEFINE_GPR_PSEUDO_8L(sil, rsi),
+ DEFINE_GPR_PSEUDO_8L(bpl, rbp),
+ DEFINE_GPR_PSEUDO_8L(spl, rsp),
+ DEFINE_GPR_PSEUDO_8L(r8l, r8),
+ DEFINE_GPR_PSEUDO_8L(r9l, r9),
+ DEFINE_GPR_PSEUDO_8L(r10l, r10),
+ DEFINE_GPR_PSEUDO_8L(r11l, r11),
+ 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. GCC, DWARF, Generic, GDB
+ DEFINE_FPR(fctrl, fctrl, gcc_dwarf_fctrl_x86_64, gcc_dwarf_fctrl_x86_64, LLDB_INVALID_REGNUM, gdb_fctrl_x86_64),
+ DEFINE_FPR(fstat, fstat, gcc_dwarf_fstat_x86_64, gcc_dwarf_fstat_x86_64, LLDB_INVALID_REGNUM, gdb_fstat_x86_64),
+ DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftag_x86_64),
+ DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop_x86_64),
+ DEFINE_FPR(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fiseg_x86_64),
+ DEFINE_FPR(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fioff_x86_64),
+ DEFINE_FPR(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_foseg_x86_64),
+ DEFINE_FPR(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fooff_x86_64),
+ DEFINE_FPR(mxcsr, mxcsr, gcc_dwarf_mxcsr_x86_64, gcc_dwarf_mxcsr_x86_64, LLDB_INVALID_REGNUM, gdb_mxcsr_x86_64),
+ 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),
+
+ // XMM registers
+ DEFINE_XMM(xmm, 0),
+ DEFINE_XMM(xmm, 1),
+ DEFINE_XMM(xmm, 2),
+ DEFINE_XMM(xmm, 3),
+ DEFINE_XMM(xmm, 4),
+ DEFINE_XMM(xmm, 5),
+ DEFINE_XMM(xmm, 6),
+ DEFINE_XMM(xmm, 7),
+ DEFINE_XMM(xmm, 8),
+ DEFINE_XMM(xmm, 9),
+ DEFINE_XMM(xmm, 10),
+ DEFINE_XMM(xmm, 11),
+ DEFINE_XMM(xmm, 12),
+ DEFINE_XMM(xmm, 13),
+ DEFINE_XMM(xmm, 14),
+ DEFINE_XMM(xmm, 15),
+
+ // Copy of YMM registers assembled from xmm and ymmh
+ DEFINE_YMM(ymm, 0),
+ DEFINE_YMM(ymm, 1),
+ DEFINE_YMM(ymm, 2),
+ DEFINE_YMM(ymm, 3),
+ DEFINE_YMM(ymm, 4),
+ DEFINE_YMM(ymm, 5),
+ DEFINE_YMM(ymm, 6),
+ DEFINE_YMM(ymm, 7),
+ DEFINE_YMM(ymm, 8),
+ DEFINE_YMM(ymm, 9),
+ DEFINE_YMM(ymm, 10),
+ DEFINE_YMM(ymm, 11),
+ DEFINE_YMM(ymm, 12),
+ DEFINE_YMM(ymm, 13),
+ DEFINE_YMM(ymm, 14),
+ DEFINE_YMM(ymm, 15),
+
+ // Debug registers for lldb internal use
+ DEFINE_DR(dr, 0),
+ DEFINE_DR(dr, 1),
+ DEFINE_DR(dr, 2),
+ DEFINE_DR(dr, 3),
+ DEFINE_DR(dr, 4),
+ DEFINE_DR(dr, 5),
+ DEFINE_DR(dr, 6),
+ DEFINE_DR(dr, 7)
+};
+static_assert((sizeof(g_register_infos_x86_64) / sizeof(g_register_infos_x86_64[0])) == k_num_registers_x86_64,
+ "g_register_infos_x86_64 has wrong number of register infos");
+
+#undef FPR_SIZE
+#undef FP_SIZE
+#undef XMM_SIZE
+#undef YMM_SIZE
+#undef DEFINE_GPR
+#undef DEFINE_FPR
+#undef DEFINE_FP
+#undef DEFINE_XMM
+#undef DEFINE_YMM
+#undef DEFINE_DR
+#undef DEFINE_GPR_PSEUDO_32
+#undef DEFINE_GPR_PSEUDO_16
+#undef DEFINE_GPR_PSEUDO_8H
+#undef DEFINE_GPR_PSEUDO_8L
+
+#endif // DECLARE_REGISTER_INFOS_X86_64_STRUCT
+
+
+#ifdef UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+
+#define UPDATE_GPR_INFO(reg, reg64) \
+do { \
+ g_register_infos[lldb_##reg##_i386].byte_offset = GPR_OFFSET(reg64); \
+} while(false);
+
+#define UPDATE_GPR_INFO_8H(reg, reg64) \
+do { \
+ g_register_infos[lldb_##reg##_i386].byte_offset = GPR_OFFSET(reg64) + 1; \
+} while(false);
+
+#define UPDATE_FPR_INFO(reg, reg64) \
+do { \
+ g_register_infos[lldb_##reg##_i386].byte_offset = FPR_OFFSET(reg64); \
+} while(false);
+
+#define UPDATE_FP_INFO(reg, i) \
+do { \
+ g_register_infos[lldb_##reg##i##_i386].byte_offset = FPR_OFFSET(stmm[i]); \
+} while(false);
+
+#define UPDATE_XMM_INFO(reg, i) \
+do { \
+ g_register_infos[lldb_##reg##i##_i386].byte_offset = FPR_OFFSET(reg[i]); \
+} while(false);
+
+#define UPDATE_YMM_INFO(reg, i) \
+do { \
+ g_register_infos[lldb_##reg##i##_i386].byte_offset = YMM_OFFSET(i); \
+} while(false);
+
+#define UPDATE_DR_INFO(reg_index) \
+do { \
+ g_register_infos[lldb_dr##reg_index##_i386].byte_offset = DR_OFFSET(reg_index); \
+} while(false);
+
+ // Update the register offsets
+ UPDATE_GPR_INFO(eax, rax);
+ UPDATE_GPR_INFO(ebx, rbx);
+ UPDATE_GPR_INFO(ecx, rcx);
+ UPDATE_GPR_INFO(edx, rdx);
+ UPDATE_GPR_INFO(edi, rdi);
+ UPDATE_GPR_INFO(esi, rsi);
+ UPDATE_GPR_INFO(ebp, rbp);
+ UPDATE_GPR_INFO(esp, rsp);
+ UPDATE_GPR_INFO(eip, rip);
+ UPDATE_GPR_INFO(eflags, rflags);
+ UPDATE_GPR_INFO(cs, cs);
+ UPDATE_GPR_INFO(fs, fs);
+ UPDATE_GPR_INFO(gs, gs);
+ UPDATE_GPR_INFO(ss, ss);
+ UPDATE_GPR_INFO(ds, ds);
+ UPDATE_GPR_INFO(es, es);
+
+ UPDATE_GPR_INFO(ax, rax);
+ UPDATE_GPR_INFO(bx, rbx);
+ UPDATE_GPR_INFO(cx, rcx);
+ UPDATE_GPR_INFO(dx, rdx);
+ UPDATE_GPR_INFO(di, rdi);
+ UPDATE_GPR_INFO(si, rsi);
+ UPDATE_GPR_INFO(bp, rbp);
+ UPDATE_GPR_INFO(sp, rsp);
+ UPDATE_GPR_INFO_8H(ah, rax);
+ UPDATE_GPR_INFO_8H(bh, rbx);
+ UPDATE_GPR_INFO_8H(ch, rcx);
+ UPDATE_GPR_INFO_8H(dh, rdx);
+ UPDATE_GPR_INFO(al, rax);
+ UPDATE_GPR_INFO(bl, rbx);
+ UPDATE_GPR_INFO(cl, rcx);
+ UPDATE_GPR_INFO(dl, rdx);
+
+ UPDATE_FPR_INFO(fctrl, fctrl);
+ UPDATE_FPR_INFO(fstat, fstat);
+ UPDATE_FPR_INFO(ftag, ftag);
+ UPDATE_FPR_INFO(fop, fop);
+ UPDATE_FPR_INFO(fiseg, ptr.i386_.fiseg);
+ UPDATE_FPR_INFO(fioff, ptr.i386_.fioff);
+ UPDATE_FPR_INFO(fooff, ptr.i386_.fooff);
+ UPDATE_FPR_INFO(foseg, ptr.i386_.foseg);
+ UPDATE_FPR_INFO(mxcsr, mxcsr);
+ UPDATE_FPR_INFO(mxcsrmask, mxcsrmask);
+
+ UPDATE_FP_INFO(st, 0);
+ UPDATE_FP_INFO(st, 1);
+ UPDATE_FP_INFO(st, 2);
+ UPDATE_FP_INFO(st, 3);
+ UPDATE_FP_INFO(st, 4);
+ UPDATE_FP_INFO(st, 5);
+ UPDATE_FP_INFO(st, 6);
+ UPDATE_FP_INFO(st, 7);
+ UPDATE_FP_INFO(mm, 0);
+ UPDATE_FP_INFO(mm, 1);
+ UPDATE_FP_INFO(mm, 2);
+ UPDATE_FP_INFO(mm, 3);
+ UPDATE_FP_INFO(mm, 4);
+ UPDATE_FP_INFO(mm, 5);
+ UPDATE_FP_INFO(mm, 6);
+ UPDATE_FP_INFO(mm, 7);
+
+ UPDATE_XMM_INFO(xmm, 0);
+ UPDATE_XMM_INFO(xmm, 1);
+ UPDATE_XMM_INFO(xmm, 2);
+ UPDATE_XMM_INFO(xmm, 3);
+ UPDATE_XMM_INFO(xmm, 4);
+ UPDATE_XMM_INFO(xmm, 5);
+ UPDATE_XMM_INFO(xmm, 6);
+ UPDATE_XMM_INFO(xmm, 7);
+
+ UPDATE_YMM_INFO(ymm, 0);
+ UPDATE_YMM_INFO(ymm, 1);
+ UPDATE_YMM_INFO(ymm, 2);
+ UPDATE_YMM_INFO(ymm, 3);
+ UPDATE_YMM_INFO(ymm, 4);
+ UPDATE_YMM_INFO(ymm, 5);
+ UPDATE_YMM_INFO(ymm, 6);
+ UPDATE_YMM_INFO(ymm, 7);
+
+ UPDATE_DR_INFO(0);
+ UPDATE_DR_INFO(1);
+ UPDATE_DR_INFO(2);
+ UPDATE_DR_INFO(3);
+ UPDATE_DR_INFO(4);
+ UPDATE_DR_INFO(5);
+ UPDATE_DR_INFO(6);
+ UPDATE_DR_INFO(7);
+
+#undef UPDATE_GPR_INFO
+#undef UPDATE_GPR_INFO_8H
+#undef UPDATE_FPR_INFO
+#undef UPDATE_FP_INFO
+#undef UPDATE_XMM_INFO
+#undef UPDATE_YMM_INFO
+#undef UPDATE_DR_INFO
+
+#endif // UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS
+
+#undef GPR_OFFSET
+#undef FPR_OFFSET
+#undef YMM_OFFSET
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
new file mode 100644
index 0000000..7c68d0d
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
@@ -0,0 +1,529 @@
+//===-- StopInfoMachException.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StopInfoMachException.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/UnixSignals.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *
+StopInfoMachException::GetDescription ()
+{
+ if (m_description.empty() && m_value != 0)
+ {
+ ExecutionContext exe_ctx (m_thread_wp.lock());
+ Target *target = exe_ctx.GetTargetPtr();
+ const llvm::Triple::ArchType cpu = target ? target->GetArchitecture().GetMachine() : llvm::Triple::UnknownArch;
+
+ const char *exc_desc = NULL;
+ const char *code_label = "code";
+ const char *code_desc = NULL;
+ const char *subcode_label = "subcode";
+ const char *subcode_desc = NULL;
+ switch (m_value)
+ {
+ case 1: // EXC_BAD_ACCESS
+ exc_desc = "EXC_BAD_ACCESS";
+ subcode_label = "address";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code)
+ {
+ case 0xd: code_desc = "EXC_I386_GPFLT"; m_exc_data_count = 1; break;
+ }
+ break;
+ case llvm::Triple::arm:
+ switch (m_exc_code)
+ {
+ case 0x101: code_desc = "EXC_ARM_DA_ALIGN"; break;
+ case 0x102: code_desc = "EXC_ARM_DA_DEBUG"; break;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 0x101: code_desc = "EXC_PPC_VM_PROT_READ"; break;
+ case 0x102: code_desc = "EXC_PPC_BADSPACE"; break;
+ case 0x103: code_desc = "EXC_PPC_UNALIGNED"; break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 2: // EXC_BAD_INSTRUCTION
+ exc_desc = "EXC_BAD_INSTRUCTION";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (m_exc_code == 1)
+ code_desc = "EXC_I386_INVOP";
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_PPC_INVALID_SYSCALL"; break;
+ case 2: code_desc = "EXC_PPC_UNIPL_INST"; break;
+ case 3: code_desc = "EXC_PPC_PRIVINST"; break;
+ case 4: code_desc = "EXC_PPC_PRIVREG"; break;
+ case 5: code_desc = "EXC_PPC_TRACE"; break;
+ case 6: code_desc = "EXC_PPC_PERFMON"; break;
+ }
+ break;
+
+ case llvm::Triple::arm:
+ if (m_exc_code == 1)
+ code_desc = "EXC_ARM_UNDEFINED";
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 3: // EXC_ARITHMETIC
+ exc_desc = "EXC_ARITHMETIC";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_I386_DIV"; break;
+ case 2: code_desc = "EXC_I386_INTO"; break;
+ case 3: code_desc = "EXC_I386_NOEXT"; break;
+ case 4: code_desc = "EXC_I386_EXTOVR"; break;
+ case 5: code_desc = "EXC_I386_EXTERR"; break;
+ case 6: code_desc = "EXC_I386_EMERR"; break;
+ case 7: code_desc = "EXC_I386_BOUND"; break;
+ case 8: code_desc = "EXC_I386_SSEEXTERR"; break;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_PPC_OVERFLOW"; break;
+ case 2: code_desc = "EXC_PPC_ZERO_DIVIDE"; break;
+ case 3: code_desc = "EXC_PPC_FLT_INEXACT"; break;
+ case 4: code_desc = "EXC_PPC_FLT_ZERO_DIVIDE"; break;
+ case 5: code_desc = "EXC_PPC_FLT_UNDERFLOW"; break;
+ case 6: code_desc = "EXC_PPC_FLT_OVERFLOW"; break;
+ case 7: code_desc = "EXC_PPC_FLT_NOT_A_NUMBER"; break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 4: // EXC_EMULATION
+ exc_desc = "EXC_EMULATION";
+ break;
+
+
+ case 5: // EXC_SOFTWARE
+ exc_desc = "EXC_SOFTWARE";
+ if (m_exc_code == 0x10003)
+ {
+ subcode_desc = "EXC_SOFT_SIGNAL";
+ subcode_label = "signo";
+ }
+ break;
+
+ case 6: // EXC_BREAKPOINT
+ {
+ exc_desc = "EXC_BREAKPOINT";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_I386_SGL"; break;
+ case 2: code_desc = "EXC_I386_BPT"; break;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_PPC_BREAKPOINT"; break;
+ }
+ break;
+
+ case llvm::Triple::arm:
+ switch (m_exc_code)
+ {
+ case 0x101: code_desc = "EXC_ARM_DA_ALIGN"; break;
+ case 0x102: code_desc = "EXC_ARM_DA_DEBUG"; break;
+ case 1: code_desc = "EXC_ARM_BREAKPOINT"; break;
+ // FIXME temporary workaround, exc_code 0 does not really mean EXC_ARM_BREAKPOINT
+ case 0: code_desc = "EXC_ARM_BREAKPOINT"; break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case 7:
+ exc_desc = "EXC_SYSCALL";
+ break;
+
+ case 8:
+ exc_desc = "EXC_MACH_SYSCALL";
+ break;
+
+ case 9:
+ exc_desc = "EXC_RPC_ALERT";
+ break;
+
+ case 10:
+ exc_desc = "EXC_CRASH";
+ break;
+ case 11:
+ exc_desc = "EXC_RESOURCE";
+ break;
+ case 12:
+ exc_desc = "EXC_GUARD";
+ break;
+ }
+
+ StreamString strm;
+
+ if (exc_desc)
+ strm.PutCString(exc_desc);
+ else
+ strm.Printf("EXC_??? (%" PRIu64 ")", m_value);
+
+ if (m_exc_data_count >= 1)
+ {
+ if (code_desc)
+ strm.Printf(" (%s=%s", code_label, code_desc);
+ else
+ strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code);
+ }
+
+ if (m_exc_data_count >= 2)
+ {
+ if (subcode_desc)
+ strm.Printf(", %s=%s", subcode_label, subcode_desc);
+ else
+ strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode);
+ }
+
+ if (m_exc_data_count > 0)
+ strm.PutChar(')');
+
+ m_description.swap (strm.GetString());
+ }
+ return m_description.c_str();
+}
+
+
+
+
+
+StopInfoSP
+StopInfoMachException::CreateStopReasonWithMachException
+(
+ Thread &thread,
+ uint32_t exc_type,
+ uint32_t exc_data_count,
+ uint64_t exc_code,
+ uint64_t exc_sub_code,
+ uint64_t exc_sub_sub_code,
+ bool pc_already_adjusted,
+ bool adjust_pc_if_needed
+)
+{
+ if (exc_type != 0)
+ {
+ uint32_t pc_decrement = 0;
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ const llvm::Triple::ArchType cpu = target ? target->GetArchitecture().GetMachine() : llvm::Triple::UnknownArch;
+
+ switch (exc_type)
+ {
+ case 1: // EXC_BAD_ACCESS
+ break;
+
+ case 2: // EXC_BAD_INSTRUCTION
+ switch (cpu)
+ {
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (exc_code)
+ {
+ case 1: // EXC_PPC_INVALID_SYSCALL
+ case 2: // EXC_PPC_UNIPL_INST
+ case 3: // EXC_PPC_PRIVINST
+ case 4: // EXC_PPC_PRIVREG
+ break;
+ case 5: // EXC_PPC_TRACE
+ return StopInfo::CreateStopReasonToTrace (thread);
+ case 6: // EXC_PPC_PERFMON
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 3: // EXC_ARITHMETIC
+ case 4: // EXC_EMULATION
+ break;
+
+ case 5: // EXC_SOFTWARE
+ if (exc_code == 0x10003) // EXC_SOFT_SIGNAL
+ {
+ if (exc_sub_code == 5)
+ {
+ // On MacOSX, a SIGTRAP can signify that a process has called
+ // exec, so we should check with our dynamic loader to verify.
+ ProcessSP process_sp (thread.GetProcess());
+ if (process_sp)
+ {
+ DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader();
+ if (dynamic_loader && dynamic_loader->ProcessDidExec())
+ {
+ // The program was re-exec'ed
+ return StopInfo::CreateStopReasonWithExec (thread);
+ }
+// if (!process_did_exec)
+// {
+// // We have a SIGTRAP, make sure we didn't exec by checking
+// // for the PC being at "_dyld_start"...
+// lldb::StackFrameSP frame_sp (thread.GetStackFrameAtIndex(0));
+// if (frame_sp)
+// {
+// const Symbol *symbol = frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol;
+// if (symbol)
+// {
+// if (symbol->GetName() == ConstString("_dyld_start"))
+// process_did_exec = true;
+// }
+// }
+// }
+ }
+ }
+ return StopInfo::CreateStopReasonWithSignal (thread, exc_sub_code);
+ }
+ break;
+
+ case 6: // EXC_BREAKPOINT
+ {
+ bool is_actual_breakpoint = false;
+ bool is_trace_if_actual_breakpoint_missing = false;
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (exc_code == 1) // EXC_I386_SGL
+ {
+ if (!exc_sub_code)
+ {
+ // This looks like a plain trap.
+ // Have to check if there is a breakpoint here as well. When you single-step onto a trap,
+ // the single step stops you not to trap. Since we also do that check below, let's just use
+ // that logic.
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
+ else
+ {
+
+ // It's a watchpoint, then.
+ // The exc_sub_code indicates the data break address.
+ lldb::WatchpointSP wp_sp;
+ if (target)
+ wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
+ if (wp_sp && wp_sp->IsEnabled())
+ {
+ // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data.
+ // Set the hardware index if that's the case.
+ if (exc_data_count >=3)
+ wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
+ return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
+ }
+ }
+ }
+ else if (exc_code == 2 || // EXC_I386_BPT
+ exc_code == 3) // EXC_I386_BPTFLT
+ {
+ // KDP returns EXC_I386_BPTFLT for trace breakpoints
+ if (exc_code == 3)
+ is_trace_if_actual_breakpoint_missing = true;
+
+ is_actual_breakpoint = true;
+ if (!pc_already_adjusted)
+ pc_decrement = 1;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ is_actual_breakpoint = exc_code == 1; // EXC_PPC_BREAKPOINT
+ break;
+
+ case llvm::Triple::arm:
+ if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
+ {
+ // It's a watchpoint, then, if the exc_sub_code indicates a known/enabled
+ // data break address from our watchpoint list.
+ lldb::WatchpointSP wp_sp;
+ if (target)
+ wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
+ if (wp_sp && wp_sp->IsEnabled())
+ {
+ // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data.
+ // Set the hardware index if that's the case.
+ if (exc_data_count >=3)
+ wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
+ return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
+ }
+ else
+ {
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
+ }
+ else if (exc_code == 1) // EXC_ARM_BREAKPOINT
+ {
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
+ else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel is currently returning this so accept it as indicating a breakpoint until the kernel is fixed
+ {
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
+ break;
+
+ case llvm::Triple::aarch64:
+ {
+ if (exc_code == 1 && exc_sub_code == 0) // EXC_ARM_BREAKPOINT
+ {
+ // This is hit when we single instruction step aka MDSCR_EL1 SS bit 0 is set
+ return StopInfo::CreateStopReasonToTrace(thread);
+ }
+ if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
+ {
+ // It's a watchpoint, then, if the exc_sub_code indicates a known/enabled
+ // data break address from our watchpoint list.
+ lldb::WatchpointSP wp_sp;
+ if (target)
+ wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
+ if (wp_sp && wp_sp->IsEnabled())
+ {
+ // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data.
+ // Set the hardware index if that's the case.
+ if (exc_data_count >= 3)
+ wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
+ return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
+ }
+ // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as EXC_BAD_ACCESS
+ if (thread.GetTemporaryResumeState() == eStateStepping)
+ return StopInfo::CreateStopReasonToTrace(thread);
+ }
+ // It looks like exc_sub_code has the 4 bytes of the instruction that triggered the
+ // exception, i.e. our breakpoint opcode
+ is_actual_breakpoint = exc_code == 1;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (is_actual_breakpoint)
+ {
+ RegisterContextSP reg_ctx_sp (thread.GetRegisterContext());
+ addr_t pc = reg_ctx_sp->GetPC() - pc_decrement;
+
+ ProcessSP process_sp (thread.CalculateProcess());
+
+ lldb::BreakpointSiteSP bp_site_sp;
+ if (process_sp)
+ bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc);
+ if (bp_site_sp && bp_site_sp->IsEnabled())
+ {
+ // Update the PC if we were asked to do so, but only do
+ // so if we find a breakpoint that we know about cause
+ // this could be a trap instruction in the code
+ if (pc_decrement > 0 && adjust_pc_if_needed)
+ reg_ctx_sp->SetPC (pc);
+
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ // If we have an operating system plug-in, we might have set a thread specific breakpoint using the
+ // operating system thread ID, so we can't make any assumptions about the thread ID so we must always
+ // report the breakpoint regardless of the thread.
+ if (bp_site_sp->ValidForThisThread (&thread) || thread.GetProcess()->GetOperatingSystem () != NULL)
+ return StopInfo::CreateStopReasonWithBreakpointSiteID (thread, bp_site_sp->GetID());
+ else
+ return StopInfoSP();
+ }
+
+ // Don't call this a trace if we weren't single stepping this thread.
+ if (is_trace_if_actual_breakpoint_missing && thread.GetTemporaryResumeState() == eStateStepping)
+ {
+ return StopInfo::CreateStopReasonToTrace (thread);
+ }
+ }
+ }
+ break;
+
+ case 7: // EXC_SYSCALL
+ case 8: // EXC_MACH_SYSCALL
+ case 9: // EXC_RPC_ALERT
+ case 10: // EXC_CRASH
+ break;
+ }
+
+ return StopInfoSP(new StopInfoMachException (thread, exc_type, exc_data_count, exc_code, exc_sub_code));
+ }
+ return StopInfoSP();
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.h
new file mode 100644
index 0000000..130ee0b
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/StopInfoMachException.h
@@ -0,0 +1,77 @@
+//===-- StopInfoMachException.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_StopInfoMachException_h_
+#define liblldb_StopInfoMachException_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/StopInfo.h"
+
+namespace lldb_private {
+
+class StopInfoMachException : public StopInfo
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StopInfoMachException (Thread &thread,
+ uint32_t exc_type,
+ uint32_t exc_data_count,
+ uint64_t exc_code,
+ uint64_t exc_subcode) :
+ StopInfo (thread, exc_type),
+ m_exc_data_count (exc_data_count),
+ m_exc_code (exc_code),
+ m_exc_subcode (exc_subcode)
+ {
+ }
+
+ virtual ~StopInfoMachException()
+ {
+ }
+
+
+ virtual lldb::StopReason
+ GetStopReason () const
+ {
+ return lldb::eStopReasonException;
+ }
+
+ virtual const char *
+ GetDescription ();
+
+ // Since some mach exceptions will be reported as breakpoints, signals,
+ // or trace, we use this static accessor which will translate the mach
+ // exception into the correct StopInfo.
+ static lldb::StopInfoSP
+ CreateStopReasonWithMachException (Thread &thread,
+ uint32_t exc_type,
+ uint32_t exc_data_count,
+ uint64_t exc_code,
+ uint64_t exc_sub_code,
+ uint64_t exc_sub_sub_code,
+ bool pc_already_adjusted = true,
+ bool adjust_pc_if_needed = false);
+
+protected:
+ uint32_t m_exc_data_count;
+ uint64_t m_exc_code;
+ uint64_t m_exc_subcode;
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_StopInfoMachException_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
new file mode 100644
index 0000000..6a7aa62
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp
@@ -0,0 +1,140 @@
+//===-- ThreadMemory.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Process/Utility/ThreadMemory.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Unwind.h"
+#include "Plugins/Process/Utility/RegisterContextThreadMemory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ThreadMemory::ThreadMemory (Process &process,
+ tid_t tid,
+ const ValueObjectSP &thread_info_valobj_sp) :
+ Thread (process, tid),
+ m_backing_thread_sp (),
+ m_thread_info_valobj_sp (thread_info_valobj_sp),
+ m_name(),
+ m_queue()
+{
+}
+
+
+ThreadMemory::ThreadMemory (Process &process,
+ lldb::tid_t tid,
+ const char *name,
+ const char *queue,
+ lldb::addr_t register_data_addr) :
+ Thread (process, tid),
+ m_backing_thread_sp (),
+ m_thread_info_valobj_sp (),
+ m_name(),
+ m_queue(),
+ m_register_data_addr (register_data_addr)
+{
+ if (name)
+ m_name = name;
+ if (queue)
+ m_queue = queue;
+}
+
+
+ThreadMemory::~ThreadMemory()
+{
+ DestroyThread();
+}
+
+void
+ThreadMemory::WillResume (StateType resume_state)
+{
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->WillResume(resume_state);
+}
+
+void
+ThreadMemory::ClearStackFrames ()
+{
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->ClearStackFrames();
+ Thread::ClearStackFrames();
+}
+
+RegisterContextSP
+ThreadMemory::GetRegisterContext ()
+{
+ if (!m_reg_context_sp)
+ m_reg_context_sp.reset (new RegisterContextThreadMemory (*this, m_register_data_addr));
+ return m_reg_context_sp;
+}
+
+RegisterContextSP
+ThreadMemory::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex ();
+
+ if (concrete_frame_idx == 0)
+ {
+ reg_ctx_sp = GetRegisterContext ();
+ }
+ else
+ {
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ reg_ctx_sp = unwinder->CreateRegisterContextForFrame (frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool
+ThreadMemory::CalculateStopInfo ()
+{
+ if (m_backing_thread_sp)
+ {
+ lldb::StopInfoSP backing_stop_info_sp (m_backing_thread_sp->GetPrivateStopInfo());
+ if (backing_stop_info_sp && backing_stop_info_sp->IsValidForOperatingSystemThread(*this))
+ {
+ backing_stop_info_sp->SetThread (shared_from_this());
+ SetStopInfo (backing_stop_info_sp);
+ return true;
+ }
+ }
+ else
+ {
+ ProcessSP process_sp (GetProcess());
+
+ if (process_sp)
+ {
+ OperatingSystem *os = process_sp->GetOperatingSystem ();
+ if (os)
+ {
+ SetStopInfo (os->CreateThreadStopReason (this));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void
+ThreadMemory::RefreshStateAfterStop()
+{
+ if (m_backing_thread_sp)
+ return m_backing_thread_sp->RefreshStateAfterStop();
+
+ if (m_reg_context_sp)
+ m_reg_context_sp->InvalidateAllRegisters();
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.h
new file mode 100644
index 0000000..07eb45d
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/ThreadMemory.h
@@ -0,0 +1,152 @@
+//===-- ThreadMemory.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ThreadMemory_h_
+#define liblldb_ThreadMemory_h_
+
+#include "lldb/Target/Thread.h"
+
+class ThreadMemory :
+ public lldb_private::Thread
+{
+public:
+
+ ThreadMemory (lldb_private::Process &process,
+ lldb::tid_t tid,
+ const lldb::ValueObjectSP &thread_info_valobj_sp);
+
+ ThreadMemory (lldb_private::Process &process,
+ lldb::tid_t tid,
+ const char *name,
+ const char *queue,
+ lldb::addr_t register_data_addr);
+
+ virtual
+ ~ThreadMemory();
+
+ //------------------------------------------------------------------
+ // lldb_private::Thread methods
+ //------------------------------------------------------------------
+ virtual lldb::RegisterContextSP
+ GetRegisterContext ();
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ virtual bool
+ CalculateStopInfo ();
+
+ virtual const char *
+ GetInfo ()
+ {
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->GetInfo();
+ return NULL;
+ }
+
+ virtual const char *
+ GetName ()
+ {
+ if (!m_name.empty())
+ return m_name.c_str();
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->GetName();
+ return NULL;
+ }
+
+ virtual const char *
+ GetQueueName ()
+ {
+ if (!m_queue.empty())
+ return m_queue.c_str();
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->GetQueueName();
+ return NULL;
+ }
+
+ virtual void
+ WillResume (lldb::StateType resume_state);
+
+ virtual void
+ DidResume ()
+ {
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->DidResume();
+ }
+
+ virtual lldb::user_id_t
+ GetProtocolID () const
+ {
+ if (m_backing_thread_sp)
+ return m_backing_thread_sp->GetProtocolID();
+ return Thread::GetProtocolID();
+ }
+
+ virtual void
+ RefreshStateAfterStop();
+
+ lldb::ValueObjectSP &
+ GetValueObject ()
+ {
+ return m_thread_info_valobj_sp;
+ }
+
+ virtual void
+ ClearStackFrames ();
+
+ virtual void
+ ClearBackingThread ()
+ {
+ m_backing_thread_sp.reset();
+ }
+
+ virtual bool
+ SetBackingThread (const lldb::ThreadSP &thread_sp)
+ {
+ //printf ("Thread 0x%llx is being backed by thread 0x%llx\n", GetID(), thread_sp->GetID());
+ m_backing_thread_sp = thread_sp;
+ return (bool)thread_sp;
+ }
+
+ virtual lldb::ThreadSP
+ GetBackingThread () const
+ {
+ return m_backing_thread_sp;
+ }
+
+protected:
+
+ virtual bool
+ IsOperatingSystemPluginThread () const
+ {
+ return true;
+ }
+
+
+ //------------------------------------------------------------------
+ // For ThreadMemory and subclasses
+ //------------------------------------------------------------------
+ // If this memory thread is actually represented by a thread from the
+ // lldb_private::Process subclass, then fill in the thread here and
+ // all APIs will be routed through this thread object. If m_backing_thread_sp
+ // is empty, then this thread is simply in memory with no representation
+ // through the process plug-in.
+ lldb::ThreadSP m_backing_thread_sp;
+ lldb::ValueObjectSP m_thread_info_valobj_sp;
+ std::string m_name;
+ std::string m_queue;
+ lldb::addr_t m_register_data_addr;
+private:
+ //------------------------------------------------------------------
+ // For ThreadMemory only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ThreadMemory);
+};
+
+#endif // liblldb_ThreadMemory_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp
new file mode 100644
index 0000000..1cdae90
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp
@@ -0,0 +1,451 @@
+//===-- UnwindLLDB.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "UnwindLLDB.h"
+#include "RegisterContextLLDB.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindLLDB::UnwindLLDB (Thread &thread) :
+ Unwind (thread),
+ m_frames(),
+ m_unwind_complete(false),
+ m_user_supplied_trap_handler_functions()
+{
+ ProcessSP process_sp(thread.GetProcess());
+ if (process_sp)
+ {
+ Args args;
+ process_sp->GetTarget().GetUserSpecifiedTrapHandlerNames (args);
+ size_t count = args.GetArgumentCount();
+ for (size_t i = 0; i < count; i++)
+ {
+ const char *func_name = args.GetArgumentAtIndex(i);
+ m_user_supplied_trap_handler_functions.push_back (ConstString (func_name));
+ }
+ }
+}
+
+uint32_t
+UnwindLLDB::DoGetFrameCount()
+{
+ if (!m_unwind_complete)
+ {
+//#define DEBUG_FRAME_SPEED 1
+#if DEBUG_FRAME_SPEED
+#define FRAME_COUNT 10000
+ TimeValue time_value (TimeValue::Now());
+#endif
+ if (!AddFirstFrame ())
+ return 0;
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+
+ while (AddOneMoreFrame (abi))
+ {
+#if DEBUG_FRAME_SPEED
+ if ((m_frames.size() % FRAME_COUNT) == 0)
+ {
+ TimeValue now(TimeValue::Now());
+ uint64_t delta_t = now - time_value;
+ printf ("%u frames in %" PRIu64 ".%09llu ms (%g frames/sec)\n",
+ FRAME_COUNT,
+ delta_t / TimeValue::NanoSecPerSec,
+ delta_t % TimeValue::NanoSecPerSec,
+ (float)FRAME_COUNT / ((float)delta_t / (float)TimeValue::NanoSecPerSec));
+ time_value = now;
+ }
+#endif
+ }
+ }
+ return m_frames.size ();
+}
+
+bool
+UnwindLLDB::AddFirstFrame ()
+{
+ if (m_frames.size() > 0)
+ return true;
+
+ // First, set up the 0th (initial) frame
+ CursorSP first_cursor_sp(new Cursor ());
+ RegisterContextLLDBSP reg_ctx_sp (new RegisterContextLLDB (m_thread,
+ RegisterContextLLDBSP(),
+ first_cursor_sp->sctx,
+ 0, *this));
+ if (reg_ctx_sp.get() == NULL)
+ goto unwind_done;
+
+ if (!reg_ctx_sp->IsValid())
+ goto unwind_done;
+
+ if (!reg_ctx_sp->GetCFA (first_cursor_sp->cfa))
+ goto unwind_done;
+
+ if (!reg_ctx_sp->ReadPC (first_cursor_sp->start_pc))
+ goto unwind_done;
+
+ // Everything checks out, so release the auto pointer value and let the
+ // cursor own it in its shared pointer
+ first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;
+ m_frames.push_back (first_cursor_sp);
+ return true;
+
+unwind_done:
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log)
+ {
+ log->Printf ("th%d Unwind of this thread is complete.", m_thread.GetIndexID());
+ }
+ m_unwind_complete = true;
+ return false;
+}
+
+UnwindLLDB::CursorSP
+UnwindLLDB::GetOneMoreFrame (ABI* abi)
+{
+ assert (m_frames.size() != 0 && "Get one more frame called with empty frame list");
+
+ // If we've already gotten to the end of the stack, don't bother to try again...
+ if (m_unwind_complete)
+ return nullptr;
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+
+ CursorSP prev_frame = m_frames.back();
+ uint32_t cur_idx = m_frames.size();
+
+ CursorSP cursor_sp(new Cursor ());
+ RegisterContextLLDBSP reg_ctx_sp(new RegisterContextLLDB (m_thread,
+ prev_frame->reg_ctx_lldb_sp,
+ cursor_sp->sctx,
+ cur_idx,
+ *this));
+
+ // We want to detect an unwind that cycles erroneously and stop backtracing.
+ // Don't want this maximum unwind limit to be too low -- if you have a backtrace
+ // with an "infinitely recursing" bug, it will crash when the stack blows out
+ // and the first 35,000 frames are uninteresting - it's the top most 5 frames that
+ // you actually care about. So you can't just cap the unwind at 10,000 or something.
+ // Realistically anything over around 200,000 is going to blow out the stack space.
+ // If we're still unwinding at that point, we're probably never going to finish.
+ if (cur_idx > 300000)
+ {
+ if (log)
+ log->Printf ("%*sFrame %d unwound too many frames, assuming unwind has gone astray, stopping.",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ return nullptr;
+ }
+
+ if (reg_ctx_sp.get() == NULL)
+ {
+ // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return
+ // true. Subsequent calls to TryFallbackUnwindPlan() will return false.
+ if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
+ return GetOneMoreFrame (abi);
+
+ if (log)
+ log->Printf ("%*sFrame %d did not get a RegisterContext, stopping.",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ return nullptr;
+ }
+
+ if (!reg_ctx_sp->IsValid())
+ {
+ // We failed to get a valid RegisterContext.
+ // See if the regctx below this on the stack has a fallback unwind plan it can use.
+ // Subsequent calls to TryFallbackUnwindPlan() will return false.
+ if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
+ return GetOneMoreFrame (abi);
+
+ if (log)
+ log->Printf("%*sFrame %d invalid RegisterContext for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ return nullptr;
+ }
+ if (!reg_ctx_sp->GetCFA (cursor_sp->cfa))
+ {
+ // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return
+ // true. Subsequent calls to TryFallbackUnwindPlan() will return false.
+ if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
+ return GetOneMoreFrame (abi);
+
+ if (log)
+ log->Printf("%*sFrame %d did not get CFA for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ return nullptr;
+ }
+ if (abi && !abi->CallFrameAddressIsValid(cursor_sp->cfa))
+ {
+ // On Mac OS X, the _sigtramp asynchronous signal trampoline frame may not have
+ // its (constructed) CFA aligned correctly -- don't do the abi alignment check for
+ // these.
+ if (reg_ctx_sp->IsTrapHandlerFrame() == false)
+ {
+ // See if we can find a fallback unwind plan for THIS frame. It may be
+ // that the UnwindPlan we're using for THIS frame was bad and gave us a
+ // bad CFA.
+ // If that's not it, then see if we can change the UnwindPlan for the frame
+ // below us ("NEXT") -- see if using that other UnwindPlan gets us a better
+ // unwind state.
+ if (reg_ctx_sp->TryFallbackUnwindPlan() == false
+ || reg_ctx_sp->GetCFA (cursor_sp->cfa) == false
+ || abi->CallFrameAddressIsValid(cursor_sp->cfa) == false)
+ {
+ if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
+ return GetOneMoreFrame (abi);
+
+ if (log)
+ log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ return nullptr;
+ }
+ else
+ {
+ if (log)
+ log->Printf("%*sFrame %d had a bad CFA value but we switched the UnwindPlan being used and got one that looks more realistic.",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ }
+ }
+ if (!reg_ctx_sp->ReadPC (cursor_sp->start_pc))
+ {
+ // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return
+ // true. Subsequent calls to TryFallbackUnwindPlan() will return false.
+ if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
+ return GetOneMoreFrame (abi);
+
+ if (log)
+ log->Printf("%*sFrame %d did not get PC for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ return nullptr;
+ }
+ if (abi && !abi->CodeAddressIsValid (cursor_sp->start_pc))
+ {
+ // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return
+ // true. Subsequent calls to TryFallbackUnwindPlan() will return false.
+ if (prev_frame->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
+ return GetOneMoreFrame (abi);
+
+ if (log)
+ log->Printf("%*sFrame %d did not get a valid PC, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ return nullptr;
+ }
+ // Infinite loop where the current cursor is the same as the previous one...
+ if (prev_frame->start_pc == cursor_sp->start_pc && prev_frame->cfa == cursor_sp->cfa)
+ {
+ if (log)
+ log->Printf ("th%d pc of this frame is the same as the previous frame and CFAs for both frames are identical -- stopping unwind", m_thread.GetIndexID());
+ return nullptr;
+ }
+
+ cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;
+ return cursor_sp;
+}
+
+bool
+UnwindLLDB::AddOneMoreFrame (ABI *abi)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+
+ // Frame zero is a little different
+ if (m_frames.empty())
+ return false;
+
+ // If we've already gotten to the end of the stack, don't bother to try again...
+ if (m_unwind_complete)
+ return false;
+
+ CursorSP new_frame = m_candidate_frame;
+ if (new_frame == nullptr)
+ new_frame = GetOneMoreFrame(abi);
+
+ if (new_frame == nullptr)
+ {
+ if (log)
+ log->Printf ("th%d Unwind of this thread is complete.", m_thread.GetIndexID());
+ m_unwind_complete = true;
+ return false;
+ }
+
+ m_frames.push_back(new_frame);
+
+ // If we can get one more frame further then accept that we get back a correct frame.
+ m_candidate_frame = GetOneMoreFrame(abi);
+ if (m_candidate_frame)
+ return true;
+
+ // We can't go further from the frame returned by GetOneMore frame. Lets try to get a
+ // different frame with using the fallback unwind plan.
+ if (!m_frames[m_frames.size() - 2]->reg_ctx_lldb_sp->TryFallbackUnwindPlan())
+ {
+ // We don't have a valid fallback unwind plan. Accept the frame as it is. This is a
+ // valid situation when we are at the bottom of the stack.
+ return true;
+ }
+
+ // Remove the possibly incorrect frame from the frame list and try to add a different one with
+ // the newly selected fallback unwind plan.
+ m_frames.pop_back();
+ CursorSP new_frame_v2 = GetOneMoreFrame(abi);
+ if (new_frame_v2 == nullptr)
+ {
+ // We haven't got a new frame from the fallback unwind plan. Accept the frame from the
+ // original unwind plan. This is a valid situation when we are at the bottom of the stack.
+ m_frames.push_back(new_frame);
+ return true;
+ }
+
+ // Push the new frame to the list and try to continue from this frame. If we can get a new frame
+ // then accept it as the correct one.
+ m_frames.push_back(new_frame_v2);
+ m_candidate_frame = GetOneMoreFrame(abi);
+ if (m_candidate_frame)
+ return true;
+
+ // The new frame isn't helped in unwinding. Fall back to the original one as the default unwind
+ // plan is usually more reliable then the fallback one.
+ m_frames.pop_back();
+ m_frames.push_back(new_frame);
+ return true;
+}
+
+bool
+UnwindLLDB::DoGetFrameInfoAtIndex (uint32_t idx, addr_t& cfa, addr_t& pc)
+{
+ if (m_frames.size() == 0)
+ {
+ if (!AddFirstFrame())
+ return false;
+ }
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+
+ while (idx >= m_frames.size() && AddOneMoreFrame (abi))
+ ;
+
+ if (idx < m_frames.size ())
+ {
+ cfa = m_frames[idx]->cfa;
+ pc = m_frames[idx]->start_pc;
+ return true;
+ }
+ return false;
+}
+
+lldb::RegisterContextSP
+UnwindLLDB::DoCreateRegisterContextForFrame (StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t idx = frame->GetConcreteFrameIndex ();
+
+ if (idx == 0)
+ {
+ return m_thread.GetRegisterContext();
+ }
+
+ if (m_frames.size() == 0)
+ {
+ if (!AddFirstFrame())
+ return reg_ctx_sp;
+ }
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+
+ while (idx >= m_frames.size())
+ {
+ if (!AddOneMoreFrame (abi))
+ break;
+ }
+
+ const uint32_t num_frames = m_frames.size();
+ if (idx < num_frames)
+ {
+ Cursor *frame_cursor = m_frames[idx].get();
+ reg_ctx_sp = frame_cursor->reg_ctx_lldb_sp;
+ }
+ return reg_ctx_sp;
+}
+
+UnwindLLDB::RegisterContextLLDBSP
+UnwindLLDB::GetRegisterContextForFrameNum (uint32_t frame_num)
+{
+ RegisterContextLLDBSP reg_ctx_sp;
+ if (frame_num < m_frames.size())
+ reg_ctx_sp = m_frames[frame_num]->reg_ctx_lldb_sp;
+ return reg_ctx_sp;
+}
+
+bool
+UnwindLLDB::SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc, uint32_t starting_frame_num, bool pc_reg)
+{
+ int64_t frame_num = starting_frame_num;
+ if (static_cast<size_t>(frame_num) >= m_frames.size())
+ return false;
+
+ // Never interrogate more than one level while looking for the saved pc value. If the value
+ // isn't saved by frame_num, none of the frames lower on the stack will have a useful value.
+ if (pc_reg)
+ {
+ UnwindLLDB::RegisterSearchResult result;
+ result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister (lldb_regnum, regloc);
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound)
+ return true;
+ else
+ return false;
+ }
+ while (frame_num >= 0)
+ {
+ UnwindLLDB::RegisterSearchResult result;
+ result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister (lldb_regnum, regloc);
+
+ // We descended down to the live register context aka stack frame 0 and are reading the value
+ // out of a live register.
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound
+ && regloc.type == UnwindLLDB::RegisterLocation::eRegisterInLiveRegisterContext)
+ {
+ return true;
+ }
+
+ // If we have unwind instructions saying that register N is saved in register M in the middle of
+ // the stack (and N can equal M here, meaning the register was not used in this function), then
+ // change the register number we're looking for to M and keep looking for a concrete location
+ // down the stack, or an actual value from a live RegisterContext at frame 0.
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound
+ && regloc.type == UnwindLLDB::RegisterLocation::eRegisterInRegister
+ && frame_num > 0)
+ {
+ result = UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ lldb_regnum = regloc.location.register_number;
+ }
+
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound)
+ return true;
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile)
+ return false;
+ frame_num--;
+ }
+ return false;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h
new file mode 100644
index 0000000..ce897cd
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h
@@ -0,0 +1,154 @@
+//===-- UnwindLLDB.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_UnwindLLDB_h_
+#define lldb_UnwindLLDB_h_
+
+#include <vector>
+
+#include "lldb/lldb-public.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Unwind.h"
+
+namespace lldb_private {
+
+class RegisterContextLLDB;
+
+class UnwindLLDB : public lldb_private::Unwind
+{
+public:
+ UnwindLLDB (lldb_private::Thread &thread);
+
+ virtual
+ ~UnwindLLDB() { }
+
+ enum RegisterSearchResult
+ {
+ eRegisterFound = 0,
+ eRegisterNotFound,
+ eRegisterIsVolatile
+ };
+
+protected:
+ friend class lldb_private::RegisterContextLLDB;
+
+ struct RegisterLocation {
+ enum RegisterLocationTypes
+ {
+ eRegisterNotSaved = 0, // register was not preserved by callee. If volatile reg, is unavailable
+ eRegisterSavedAtMemoryLocation, // register is saved at a specific word of target mem (target_memory_location)
+ eRegisterInRegister, // register is available in a (possible other) register (register_number)
+ eRegisterSavedAtHostMemoryLocation, // register is saved at a word in lldb's address space
+ eRegisterValueInferred, // register val was computed (and is in inferred_value)
+ eRegisterInLiveRegisterContext // register value is in a live (stack frame #0) register
+ };
+ int type;
+ union
+ {
+ lldb::addr_t target_memory_location;
+ uint32_t register_number; // in eRegisterKindLLDB register numbering system
+ void* host_memory_location;
+ uint64_t inferred_value; // eRegisterValueInferred - e.g. stack pointer == cfa + offset
+ } location;
+ };
+
+ void
+ DoClear()
+ {
+ m_frames.clear();
+ m_candidate_frame.reset();
+ m_unwind_complete = false;
+ }
+
+ virtual uint32_t
+ DoGetFrameCount();
+
+ bool
+ DoGetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& start_pc);
+
+ lldb::RegisterContextSP
+ DoCreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ typedef std::shared_ptr<RegisterContextLLDB> RegisterContextLLDBSP;
+
+ // Needed to retrieve the "next" frame (e.g. frame 2 needs to retrieve frame 1's RegisterContextLLDB)
+ // The RegisterContext for frame_num must already exist or this returns an empty shared pointer.
+ RegisterContextLLDBSP
+ GetRegisterContextForFrameNum (uint32_t frame_num);
+
+ // Iterate over the RegisterContextLLDB's in our m_frames vector, look for the first one that
+ // has a saved location for this reg.
+ bool
+ SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc, uint32_t starting_frame_num, bool pc_register);
+
+
+ //------------------------------------------------------------------
+ /// Provide the list of user-specified trap handler functions
+ ///
+ /// The Platform is one source of trap handler function names; that
+ /// may be augmented via a setting. The setting needs to be converted
+ /// into an array of ConstStrings before it can be used - we only want
+ /// to do that once per thread so it's here in the UnwindLLDB object.
+ ///
+ /// @return
+ /// Vector of ConstStrings of trap handler function names. May be
+ /// empty.
+ //------------------------------------------------------------------
+ const std::vector<ConstString> &
+ GetUserSpecifiedTrapHandlerFunctionNames ()
+ {
+ return m_user_supplied_trap_handler_functions;
+ }
+
+private:
+
+ struct Cursor
+ {
+ lldb::addr_t start_pc; // The start address of the function/symbol for this frame - current pc if unknown
+ lldb::addr_t cfa; // The canonical frame address for this stack frame
+ lldb_private::SymbolContext sctx; // A symbol context we'll contribute to & provide to the StackFrame creation
+ RegisterContextLLDBSP reg_ctx_lldb_sp; // These are all RegisterContextLLDB's
+
+ Cursor () : start_pc (LLDB_INVALID_ADDRESS), cfa (LLDB_INVALID_ADDRESS), sctx(), reg_ctx_lldb_sp() { }
+ private:
+ DISALLOW_COPY_AND_ASSIGN (Cursor);
+ };
+
+ typedef std::shared_ptr<Cursor> CursorSP;
+ std::vector<CursorSP> m_frames;
+ CursorSP m_candidate_frame;
+ bool m_unwind_complete; // If this is true, we've enumerated all the frames in the stack, and m_frames.size() is the
+ // number of frames, etc. Otherwise we've only gone as far as directly asked, and m_frames.size()
+ // is how far we've currently gone.
+
+ std::vector<ConstString> m_user_supplied_trap_handler_functions;
+
+ CursorSP
+ GetOneMoreFrame (ABI* abi);
+
+ bool
+ AddOneMoreFrame (ABI *abi);
+
+ bool
+ AddFirstFrame ();
+
+ //------------------------------------------------------------------
+ // For UnwindLLDB only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (UnwindLLDB);
+};
+
+} // namespace lldb_private
+
+#endif // lldb_UnwindLLDB_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
new file mode 100644
index 0000000..d011314
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
@@ -0,0 +1,275 @@
+//===-- UnwindMacOSXFrameBackchain.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "RegisterContextMacOSXFrameBackchain.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindMacOSXFrameBackchain::UnwindMacOSXFrameBackchain (Thread &thread) :
+ Unwind (thread),
+ m_cursors()
+{
+}
+
+uint32_t
+UnwindMacOSXFrameBackchain::DoGetFrameCount()
+{
+ if (m_cursors.empty())
+ {
+ ExecutionContext exe_ctx (m_thread.shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ const ArchSpec& target_arch = target->GetArchitecture ();
+ // Frame zero should always be supplied by the thread...
+ exe_ctx.SetFrameSP (m_thread.GetStackFrameAtIndex (0));
+
+ if (target_arch.GetAddressByteSize() == 8)
+ GetStackFrameData_x86_64 (exe_ctx);
+ else
+ GetStackFrameData_i386 (exe_ctx);
+ }
+ }
+ return m_cursors.size();
+}
+
+bool
+UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex (uint32_t idx, addr_t& cfa, addr_t& pc)
+{
+ const uint32_t frame_count = GetFrameCount();
+ if (idx < frame_count)
+ {
+ if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS)
+ return false;
+ if (m_cursors[idx].fp == LLDB_INVALID_ADDRESS)
+ return false;
+
+ pc = m_cursors[idx].pc;
+ cfa = m_cursors[idx].fp;
+
+ return true;
+ }
+ return false;
+}
+
+lldb::RegisterContextSP
+UnwindMacOSXFrameBackchain::DoCreateRegisterContextForFrame (StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_idx = frame->GetConcreteFrameIndex ();
+ const uint32_t frame_count = GetFrameCount();
+ if (concrete_idx < frame_count)
+ reg_ctx_sp.reset (new RegisterContextMacOSXFrameBackchain (m_thread, concrete_idx, m_cursors[concrete_idx]));
+ return reg_ctx_sp;
+}
+
+size_t
+UnwindMacOSXFrameBackchain::GetStackFrameData_i386 (const ExecutionContext &exe_ctx)
+{
+ m_cursors.clear();
+
+ StackFrame *first_frame = exe_ctx.GetFramePtr();
+
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ return 0;
+
+ std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
+
+ struct Frame_i386
+ {
+ uint32_t fp;
+ uint32_t pc;
+ };
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+ assert (reg_ctx);
+
+ Cursor cursor;
+ cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
+ cursor.fp = reg_ctx->GetFP (0);
+
+ Frame_i386 frame = { static_cast<uint32_t>(cursor.fp), static_cast<uint32_t>(cursor.pc) };
+
+ m_cursors.push_back(cursor);
+
+ const size_t k_frame_size = sizeof(frame);
+ Error error;
+ while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
+ {
+ // Read both the FP and PC (8 bytes)
+ if (process->ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
+ break;
+ if (frame.pc >= 0x1000)
+ {
+ cursor.pc = frame.pc;
+ cursor.fp = frame.fp;
+ m_cursors.push_back (cursor);
+ }
+ }
+ if (!m_cursors.empty())
+ {
+ lldb::addr_t first_frame_pc = m_cursors.front().pc;
+ if (first_frame_pc != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t resolve_scope = eSymbolContextModule |
+ eSymbolContextCompUnit |
+ eSymbolContextFunction |
+ eSymbolContextSymbol;
+
+ SymbolContext first_frame_sc (first_frame->GetSymbolContext(resolve_scope));
+ const AddressRange *addr_range_ptr = NULL;
+ AddressRange range;
+ if (first_frame_sc.function)
+ addr_range_ptr = &first_frame_sc.function->GetAddressRange();
+ else if (first_frame_sc.symbol)
+ {
+ range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
+ range.SetByteSize (first_frame_sc.symbol->GetByteSize());
+ addr_range_ptr = &range;
+ }
+
+ if (addr_range_ptr)
+ {
+ if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
+ {
+ // We are at the first instruction, so we can recover the
+ // previous PC by dereferencing the SP
+ lldb::addr_t first_frame_sp = reg_ctx->GetSP (0);
+ // Read the real second frame return address into frame.pc
+ if (first_frame_sp && process->ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
+ {
+ cursor.fp = m_cursors.front().fp;
+ cursor.pc = frame.pc; // Set the new second frame PC
+
+ // Insert the second frame
+ m_cursors.insert(m_cursors.begin()+1, cursor);
+
+ m_cursors.front().fp = first_frame_sp;
+ }
+ }
+ }
+ }
+ }
+// uint32_t i=0;
+// printf(" PC FP\n");
+// printf(" ------------------ ------------------ \n");
+// for (i=0; i<m_cursors.size(); ++i)
+// {
+// printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 "\n", i, m_cursors[i].pc, m_cursors[i].fp);
+// }
+ return m_cursors.size();
+}
+
+
+size_t
+UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64 (const ExecutionContext &exe_ctx)
+{
+ m_cursors.clear();
+
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ return 0;
+
+ StackFrame *first_frame = exe_ctx.GetFramePtr();
+
+ std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
+
+ struct Frame_x86_64
+ {
+ uint64_t fp;
+ uint64_t pc;
+ };
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+ assert (reg_ctx);
+
+ Cursor cursor;
+ cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
+ cursor.fp = reg_ctx->GetFP (0);
+
+ Frame_x86_64 frame = { cursor.fp, cursor.pc };
+
+ m_cursors.push_back(cursor);
+ Error error;
+ const size_t k_frame_size = sizeof(frame);
+ while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
+ {
+ // Read both the FP and PC (16 bytes)
+ if (process->ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
+ break;
+
+ if (frame.pc >= 0x1000)
+ {
+ cursor.pc = frame.pc;
+ cursor.fp = frame.fp;
+ m_cursors.push_back (cursor);
+ }
+ }
+ if (!m_cursors.empty())
+ {
+ lldb::addr_t first_frame_pc = m_cursors.front().pc;
+ if (first_frame_pc != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t resolve_scope = eSymbolContextModule |
+ eSymbolContextCompUnit |
+ eSymbolContextFunction |
+ eSymbolContextSymbol;
+
+ SymbolContext first_frame_sc(first_frame->GetSymbolContext(resolve_scope));
+ const AddressRange *addr_range_ptr = NULL;
+ AddressRange range;
+ if (first_frame_sc.function)
+ addr_range_ptr = &first_frame_sc.function->GetAddressRange();
+ else if (first_frame_sc.symbol)
+ {
+ range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
+ range.SetByteSize (first_frame_sc.symbol->GetByteSize());
+ addr_range_ptr = &range;
+ }
+
+ if (addr_range_ptr)
+ {
+ if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
+ {
+ // We are at the first instruction, so we can recover the
+ // previous PC by dereferencing the SP
+ lldb::addr_t first_frame_sp = reg_ctx->GetSP (0);
+ // Read the real second frame return address into frame.pc
+ if (process->ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
+ {
+ cursor.fp = m_cursors.front().fp;
+ cursor.pc = frame.pc; // Set the new second frame PC
+
+ // Insert the second frame
+ m_cursors.insert(m_cursors.begin()+1, cursor);
+
+ m_cursors.front().fp = first_frame_sp;
+ }
+ }
+ }
+ }
+ }
+ return m_cursors.size();
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h
new file mode 100644
index 0000000..2695376
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h
@@ -0,0 +1,74 @@
+//===-- UnwindMacOSXFrameBackchain.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_UnwindMacOSXFrameBackchain_h_
+#define lldb_UnwindMacOSXFrameBackchain_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/Unwind.h"
+
+class UnwindMacOSXFrameBackchain : public lldb_private::Unwind
+{
+public:
+ UnwindMacOSXFrameBackchain (lldb_private::Thread &thread);
+
+ virtual
+ ~UnwindMacOSXFrameBackchain()
+ {
+ }
+
+protected:
+ virtual void
+ DoClear()
+ {
+ m_cursors.clear();
+ }
+
+ virtual uint32_t
+ DoGetFrameCount();
+
+ bool
+ DoGetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& pc);
+
+ lldb::RegisterContextSP
+ DoCreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ friend class RegisterContextMacOSXFrameBackchain;
+
+ struct Cursor
+ {
+ lldb::addr_t pc; // Program counter
+ lldb::addr_t fp; // Frame pointer for us with backchain
+ };
+
+private:
+ std::vector<Cursor> m_cursors;
+
+ size_t
+ GetStackFrameData_i386 (const lldb_private::ExecutionContext &exe_ctx);
+
+ size_t
+ GetStackFrameData_x86_64 (const lldb_private::ExecutionContext &exe_ctx);
+
+ //------------------------------------------------------------------
+ // For UnwindMacOSXFrameBackchain only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (UnwindMacOSXFrameBackchain);
+};
+
+#endif // lldb_UnwindMacOSXFrameBackchain_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-arm-register-enums.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-arm-register-enums.h
new file mode 100644
index 0000000..a617f65
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-arm-register-enums.h
@@ -0,0 +1,153 @@
+//===-- lldb-arm-register-enums.h -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_arm_register_enums_h
+#define lldb_arm_register_enums_h
+
+namespace lldb_private
+{
+ // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+ //---------------------------------------------------------------------------
+ // Internal codes for all ARM registers.
+ //---------------------------------------------------------------------------
+ enum
+ {
+ k_first_gpr_arm = 0,
+ gpr_r0_arm = k_first_gpr_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_r13_arm, gpr_sp_arm = gpr_r13_arm,
+ gpr_r14_arm, gpr_lr_arm = gpr_r14_arm,
+ gpr_r15_arm, gpr_pc_arm = gpr_r15_arm,
+ gpr_cpsr_arm,
+
+ k_last_gpr_arm = gpr_cpsr_arm,
+
+ k_first_fpr_arm,
+ fpu_s0_arm = k_first_fpr_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,
+ k_last_fpr_arm = fpu_fpscr_arm,
+ exc_exception_arm,
+ exc_fsr_arm,
+ exc_far_arm,
+
+ dbg_bvr0_arm,
+ dbg_bvr1_arm,
+ dbg_bvr2_arm,
+ dbg_bvr3_arm,
+ dbg_bvr4_arm,
+ dbg_bvr5_arm,
+ dbg_bvr6_arm,
+ dbg_bvr7_arm,
+ dbg_bvr8_arm,
+ dbg_bvr9_arm,
+ dbg_bvr10_arm,
+ dbg_bvr11_arm,
+ dbg_bvr12_arm,
+ dbg_bvr13_arm,
+ dbg_bvr14_arm,
+ dbg_bvr15_arm,
+ dbg_bcr0_arm,
+ dbg_bcr1_arm,
+ dbg_bcr2_arm,
+ dbg_bcr3_arm,
+ dbg_bcr4_arm,
+ dbg_bcr5_arm,
+ dbg_bcr6_arm,
+ dbg_bcr7_arm,
+ dbg_bcr8_arm,
+ dbg_bcr9_arm,
+ dbg_bcr10_arm,
+ dbg_bcr11_arm,
+ dbg_bcr12_arm,
+ dbg_bcr13_arm,
+ dbg_bcr14_arm,
+ dbg_bcr15_arm,
+ dbg_wvr0_arm,
+ dbg_wvr1_arm,
+ dbg_wvr2_arm,
+ dbg_wvr3_arm,
+ dbg_wvr4_arm,
+ dbg_wvr5_arm,
+ dbg_wvr6_arm,
+ dbg_wvr7_arm,
+ dbg_wvr8_arm,
+ dbg_wvr9_arm,
+ dbg_wvr10_arm,
+ dbg_wvr11_arm,
+ dbg_wvr12_arm,
+ dbg_wvr13_arm,
+ dbg_wvr14_arm,
+ dbg_wvr15_arm,
+ dbg_wcr0_arm,
+ dbg_wcr1_arm,
+ dbg_wcr2_arm,
+ dbg_wcr3_arm,
+ dbg_wcr4_arm,
+ dbg_wcr5_arm,
+ dbg_wcr6_arm,
+ dbg_wcr7_arm,
+ dbg_wcr8_arm,
+ dbg_wcr9_arm,
+ dbg_wcr10_arm,
+ dbg_wcr11_arm,
+ dbg_wcr12_arm,
+ dbg_wcr13_arm,
+ dbg_wcr14_arm,
+ dbg_wcr15_arm,
+
+ k_num_registers_arm,
+ k_num_gpr_registers_arm = k_last_gpr_arm - k_first_gpr_arm + 1,
+ k_num_fpr_registers_arm = k_last_fpr_arm - k_first_fpr_arm + 1
+ };
+}
+
+#endif // #ifndef lldb_arm64_register_enums_h
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-arm64-register-enums.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-arm64-register-enums.h
new file mode 100644
index 0000000..a0c0db0
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-arm64-register-enums.h
@@ -0,0 +1,172 @@
+//===-- lldb-arm64-register-enums.h -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_arm64_register_enums_h
+#define lldb_arm64_register_enums_h
+
+namespace lldb_private
+{
+ // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+ //---------------------------------------------------------------------------
+ // Internal codes for all ARM64 registers.
+ //---------------------------------------------------------------------------
+ enum
+ {
+ k_first_gpr_arm64,
+ gpr_x0_arm64 = k_first_gpr_arm64,
+ gpr_x1_arm64,
+ gpr_x2_arm64,
+ gpr_x3_arm64,
+ gpr_x4_arm64,
+ gpr_x5_arm64,
+ gpr_x6_arm64,
+ gpr_x7_arm64,
+ gpr_x8_arm64,
+ gpr_x9_arm64,
+ gpr_x10_arm64,
+ gpr_x11_arm64,
+ gpr_x12_arm64,
+ gpr_x13_arm64,
+ gpr_x14_arm64,
+ gpr_x15_arm64,
+ gpr_x16_arm64,
+ gpr_x17_arm64,
+ gpr_x18_arm64,
+ gpr_x19_arm64,
+ gpr_x20_arm64,
+ gpr_x21_arm64,
+ gpr_x22_arm64,
+ gpr_x23_arm64,
+ gpr_x24_arm64,
+ gpr_x25_arm64,
+ gpr_x26_arm64,
+ gpr_x27_arm64,
+ gpr_x28_arm64,
+ gpr_fp_arm64,
+ gpr_lr_arm64,
+ gpr_sp_arm64,
+ gpr_pc_arm64,
+ gpr_cpsr_arm64,
+
+ k_last_gpr_arm64 = gpr_cpsr_arm64,
+
+ k_first_fpr_arm64,
+ fpu_v0_arm64 = k_first_fpr_arm64,
+ fpu_v1_arm64,
+ fpu_v2_arm64,
+ fpu_v3_arm64,
+ fpu_v4_arm64,
+ fpu_v5_arm64,
+ fpu_v6_arm64,
+ fpu_v7_arm64,
+ fpu_v8_arm64,
+ fpu_v9_arm64,
+ fpu_v10_arm64,
+ fpu_v11_arm64,
+ fpu_v12_arm64,
+ fpu_v13_arm64,
+ fpu_v14_arm64,
+ fpu_v15_arm64,
+ fpu_v16_arm64,
+ fpu_v17_arm64,
+ fpu_v18_arm64,
+ fpu_v19_arm64,
+ fpu_v20_arm64,
+ fpu_v21_arm64,
+ fpu_v22_arm64,
+ fpu_v23_arm64,
+ fpu_v24_arm64,
+ fpu_v25_arm64,
+ fpu_v26_arm64,
+ fpu_v27_arm64,
+ fpu_v28_arm64,
+ fpu_v29_arm64,
+ fpu_v30_arm64,
+ fpu_v31_arm64,
+ fpu_fpsr_arm64,
+ fpu_fpcr_arm64,
+ k_last_fpr_arm64 = fpu_fpcr_arm64,
+
+ exc_far_arm64,
+ exc_esr_arm64,
+ exc_exception_arm64,
+
+ dbg_bvr0_arm64,
+ dbg_bvr1_arm64,
+ dbg_bvr2_arm64,
+ dbg_bvr3_arm64,
+ dbg_bvr4_arm64,
+ dbg_bvr5_arm64,
+ dbg_bvr6_arm64,
+ dbg_bvr7_arm64,
+ dbg_bvr8_arm64,
+ dbg_bvr9_arm64,
+ dbg_bvr10_arm64,
+ dbg_bvr11_arm64,
+ dbg_bvr12_arm64,
+ dbg_bvr13_arm64,
+ dbg_bvr14_arm64,
+ dbg_bvr15_arm64,
+ dbg_bcr0_arm64,
+ dbg_bcr1_arm64,
+ dbg_bcr2_arm64,
+ dbg_bcr3_arm64,
+ dbg_bcr4_arm64,
+ dbg_bcr5_arm64,
+ dbg_bcr6_arm64,
+ dbg_bcr7_arm64,
+ dbg_bcr8_arm64,
+ dbg_bcr9_arm64,
+ dbg_bcr10_arm64,
+ dbg_bcr11_arm64,
+ dbg_bcr12_arm64,
+ dbg_bcr13_arm64,
+ dbg_bcr14_arm64,
+ dbg_bcr15_arm64,
+ dbg_wvr0_arm64,
+ dbg_wvr1_arm64,
+ dbg_wvr2_arm64,
+ dbg_wvr3_arm64,
+ dbg_wvr4_arm64,
+ dbg_wvr5_arm64,
+ dbg_wvr6_arm64,
+ dbg_wvr7_arm64,
+ dbg_wvr8_arm64,
+ dbg_wvr9_arm64,
+ dbg_wvr10_arm64,
+ dbg_wvr11_arm64,
+ dbg_wvr12_arm64,
+ dbg_wvr13_arm64,
+ dbg_wvr14_arm64,
+ dbg_wvr15_arm64,
+ dbg_wcr0_arm64,
+ dbg_wcr1_arm64,
+ dbg_wcr2_arm64,
+ dbg_wcr3_arm64,
+ dbg_wcr4_arm64,
+ dbg_wcr5_arm64,
+ dbg_wcr6_arm64,
+ dbg_wcr7_arm64,
+ dbg_wcr8_arm64,
+ dbg_wcr9_arm64,
+ dbg_wcr10_arm64,
+ dbg_wcr11_arm64,
+ dbg_wcr12_arm64,
+ dbg_wcr13_arm64,
+ dbg_wcr14_arm64,
+ dbg_wcr15_arm64,
+
+ k_num_registers_arm64,
+ k_num_gpr_registers_arm64 = k_last_gpr_arm64 - k_first_gpr_arm64 + 1,
+ k_num_fpr_registers_arm64 = k_last_fpr_arm64 - k_first_fpr_arm64 + 1
+ };
+}
+
+#endif // #ifndef lldb_arm64_register_enums_h
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h
new file mode 100644
index 0000000..69dc9ef
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h
@@ -0,0 +1,70 @@
+//===-- lldb-mips-frebsd-register-enums.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_mips_freebsd_register_enums_h
+#define lldb_mips_freebsd_register_enums_h
+
+namespace lldb_private
+{
+ // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+ //---------------------------------------------------------------------------
+ // Internal codes for all mips registers.
+ //---------------------------------------------------------------------------
+ enum
+ {
+ k_first_gpr_mips64,
+ gpr_zero_mips64 = k_first_gpr_mips64,
+ gpr_r1_mips64,
+ gpr_r2_mips64,
+ gpr_r3_mips64,
+ gpr_r4_mips64,
+ gpr_r5_mips64,
+ gpr_r6_mips64,
+ gpr_r7_mips64,
+ gpr_r8_mips64,
+ gpr_r9_mips64,
+ gpr_r10_mips64,
+ gpr_r11_mips64,
+ gpr_r12_mips64,
+ gpr_r13_mips64,
+ gpr_r14_mips64,
+ gpr_r15_mips64,
+ gpr_r16_mips64,
+ gpr_r17_mips64,
+ gpr_r18_mips64,
+ gpr_r19_mips64,
+ gpr_r20_mips64,
+ gpr_r21_mips64,
+ gpr_r22_mips64,
+ gpr_r23_mips64,
+ gpr_r24_mips64,
+ gpr_r25_mips64,
+ gpr_r26_mips64,
+ gpr_r27_mips64,
+ gpr_gp_mips64,
+ gpr_sp_mips64,
+ gpr_r30_mips64,
+ gpr_ra_mips64,
+ gpr_sr_mips64,
+ gpr_mullo_mips64,
+ gpr_mulhi_mips64,
+ gpr_badvaddr_mips64,
+ gpr_cause_mips64,
+ gpr_pc_mips64,
+ gpr_ic_mips64,
+ gpr_dummy_mips64,
+ k_last_gpr_mips64 = gpr_dummy_mips64,
+
+ k_num_registers_mips64,
+
+ k_num_gpr_registers_mips64 = k_last_gpr_mips64 - k_first_gpr_mips64 + 1
+ };
+}
+#endif // #ifndef lldb_mips_freebsd_register_enums_h
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-mips-linux-register-enums.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-mips-linux-register-enums.h
new file mode 100644
index 0000000..6c00025
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-mips-linux-register-enums.h
@@ -0,0 +1,285 @@
+//===-- lldb-mips-linux-register-enums.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_mips_linux_register_enums_h
+#define lldb_mips_linux_register_enums_h
+
+namespace lldb_private
+{
+ // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+ //---------------------------------------------------------------------------
+ // Internal codes for all mips registers.
+ //---------------------------------------------------------------------------
+ enum
+ {
+ k_first_gpr_mips,
+ gpr_zero_mips = k_first_gpr_mips,
+ gpr_r1_mips,
+ gpr_r2_mips,
+ gpr_r3_mips,
+ gpr_r4_mips,
+ gpr_r5_mips,
+ gpr_r6_mips,
+ gpr_r7_mips,
+ gpr_r8_mips,
+ gpr_r9_mips,
+ gpr_r10_mips,
+ gpr_r11_mips,
+ gpr_r12_mips,
+ gpr_r13_mips,
+ gpr_r14_mips,
+ gpr_r15_mips,
+ gpr_r16_mips,
+ gpr_r17_mips,
+ gpr_r18_mips,
+ gpr_r19_mips,
+ gpr_r20_mips,
+ gpr_r21_mips,
+ gpr_r22_mips,
+ gpr_r23_mips,
+ gpr_r24_mips,
+ gpr_r25_mips,
+ gpr_r26_mips,
+ gpr_r27_mips,
+ gpr_gp_mips,
+ gpr_sp_mips,
+ gpr_r30_mips,
+ gpr_ra_mips,
+ gpr_sr_mips,
+ gpr_mullo_mips,
+ gpr_mulhi_mips,
+ gpr_badvaddr_mips,
+ gpr_cause_mips,
+ gpr_pc_mips,
+ gpr_config5_mips,
+
+ k_last_gpr_mips = gpr_config5_mips,
+
+ k_first_fpr_mips,
+ fpr_f0_mips = k_first_fpr_mips,
+ fpr_f1_mips,
+ fpr_f2_mips,
+ fpr_f3_mips,
+ fpr_f4_mips,
+ fpr_f5_mips,
+ fpr_f6_mips,
+ fpr_f7_mips,
+ fpr_f8_mips,
+ fpr_f9_mips,
+ fpr_f10_mips,
+ fpr_f11_mips,
+ fpr_f12_mips,
+ fpr_f13_mips,
+ fpr_f14_mips,
+ fpr_f15_mips,
+ fpr_f16_mips,
+ fpr_f17_mips,
+ fpr_f18_mips,
+ fpr_f19_mips,
+ fpr_f20_mips,
+ fpr_f21_mips,
+ fpr_f22_mips,
+ fpr_f23_mips,
+ fpr_f24_mips,
+ fpr_f25_mips,
+ fpr_f26_mips,
+ fpr_f27_mips,
+ fpr_f28_mips,
+ fpr_f29_mips,
+ fpr_f30_mips,
+ fpr_f31_mips,
+ fpr_fcsr_mips,
+ fpr_fir_mips,
+ fpr_config5_mips,
+ k_last_fpr_mips = fpr_config5_mips,
+
+ k_first_msa_mips,
+ msa_w0_mips = k_first_msa_mips,
+ msa_w1_mips,
+ msa_w2_mips,
+ msa_w3_mips,
+ msa_w4_mips,
+ msa_w5_mips,
+ msa_w6_mips,
+ msa_w7_mips,
+ msa_w8_mips,
+ msa_w9_mips,
+ msa_w10_mips,
+ msa_w11_mips,
+ msa_w12_mips,
+ msa_w13_mips,
+ msa_w14_mips,
+ msa_w15_mips,
+ msa_w16_mips,
+ msa_w17_mips,
+ msa_w18_mips,
+ msa_w19_mips,
+ msa_w20_mips,
+ msa_w21_mips,
+ msa_w22_mips,
+ msa_w23_mips,
+ msa_w24_mips,
+ msa_w25_mips,
+ msa_w26_mips,
+ msa_w27_mips,
+ msa_w28_mips,
+ msa_w29_mips,
+ msa_w30_mips,
+ msa_w31_mips,
+ msa_fcsr_mips,
+ msa_fir_mips,
+ msa_mcsr_mips,
+ msa_mir_mips,
+ msa_config5_mips,
+ k_last_msa_mips = msa_config5_mips,
+
+ k_num_registers_mips,
+
+ k_num_gpr_registers_mips = k_last_gpr_mips - k_first_gpr_mips + 1,
+ k_num_fpr_registers_mips = k_last_fpr_mips - k_first_fpr_mips + 1,
+ k_num_msa_registers_mips = k_last_msa_mips - k_first_msa_mips + 1,
+ k_num_user_registers_mips = k_num_gpr_registers_mips + k_num_fpr_registers_mips + k_num_msa_registers_mips
+ };
+
+ //---------------------------------------------------------------------------
+ // Internal codes for all mips64 registers.
+ //---------------------------------------------------------------------------
+ enum
+ {
+ k_first_gpr_mips64,
+ gpr_zero_mips64 = k_first_gpr_mips64,
+ gpr_r1_mips64,
+ gpr_r2_mips64,
+ gpr_r3_mips64,
+ gpr_r4_mips64,
+ gpr_r5_mips64,
+ gpr_r6_mips64,
+ gpr_r7_mips64,
+ gpr_r8_mips64,
+ gpr_r9_mips64,
+ gpr_r10_mips64,
+ gpr_r11_mips64,
+ gpr_r12_mips64,
+ gpr_r13_mips64,
+ gpr_r14_mips64,
+ gpr_r15_mips64,
+ gpr_r16_mips64,
+ gpr_r17_mips64,
+ gpr_r18_mips64,
+ gpr_r19_mips64,
+ gpr_r20_mips64,
+ gpr_r21_mips64,
+ gpr_r22_mips64,
+ gpr_r23_mips64,
+ gpr_r24_mips64,
+ gpr_r25_mips64,
+ gpr_r26_mips64,
+ gpr_r27_mips64,
+ gpr_gp_mips64,
+ gpr_sp_mips64,
+ gpr_r30_mips64,
+ gpr_ra_mips64,
+ gpr_sr_mips64,
+ gpr_mullo_mips64,
+ gpr_mulhi_mips64,
+ gpr_badvaddr_mips64,
+ gpr_cause_mips64,
+ gpr_pc_mips64,
+ gpr_config5_mips64,
+ k_last_gpr_mips64 = gpr_config5_mips64,
+
+ k_first_fpr_mips64,
+ fpr_f0_mips64 = k_first_fpr_mips64,
+ fpr_f1_mips64,
+ fpr_f2_mips64,
+ fpr_f3_mips64,
+ fpr_f4_mips64,
+ fpr_f5_mips64,
+ fpr_f6_mips64,
+ fpr_f7_mips64,
+ fpr_f8_mips64,
+ fpr_f9_mips64,
+ fpr_f10_mips64,
+ fpr_f11_mips64,
+ fpr_f12_mips64,
+ fpr_f13_mips64,
+ fpr_f14_mips64,
+ fpr_f15_mips64,
+ fpr_f16_mips64,
+ fpr_f17_mips64,
+ fpr_f18_mips64,
+ fpr_f19_mips64,
+ fpr_f20_mips64,
+ fpr_f21_mips64,
+ fpr_f22_mips64,
+ fpr_f23_mips64,
+ fpr_f24_mips64,
+ fpr_f25_mips64,
+ fpr_f26_mips64,
+ fpr_f27_mips64,
+ fpr_f28_mips64,
+ fpr_f29_mips64,
+ fpr_f30_mips64,
+ fpr_f31_mips64,
+ fpr_fcsr_mips64,
+ fpr_fir_mips64,
+ fpr_config5_mips64,
+ k_last_fpr_mips64 = fpr_config5_mips64,
+
+ k_first_msa_mips64,
+ msa_w0_mips64 = k_first_msa_mips64,
+ msa_w1_mips64,
+ msa_w2_mips64,
+ msa_w3_mips64,
+ msa_w4_mips64,
+ msa_w5_mips64,
+ msa_w6_mips64,
+ msa_w7_mips64,
+ msa_w8_mips64,
+ msa_w9_mips64,
+ msa_w10_mips64,
+ msa_w11_mips64,
+ msa_w12_mips64,
+ msa_w13_mips64,
+ msa_w14_mips64,
+ msa_w15_mips64,
+ msa_w16_mips64,
+ msa_w17_mips64,
+ msa_w18_mips64,
+ msa_w19_mips64,
+ msa_w20_mips64,
+ msa_w21_mips64,
+ msa_w22_mips64,
+ msa_w23_mips64,
+ msa_w24_mips64,
+ msa_w25_mips64,
+ msa_w26_mips64,
+ msa_w27_mips64,
+ msa_w28_mips64,
+ msa_w29_mips64,
+ msa_w30_mips64,
+ msa_w31_mips64,
+ msa_fcsr_mips64,
+ msa_fir_mips64,
+ msa_mcsr_mips64,
+ msa_mir_mips64,
+ msa_config5_mips64,
+ k_last_msa_mips64 = msa_config5_mips64,
+
+ k_num_registers_mips64,
+
+ k_num_gpr_registers_mips64 = k_last_gpr_mips64 - k_first_gpr_mips64 + 1,
+ k_num_fpr_registers_mips64 = k_last_fpr_mips64 - k_first_fpr_mips64 + 1,
+ k_num_msa_registers_mips64 = k_last_msa_mips64 - k_first_msa_mips64 + 1,
+ k_num_user_registers_mips64 = k_num_gpr_registers_mips64 + k_num_fpr_registers_mips64 + k_num_msa_registers_mips64
+ };
+}
+
+#endif // #ifndef lldb_mips_linux_register_enums_h
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h
new file mode 100644
index 0000000..63027b4
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h
@@ -0,0 +1,295 @@
+//===-- lldb-x86-register-enums.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_x86_register_enums_h
+#define lldb_x86_register_enums_h
+
+namespace lldb_private
+{
+ // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB)
+
+ //---------------------------------------------------------------------------
+ // Internal codes for all i386 registers.
+ //---------------------------------------------------------------------------
+ enum
+ {
+ k_first_gpr_i386,
+ lldb_eax_i386 = k_first_gpr_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,
+
+ k_first_alias_i386,
+ lldb_ax_i386 = k_first_alias_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,
+ k_last_alias_i386 = lldb_dl_i386,
+
+ k_last_gpr_i386 = k_last_alias_i386,
+
+ k_first_fpr_i386,
+ lldb_fctrl_i386 = k_first_fpr_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,
+ k_last_fpr_i386 = lldb_xmm7_i386,
+
+ k_first_avx_i386,
+ lldb_ymm0_i386 = k_first_avx_i386,
+ lldb_ymm1_i386,
+ lldb_ymm2_i386,
+ lldb_ymm3_i386,
+ lldb_ymm4_i386,
+ lldb_ymm5_i386,
+ lldb_ymm6_i386,
+ lldb_ymm7_i386,
+ k_last_avx_i386 = lldb_ymm7_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,
+
+ k_num_registers_i386,
+ k_num_gpr_registers_i386 = k_last_gpr_i386 - k_first_gpr_i386 + 1,
+ k_num_fpr_registers_i386 = k_last_fpr_i386 - k_first_fpr_i386 + 1,
+ k_num_avx_registers_i386 = k_last_avx_i386 - k_first_avx_i386 + 1,
+ k_num_user_registers_i386 = k_num_gpr_registers_i386 + k_num_fpr_registers_i386 + k_num_avx_registers_i386,
+ };
+
+ //---------------------------------------------------------------------------
+ // Internal codes for all x86_64 registers.
+ //---------------------------------------------------------------------------
+ enum
+ {
+ k_first_gpr_x86_64,
+ lldb_rax_x86_64 = k_first_gpr_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,
+
+ k_first_alias_x86_64,
+ lldb_eax_x86_64 = k_first_alias_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 of r8
+ lldb_r9d_x86_64, // Low 32 bits of r9
+ lldb_r10d_x86_64, // Low 32 bits of r10
+ lldb_r11d_x86_64, // Low 32 bits of r11
+ lldb_r12d_x86_64, // Low 32 bits of r12
+ lldb_r13d_x86_64, // Low 32 bits of r13
+ lldb_r14d_x86_64, // Low 32 bits of r14
+ lldb_r15d_x86_64, // Low 32 bits of 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 of r8
+ lldb_r9w_x86_64, // Low 16 bits of r9
+ lldb_r10w_x86_64, // Low 16 bits of r10
+ lldb_r11w_x86_64, // Low 16 bits of r11
+ lldb_r12w_x86_64, // Low 16 bits of r12
+ lldb_r13w_x86_64, // Low 16 bits of r13
+ lldb_r14w_x86_64, // Low 16 bits of r14
+ lldb_r15w_x86_64, // Low 16 bits of 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 of r8
+ lldb_r9l_x86_64, // Low 8 bits of r9
+ lldb_r10l_x86_64, // Low 8 bits of r10
+ lldb_r11l_x86_64, // Low 8 bits of r11
+ lldb_r12l_x86_64, // Low 8 bits of r12
+ lldb_r13l_x86_64, // Low 8 bits of r13
+ lldb_r14l_x86_64, // Low 8 bits of r14
+ lldb_r15l_x86_64, // Low 8 bits of r15
+ k_last_alias_x86_64 = lldb_r15l_x86_64,
+
+ k_last_gpr_x86_64 = k_last_alias_x86_64,
+
+ k_first_fpr_x86_64,
+ lldb_fctrl_x86_64 = k_first_fpr_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,
+ k_last_fpr_x86_64 = lldb_xmm15_x86_64,
+
+ k_first_avx_x86_64,
+ lldb_ymm0_x86_64 = k_first_avx_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,
+ k_last_avx_x86_64 = lldb_ymm15_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,
+
+ k_num_registers_x86_64,
+ k_num_gpr_registers_x86_64 = k_last_gpr_x86_64 - k_first_gpr_x86_64 + 1,
+ k_num_fpr_registers_x86_64 = k_last_fpr_x86_64 - k_first_fpr_x86_64 + 1,
+ k_num_avx_registers_x86_64 = k_last_avx_x86_64 - k_first_avx_x86_64 + 1,
+ k_num_user_registers_x86_64 = k_num_gpr_registers_x86_64 + k_num_fpr_registers_x86_64 + k_num_avx_registers_x86_64,
+ };
+
+}
+
+#endif // #ifndef lldb_x86_register_enums_h
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
new file mode 100644
index 0000000..bf5cad8
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -0,0 +1,596 @@
+//===-- ProcessElfCore.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <stdlib.h>
+
+// C++ Includes
+#include <mutex>
+
+// Other libraries and framework includes
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/UnixSignals.h"
+
+#include "llvm/Support/ELF.h"
+
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
+
+// Project includes
+#include "ProcessElfCore.h"
+#include "ThreadElfCore.h"
+
+using namespace lldb_private;
+
+ConstString
+ProcessElfCore::GetPluginNameStatic()
+{
+ static ConstString g_name("elf-core");
+ return g_name;
+}
+
+const char *
+ProcessElfCore::GetPluginDescriptionStatic()
+{
+ return "ELF core dump plug-in.";
+}
+
+void
+ProcessElfCore::Terminate()
+{
+ PluginManager::UnregisterPlugin (ProcessElfCore::CreateInstance);
+}
+
+
+lldb::ProcessSP
+ProcessElfCore::CreateInstance (Target &target, Listener &listener, const FileSpec *crash_file)
+{
+ lldb::ProcessSP process_sp;
+ if (crash_file)
+ {
+ // Read enough data for a ELF32 header or ELF64 header
+ const size_t header_size = sizeof(llvm::ELF::Elf64_Ehdr);
+
+ lldb::DataBufferSP data_sp (crash_file->ReadFileContents(0, header_size));
+ if (data_sp && data_sp->GetByteSize() == header_size &&
+ elf::ELFHeader::MagicBytesMatch (data_sp->GetBytes()))
+ {
+ elf::ELFHeader elf_header;
+ DataExtractor data(data_sp, lldb::eByteOrderLittle, 4);
+ lldb::offset_t data_offset = 0;
+ if (elf_header.Parse(data, &data_offset))
+ {
+ if (elf_header.e_type == llvm::ELF::ET_CORE)
+ process_sp.reset(new ProcessElfCore (target, listener, *crash_file));
+ }
+ }
+ }
+ return process_sp;
+}
+
+bool
+ProcessElfCore::CanDebug(Target &target, bool plugin_specified_by_name)
+{
+ // For now we are just making sure the file exists for a given module
+ if (!m_core_module_sp && m_core_file.Exists())
+ {
+ ModuleSpec core_module_spec(m_core_file, target.GetArchitecture());
+ Error error (ModuleList::GetSharedModule (core_module_spec, m_core_module_sp,
+ NULL, NULL, NULL));
+ if (m_core_module_sp)
+ {
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+ if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile)
+ return true;
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// ProcessElfCore constructor
+//----------------------------------------------------------------------
+ProcessElfCore::ProcessElfCore(Target& target, Listener &listener,
+ const FileSpec &core_file) :
+ Process (target, listener),
+ m_core_module_sp (),
+ m_core_file (core_file),
+ m_dyld_plugin_name (),
+ m_os(llvm::Triple::UnknownOS),
+ m_thread_data_valid(false),
+ m_thread_data(),
+ m_core_aranges ()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessElfCore::~ProcessElfCore()
+{
+ Clear();
+ // We need to call finalize on the process before destroying ourselves
+ // to make sure all of the broadcaster cleanup goes as planned. If we
+ // destruct this class, then Process::~Process() might have problems
+ // trying to fully destroy the broadcaster.
+ Finalize();
+}
+
+//----------------------------------------------------------------------
+// PluginInterface
+//----------------------------------------------------------------------
+ConstString
+ProcessElfCore::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessElfCore::GetPluginVersion()
+{
+ return 1;
+}
+
+lldb::addr_t
+ProcessElfCore::AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader *header)
+{
+ lldb::addr_t addr = header->p_vaddr;
+ FileRange file_range (header->p_offset, header->p_filesz);
+ VMRangeToFileOffset::Entry range_entry(addr, header->p_memsz, file_range);
+
+ VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back();
+ if (last_entry &&
+ last_entry->GetRangeEnd() == range_entry.GetRangeBase() &&
+ last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase() &&
+ last_entry->GetByteSize() == last_entry->data.GetByteSize())
+ {
+ last_entry->SetRangeEnd (range_entry.GetRangeEnd());
+ last_entry->data.SetRangeEnd (range_entry.data.GetRangeEnd());
+ }
+ else
+ {
+ m_core_aranges.Append(range_entry);
+ }
+
+ return addr;
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+Error
+ProcessElfCore::DoLoadCore ()
+{
+ Error error;
+ if (!m_core_module_sp)
+ {
+ error.SetErrorString ("invalid core module");
+ return error;
+ }
+
+ ObjectFileELF *core = (ObjectFileELF *)(m_core_module_sp->GetObjectFile());
+ if (core == NULL)
+ {
+ error.SetErrorString ("invalid core object file");
+ return error;
+ }
+
+ const uint32_t num_segments = core->GetProgramHeaderCount();
+ if (num_segments == 0)
+ {
+ error.SetErrorString ("core file has no segments");
+ return error;
+ }
+
+ SetCanJIT(false);
+
+ m_thread_data_valid = true;
+
+ bool ranges_are_sorted = true;
+ lldb::addr_t vm_addr = 0;
+ /// Walk through segments and Thread and Address Map information.
+ /// PT_NOTE - Contains Thread and Register information
+ /// PT_LOAD - Contains a contiguous range of Process Address Space
+ for(uint32_t i = 1; i <= num_segments; i++)
+ {
+ const elf::ELFProgramHeader *header = core->GetProgramHeaderByIndex(i);
+ assert(header != NULL);
+
+ DataExtractor data = core->GetSegmentDataByIndex(i);
+
+ // Parse thread contexts and auxv structure
+ if (header->p_type == llvm::ELF::PT_NOTE)
+ ParseThreadContextsFromNoteSegment(header, data);
+
+ // PT_LOAD segments contains address map
+ if (header->p_type == llvm::ELF::PT_LOAD)
+ {
+ lldb::addr_t last_addr = AddAddressRangeFromLoadSegment(header);
+ if (vm_addr > last_addr)
+ ranges_are_sorted = false;
+ vm_addr = last_addr;
+ }
+ }
+
+ if (!ranges_are_sorted)
+ m_core_aranges.Sort();
+
+ // Even if the architecture is set in the target, we need to override
+ // it to match the core file which is always single arch.
+ ArchSpec arch (m_core_module_sp->GetArchitecture());
+ if (arch.IsValid())
+ m_target.SetArchitecture(arch);
+
+ SetUnixSignals(UnixSignals::Create(GetArchitecture()));
+
+ return error;
+}
+
+lldb_private::DynamicLoader *
+ProcessElfCore::GetDynamicLoader ()
+{
+ if (m_dyld_ap.get() == NULL)
+ m_dyld_ap.reset (DynamicLoader::FindPlugin(this, DynamicLoaderPOSIXDYLD::GetPluginNameStatic().GetCString()));
+ return m_dyld_ap.get();
+}
+
+bool
+ProcessElfCore::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ const uint32_t num_threads = GetNumThreadContexts ();
+ if (!m_thread_data_valid)
+ return false;
+
+ for (lldb::tid_t tid = 0; tid < num_threads; ++tid)
+ {
+ const ThreadData &td = m_thread_data[tid];
+ lldb::ThreadSP thread_sp(new ThreadElfCore (*this, tid, td));
+ new_thread_list.AddThread (thread_sp);
+ }
+ return new_thread_list.GetSize(false) > 0;
+}
+
+void
+ProcessElfCore::RefreshStateAfterStop ()
+{
+}
+
+Error
+ProcessElfCore::DoDestroy ()
+{
+ return Error();
+}
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessElfCore::IsAlive ()
+{
+ return true;
+}
+
+//------------------------------------------------------------------
+// Process Memory
+//------------------------------------------------------------------
+size_t
+ProcessElfCore::ReadMemory (lldb::addr_t addr, void *buf, size_t size, Error &error)
+{
+ // Don't allow the caching that lldb_private::Process::ReadMemory does
+ // since in core files we have it all cached our our core file anyway.
+ return DoReadMemory (addr, buf, size, error);
+}
+
+size_t
+ProcessElfCore::DoReadMemory (lldb::addr_t addr, void *buf, size_t size, Error &error)
+{
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+
+ if (core_objfile == NULL)
+ return 0;
+
+ // Get the address range
+ const VMRangeToFileOffset::Entry *address_range = m_core_aranges.FindEntryThatContains (addr);
+ if (address_range == NULL || address_range->GetRangeEnd() < addr)
+ {
+ error.SetErrorStringWithFormat ("core file does not contain 0x%" PRIx64, addr);
+ return 0;
+ }
+
+ // Convert the address into core file offset
+ const lldb::addr_t offset = addr - address_range->GetRangeBase();
+ const lldb::addr_t file_start = address_range->data.GetRangeBase();
+ const lldb::addr_t file_end = address_range->data.GetRangeEnd();
+ size_t bytes_to_read = size; // Number of bytes to read from the core file
+ size_t bytes_copied = 0; // Number of bytes actually read from the core file
+ size_t zero_fill_size = 0; // Padding
+ lldb::addr_t bytes_left = 0; // Number of bytes available in the core file from the given address
+
+ // Figure out how many on-disk bytes remain in this segment
+ // starting at the given offset
+ if (file_end > file_start + offset)
+ bytes_left = file_end - (file_start + offset);
+
+ // Figure out how many bytes we need to zero-fill if we are
+ // reading more bytes than available in the on-disk segment
+ if (bytes_to_read > bytes_left)
+ {
+ zero_fill_size = bytes_to_read - bytes_left;
+ bytes_to_read = bytes_left;
+ }
+
+ // If there is data available on the core file read it
+ if (bytes_to_read)
+ bytes_copied = core_objfile->CopyData(offset + file_start, bytes_to_read, buf);
+
+ assert(zero_fill_size <= size);
+ // Pad remaining bytes
+ if (zero_fill_size)
+ memset(((char *)buf) + bytes_copied, 0, zero_fill_size);
+
+ return bytes_copied + zero_fill_size;
+}
+
+void
+ProcessElfCore::Clear()
+{
+ m_thread_list.Clear();
+ m_os = llvm::Triple::UnknownOS;
+
+ static const auto s_default_unix_signals_sp = std::make_shared<UnixSignals>();
+ SetUnixSignals(s_default_unix_signals_sp);
+}
+
+void
+ProcessElfCore::Initialize()
+{
+ static std::once_flag g_once_flag;
+
+ std::call_once(g_once_flag, []()
+ {
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance);
+ });
+}
+
+lldb::addr_t
+ProcessElfCore::GetImageInfoAddress()
+{
+ Target *target = &GetTarget();
+ ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
+ Address addr = obj_file->GetImageInfoAddress(target);
+
+ if (addr.IsValid())
+ return addr.GetLoadAddress(target);
+ return LLDB_INVALID_ADDRESS;
+}
+
+/// Core files PT_NOTE segment descriptor types
+enum {
+ NT_PRSTATUS = 1,
+ NT_FPREGSET,
+ NT_PRPSINFO,
+ NT_TASKSTRUCT,
+ NT_PLATFORM,
+ NT_AUXV
+};
+
+namespace FREEBSD {
+
+enum {
+ NT_PRSTATUS = 1,
+ NT_FPREGSET,
+ NT_PRPSINFO,
+ NT_THRMISC = 7,
+ NT_PROCSTAT_AUXV = 16,
+ NT_PPC_VMX = 0x100
+};
+
+}
+
+// Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details.
+static void
+ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data,
+ ArchSpec &arch)
+{
+ lldb::offset_t offset = 0;
+ bool lp64 = (arch.GetMachine() == llvm::Triple::aarch64 ||
+ arch.GetMachine() == llvm::Triple::mips64 ||
+ arch.GetMachine() == llvm::Triple::ppc64 ||
+ arch.GetMachine() == llvm::Triple::x86_64);
+ int pr_version = data.GetU32(&offset);
+
+ Log *log (GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ {
+ if (pr_version > 1)
+ log->Printf("FreeBSD PRSTATUS unexpected version %d", pr_version);
+ }
+
+ // Skip padding, pr_statussz, pr_gregsetsz, pr_fpregsetsz, pr_osreldate
+ if (lp64)
+ offset += 32;
+ else
+ offset += 16;
+
+ thread_data.signo = data.GetU32(&offset); // pr_cursig
+ offset += 4; // pr_pid
+ if (lp64)
+ offset += 4;
+
+ size_t len = data.GetByteSize() - offset;
+ thread_data.gpregset = DataExtractor(data, offset, len);
+}
+
+static void
+ParseFreeBSDThrMisc(ThreadData &thread_data, DataExtractor &data)
+{
+ lldb::offset_t offset = 0;
+ thread_data.name = data.GetCStr(&offset, 20);
+}
+
+/// Parse Thread context from PT_NOTE segment and store it in the thread list
+/// Notes:
+/// 1) A PT_NOTE segment is composed of one or more NOTE entries.
+/// 2) NOTE Entry contains a standard header followed by variable size data.
+/// (see ELFNote structure)
+/// 3) A Thread Context in a core file usually described by 3 NOTE entries.
+/// a) NT_PRSTATUS - Register context
+/// b) NT_PRPSINFO - Process info(pid..)
+/// c) NT_FPREGSET - Floating point registers
+/// 4) The NOTE entries can be in any order
+/// 5) If a core file contains multiple thread contexts then there is two data forms
+/// a) Each thread context(2 or more NOTE entries) contained in its own segment (PT_NOTE)
+/// b) All thread context is stored in a single segment(PT_NOTE).
+/// This case is little tricker since while parsing we have to find where the
+/// new thread starts. The current implementation marks beginning of
+/// new thread when it finds NT_PRSTATUS or NT_PRPSINFO NOTE entry.
+/// For case (b) there may be either one NT_PRPSINFO per thread, or a single
+/// one that applies to all threads (depending on the platform type).
+void
+ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *segment_header,
+ DataExtractor segment_data)
+{
+ assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE);
+
+ lldb::offset_t offset = 0;
+ std::unique_ptr<ThreadData> thread_data(new ThreadData);
+ bool have_prstatus = false;
+ bool have_prpsinfo = false;
+
+ ArchSpec arch = GetArchitecture();
+ ELFLinuxPrPsInfo prpsinfo;
+ ELFLinuxPrStatus prstatus;
+ size_t header_size;
+ size_t len;
+
+ // Loop through the NOTE entires in the segment
+ while (offset < segment_header->p_filesz)
+ {
+ ELFNote note = ELFNote();
+ note.Parse(segment_data, &offset);
+
+ // Beginning of new thread
+ if ((note.n_type == NT_PRSTATUS && have_prstatus) ||
+ (note.n_type == NT_PRPSINFO && have_prpsinfo))
+ {
+ assert(thread_data->gpregset.GetByteSize() > 0);
+ // Add the new thread to thread list
+ m_thread_data.push_back(*thread_data);
+ *thread_data = ThreadData();
+ have_prstatus = false;
+ have_prpsinfo = false;
+ }
+
+ size_t note_start, note_size;
+ note_start = offset;
+ note_size = llvm::RoundUpToAlignment(note.n_descsz, 4);
+
+ // Store the NOTE information in the current thread
+ DataExtractor note_data (segment_data, note_start, note_size);
+ if (note.n_name == "FreeBSD")
+ {
+ m_os = llvm::Triple::FreeBSD;
+ switch (note.n_type)
+ {
+ case FREEBSD::NT_PRSTATUS:
+ have_prstatus = true;
+ ParseFreeBSDPrStatus(*thread_data, note_data, arch);
+ break;
+ case FREEBSD::NT_FPREGSET:
+ thread_data->fpregset = note_data;
+ break;
+ case FREEBSD::NT_PRPSINFO:
+ have_prpsinfo = true;
+ break;
+ case FREEBSD::NT_THRMISC:
+ ParseFreeBSDThrMisc(*thread_data, note_data);
+ break;
+ case FREEBSD::NT_PROCSTAT_AUXV:
+ // FIXME: FreeBSD sticks an int at the beginning of the note
+ m_auxv = DataExtractor(segment_data, note_start + 4, note_size - 4);
+ break;
+ case FREEBSD::NT_PPC_VMX:
+ thread_data->vregset = note_data;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (note.n_type)
+ {
+ case NT_PRSTATUS:
+ have_prstatus = true;
+ prstatus.Parse(note_data, arch);
+ thread_data->signo = prstatus.pr_cursig;
+ header_size = ELFLinuxPrStatus::GetSize(arch);
+ len = note_data.GetByteSize() - header_size;
+ thread_data->gpregset = DataExtractor(note_data, header_size, len);
+ break;
+ case NT_FPREGSET:
+ thread_data->fpregset = note_data;
+ break;
+ case NT_PRPSINFO:
+ have_prpsinfo = true;
+ prpsinfo.Parse(note_data, arch);
+ thread_data->name = prpsinfo.pr_fname;
+ break;
+ case NT_AUXV:
+ m_auxv = DataExtractor(note_data);
+ break;
+ default:
+ break;
+ }
+ }
+
+ offset += note_size;
+ }
+ // Add last entry in the note section
+ if (thread_data && thread_data->gpregset.GetByteSize() > 0)
+ {
+ m_thread_data.push_back(*thread_data);
+ }
+}
+
+uint32_t
+ProcessElfCore::GetNumThreadContexts ()
+{
+ if (!m_thread_data_valid)
+ DoLoadCore();
+ return m_thread_data.size();
+}
+
+ArchSpec
+ProcessElfCore::GetArchitecture()
+{
+ ObjectFileELF *core_file = (ObjectFileELF *)(m_core_module_sp->GetObjectFile());
+ ArchSpec arch;
+ core_file->GetArchitecture(arch);
+ return arch;
+}
+
+const lldb::DataBufferSP
+ProcessElfCore::GetAuxvData()
+{
+ const uint8_t *start = m_auxv.GetDataStart();
+ size_t len = m_auxv.GetByteSize();
+ lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(start, len));
+ return buffer;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
new file mode 100644
index 0000000..775d9e9
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -0,0 +1,160 @@
+//===-- ProcessElfCore.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+// Notes about Linux Process core dumps:
+// 1) Linux core dump is stored as ELF file.
+// 2) The ELF file's PT_NOTE and PT_LOAD segments describes the program's
+// address space and thread contexts.
+// 3) PT_NOTE segment contains note entries which describes a thread context.
+// 4) PT_LOAD segment describes a valid contigous range of process address
+// space.
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessElfCore_h_
+#define liblldb_ProcessElfCore_h_
+
+// C++ Includes
+#include <list>
+#include <vector>
+
+// Other libraries and framework includes
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Target/Process.h"
+
+#include "Plugins/ObjectFile/ELF/ELFHeader.h"
+
+struct ThreadData;
+
+class ProcessElfCore : public lldb_private::Process
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ static lldb::ProcessSP
+ CreateInstance (lldb_private::Target& target,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec *crash_file_path);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ProcessElfCore(lldb_private::Target& target,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec &core_file);
+
+ virtual
+ ~ProcessElfCore();
+
+ //------------------------------------------------------------------
+ // Check if a given Process
+ //------------------------------------------------------------------
+ bool CanDebug(lldb_private::Target &target, bool plugin_specified_by_name) override;
+
+ //------------------------------------------------------------------
+ // Creating a new process, or attaching to an existing one
+ //------------------------------------------------------------------
+ lldb_private::Error DoLoadCore() override;
+
+ lldb_private::DynamicLoader *GetDynamicLoader() override;
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ lldb_private::ConstString GetPluginName() override;
+
+ uint32_t GetPluginVersion() override;
+
+ //------------------------------------------------------------------
+ // Process Control
+ //------------------------------------------------------------------
+ lldb_private::Error DoDestroy() override;
+
+ void RefreshStateAfterStop() override;
+
+ //------------------------------------------------------------------
+ // Process Queries
+ //------------------------------------------------------------------
+ bool IsAlive() override;
+
+ //------------------------------------------------------------------
+ // Process Memory
+ //------------------------------------------------------------------
+ size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override;
+
+ size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override;
+
+ lldb::addr_t GetImageInfoAddress() override;
+
+ lldb_private::ArchSpec
+ GetArchitecture();
+
+ // Returns AUXV structure found in the core file
+ const lldb::DataBufferSP
+ GetAuxvData() override;
+
+protected:
+ void
+ Clear ( );
+
+ bool UpdateThreadList(lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list) override;
+
+private:
+ //------------------------------------------------------------------
+ // For ProcessElfCore only
+ //------------------------------------------------------------------
+ typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange;
+ typedef lldb_private::RangeDataArray<lldb::addr_t, lldb::addr_t, FileRange, 1> VMRangeToFileOffset;
+
+ lldb::ModuleSP m_core_module_sp;
+ lldb_private::FileSpec m_core_file;
+ std::string m_dyld_plugin_name;
+ DISALLOW_COPY_AND_ASSIGN (ProcessElfCore);
+
+ llvm::Triple::OSType m_os;
+
+ // True if m_thread_contexts contains valid entries
+ bool m_thread_data_valid;
+
+ // Contain thread data read from NOTE segments
+ std::vector<ThreadData> m_thread_data;
+
+ // AUXV structure found from the NOTE segment
+ lldb_private::DataExtractor m_auxv;
+
+ // Address ranges found in the core
+ VMRangeToFileOffset m_core_aranges;
+
+ // Parse thread(s) data structures(prstatus, prpsinfo) from given NOTE segment
+ void
+ ParseThreadContextsFromNoteSegment (const elf::ELFProgramHeader *segment_header,
+ lldb_private::DataExtractor segment_data);
+
+ // Returns number of thread contexts stored in the core file
+ uint32_t
+ GetNumThreadContexts();
+
+ // Parse a contiguous address range of the process from LOAD segment
+ lldb::addr_t
+ AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader *header);
+};
+
+#endif // liblldb_ProcessElffCore_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp
new file mode 100644
index 0000000..f046c112
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp
@@ -0,0 +1,94 @@
+//===-- RegisterContextCorePOSIX_arm.cpp ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX.h"
+#include "RegisterContextPOSIXCore_arm.h"
+
+using namespace lldb_private;
+
+RegisterContextCorePOSIX_arm::RegisterContextCorePOSIX_arm(Thread &thread,
+ RegisterInfoInterface *register_info,
+ const DataExtractor &gpregset,
+ const DataExtractor &fpregset)
+ : RegisterContextPOSIX_arm(thread, 0, register_info)
+{
+ m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize()));
+ m_gpr.SetData(m_gpr_buffer);
+ m_gpr.SetByteOrder(gpregset.GetByteOrder());
+}
+
+RegisterContextCorePOSIX_arm::~RegisterContextCorePOSIX_arm()
+{
+}
+
+bool
+RegisterContextCorePOSIX_arm::ReadGPR()
+{
+ return true;
+}
+
+bool
+RegisterContextCorePOSIX_arm::ReadFPR()
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm::WriteGPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm::WriteFPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ lldb::offset_t offset = reg_info->byte_offset;
+ uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
+ if (offset == reg_info->byte_offset + reg_info->byte_size)
+ {
+ value = v;
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm::HardwareSingleStep(bool enable)
+{
+ return false;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
new file mode 100644
index 0000000..73e2ef7
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h
@@ -0,0 +1,60 @@
+//===-- RegisterContextCorePOSIX_arm.h -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextCorePOSIX_arm_H_
+#define liblldb_RegisterContextCorePOSIX_arm_H_
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm.h"
+
+class RegisterContextCorePOSIX_arm :
+ public RegisterContextPOSIX_arm
+{
+public:
+ RegisterContextCorePOSIX_arm (lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ const lldb_private::DataExtractor &gpregset,
+ const lldb_private::DataExtractor &fpregset);
+
+ ~RegisterContextCorePOSIX_arm();
+
+ virtual bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+protected:
+ bool
+ ReadGPR();
+
+ bool
+ ReadFPR();
+
+ bool
+ WriteGPR();
+
+ bool
+ WriteFPR();
+
+private:
+ lldb::DataBufferSP m_gpr_buffer;
+ lldb_private::DataExtractor m_gpr;
+};
+
+#endif // #ifndef liblldb_RegisterContextCorePOSIX_arm_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
new file mode 100644
index 0000000..53c0c83
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
@@ -0,0 +1,94 @@
+//===-- RegisterContextCorePOSIX_arm64.cpp ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX.h"
+#include "RegisterContextPOSIXCore_arm64.h"
+
+using namespace lldb_private;
+
+RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(Thread &thread,
+ RegisterInfoInterface *register_info,
+ const DataExtractor &gpregset,
+ const DataExtractor &fpregset)
+ : RegisterContextPOSIX_arm64(thread, 0, register_info)
+{
+ m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize()));
+ m_gpr.SetData(m_gpr_buffer);
+ m_gpr.SetByteOrder(gpregset.GetByteOrder());
+}
+
+RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64()
+{
+}
+
+bool
+RegisterContextCorePOSIX_arm64::ReadGPR()
+{
+ return true;
+}
+
+bool
+RegisterContextCorePOSIX_arm64::ReadFPR()
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm64::WriteGPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm64::WriteFPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ lldb::offset_t offset = reg_info->byte_offset;
+ uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
+ if (offset == reg_info->byte_offset + reg_info->byte_size)
+ {
+ value = v;
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_arm64::HardwareSingleStep(bool enable)
+{
+ return false;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
new file mode 100644
index 0000000..2e1d6b4
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
@@ -0,0 +1,60 @@
+//===-- RegisterContextCorePOSIX_arm64.h -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextCorePOSIX_arm64_H_
+#define liblldb_RegisterContextCorePOSIX_arm64_H_
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
+
+class RegisterContextCorePOSIX_arm64 :
+ public RegisterContextPOSIX_arm64
+{
+public:
+ RegisterContextCorePOSIX_arm64 (lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ const lldb_private::DataExtractor &gpregset,
+ const lldb_private::DataExtractor &fpregset);
+
+ ~RegisterContextCorePOSIX_arm64();
+
+ virtual bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+protected:
+ bool
+ ReadGPR();
+
+ bool
+ ReadFPR();
+
+ bool
+ WriteGPR();
+
+ bool
+ WriteFPR();
+
+private:
+ lldb::DataBufferSP m_gpr_buffer;
+ lldb_private::DataExtractor m_gpr;
+};
+
+#endif // #ifndef liblldb_RegisterContextCorePOSIX_arm64_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp
new file mode 100644
index 0000000..f0750a0
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp
@@ -0,0 +1,94 @@
+//===-- RegisterContextCorePOSIX_mips64.cpp ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX.h"
+#include "RegisterContextPOSIXCore_mips64.h"
+
+using namespace lldb_private;
+
+RegisterContextCorePOSIX_mips64::RegisterContextCorePOSIX_mips64(Thread &thread,
+ RegisterInfoInterface *register_info,
+ const DataExtractor &gpregset,
+ const DataExtractor &fpregset)
+ : RegisterContextPOSIX_mips64(thread, 0, register_info)
+{
+ m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize()));
+ m_gpr.SetData(m_gpr_buffer);
+ m_gpr.SetByteOrder(gpregset.GetByteOrder());
+}
+
+RegisterContextCorePOSIX_mips64::~RegisterContextCorePOSIX_mips64()
+{
+}
+
+bool
+RegisterContextCorePOSIX_mips64::ReadGPR()
+{
+ return true;
+}
+
+bool
+RegisterContextCorePOSIX_mips64::ReadFPR()
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_mips64::WriteGPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_mips64::WriteFPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_mips64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ lldb::offset_t offset = reg_info->byte_offset;
+ uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
+ if (offset == reg_info->byte_offset + reg_info->byte_size)
+ {
+ value = v;
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_mips64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_mips64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_mips64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_mips64::HardwareSingleStep(bool enable)
+{
+ return false;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h
new file mode 100644
index 0000000..ca29d4f
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.h
@@ -0,0 +1,60 @@
+//===-- RegisterContextCorePOSIX_mips64.h ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextCorePOSIX_mips64_H_
+#define liblldb_RegisterContextCorePOSIX_mips64_H_
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX_mips64.h"
+
+class RegisterContextCorePOSIX_mips64 :
+ public RegisterContextPOSIX_mips64
+{
+public:
+ RegisterContextCorePOSIX_mips64 (lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ const lldb_private::DataExtractor &gpregset,
+ const lldb_private::DataExtractor &fpregset);
+
+ ~RegisterContextCorePOSIX_mips64();
+
+ virtual bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+protected:
+ bool
+ ReadGPR();
+
+ bool
+ ReadFPR();
+
+ bool
+ WriteGPR();
+
+ bool
+ WriteFPR();
+
+private:
+ lldb::DataBufferSP m_gpr_buffer;
+ lldb_private::DataExtractor m_gpr;
+};
+
+#endif // #ifndef liblldb_RegisterContextCorePOSIX_mips64_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp
new file mode 100644
index 0000000..d12df21
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp
@@ -0,0 +1,134 @@
+//===-- RegisterContextCorePOSIX_powerpc.cpp ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+#include "RegisterContextPOSIX.h"
+#include "RegisterContextPOSIXCore_powerpc.h"
+
+using namespace lldb_private;
+
+RegisterContextCorePOSIX_powerpc::RegisterContextCorePOSIX_powerpc(Thread &thread,
+ RegisterInfoInterface *register_info,
+ const DataExtractor &gpregset,
+ const DataExtractor &fpregset,
+ const DataExtractor &vregset)
+ : RegisterContextPOSIX_powerpc(thread, 0, register_info)
+{
+ m_gpr_buffer.reset(new DataBufferHeap(gpregset.GetDataStart(), gpregset.GetByteSize()));
+ m_gpr.SetData(m_gpr_buffer);
+ m_gpr.SetByteOrder(gpregset.GetByteOrder());
+ m_fpr_buffer.reset(new DataBufferHeap(fpregset.GetDataStart(), fpregset.GetByteSize()));
+ m_fpr.SetData(m_fpr_buffer);
+ m_fpr.SetByteOrder(fpregset.GetByteOrder());
+ m_vec_buffer.reset(new DataBufferHeap(vregset.GetDataStart(), vregset.GetByteSize()));
+ m_vec.SetData(m_vec_buffer);
+ m_vec.SetByteOrder(fpregset.GetByteOrder());
+}
+
+RegisterContextCorePOSIX_powerpc::~RegisterContextCorePOSIX_powerpc()
+{
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::ReadGPR()
+{
+ return true;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::ReadFPR()
+{
+ return true;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::ReadVMX()
+{
+ return true;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::WriteGPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::WriteFPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::WriteVMX()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ lldb::offset_t offset = reg_info->byte_offset;
+ if (IsFPR(reg_info->kinds[lldb::eRegisterKindLLDB])) {
+ uint64_t v = m_fpr.GetMaxU64(&offset, reg_info->byte_size);
+ if (offset == reg_info->byte_offset + reg_info->byte_size)
+ {
+ value = v;
+ return true;
+ }
+ } else if (IsVMX(reg_info->kinds[lldb::eRegisterKindLLDB])) {
+ uint32_t v[4];
+ offset = m_vec.CopyData(offset, reg_info->byte_size, &v);
+ if (offset == reg_info->byte_size)
+ {
+ value.SetBytes(v, reg_info->byte_size, m_vec.GetByteOrder());
+ return true;
+ }
+ } else {
+ uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size);
+ if (offset == reg_info->byte_offset + reg_info->byte_size)
+ {
+ if (reg_info->byte_size < sizeof(v))
+ value = (uint32_t)v;
+ else
+ value = v;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_powerpc::HardwareSingleStep(bool enable)
+{
+ return false;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h
new file mode 100644
index 0000000..a359060
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.h
@@ -0,0 +1,71 @@
+//===-- RegisterContextCorePOSIX_powerpc.h ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextCorePOSIX_powerpc_H_
+#define liblldb_RegisterContextCorePOSIX_powerpc_H_
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h"
+
+class RegisterContextCorePOSIX_powerpc :
+ public RegisterContextPOSIX_powerpc
+{
+public:
+ RegisterContextCorePOSIX_powerpc (lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ const lldb_private::DataExtractor &gpregset,
+ const lldb_private::DataExtractor &fpregset,
+ const lldb_private::DataExtractor &vregset);
+
+ ~RegisterContextCorePOSIX_powerpc();
+
+ virtual bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+protected:
+ bool
+ ReadGPR();
+
+ bool
+ ReadFPR();
+
+ bool
+ ReadVMX();
+
+ bool
+ WriteGPR();
+
+ bool
+ WriteFPR();
+
+ bool
+ WriteVMX();
+
+private:
+ lldb::DataBufferSP m_gpr_buffer;
+ lldb::DataBufferSP m_fpr_buffer;
+ lldb::DataBufferSP m_vec_buffer;
+ lldb_private::DataExtractor m_gpr;
+ lldb_private::DataExtractor m_fpr;
+ lldb_private::DataExtractor m_vec;
+};
+
+#endif // #ifndef liblldb_RegisterContextCorePOSIX_powerpc_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp
new file mode 100644
index 0000000..412c7ad
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp
@@ -0,0 +1,100 @@
+//===-- RegisterContextCorePOSIX_x86_64.cpp ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+#include "Plugins/Process/Utility/RegisterContextPOSIX.h"
+#include "RegisterContextPOSIXCore_x86_64.h"
+
+using namespace lldb_private;
+
+RegisterContextCorePOSIX_x86_64::RegisterContextCorePOSIX_x86_64(Thread &thread,
+ RegisterInfoInterface *register_info,
+ const DataExtractor &gpregset,
+ const DataExtractor &fpregset)
+ : RegisterContextPOSIX_x86 (thread, 0, register_info)
+{
+ size_t size, len;
+
+ size = GetGPRSize();
+ m_gpregset = new uint8_t[size];
+ len = gpregset.ExtractBytes (0, size, lldb::eByteOrderLittle, m_gpregset);
+ assert(len == size);
+}
+
+RegisterContextCorePOSIX_x86_64::~RegisterContextCorePOSIX_x86_64()
+{
+ delete [] m_gpregset;
+}
+
+bool
+RegisterContextCorePOSIX_x86_64::ReadGPR()
+{
+ return m_gpregset != NULL;
+}
+
+bool
+RegisterContextCorePOSIX_x86_64::ReadFPR()
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_x86_64::WriteGPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_x86_64::WriteFPR()
+{
+ assert(0);
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ switch (reg_info->byte_size)
+ {
+ case 4:
+ value = *(uint32_t *)(m_gpregset + reg_info->byte_offset);
+ return true;
+ case 8:
+ value = *(uint64_t *)(m_gpregset + reg_info->byte_offset);
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_x86_64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_x86_64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCorePOSIX_x86_64::HardwareSingleStep(bool enable)
+{
+ return false;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h
new file mode 100644
index 0000000..ac0f49c
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h
@@ -0,0 +1,58 @@
+//===-- RegisterContextCorePOSIX_x86_64.h ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextCorePOSIX_x86_64_H_
+#define liblldb_RegisterContextCorePOSIX_x86_64_H_
+
+#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h"
+
+class RegisterContextCorePOSIX_x86_64 :
+ public RegisterContextPOSIX_x86
+{
+public:
+ RegisterContextCorePOSIX_x86_64 (lldb_private::Thread &thread,
+ lldb_private::RegisterInfoInterface *register_info,
+ const lldb_private::DataExtractor &gpregset,
+ const lldb_private::DataExtractor &fpregset);
+
+ ~RegisterContextCorePOSIX_x86_64();
+
+ virtual bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+protected:
+ bool
+ ReadGPR();
+
+ bool
+ ReadFPR();
+
+ bool
+ WriteGPR();
+
+ bool
+ WriteFPR();
+
+private:
+ uint8_t *m_gpregset;
+};
+
+#endif // #ifndef liblldb_RegisterContextCorePOSIX_x86_64_H_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp
new file mode 100644
index 0000000..2abb6ba
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp
@@ -0,0 +1,252 @@
+//===-- ThreadElfCore.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Unwind.h"
+
+#include "ThreadElfCore.h"
+#include "ProcessElfCore.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_arm.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_arm64.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_arm64.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h"
+#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h"
+#include "RegisterContextPOSIXCore_arm.h"
+#include "RegisterContextPOSIXCore_arm64.h"
+#include "RegisterContextPOSIXCore_mips64.h"
+#include "RegisterContextPOSIXCore_powerpc.h"
+#include "RegisterContextPOSIXCore_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Construct a Thread object with given data
+//----------------------------------------------------------------------
+ThreadElfCore::ThreadElfCore (Process &process, tid_t tid,
+ const ThreadData &td) :
+ Thread(process, tid),
+ m_thread_name(td.name),
+ m_thread_reg_ctx_sp (),
+ m_signo(td.signo),
+ m_gpregset_data(td.gpregset),
+ m_fpregset_data(td.fpregset),
+ m_vregset_data(td.vregset)
+{
+}
+
+ThreadElfCore::~ThreadElfCore ()
+{
+ DestroyThread();
+}
+
+void
+ThreadElfCore::RefreshStateAfterStop()
+{
+ GetRegisterContext()->InvalidateIfNeeded (false);
+}
+
+void
+ThreadElfCore::ClearStackFrames ()
+{
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ unwinder->Clear();
+ Thread::ClearStackFrames();
+}
+
+RegisterContextSP
+ThreadElfCore::GetRegisterContext ()
+{
+ if (m_reg_context_sp.get() == NULL) {
+ m_reg_context_sp = CreateRegisterContextForFrame (NULL);
+ }
+ return m_reg_context_sp;
+}
+
+RegisterContextSP
+ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+ Log *log (GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex ();
+
+ if (concrete_frame_idx == 0)
+ {
+ if (m_thread_reg_ctx_sp)
+ return m_thread_reg_ctx_sp;
+
+ ProcessElfCore *process = static_cast<ProcessElfCore *>(GetProcess().get());
+ ArchSpec arch = process->GetArchitecture();
+ RegisterInfoInterface *reg_interface = NULL;
+
+ switch (arch.GetTriple().getOS())
+ {
+ case llvm::Triple::FreeBSD:
+ {
+ switch (arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ reg_interface = new RegisterContextFreeBSD_arm64(arch);
+ break;
+ case llvm::Triple::arm:
+ reg_interface = new RegisterContextFreeBSD_arm(arch);
+ break;
+ case llvm::Triple::ppc:
+ reg_interface = new RegisterContextFreeBSD_powerpc32(arch);
+ break;
+ case llvm::Triple::ppc64:
+ reg_interface = new RegisterContextFreeBSD_powerpc64(arch);
+ break;
+ case llvm::Triple::mips64:
+ reg_interface = new RegisterContextFreeBSD_mips64(arch);
+ break;
+ case llvm::Triple::x86:
+ reg_interface = new RegisterContextFreeBSD_i386(arch);
+ break;
+ case llvm::Triple::x86_64:
+ reg_interface = new RegisterContextFreeBSD_x86_64(arch);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ case llvm::Triple::Linux:
+ {
+ switch (arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ reg_interface = new RegisterContextLinux_arm(arch);
+ break;
+ case llvm::Triple::aarch64:
+ reg_interface = new RegisterContextLinux_arm64(arch);
+ break;
+ case llvm::Triple::x86_64:
+ reg_interface = new RegisterContextLinux_x86_64(arch);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ if (!reg_interface) {
+ if (log)
+ log->Printf ("elf-core::%s:: Architecture(%d) or OS(%d) not supported",
+ __FUNCTION__, arch.GetMachine(), arch.GetTriple().getOS());
+ assert (false && "Architecture or OS not supported");
+ }
+
+ switch (arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_arm64 (*this, reg_interface, m_gpregset_data, m_fpregset_data));
+ break;
+ case llvm::Triple::arm:
+ m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_arm (*this, reg_interface, m_gpregset_data, m_fpregset_data));
+ break;
+ case llvm::Triple::mips64:
+ m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, reg_interface, m_gpregset_data, m_fpregset_data));
+ break;
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_powerpc (*this, reg_interface, m_gpregset_data, m_fpregset_data, m_vregset_data));
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, reg_interface, m_gpregset_data, m_fpregset_data));
+ break;
+ default:
+ break;
+ }
+
+ reg_ctx_sp = m_thread_reg_ctx_sp;
+ }
+ else if (m_unwinder_ap.get())
+ {
+ reg_ctx_sp = m_unwinder_ap->CreateRegisterContextForFrame (frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool
+ThreadElfCore::CalculateStopInfo ()
+{
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ SetStopInfo(StopInfo::CreateStopReasonWithSignal (*this, m_signo));
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------
+// Parse PRSTATUS from NOTE entry
+//----------------------------------------------------------------
+ELFLinuxPrStatus::ELFLinuxPrStatus()
+{
+ memset(this, 0, sizeof(ELFLinuxPrStatus));
+}
+
+bool
+ELFLinuxPrStatus::Parse(DataExtractor &data, ArchSpec &arch)
+{
+ ByteOrder byteorder = data.GetByteOrder();
+ size_t len;
+ switch(arch.GetCore())
+ {
+ case ArchSpec::eCore_x86_64_x86_64:
+ len = data.ExtractBytes(0, ELFLINUXPRSTATUS64_SIZE, byteorder, this);
+ return len == ELFLINUXPRSTATUS64_SIZE;
+ default:
+ return false;
+ }
+}
+
+//----------------------------------------------------------------
+// Parse PRPSINFO from NOTE entry
+//----------------------------------------------------------------
+ELFLinuxPrPsInfo::ELFLinuxPrPsInfo()
+{
+ memset(this, 0, sizeof(ELFLinuxPrPsInfo));
+}
+
+bool
+ELFLinuxPrPsInfo::Parse(DataExtractor &data, ArchSpec &arch)
+{
+ ByteOrder byteorder = data.GetByteOrder();
+ size_t len;
+ switch(arch.GetCore())
+ {
+ case ArchSpec::eCore_x86_64_x86_64:
+ len = data.ExtractBytes(0, ELFLINUXPRPSINFO64_SIZE, byteorder, this);
+ return len == ELFLINUXPRPSINFO64_SIZE;
+ default:
+ return false;
+ }
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h
new file mode 100644
index 0000000..50502c1
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.h
@@ -0,0 +1,180 @@
+//===-- ThreadElfCore.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ThreadElfCore_h_
+#define liblldb_ThreadElfCore_h_
+
+#include <string>
+
+#include "lldb/Target/Thread.h"
+#include "lldb/Core/DataExtractor.h"
+
+struct compat_timeval
+{
+ int64_t tv_sec;
+ int32_t tv_usec;
+};
+
+// PRSTATUS structure's size differs based on architecture.
+// Currently parsing done only for x86-64 architecture by
+// simply reading data from the buffer.
+// The following macros are used to specify the size.
+// Calculating size using sizeof() wont work because of padding.
+#define ELFLINUXPRSTATUS64_SIZE (112)
+#define ELFLINUXPRPSINFO64_SIZE (132)
+
+#undef si_signo
+#undef si_code
+#undef si_errno
+
+struct ELFLinuxPrStatus
+{
+ int32_t si_signo;
+ int32_t si_code;
+ int32_t si_errno;
+
+ int16_t pr_cursig;
+
+ uint64_t pr_sigpend;
+ uint64_t pr_sighold;
+
+ uint32_t pr_pid;
+ uint32_t pr_ppid;
+ uint32_t pr_pgrp;
+ uint32_t pr_sid;
+
+ compat_timeval pr_utime;
+ compat_timeval pr_stime;
+ compat_timeval pr_cutime;
+ compat_timeval pr_cstime;
+
+ ELFLinuxPrStatus();
+
+ bool
+ Parse(lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch);
+
+ static size_t
+ GetSize(lldb_private::ArchSpec &arch)
+ {
+ switch(arch.GetCore())
+ {
+ case lldb_private::ArchSpec::eCore_x86_64_x86_64:
+ return ELFLINUXPRSTATUS64_SIZE;
+ default:
+ return 0;
+ }
+ }
+};
+
+struct ELFLinuxPrPsInfo
+{
+ char pr_state;
+ char pr_sname;
+ char pr_zomb;
+ char pr_nice;
+ uint64_t pr_flag;
+ uint32_t pr_uid;
+ uint32_t pr_gid;
+ int32_t pr_pid;
+ int32_t pr_ppid;
+ int32_t pr_pgrp;
+ int32_t pr_sid;
+ char pr_fname[16];
+ char pr_psargs[80];
+
+ ELFLinuxPrPsInfo();
+
+ bool
+ Parse(lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch);
+
+ static size_t
+ GetSize(lldb_private::ArchSpec &arch)
+ {
+ switch(arch.GetCore())
+ {
+ case lldb_private::ArchSpec::eCore_x86_64_x86_64:
+ return ELFLINUXPRPSINFO64_SIZE;
+ default:
+ return 0;
+ }
+ }
+
+};
+
+struct ThreadData
+{
+ lldb_private::DataExtractor gpregset;
+ lldb_private::DataExtractor fpregset;
+ lldb_private::DataExtractor vregset;
+ int signo;
+ std::string name;
+};
+
+class ThreadElfCore : public lldb_private::Thread
+{
+public:
+ ThreadElfCore (lldb_private::Process &process, lldb::tid_t tid,
+ const ThreadData &td);
+
+ virtual
+ ~ThreadElfCore ();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ virtual lldb::RegisterContextSP
+ GetRegisterContext ();
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ virtual void
+ ClearStackFrames ();
+
+ static bool
+ ThreadIDIsValid (lldb::tid_t thread)
+ {
+ return thread != 0;
+ }
+
+ virtual const char *
+ GetName ()
+ {
+ if (m_thread_name.empty())
+ return NULL;
+ return m_thread_name.c_str();
+ }
+
+ void
+ SetName (const char *name)
+ {
+ if (name && name[0])
+ m_thread_name.assign (name);
+ else
+ m_thread_name.clear();
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ std::string m_thread_name;
+ lldb::RegisterContextSP m_thread_reg_ctx_sp;
+
+ int m_signo;
+
+ lldb_private::DataExtractor m_gpregset_data;
+ lldb_private::DataExtractor m_fpregset_data;
+ lldb_private::DataExtractor m_vregset_data;
+
+ virtual bool CalculateStopInfo();
+
+};
+
+#endif // liblldb_ThreadElfCore_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
new file mode 100644
index 0000000..9c263c8
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -0,0 +1,1456 @@
+//===-- GDBRemoteCommunication.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "GDBRemoteCommunication.h"
+
+// C Includes
+#include <limits.h>
+#include <string.h>
+#include <sys/stat.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/Pipe.h"
+#include "lldb/Host/Socket.h"
+#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Target/Process.h"
+#include "llvm/ADT/SmallString.h"
+
+// Project includes
+#include "ProcessGDBRemoteLog.h"
+
+#if defined(__APPLE__)
+# define DEBUGSERVER_BASENAME "debugserver"
+#else
+# define DEBUGSERVER_BASENAME "lldb-server"
+#endif
+
+#if defined (HAVE_LIBCOMPRESSION)
+#include <compression.h>
+#endif
+
+#if defined (HAVE_LIBZ)
+#include <zlib.h>
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+GDBRemoteCommunication::History::History (uint32_t size) :
+ m_packets(),
+ m_curr_idx (0),
+ m_total_packet_count (0),
+ m_dumped_to_log (false)
+{
+ m_packets.resize(size);
+}
+
+GDBRemoteCommunication::History::~History ()
+{
+}
+
+void
+GDBRemoteCommunication::History::AddPacket (char packet_char,
+ PacketType type,
+ uint32_t bytes_transmitted)
+{
+ const size_t size = m_packets.size();
+ if (size > 0)
+ {
+ const uint32_t idx = GetNextIndex();
+ m_packets[idx].packet.assign (1, packet_char);
+ m_packets[idx].type = type;
+ m_packets[idx].bytes_transmitted = bytes_transmitted;
+ m_packets[idx].packet_idx = m_total_packet_count;
+ m_packets[idx].tid = Host::GetCurrentThreadID();
+ }
+}
+
+void
+GDBRemoteCommunication::History::AddPacket (const std::string &src,
+ uint32_t src_len,
+ PacketType type,
+ uint32_t bytes_transmitted)
+{
+ const size_t size = m_packets.size();
+ if (size > 0)
+ {
+ const uint32_t idx = GetNextIndex();
+ m_packets[idx].packet.assign (src, 0, src_len);
+ m_packets[idx].type = type;
+ m_packets[idx].bytes_transmitted = bytes_transmitted;
+ m_packets[idx].packet_idx = m_total_packet_count;
+ m_packets[idx].tid = Host::GetCurrentThreadID();
+ }
+}
+
+void
+GDBRemoteCommunication::History::Dump (Stream &strm) const
+{
+ const uint32_t size = GetNumPacketsInHistory ();
+ const uint32_t first_idx = GetFirstSavedPacketIndex ();
+ const uint32_t stop_idx = m_curr_idx + size;
+ for (uint32_t i = first_idx; i < stop_idx; ++i)
+ {
+ const uint32_t idx = NormalizeIndex (i);
+ const Entry &entry = m_packets[idx];
+ if (entry.type == ePacketTypeInvalid || entry.packet.empty())
+ break;
+ strm.Printf ("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s\n",
+ entry.packet_idx,
+ entry.tid,
+ entry.bytes_transmitted,
+ (entry.type == ePacketTypeSend) ? "send" : "read",
+ entry.packet.c_str());
+ }
+}
+
+void
+GDBRemoteCommunication::History::Dump (Log *log) const
+{
+ if (log && !m_dumped_to_log)
+ {
+ m_dumped_to_log = true;
+ const uint32_t size = GetNumPacketsInHistory ();
+ const uint32_t first_idx = GetFirstSavedPacketIndex ();
+ const uint32_t stop_idx = m_curr_idx + size;
+ for (uint32_t i = first_idx; i < stop_idx; ++i)
+ {
+ const uint32_t idx = NormalizeIndex (i);
+ const Entry &entry = m_packets[idx];
+ if (entry.type == ePacketTypeInvalid || entry.packet.empty())
+ break;
+ log->Printf ("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s",
+ entry.packet_idx,
+ entry.tid,
+ entry.bytes_transmitted,
+ (entry.type == ePacketTypeSend) ? "send" : "read",
+ entry.packet.c_str());
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunication constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name,
+ const char *listener_name) :
+ Communication(comm_name),
+#ifdef LLDB_CONFIGURATION_DEBUG
+ m_packet_timeout (1000),
+#else
+ m_packet_timeout (1),
+#endif
+ m_echo_number(0),
+ m_supports_qEcho (eLazyBoolCalculate),
+ m_sequence_mutex (Mutex::eMutexTypeRecursive),
+ m_public_is_running (false),
+ m_private_is_running (false),
+ m_history (512),
+ m_send_acks (true),
+ m_compression_type (CompressionType::None),
+ m_listen_url ()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunication::~GDBRemoteCommunication()
+{
+ if (IsConnected())
+ {
+ Disconnect();
+ }
+
+ // Stop the communications read thread which is used to parse all
+ // incoming packets. This function will block until the read
+ // thread returns.
+ if (m_read_thread_enabled)
+ StopReadThread();
+}
+
+char
+GDBRemoteCommunication::CalculcateChecksum (const char *payload, size_t payload_length)
+{
+ int checksum = 0;
+
+ for (size_t i = 0; i < payload_length; ++i)
+ checksum += payload[i];
+
+ return checksum & 255;
+}
+
+size_t
+GDBRemoteCommunication::SendAck ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+ ConnectionStatus status = eConnectionStatusSuccess;
+ char ch = '+';
+ const size_t bytes_written = Write (&ch, 1, status, NULL);
+ if (log)
+ log->Printf ("<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch);
+ m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written);
+ return bytes_written;
+}
+
+size_t
+GDBRemoteCommunication::SendNack ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+ ConnectionStatus status = eConnectionStatusSuccess;
+ char ch = '-';
+ const size_t bytes_written = Write (&ch, 1, status, NULL);
+ if (log)
+ log->Printf("<%4" PRIu64 "> send packet: %c", (uint64_t)bytes_written, ch);
+ m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written);
+ return bytes_written;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::SendPacket (const char *payload, size_t payload_length)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ return SendPacketNoLock (payload, payload_length);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_length)
+{
+ if (IsConnected())
+ {
+ StreamString packet(0, 4, eByteOrderBig);
+
+ packet.PutChar('$');
+ packet.Write (payload, payload_length);
+ packet.PutChar('#');
+ packet.PutHex8(CalculcateChecksum (payload, payload_length));
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+ ConnectionStatus status = eConnectionStatusSuccess;
+ const char *packet_data = packet.GetData();
+ const size_t packet_length = packet.GetSize();
+ size_t bytes_written = Write (packet_data, packet_length, status, NULL);
+ if (log)
+ {
+ size_t binary_start_offset = 0;
+ if (strncmp(packet_data, "$vFile:pwrite:", strlen("$vFile:pwrite:")) == 0)
+ {
+ const char *first_comma = strchr(packet_data, ',');
+ if (first_comma)
+ {
+ const char *second_comma = strchr(first_comma + 1, ',');
+ if (second_comma)
+ binary_start_offset = second_comma - packet_data + 1;
+ }
+ }
+
+ // If logging was just enabled and we have history, then dump out what
+ // we have to the log so we get the historical context. The Dump() call that
+ // logs all of the packet will set a boolean so that we don't dump this more
+ // than once
+ if (!m_history.DidDumpToLog ())
+ m_history.Dump (log);
+
+ if (binary_start_offset)
+ {
+ StreamString strm;
+ // Print non binary data header
+ strm.Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)binary_start_offset, packet_data);
+ const uint8_t *p;
+ // Print binary data exactly as sent
+ for (p = (const uint8_t*)packet_data + binary_start_offset; *p != '#'; ++p)
+ strm.Printf("\\x%2.2x", *p);
+ // Print the checksum
+ strm.Printf("%*s", (int)3, p);
+ log->PutCString(strm.GetString().c_str());
+ }
+ else
+ log->Printf("<%4" PRIu64 "> send packet: %.*s", (uint64_t)bytes_written, (int)packet_length, packet_data);
+ }
+
+ m_history.AddPacket (packet.GetString(), packet_length, History::ePacketTypeSend, bytes_written);
+
+
+ if (bytes_written == packet_length)
+ {
+ if (GetSendAcks ())
+ return GetAck ();
+ else
+ return PacketResult::Success;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("error: failed to send packet: %.*s", (int)packet_length, packet_data);
+ }
+ }
+ return PacketResult::ErrorSendFailed;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::GetAck ()
+{
+ StringExtractorGDBRemote packet;
+ PacketResult result = ReadPacket (packet, GetPacketTimeoutInMicroSeconds (), false);
+ if (result == PacketResult::Success)
+ {
+ if (packet.GetResponseType() == StringExtractorGDBRemote::ResponseType::eAck)
+ return PacketResult::Success;
+ else
+ return PacketResult::ErrorSendAck;
+ }
+ return result;
+}
+
+bool
+GDBRemoteCommunication::GetSequenceMutex (Mutex::Locker& locker, const char *failure_message)
+{
+ if (IsRunning())
+ return locker.TryLock (m_sequence_mutex, failure_message);
+
+ locker.Lock (m_sequence_mutex);
+ return true;
+}
+
+
+bool
+GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr)
+{
+ return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::ReadPacket (StringExtractorGDBRemote &response, uint32_t timeout_usec, bool sync_on_timeout)
+{
+ if (m_read_thread_enabled)
+ return PopPacketFromQueue (response, timeout_usec);
+ else
+ return WaitForPacketWithTimeoutMicroSecondsNoLock (response, timeout_usec, sync_on_timeout);
+}
+
+
+// This function is called when a packet is requested.
+// A whole packet is popped from the packet queue and returned to the caller.
+// Packets are placed into this queue from the communication read thread.
+// See GDBRemoteCommunication::AppendBytesToCache.
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::PopPacketFromQueue (StringExtractorGDBRemote &response, uint32_t timeout_usec)
+{
+ // Calculate absolute timeout value
+ TimeValue timeout = TimeValue::Now();
+ timeout.OffsetWithMicroSeconds(timeout_usec);
+
+ do
+ {
+ // scope for the mutex
+ {
+ // lock down the packet queue
+ Mutex::Locker locker(m_packet_queue_mutex);
+
+ // Wait on condition variable.
+ if (m_packet_queue.size() == 0)
+ m_condition_queue_not_empty.Wait(m_packet_queue_mutex, &timeout);
+
+ if (m_packet_queue.size() > 0)
+ {
+ // get the front element of the queue
+ response = m_packet_queue.front();
+
+ // remove the front element
+ m_packet_queue.pop();
+
+ // we got a packet
+ return PacketResult::Success;
+ }
+ }
+
+ // Disconnected
+ if (!IsConnected())
+ return PacketResult::ErrorDisconnected;
+
+ // Loop while not timed out
+ } while (TimeValue::Now() < timeout);
+
+ return PacketResult::ErrorReplyTimeout;
+}
+
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec, bool sync_on_timeout)
+{
+ uint8_t buffer[8192];
+ Error error;
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS | GDBR_LOG_VERBOSE));
+
+ // Check for a packet from our cache first without trying any reading...
+ if (CheckForPacket(NULL, 0, packet) != PacketType::Invalid)
+ return PacketResult::Success;
+
+ bool timed_out = false;
+ bool disconnected = false;
+ while (IsConnected() && !timed_out)
+ {
+ lldb::ConnectionStatus status = eConnectionStatusNoConnection;
+ size_t bytes_read = Read (buffer, sizeof(buffer), timeout_usec, status, &error);
+
+ if (log)
+ log->Printf ("%s: Read (buffer, (sizeof(buffer), timeout_usec = 0x%x, status = %s, error = %s) => bytes_read = %" PRIu64,
+ __PRETTY_FUNCTION__,
+ timeout_usec,
+ Communication::ConnectionStatusAsCString (status),
+ error.AsCString(),
+ (uint64_t)bytes_read);
+
+ if (bytes_read > 0)
+ {
+ if (CheckForPacket(buffer, bytes_read, packet) != PacketType::Invalid)
+ return PacketResult::Success;
+ }
+ else
+ {
+ switch (status)
+ {
+ case eConnectionStatusTimedOut:
+ case eConnectionStatusInterrupted:
+ if (sync_on_timeout)
+ {
+ //------------------------------------------------------------------
+ /// Sync the remote GDB server and make sure we get a response that
+ /// corresponds to what we send.
+ ///
+ /// Sends a "qEcho" packet and makes sure it gets the exact packet
+ /// echoed back. If the qEcho packet isn't supported, we send a qC
+ /// packet and make sure we get a valid thread ID back. We use the
+ /// "qC" packet since its response if very unique: is responds with
+ /// "QC%x" where %x is the thread ID of the current thread. This
+ /// makes the response unique enough from other packet responses to
+ /// ensure we are back on track.
+ ///
+ /// This packet is needed after we time out sending a packet so we
+ /// can ensure that we are getting the response for the packet we
+ /// are sending. There are no sequence IDs in the GDB remote
+ /// protocol (there used to be, but they are not supported anymore)
+ /// so if you timeout sending packet "abc", you might then send
+ /// packet "cde" and get the response for the previous "abc" packet.
+ /// Many responses are "OK" or "" (unsupported) or "EXX" (error) so
+ /// many responses for packets can look like responses for other
+ /// packets. So if we timeout, we need to ensure that we can get
+ /// back on track. If we can't get back on track, we must
+ /// disconnect.
+ //------------------------------------------------------------------
+ bool sync_success = false;
+ bool got_actual_response = false;
+ // We timed out, we need to sync back up with the
+ char echo_packet[32];
+ int echo_packet_len = 0;
+ RegularExpression response_regex;
+
+ if (m_supports_qEcho == eLazyBoolYes)
+ {
+ echo_packet_len = ::snprintf (echo_packet, sizeof(echo_packet), "qEcho:%u", ++m_echo_number);
+ std::string regex_str = "^";
+ regex_str += echo_packet;
+ regex_str += "$";
+ response_regex.Compile(regex_str.c_str());
+ }
+ else
+ {
+ echo_packet_len = ::snprintf (echo_packet, sizeof(echo_packet), "qC");
+ response_regex.Compile("^QC[0-9A-Fa-f]+$");
+ }
+
+ PacketResult echo_packet_result = SendPacketNoLock (echo_packet, echo_packet_len);
+ if (echo_packet_result == PacketResult::Success)
+ {
+ const uint32_t max_retries = 3;
+ uint32_t successful_responses = 0;
+ for (uint32_t i=0; i<max_retries; ++i)
+ {
+ StringExtractorGDBRemote echo_response;
+ echo_packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (echo_response, timeout_usec, false);
+ if (echo_packet_result == PacketResult::Success)
+ {
+ ++successful_responses;
+ if (response_regex.Execute(echo_response.GetStringRef().c_str()))
+ {
+ sync_success = true;
+ break;
+ }
+ else if (successful_responses == 1)
+ {
+ // We got something else back as the first successful response, it probably is
+ // the response to the packet we actually wanted, so copy it over if this
+ // is the first success and continue to try to get the qEcho response
+ packet = echo_response;
+ got_actual_response = true;
+ }
+ }
+ else if (echo_packet_result == PacketResult::ErrorReplyTimeout)
+ continue; // Packet timed out, continue waiting for a response
+ else
+ break; // Something else went wrong getting the packet back, we failed and are done trying
+ }
+ }
+
+ // We weren't able to sync back up with the server, we must abort otherwise
+ // all responses might not be from the right packets...
+ if (sync_success)
+ {
+ // We timed out, but were able to recover
+ if (got_actual_response)
+ {
+ // We initially timed out, but we did get a response that came in before the successful
+ // reply to our qEcho packet, so lets say everything is fine...
+ return PacketResult::Success;
+ }
+ }
+ else
+ {
+ disconnected = true;
+ Disconnect();
+ }
+ }
+ timed_out = true;
+ break;
+ case eConnectionStatusSuccess:
+ //printf ("status = success but error = %s\n", error.AsCString("<invalid>"));
+ break;
+
+ case eConnectionStatusEndOfFile:
+ case eConnectionStatusNoConnection:
+ case eConnectionStatusLostConnection:
+ case eConnectionStatusError:
+ disconnected = true;
+ Disconnect();
+ break;
+ }
+ }
+ }
+ packet.Clear ();
+ if (disconnected)
+ return PacketResult::ErrorDisconnected;
+ if (timed_out)
+ return PacketResult::ErrorReplyTimeout;
+ else
+ return PacketResult::ErrorReplyFailed;
+}
+
+bool
+GDBRemoteCommunication::DecompressPacket ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+
+ if (!CompressionIsEnabled())
+ return true;
+
+ size_t pkt_size = m_bytes.size();
+
+ // Smallest possible compressed packet is $N#00 - an uncompressed empty reply, most commonly indicating
+ // an unsupported packet. Anything less than 5 characters, it's definitely not a compressed packet.
+ if (pkt_size < 5)
+ return true;
+
+ if (m_bytes[0] != '$' && m_bytes[0] != '%')
+ return true;
+ if (m_bytes[1] != 'C' && m_bytes[1] != 'N')
+ return true;
+ if (m_bytes[pkt_size - 3] != '#')
+ return true;
+ if (!::isxdigit (m_bytes[pkt_size - 2]) || !::isxdigit (m_bytes[pkt_size - 1]))
+ return true;
+
+ size_t content_length = pkt_size - 5; // not counting '$', 'C' | 'N', '#', & the two hex checksum chars
+ size_t content_start = 2; // The first character of the compressed/not-compressed text of the packet
+ size_t hash_mark_idx = pkt_size - 3; // The '#' character marking the end of the packet
+ size_t checksum_idx = pkt_size - 2; // The first character of the two hex checksum characters
+
+ // Compressed packets ("$C") start with a base10 number which is the size of the uncompressed payload,
+ // then a : and then the compressed data. e.g. $C1024:<binary>#00
+ // Update content_start and content_length to only include the <binary> part of the packet.
+
+ uint64_t decompressed_bufsize = ULONG_MAX;
+ if (m_bytes[1] == 'C')
+ {
+ size_t i = content_start;
+ while (i < hash_mark_idx && isdigit(m_bytes[i]))
+ i++;
+ if (i < hash_mark_idx && m_bytes[i] == ':')
+ {
+ i++;
+ content_start = i;
+ content_length = hash_mark_idx - content_start;
+ std::string bufsize_str (m_bytes.data() + 2, i - 2 - 1);
+ errno = 0;
+ decompressed_bufsize = ::strtoul (bufsize_str.c_str(), NULL, 10);
+ if (errno != 0 || decompressed_bufsize == ULONG_MAX)
+ {
+ m_bytes.erase (0, pkt_size);
+ return false;
+ }
+ }
+ }
+
+ if (GetSendAcks ())
+ {
+ char packet_checksum_cstr[3];
+ packet_checksum_cstr[0] = m_bytes[checksum_idx];
+ packet_checksum_cstr[1] = m_bytes[checksum_idx + 1];
+ packet_checksum_cstr[2] = '\0';
+ long packet_checksum = strtol (packet_checksum_cstr, NULL, 16);
+
+ long actual_checksum = CalculcateChecksum (m_bytes.data() + 1, hash_mark_idx - 1);
+ bool success = packet_checksum == actual_checksum;
+ if (!success)
+ {
+ if (log)
+ log->Printf ("error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x",
+ (int)(pkt_size),
+ m_bytes.c_str(),
+ (uint8_t)packet_checksum,
+ (uint8_t)actual_checksum);
+ }
+ // Send the ack or nack if needed
+ if (!success)
+ {
+ SendNack();
+ m_bytes.erase (0, pkt_size);
+ return false;
+ }
+ else
+ {
+ SendAck();
+ }
+ }
+
+ if (m_bytes[1] == 'N')
+ {
+ // This packet was not compressed -- delete the 'N' character at the
+ // start and the packet may be processed as-is.
+ m_bytes.erase(1, 1);
+ return true;
+ }
+
+ // Reverse the gdb-remote binary escaping that was done to the compressed text to
+ // guard characters like '$', '#', '}', etc.
+ std::vector<uint8_t> unescaped_content;
+ unescaped_content.reserve (content_length);
+ size_t i = content_start;
+ while (i < hash_mark_idx)
+ {
+ if (m_bytes[i] == '}')
+ {
+ i++;
+ unescaped_content.push_back (m_bytes[i] ^ 0x20);
+ }
+ else
+ {
+ unescaped_content.push_back (m_bytes[i]);
+ }
+ i++;
+ }
+
+ uint8_t *decompressed_buffer = nullptr;
+ size_t decompressed_bytes = 0;
+
+ if (decompressed_bufsize != ULONG_MAX)
+ {
+ decompressed_buffer = (uint8_t *) malloc (decompressed_bufsize + 1);
+ if (decompressed_buffer == nullptr)
+ {
+ m_bytes.erase (0, pkt_size);
+ return false;
+ }
+
+ }
+
+#if defined (HAVE_LIBCOMPRESSION)
+ // libcompression is weak linked so check that compression_decode_buffer() is available
+ if (compression_decode_buffer != NULL &&
+ (m_compression_type == CompressionType::ZlibDeflate
+ || m_compression_type == CompressionType::LZFSE
+ || m_compression_type == CompressionType::LZ4))
+ {
+ compression_algorithm compression_type;
+ if (m_compression_type == CompressionType::ZlibDeflate)
+ compression_type = COMPRESSION_ZLIB;
+ else if (m_compression_type == CompressionType::LZFSE)
+ compression_type = COMPRESSION_LZFSE;
+ else if (m_compression_type == CompressionType::LZ4)
+ compression_type = COMPRESSION_LZ4_RAW;
+ else if (m_compression_type == CompressionType::LZMA)
+ compression_type = COMPRESSION_LZMA;
+
+
+ // If we have the expected size of the decompressed payload, we can allocate
+ // the right-sized buffer and do it. If we don't have that information, we'll
+ // need to try decoding into a big buffer and if the buffer wasn't big enough,
+ // increase it and try again.
+
+ if (decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr)
+ {
+ decompressed_bytes = compression_decode_buffer (decompressed_buffer, decompressed_bufsize + 10 ,
+ (uint8_t*) unescaped_content.data(),
+ unescaped_content.size(),
+ NULL,
+ compression_type);
+ }
+ }
+#endif
+
+#if defined (HAVE_LIBZ)
+ if (decompressed_bytes == 0
+ && decompressed_bufsize != ULONG_MAX
+ && decompressed_buffer != nullptr
+ && m_compression_type == CompressionType::ZlibDeflate)
+ {
+ z_stream stream;
+ memset (&stream, 0, sizeof (z_stream));
+ stream.next_in = (Bytef *) unescaped_content.data();
+ stream.avail_in = (uInt) unescaped_content.size();
+ stream.total_in = 0;
+ stream.next_out = (Bytef *) decompressed_buffer;
+ stream.avail_out = decompressed_bufsize;
+ stream.total_out = 0;
+ stream.zalloc = Z_NULL;
+ stream.zfree = Z_NULL;
+ stream.opaque = Z_NULL;
+
+ if (inflateInit2 (&stream, -15) == Z_OK)
+ {
+ int status = inflate (&stream, Z_NO_FLUSH);
+ inflateEnd (&stream);
+ if (status == Z_STREAM_END)
+ {
+ decompressed_bytes = stream.total_out;
+ }
+ }
+ }
+#endif
+
+ if (decompressed_bytes == 0 || decompressed_buffer == nullptr)
+ {
+ if (decompressed_buffer)
+ free (decompressed_buffer);
+ m_bytes.erase (0, pkt_size);
+ return false;
+ }
+
+ std::string new_packet;
+ new_packet.reserve (decompressed_bytes + 6);
+ new_packet.push_back (m_bytes[0]);
+ new_packet.append ((const char *) decompressed_buffer, decompressed_bytes);
+ new_packet.push_back ('#');
+ if (GetSendAcks ())
+ {
+ uint8_t decompressed_checksum = CalculcateChecksum ((const char *) decompressed_buffer, decompressed_bytes);
+ char decompressed_checksum_str[3];
+ snprintf (decompressed_checksum_str, 3, "%02x", decompressed_checksum);
+ new_packet.append (decompressed_checksum_str);
+ }
+ else
+ {
+ new_packet.push_back ('0');
+ new_packet.push_back ('0');
+ }
+
+ m_bytes = new_packet;
+
+ free (decompressed_buffer);
+ return true;
+}
+
+GDBRemoteCommunication::PacketType
+GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet)
+{
+ // Put the packet data into the buffer in a thread safe fashion
+ Mutex::Locker locker(m_bytes_mutex);
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+
+ if (src && src_len > 0)
+ {
+ if (log && log->GetVerbose())
+ {
+ StreamString s;
+ log->Printf ("GDBRemoteCommunication::%s adding %u bytes: %.*s",
+ __FUNCTION__,
+ (uint32_t)src_len,
+ (uint32_t)src_len,
+ src);
+ }
+ m_bytes.append ((const char *)src, src_len);
+ }
+
+ bool isNotifyPacket = false;
+
+ // Parse up the packets into gdb remote packets
+ if (!m_bytes.empty())
+ {
+ // end_idx must be one past the last valid packet byte. Start
+ // it off with an invalid value that is the same as the current
+ // index.
+ size_t content_start = 0;
+ size_t content_length = 0;
+ size_t total_length = 0;
+ size_t checksum_idx = std::string::npos;
+
+ // Size of packet before it is decompressed, for logging purposes
+ size_t original_packet_size = m_bytes.size();
+ if (CompressionIsEnabled())
+ {
+ if (DecompressPacket() == false)
+ {
+ packet.Clear();
+ return GDBRemoteCommunication::PacketType::Standard;
+ }
+ }
+
+ switch (m_bytes[0])
+ {
+ case '+': // Look for ack
+ case '-': // Look for cancel
+ case '\x03': // ^C to halt target
+ content_length = total_length = 1; // The command is one byte long...
+ break;
+
+ case '%': // Async notify packet
+ isNotifyPacket = true;
+ // Intentional fall through
+
+ case '$':
+ // Look for a standard gdb packet?
+ {
+ size_t hash_pos = m_bytes.find('#');
+ if (hash_pos != std::string::npos)
+ {
+ if (hash_pos + 2 < m_bytes.size())
+ {
+ checksum_idx = hash_pos + 1;
+ // Skip the dollar sign
+ content_start = 1;
+ // Don't include the # in the content or the $ in the content length
+ content_length = hash_pos - 1;
+
+ total_length = hash_pos + 3; // Skip the # and the two hex checksum bytes
+ }
+ else
+ {
+ // Checksum bytes aren't all here yet
+ content_length = std::string::npos;
+ }
+ }
+ }
+ break;
+
+ default:
+ {
+ // We have an unexpected byte and we need to flush all bad
+ // data that is in m_bytes, so we need to find the first
+ // byte that is a '+' (ACK), '-' (NACK), \x03 (CTRL+C interrupt),
+ // or '$' character (start of packet header) or of course,
+ // the end of the data in m_bytes...
+ const size_t bytes_len = m_bytes.size();
+ bool done = false;
+ uint32_t idx;
+ for (idx = 1; !done && idx < bytes_len; ++idx)
+ {
+ switch (m_bytes[idx])
+ {
+ case '+':
+ case '-':
+ case '\x03':
+ case '%':
+ case '$':
+ done = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'",
+ __FUNCTION__, idx - 1, idx - 1, m_bytes.c_str());
+ m_bytes.erase(0, idx - 1);
+ }
+ break;
+ }
+
+ if (content_length == std::string::npos)
+ {
+ packet.Clear();
+ return GDBRemoteCommunication::PacketType::Invalid;
+ }
+ else if (total_length > 0)
+ {
+
+ // We have a valid packet...
+ assert (content_length <= m_bytes.size());
+ assert (total_length <= m_bytes.size());
+ assert (content_length <= total_length);
+ size_t content_end = content_start + content_length;
+
+ bool success = true;
+ std::string &packet_str = packet.GetStringRef();
+ if (log)
+ {
+ // If logging was just enabled and we have history, then dump out what
+ // we have to the log so we get the historical context. The Dump() call that
+ // logs all of the packet will set a boolean so that we don't dump this more
+ // than once
+ if (!m_history.DidDumpToLog ())
+ m_history.Dump (log);
+
+ bool binary = false;
+ // Only detect binary for packets that start with a '$' and have a '#CC' checksum
+ if (m_bytes[0] == '$' && total_length > 4)
+ {
+ for (size_t i=0; !binary && i<total_length; ++i)
+ {
+ if (isprint(m_bytes[i]) == 0)
+ binary = true;
+ }
+ }
+ if (binary)
+ {
+ StreamString strm;
+ // Packet header...
+ if (CompressionIsEnabled())
+ strm.Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %c", (uint64_t) original_packet_size, (uint64_t)total_length, m_bytes[0]);
+ else
+ strm.Printf("<%4" PRIu64 "> read packet: %c", (uint64_t)total_length, m_bytes[0]);
+ for (size_t i=content_start; i<content_end; ++i)
+ {
+ // Remove binary escaped bytes when displaying the packet...
+ const char ch = m_bytes[i];
+ if (ch == 0x7d)
+ {
+ // 0x7d is the escape character. The next character is to
+ // be XOR'd with 0x20.
+ const char escapee = m_bytes[++i] ^ 0x20;
+ strm.Printf("%2.2x", escapee);
+ }
+ else
+ {
+ strm.Printf("%2.2x", (uint8_t)ch);
+ }
+ }
+ // Packet footer...
+ strm.Printf("%c%c%c", m_bytes[total_length-3], m_bytes[total_length-2], m_bytes[total_length-1]);
+ log->PutCString(strm.GetString().c_str());
+ }
+ else
+ {
+ if (CompressionIsEnabled())
+ log->Printf("<%4" PRIu64 ":%" PRIu64 "> read packet: %.*s", (uint64_t) original_packet_size, (uint64_t)total_length, (int)(total_length), m_bytes.c_str());
+ else
+ log->Printf("<%4" PRIu64 "> read packet: %.*s", (uint64_t)total_length, (int)(total_length), m_bytes.c_str());
+ }
+ }
+
+ m_history.AddPacket (m_bytes.c_str(), total_length, History::ePacketTypeRecv, total_length);
+
+ // Clear packet_str in case there is some existing data in it.
+ packet_str.clear();
+ // Copy the packet from m_bytes to packet_str expanding the
+ // run-length encoding in the process.
+ // Reserve enough byte for the most common case (no RLE used)
+ packet_str.reserve(m_bytes.length());
+ for (std::string::const_iterator c = m_bytes.begin() + content_start; c != m_bytes.begin() + content_end; ++c)
+ {
+ if (*c == '*')
+ {
+ // '*' indicates RLE. Next character will give us the
+ // repeat count and previous character is what is to be
+ // repeated.
+ char char_to_repeat = packet_str.back();
+ // Number of time the previous character is repeated
+ int repeat_count = *++c + 3 - ' ';
+ // We have the char_to_repeat and repeat_count. Now push
+ // it in the packet.
+ for (int i = 0; i < repeat_count; ++i)
+ packet_str.push_back(char_to_repeat);
+ }
+ else if (*c == 0x7d)
+ {
+ // 0x7d is the escape character. The next character is to
+ // be XOR'd with 0x20.
+ char escapee = *++c ^ 0x20;
+ packet_str.push_back(escapee);
+ }
+ else
+ {
+ packet_str.push_back(*c);
+ }
+ }
+
+ if (m_bytes[0] == '$' || m_bytes[0] == '%')
+ {
+ assert (checksum_idx < m_bytes.size());
+ if (::isxdigit (m_bytes[checksum_idx+0]) ||
+ ::isxdigit (m_bytes[checksum_idx+1]))
+ {
+ if (GetSendAcks ())
+ {
+ const char *packet_checksum_cstr = &m_bytes[checksum_idx];
+ char packet_checksum = strtol (packet_checksum_cstr, NULL, 16);
+ char actual_checksum = CalculcateChecksum (packet_str.c_str(), packet_str.size());
+ success = packet_checksum == actual_checksum;
+ if (!success)
+ {
+ if (log)
+ log->Printf ("error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x",
+ (int)(total_length),
+ m_bytes.c_str(),
+ (uint8_t)packet_checksum,
+ (uint8_t)actual_checksum);
+ }
+ // Send the ack or nack if needed
+ if (!success)
+ SendNack();
+ else
+ SendAck();
+ }
+ }
+ else
+ {
+ success = false;
+ if (log)
+ log->Printf ("error: invalid checksum in packet: '%s'\n", m_bytes.c_str());
+ }
+ }
+
+ m_bytes.erase(0, total_length);
+ packet.SetFilePos(0);
+
+ if (isNotifyPacket)
+ return GDBRemoteCommunication::PacketType::Notify;
+ else
+ return GDBRemoteCommunication::PacketType::Standard;
+ }
+ }
+ packet.Clear();
+ return GDBRemoteCommunication::PacketType::Invalid;
+}
+
+Error
+GDBRemoteCommunication::StartListenThread (const char *hostname, uint16_t port)
+{
+ Error error;
+ if (m_listen_thread.IsJoinable())
+ {
+ error.SetErrorString("listen thread already running");
+ }
+ else
+ {
+ char listen_url[512];
+ if (hostname && hostname[0])
+ snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, port);
+ else
+ snprintf(listen_url, sizeof(listen_url), "listen://%i", port);
+ m_listen_url = listen_url;
+ SetConnection(new ConnectionFileDescriptor());
+ m_listen_thread = ThreadLauncher::LaunchThread(listen_url, GDBRemoteCommunication::ListenThread, this, &error);
+ }
+ return error;
+}
+
+bool
+GDBRemoteCommunication::JoinListenThread ()
+{
+ if (m_listen_thread.IsJoinable())
+ m_listen_thread.Join(nullptr);
+ return true;
+}
+
+lldb::thread_result_t
+GDBRemoteCommunication::ListenThread (lldb::thread_arg_t arg)
+{
+ GDBRemoteCommunication *comm = (GDBRemoteCommunication *)arg;
+ Error error;
+ ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)comm->GetConnection ();
+
+ if (connection)
+ {
+ // Do the listen on another thread so we can continue on...
+ if (connection->Connect(comm->m_listen_url.c_str(), &error) != eConnectionStatusSuccess)
+ comm->SetConnection(NULL);
+ }
+ return NULL;
+}
+
+Error
+GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
+ uint16_t in_port,
+ ProcessLaunchInfo &launch_info,
+ uint16_t &out_port)
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s(hostname=%s, in_port=%" PRIu16 ", out_port=%" PRIu16, __FUNCTION__, hostname ? hostname : "<empty>", in_port, out_port);
+
+ out_port = in_port;
+ Error error;
+ // If we locate debugserver, keep that located version around
+ static FileSpec g_debugserver_file_spec;
+
+ char debugserver_path[PATH_MAX];
+ FileSpec &debugserver_file_spec = launch_info.GetExecutableFile();
+
+ // Always check to see if we have an environment override for the path
+ // to the debugserver to use and use it if we do.
+ const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH");
+ if (env_debugserver_path)
+ {
+ debugserver_file_spec.SetFile (env_debugserver_path, false);
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s() gdb-remote stub exe path set from environment variable: %s", __FUNCTION__, env_debugserver_path);
+ }
+ else
+ debugserver_file_spec = g_debugserver_file_spec;
+ bool debugserver_exists = debugserver_file_spec.Exists();
+ if (!debugserver_exists)
+ {
+ // The debugserver binary is in the LLDB.framework/Resources
+ // directory.
+ if (HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, debugserver_file_spec))
+ {
+ debugserver_file_spec.AppendPathComponent (DEBUGSERVER_BASENAME);
+ debugserver_exists = debugserver_file_spec.Exists();
+ if (debugserver_exists)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ());
+
+ g_debugserver_file_spec = debugserver_file_spec;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s() could not find gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ());
+
+ g_debugserver_file_spec.Clear();
+ debugserver_file_spec.Clear();
+ }
+ }
+ }
+
+ if (debugserver_exists)
+ {
+ debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path));
+
+ Args &debugserver_args = launch_info.GetArguments();
+ debugserver_args.Clear();
+ char arg_cstr[PATH_MAX];
+
+ // Start args with "debugserver /file/path -r --"
+ debugserver_args.AppendArgument(debugserver_path);
+
+#if !defined(__APPLE__)
+ // First argument to lldb-server must be mode in which to run.
+ debugserver_args.AppendArgument("gdbserver");
+#endif
+
+ // If a host and port is supplied then use it
+ char host_and_port[128];
+ if (hostname)
+ {
+ snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port);
+ debugserver_args.AppendArgument(host_and_port);
+ }
+ else
+ {
+ host_and_port[0] = '\0';
+ }
+
+ // use native registers, not the GDB registers
+ debugserver_args.AppendArgument("--native-regs");
+
+ if (launch_info.GetLaunchInSeparateProcessGroup())
+ {
+ debugserver_args.AppendArgument("--setsid");
+ }
+
+ llvm::SmallString<PATH_MAX> named_pipe_path;
+ Pipe port_pipe;
+
+ if (host_and_port[0] && in_port == 0)
+ {
+ // Create a temporary file to get the stdout/stderr and redirect the
+ // output of the command into this file. We will later read this file
+ // if all goes well and fill the data into "command_output_ptr"
+
+ // Binding to port zero, we need to figure out what port it ends up
+ // using using a named pipe...
+ error = port_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path);
+ if (error.Success())
+ {
+ debugserver_args.AppendArgument("--named-pipe");
+ debugserver_args.AppendArgument(named_pipe_path.c_str());
+ }
+ else
+ {
+ if (log)
+ log->Printf("GDBRemoteCommunication::%s() "
+ "named pipe creation failed: %s",
+ __FUNCTION__, error.AsCString());
+ // let's try an unnamed pipe
+ error = port_pipe.CreateNew(true);
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf("GDBRemoteCommunication::%s() "
+ "unnamed pipe creation failed: %s",
+ __FUNCTION__, error.AsCString());
+ return error;
+ }
+ int write_fd = port_pipe.GetWriteFileDescriptor();
+ debugserver_args.AppendArgument("--pipe");
+ debugserver_args.AppendArgument(std::to_string(write_fd).c_str());
+ launch_info.AppendCloseFileAction(port_pipe.GetReadFileDescriptor());
+ }
+ }
+ else
+ {
+ // No host and port given, so lets listen on our end and make the debugserver
+ // connect to us..
+ error = StartListenThread ("127.0.0.1", 0);
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s() unable to start listen thread: %s", __FUNCTION__, error.AsCString());
+ return error;
+ }
+
+ ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection ();
+ // Wait for 10 seconds to resolve the bound port
+ out_port = connection->GetListeningPort(10);
+ if (out_port > 0)
+ {
+ char port_cstr[32];
+ snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", out_port);
+ // Send the host and port down that debugserver and specify an option
+ // so that it connects back to the port we are listening to in this process
+ debugserver_args.AppendArgument("--reverse-connect");
+ debugserver_args.AppendArgument(port_cstr);
+ }
+ else
+ {
+ error.SetErrorString ("failed to bind to port 0 on 127.0.0.1");
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, error.AsCString());
+ return error;
+ }
+ }
+
+ const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE");
+ if (env_debugserver_log_file)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file);
+ debugserver_args.AppendArgument(arg_cstr);
+ }
+
+#if defined(__APPLE__)
+ const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS");
+ if (env_debugserver_log_flags)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags);
+ debugserver_args.AppendArgument(arg_cstr);
+ }
+#else
+ const char *env_debugserver_log_channels = getenv("LLDB_SERVER_LOG_CHANNELS");
+ if (env_debugserver_log_channels)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-channels=%s", env_debugserver_log_channels);
+ debugserver_args.AppendArgument(arg_cstr);
+ }
+#endif
+
+ // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an env var doesn't come back.
+ uint32_t env_var_index = 1;
+ bool has_env_var;
+ do
+ {
+ char env_var_name[64];
+ snprintf (env_var_name, sizeof (env_var_name), "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32, env_var_index++);
+ const char *extra_arg = getenv(env_var_name);
+ has_env_var = extra_arg != nullptr;
+
+ if (has_env_var)
+ {
+ debugserver_args.AppendArgument (extra_arg);
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s adding env var %s contents to stub command line (%s)", __FUNCTION__, env_var_name, extra_arg);
+ }
+ } while (has_env_var);
+
+ // Close STDIN, STDOUT and STDERR.
+ launch_info.AppendCloseFileAction (STDIN_FILENO);
+ launch_info.AppendCloseFileAction (STDOUT_FILENO);
+ launch_info.AppendCloseFileAction (STDERR_FILENO);
+
+ // Redirect STDIN, STDOUT and STDERR to "/dev/null".
+ launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false);
+ launch_info.AppendSuppressFileAction (STDOUT_FILENO, false, true);
+ launch_info.AppendSuppressFileAction (STDERR_FILENO, false, true);
+
+ error = Host::LaunchProcess(launch_info);
+
+ if (error.Success() && launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ {
+ if (named_pipe_path.size() > 0)
+ {
+ error = port_pipe.OpenAsReader(named_pipe_path, false);
+ if (error.Fail())
+ if (log)
+ log->Printf("GDBRemoteCommunication::%s() "
+ "failed to open named pipe %s for reading: %s",
+ __FUNCTION__, named_pipe_path.c_str(), error.AsCString());
+ }
+
+ if (port_pipe.CanWrite())
+ port_pipe.CloseWriteFileDescriptor();
+ if (port_pipe.CanRead())
+ {
+ char port_cstr[256];
+ port_cstr[0] = '\0';
+ size_t num_bytes = sizeof(port_cstr);
+ // Read port from pipe with 10 second timeout.
+ error = port_pipe.ReadWithTimeout(port_cstr, num_bytes,
+ std::chrono::seconds{10}, num_bytes);
+ if (error.Success())
+ {
+ assert(num_bytes > 0 && port_cstr[num_bytes-1] == '\0');
+ out_port = StringConvert::ToUInt32(port_cstr, 0);
+ if (log)
+ log->Printf("GDBRemoteCommunication::%s() "
+ "debugserver listens %u port",
+ __FUNCTION__, out_port);
+ }
+ else
+ {
+ if (log)
+ log->Printf("GDBRemoteCommunication::%s() "
+ "failed to read a port value from pipe %s: %s",
+ __FUNCTION__, named_pipe_path.c_str(), error.AsCString());
+
+ }
+ port_pipe.Close();
+ }
+
+ if (named_pipe_path.size() > 0)
+ {
+ const auto err = port_pipe.Delete(named_pipe_path);
+ if (err.Fail())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s failed to delete pipe %s: %s",
+ __FUNCTION__, named_pipe_path.c_str(), err.AsCString());
+ }
+ }
+
+ // Make sure we actually connect with the debugserver...
+ JoinListenThread();
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME );
+ }
+
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, error.AsCString());
+ }
+
+ return error;
+}
+
+void
+GDBRemoteCommunication::DumpHistory(Stream &strm)
+{
+ m_history.Dump (strm);
+}
+
+GDBRemoteCommunication::ScopedTimeout::ScopedTimeout (GDBRemoteCommunication& gdb_comm,
+ uint32_t timeout) :
+ m_gdb_comm (gdb_comm)
+{
+ m_saved_timeout = m_gdb_comm.SetPacketTimeout (timeout);
+}
+
+GDBRemoteCommunication::ScopedTimeout::~ScopedTimeout ()
+{
+ m_gdb_comm.SetPacketTimeout (m_saved_timeout);
+}
+
+// This function is called via the Communications class read thread when bytes become available
+// for this connection. This function will consume all incoming bytes and try to parse whole
+// packets as they become available. Full packets are placed in a queue, so that all packet
+// requests can simply pop from this queue. Async notification packets will be dispatched
+// immediately to the ProcessGDBRemote Async thread via an event.
+void GDBRemoteCommunication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, lldb::ConnectionStatus status)
+{
+ StringExtractorGDBRemote packet;
+
+ while (true)
+ {
+ PacketType type = CheckForPacket(bytes, len, packet);
+
+ // scrub the data so we do not pass it back to CheckForPacket
+ // on future passes of the loop
+ bytes = nullptr;
+ len = 0;
+
+ // we may have received no packet so lets bail out
+ if (type == PacketType::Invalid)
+ break;
+
+ if (type == PacketType::Standard)
+ {
+ // scope for the mutex
+ {
+ // lock down the packet queue
+ Mutex::Locker locker(m_packet_queue_mutex);
+ // push a new packet into the queue
+ m_packet_queue.push(packet);
+ // Signal condition variable that we have a packet
+ m_condition_queue_not_empty.Signal();
+
+ }
+ }
+
+ if (type == PacketType::Notify)
+ {
+ // put this packet into an event
+ const char *pdata = packet.GetStringRef().c_str();
+
+ // as the communication class, we are a broadcaster and the
+ // async thread is tuned to listen to us
+ BroadcastEvent(
+ eBroadcastBitGdbReadThreadGotNotify,
+ new EventDataBytes(pdata));
+ }
+ }
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
new file mode 100644
index 0000000..7379bb3
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
@@ -0,0 +1,384 @@
+//===-- GDBRemoteCommunication.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_GDBRemoteCommunication_h_
+#define liblldb_GDBRemoteCommunication_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <string>
+#include <queue>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Listener.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/Predicate.h"
+#include "lldb/Host/TimeValue.h"
+
+#include "Utility/StringExtractorGDBRemote.h"
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+typedef enum
+{
+ eStoppointInvalid = -1,
+ eBreakpointSoftware = 0,
+ eBreakpointHardware,
+ eWatchpointWrite,
+ eWatchpointRead,
+ eWatchpointReadWrite
+} GDBStoppointType;
+
+enum class CompressionType
+{
+ None = 0, // no compression
+ ZlibDeflate, // zlib's deflate compression scheme, requires zlib or Apple's libcompression
+ LZFSE, // an Apple compression scheme, requires Apple's libcompression
+ LZ4, // lz compression - called "lz4 raw" in libcompression terms, compat with https://code.google.com/p/lz4/
+ LZMA, // Lempel–Ziv–Markov chain algorithm
+};
+
+class ProcessGDBRemote;
+
+class GDBRemoteCommunication : public Communication
+{
+public:
+ enum
+ {
+ eBroadcastBitRunPacketSent = kLoUserBroadcastBit,
+ eBroadcastBitGdbReadThreadGotNotify = kLoUserBroadcastBit << 1 // Sent when we received a notify packet.
+ };
+
+ enum class PacketType
+ {
+ Invalid = 0,
+ Standard,
+ Notify
+ };
+
+ enum class PacketResult
+ {
+ Success = 0, // Success
+ ErrorSendFailed, // Error sending the packet
+ ErrorSendAck, // Didn't get an ack back after sending a packet
+ ErrorReplyFailed, // Error getting the reply
+ ErrorReplyTimeout, // Timed out waiting for reply
+ ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that was sent
+ ErrorReplyAck, // Sending reply ack failed
+ ErrorDisconnected, // We were disconnected
+ ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet request
+ };
+
+ // Class to change the timeout for a given scope and restore it to the original value when the
+ // created ScopedTimeout object got out of scope
+ class ScopedTimeout
+ {
+ public:
+ ScopedTimeout (GDBRemoteCommunication& gdb_comm, uint32_t timeout);
+ ~ScopedTimeout ();
+
+ private:
+ GDBRemoteCommunication& m_gdb_comm;
+ uint32_t m_saved_timeout;
+ };
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteCommunication(const char *comm_name,
+ const char *listener_name);
+
+ virtual
+ ~GDBRemoteCommunication();
+
+ PacketResult
+ GetAck ();
+
+ size_t
+ SendAck ();
+
+ size_t
+ SendNack ();
+
+ char
+ CalculcateChecksum (const char *payload,
+ size_t payload_length);
+
+ bool
+ GetSequenceMutex (Mutex::Locker& locker, const char *failure_message = NULL);
+
+ PacketType
+ CheckForPacket (const uint8_t *src,
+ size_t src_len,
+ StringExtractorGDBRemote &packet);
+ bool
+ IsRunning() const
+ {
+ return m_public_is_running.GetValue();
+ }
+
+ bool
+ GetSendAcks ()
+ {
+ return m_send_acks;
+ }
+
+ //------------------------------------------------------------------
+ // Client and server must implement these pure virtual functions
+ //------------------------------------------------------------------
+ virtual bool
+ GetThreadSuffixSupported () = 0;
+
+ //------------------------------------------------------------------
+ // Set the global packet timeout.
+ //
+ // For clients, this is the timeout that gets used when sending
+ // packets and waiting for responses. For servers, this might not
+ // get used, and if it doesn't this should be moved to the
+ // GDBRemoteCommunicationClient.
+ //------------------------------------------------------------------
+ uint32_t
+ SetPacketTimeout (uint32_t packet_timeout)
+ {
+ const uint32_t old_packet_timeout = m_packet_timeout;
+ m_packet_timeout = packet_timeout;
+ return old_packet_timeout;
+ }
+
+ uint32_t
+ GetPacketTimeoutInMicroSeconds () const
+ {
+ return m_packet_timeout * TimeValue::MicroSecPerSec;
+ }
+ //------------------------------------------------------------------
+ // Start a debugserver instance on the current host using the
+ // supplied connection URL.
+ //------------------------------------------------------------------
+ Error
+ StartDebugserverProcess (const char *hostname,
+ uint16_t in_port, // If set to zero, then out_port will contain the bound port on exit
+ ProcessLaunchInfo &launch_info,
+ uint16_t &out_port);
+
+ void
+ DumpHistory(Stream &strm);
+
+protected:
+
+ class History
+ {
+ public:
+ enum PacketType
+ {
+ ePacketTypeInvalid = 0,
+ ePacketTypeSend,
+ ePacketTypeRecv
+ };
+
+ struct Entry
+ {
+ Entry() :
+ packet(),
+ type (ePacketTypeInvalid),
+ bytes_transmitted (0),
+ packet_idx (0),
+ tid (LLDB_INVALID_THREAD_ID)
+ {
+ }
+
+ void
+ Clear ()
+ {
+ packet.clear();
+ type = ePacketTypeInvalid;
+ bytes_transmitted = 0;
+ packet_idx = 0;
+ tid = LLDB_INVALID_THREAD_ID;
+ }
+ std::string packet;
+ PacketType type;
+ uint32_t bytes_transmitted;
+ uint32_t packet_idx;
+ lldb::tid_t tid;
+ };
+
+ History (uint32_t size);
+
+ ~History ();
+
+ // For single char packets for ack, nack and /x03
+ void
+ AddPacket (char packet_char,
+ PacketType type,
+ uint32_t bytes_transmitted);
+ void
+ AddPacket (const std::string &src,
+ uint32_t src_len,
+ PacketType type,
+ uint32_t bytes_transmitted);
+
+ void
+ Dump (Stream &strm) const;
+
+ void
+ Dump (Log *log) const;
+
+ bool
+ DidDumpToLog () const
+ {
+ return m_dumped_to_log;
+ }
+
+protected:
+ uint32_t
+ GetFirstSavedPacketIndex () const
+ {
+ if (m_total_packet_count < m_packets.size())
+ return 0;
+ else
+ return m_curr_idx + 1;
+ }
+
+ uint32_t
+ GetNumPacketsInHistory () const
+ {
+ if (m_total_packet_count < m_packets.size())
+ return m_total_packet_count;
+ else
+ return (uint32_t)m_packets.size();
+ }
+
+ uint32_t
+ GetNextIndex()
+ {
+ ++m_total_packet_count;
+ const uint32_t idx = m_curr_idx;
+ m_curr_idx = NormalizeIndex(idx + 1);
+ return idx;
+ }
+
+ uint32_t
+ NormalizeIndex (uint32_t i) const
+ {
+ return i % m_packets.size();
+ }
+
+
+ std::vector<Entry> m_packets;
+ uint32_t m_curr_idx;
+ uint32_t m_total_packet_count;
+ mutable bool m_dumped_to_log;
+ };
+
+ PacketResult
+ SendPacket (const char *payload,
+ size_t payload_length);
+
+ PacketResult
+ SendPacketNoLock (const char *payload,
+ size_t payload_length);
+
+ PacketResult
+ ReadPacket (StringExtractorGDBRemote &response, uint32_t timeout_usec, bool sync_on_timeout);
+
+ // Pop a packet from the queue in a thread safe manner
+ PacketResult
+ PopPacketFromQueue (StringExtractorGDBRemote &response, uint32_t timeout_usec);
+
+ PacketResult
+ WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &response,
+ uint32_t timeout_usec,
+ bool sync_on_timeout);
+
+ bool
+ WaitForNotRunningPrivate (const TimeValue *timeout_ptr);
+
+ bool
+ CompressionIsEnabled ()
+ {
+ return m_compression_type != CompressionType::None;
+ }
+
+ // If compression is enabled, decompress the packet in m_bytes and update
+ // m_bytes with the uncompressed version.
+ // Returns 'true' packet was decompressed and m_bytes is the now-decompressed text.
+ // Returns 'false' if unable to decompress or if the checksum was invalid.
+ //
+ // NB: Once the packet has been decompressed, checksum cannot be computed based
+ // on m_bytes. The checksum was for the compressed packet.
+ bool
+ DecompressPacket ();
+
+ //------------------------------------------------------------------
+ // Classes that inherit from GDBRemoteCommunication can see and modify these
+ //------------------------------------------------------------------
+ uint32_t m_packet_timeout;
+ uint32_t m_echo_number;
+ LazyBool m_supports_qEcho;
+#ifdef ENABLE_MUTEX_ERROR_CHECKING
+ TrackingMutex m_sequence_mutex;
+#else
+ Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time
+#endif
+ Predicate<bool> m_public_is_running;
+ Predicate<bool> m_private_is_running;
+ History m_history;
+ bool m_send_acks;
+ bool m_is_platform; // Set to true if this class represents a platform,
+ // false if this class represents a debug session for
+ // a single process
+
+ CompressionType m_compression_type;
+
+ Error
+ StartListenThread (const char *hostname = "127.0.0.1", uint16_t port = 0);
+
+ bool
+ JoinListenThread ();
+
+ static lldb::thread_result_t
+ ListenThread (lldb::thread_arg_t arg);
+
+ // GDB-Remote read thread
+ // . this thread constantly tries to read from the communication
+ // class and stores all packets received in a queue. The usual
+ // threads read requests simply pop packets off the queue in the
+ // usual order.
+ // This setup allows us to intercept and handle async packets, such
+ // as the notify packet.
+
+ // This method is defined as part of communication.h
+ // when the read thread gets any bytes it will pass them on to this function
+ virtual void AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, lldb::ConnectionStatus status);
+
+private:
+
+ std::queue<StringExtractorGDBRemote> m_packet_queue; // The packet queue
+ lldb_private::Mutex m_packet_queue_mutex; // Mutex for accessing queue
+ Condition m_condition_queue_not_empty; // Condition variable to wait for packets
+
+ HostThread m_listen_thread;
+ std::string m_listen_url;
+
+ //------------------------------------------------------------------
+ // For GDBRemoteCommunication only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunication);
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // liblldb_GDBRemoteCommunication_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
new file mode 100644
index 0000000..b8c67c5
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -0,0 +1,4455 @@
+//===-- GDBRemoteCommunicationClient.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "GDBRemoteCommunicationClient.h"
+
+// C Includes
+#include <math.h>
+#include <sys/stat.h>
+
+// C++ Includes
+#include <sstream>
+#include <numeric>
+
+// Other libraries and framework includes
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamGDBRemote.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/UnixSignals.h"
+
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "lldb/Host/Config.h"
+
+#if defined (HAVE_LIBCOMPRESSION)
+#include <compression.h>
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunicationClient constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() :
+ GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet"),
+ m_supports_not_sending_acks (eLazyBoolCalculate),
+ m_supports_thread_suffix (eLazyBoolCalculate),
+ m_supports_threads_in_stop_reply (eLazyBoolCalculate),
+ m_supports_vCont_all (eLazyBoolCalculate),
+ m_supports_vCont_any (eLazyBoolCalculate),
+ m_supports_vCont_c (eLazyBoolCalculate),
+ m_supports_vCont_C (eLazyBoolCalculate),
+ m_supports_vCont_s (eLazyBoolCalculate),
+ m_supports_vCont_S (eLazyBoolCalculate),
+ m_qHostInfo_is_valid (eLazyBoolCalculate),
+ m_curr_pid_is_valid (eLazyBoolCalculate),
+ m_qProcessInfo_is_valid (eLazyBoolCalculate),
+ m_qGDBServerVersion_is_valid (eLazyBoolCalculate),
+ m_supports_alloc_dealloc_memory (eLazyBoolCalculate),
+ m_supports_memory_region_info (eLazyBoolCalculate),
+ m_supports_watchpoint_support_info (eLazyBoolCalculate),
+ m_supports_detach_stay_stopped (eLazyBoolCalculate),
+ m_watchpoints_trigger_after_instruction(eLazyBoolCalculate),
+ m_attach_or_wait_reply(eLazyBoolCalculate),
+ m_prepare_for_reg_writing_reply (eLazyBoolCalculate),
+ m_supports_p (eLazyBoolCalculate),
+ m_supports_x (eLazyBoolCalculate),
+ m_avoid_g_packets (eLazyBoolCalculate),
+ m_supports_QSaveRegisterState (eLazyBoolCalculate),
+ m_supports_qXfer_auxv_read (eLazyBoolCalculate),
+ m_supports_qXfer_libraries_read (eLazyBoolCalculate),
+ m_supports_qXfer_libraries_svr4_read (eLazyBoolCalculate),
+ m_supports_qXfer_features_read (eLazyBoolCalculate),
+ m_supports_augmented_libraries_svr4_read (eLazyBoolCalculate),
+ m_supports_jThreadExtendedInfo (eLazyBoolCalculate),
+ m_supports_jLoadedDynamicLibrariesInfos (eLazyBoolCalculate),
+ m_supports_qProcessInfoPID (true),
+ m_supports_qfProcessInfo (true),
+ m_supports_qUserName (true),
+ m_supports_qGroupName (true),
+ m_supports_qThreadStopInfo (true),
+ m_supports_z0 (true),
+ m_supports_z1 (true),
+ m_supports_z2 (true),
+ m_supports_z3 (true),
+ m_supports_z4 (true),
+ m_supports_QEnvironment (true),
+ m_supports_QEnvironmentHexEncoded (true),
+ m_supports_qSymbol (true),
+ m_supports_jThreadsInfo (true),
+ m_curr_pid (LLDB_INVALID_PROCESS_ID),
+ m_curr_tid (LLDB_INVALID_THREAD_ID),
+ m_curr_tid_run (LLDB_INVALID_THREAD_ID),
+ m_num_supported_hardware_watchpoints (0),
+ m_async_mutex (Mutex::eMutexTypeRecursive),
+ m_async_packet_predicate (false),
+ m_async_packet (),
+ m_async_result (PacketResult::Success),
+ m_async_response (),
+ m_async_signal (-1),
+ m_interrupt_sent (false),
+ m_thread_id_to_used_usec_map (),
+ m_host_arch(),
+ m_process_arch(),
+ m_os_version_major (UINT32_MAX),
+ m_os_version_minor (UINT32_MAX),
+ m_os_version_update (UINT32_MAX),
+ m_os_build (),
+ m_os_kernel (),
+ m_hostname (),
+ m_gdb_server_name(),
+ m_gdb_server_version(UINT32_MAX),
+ m_default_packet_timeout (0),
+ m_max_packet_size (0)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient()
+{
+ if (IsConnected())
+ Disconnect();
+}
+
+bool
+GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr)
+{
+ ResetDiscoverableSettings(false);
+
+ // Start the read thread after we send the handshake ack since if we
+ // fail to send the handshake ack, there is no reason to continue...
+ if (SendAck())
+ {
+ // Wait for any responses that might have been queued up in the remote
+ // GDB server and flush them all
+ StringExtractorGDBRemote response;
+ PacketResult packet_result = PacketResult::Success;
+ const uint32_t timeout_usec = 10 * 1000; // Wait for 10 ms for a response
+ while (packet_result == PacketResult::Success)
+ packet_result = ReadPacket (response, timeout_usec, false);
+
+ // The return value from QueryNoAckModeSupported() is true if the packet
+ // was sent and _any_ response (including UNIMPLEMENTED) was received),
+ // or false if no response was received. This quickly tells us if we have
+ // a live connection to a remote GDB server...
+ if (QueryNoAckModeSupported())
+ {
+ return true;
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("failed to get reply to handshake packet");
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("failed to send the handshake ack");
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetEchoSupported ()
+{
+ if (m_supports_qEcho == eLazyBoolCalculate)
+ {
+ GetRemoteQSupported();
+ }
+ return m_supports_qEcho == eLazyBoolYes;
+}
+
+
+bool
+GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported ()
+{
+ if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate)
+ {
+ GetRemoteQSupported();
+ }
+ return m_supports_augmented_libraries_svr4_read == eLazyBoolYes;
+}
+
+bool
+GDBRemoteCommunicationClient::GetQXferLibrariesSVR4ReadSupported ()
+{
+ if (m_supports_qXfer_libraries_svr4_read == eLazyBoolCalculate)
+ {
+ GetRemoteQSupported();
+ }
+ return m_supports_qXfer_libraries_svr4_read == eLazyBoolYes;
+}
+
+bool
+GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported ()
+{
+ if (m_supports_qXfer_libraries_read == eLazyBoolCalculate)
+ {
+ GetRemoteQSupported();
+ }
+ return m_supports_qXfer_libraries_read == eLazyBoolYes;
+}
+
+bool
+GDBRemoteCommunicationClient::GetQXferAuxvReadSupported ()
+{
+ if (m_supports_qXfer_auxv_read == eLazyBoolCalculate)
+ {
+ GetRemoteQSupported();
+ }
+ return m_supports_qXfer_auxv_read == eLazyBoolYes;
+}
+
+bool
+GDBRemoteCommunicationClient::GetQXferFeaturesReadSupported ()
+{
+ if (m_supports_qXfer_features_read == eLazyBoolCalculate)
+ {
+ GetRemoteQSupported();
+ }
+ return m_supports_qXfer_features_read == eLazyBoolYes;
+}
+
+uint64_t
+GDBRemoteCommunicationClient::GetRemoteMaxPacketSize()
+{
+ if (m_max_packet_size == 0)
+ {
+ GetRemoteQSupported();
+ }
+ return m_max_packet_size;
+}
+
+bool
+GDBRemoteCommunicationClient::QueryNoAckModeSupported ()
+{
+ if (m_supports_not_sending_acks == eLazyBoolCalculate)
+ {
+ m_send_acks = true;
+ m_supports_not_sending_acks = eLazyBoolNo;
+
+ // This is the first real packet that we'll send in a debug session and it may take a little
+ // longer than normal to receive a reply. Wait at least 6 seconds for a reply to this packet.
+
+ const uint32_t minimum_timeout = 6;
+ uint32_t old_timeout = GetPacketTimeoutInMicroSeconds() / lldb_private::TimeValue::MicroSecPerSec;
+ GDBRemoteCommunication::ScopedTimeout timeout (*this, std::max (old_timeout, minimum_timeout));
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ {
+ m_send_acks = false;
+ m_supports_not_sending_acks = eLazyBoolYes;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported ()
+{
+ if (m_supports_threads_in_stop_reply == eLazyBoolCalculate)
+ {
+ m_supports_threads_in_stop_reply = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ m_supports_threads_in_stop_reply = eLazyBoolYes;
+ }
+ }
+}
+
+bool
+GDBRemoteCommunicationClient::GetVAttachOrWaitSupported ()
+{
+ if (m_attach_or_wait_reply == eLazyBoolCalculate)
+ {
+ m_attach_or_wait_reply = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ m_attach_or_wait_reply = eLazyBoolYes;
+ }
+ }
+ if (m_attach_or_wait_reply == eLazyBoolYes)
+ return true;
+ else
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetSyncThreadStateSupported ()
+{
+ if (m_prepare_for_reg_writing_reply == eLazyBoolCalculate)
+ {
+ m_prepare_for_reg_writing_reply = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ m_prepare_for_reg_writing_reply = eLazyBoolYes;
+ }
+ }
+ if (m_prepare_for_reg_writing_reply == eLazyBoolYes)
+ return true;
+ else
+ return false;
+}
+
+
+void
+GDBRemoteCommunicationClient::ResetDiscoverableSettings (bool did_exec)
+{
+ if (did_exec == false)
+ {
+ // Hard reset everything, this is when we first connect to a GDB server
+ m_supports_not_sending_acks = eLazyBoolCalculate;
+ m_supports_thread_suffix = eLazyBoolCalculate;
+ m_supports_threads_in_stop_reply = eLazyBoolCalculate;
+ m_supports_vCont_c = eLazyBoolCalculate;
+ m_supports_vCont_C = eLazyBoolCalculate;
+ m_supports_vCont_s = eLazyBoolCalculate;
+ m_supports_vCont_S = eLazyBoolCalculate;
+ m_supports_p = eLazyBoolCalculate;
+ m_supports_x = eLazyBoolCalculate;
+ m_supports_QSaveRegisterState = eLazyBoolCalculate;
+ m_qHostInfo_is_valid = eLazyBoolCalculate;
+ m_curr_pid_is_valid = eLazyBoolCalculate;
+ m_qGDBServerVersion_is_valid = eLazyBoolCalculate;
+ m_supports_alloc_dealloc_memory = eLazyBoolCalculate;
+ m_supports_memory_region_info = eLazyBoolCalculate;
+ m_prepare_for_reg_writing_reply = eLazyBoolCalculate;
+ m_attach_or_wait_reply = eLazyBoolCalculate;
+ m_avoid_g_packets = eLazyBoolCalculate;
+ m_supports_qXfer_auxv_read = eLazyBoolCalculate;
+ m_supports_qXfer_libraries_read = eLazyBoolCalculate;
+ m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate;
+ m_supports_qXfer_features_read = eLazyBoolCalculate;
+ m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate;
+ m_supports_qProcessInfoPID = true;
+ m_supports_qfProcessInfo = true;
+ m_supports_qUserName = true;
+ m_supports_qGroupName = true;
+ m_supports_qThreadStopInfo = true;
+ m_supports_z0 = true;
+ m_supports_z1 = true;
+ m_supports_z2 = true;
+ m_supports_z3 = true;
+ m_supports_z4 = true;
+ m_supports_QEnvironment = true;
+ m_supports_QEnvironmentHexEncoded = true;
+ m_supports_qSymbol = true;
+ m_host_arch.Clear();
+ m_os_version_major = UINT32_MAX;
+ m_os_version_minor = UINT32_MAX;
+ m_os_version_update = UINT32_MAX;
+ m_os_build.clear();
+ m_os_kernel.clear();
+ m_hostname.clear();
+ m_gdb_server_name.clear();
+ m_gdb_server_version = UINT32_MAX;
+ m_default_packet_timeout = 0;
+ m_max_packet_size = 0;
+ }
+
+ // These flags should be reset when we first connect to a GDB server
+ // and when our inferior process execs
+ m_qProcessInfo_is_valid = eLazyBoolCalculate;
+ m_process_arch.Clear();
+}
+
+void
+GDBRemoteCommunicationClient::GetRemoteQSupported ()
+{
+ // Clear out any capabilities we expect to see in the qSupported response
+ m_supports_qXfer_auxv_read = eLazyBoolNo;
+ m_supports_qXfer_libraries_read = eLazyBoolNo;
+ m_supports_qXfer_libraries_svr4_read = eLazyBoolNo;
+ m_supports_augmented_libraries_svr4_read = eLazyBoolNo;
+ m_supports_qXfer_features_read = eLazyBoolNo;
+ m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if not, we assume no limit
+
+ // build the qSupported packet
+ std::vector<std::string> features = {"xmlRegisters=i386,arm,mips"};
+ StreamString packet;
+ packet.PutCString( "qSupported" );
+ for ( uint32_t i = 0; i < features.size( ); ++i )
+ {
+ packet.PutCString( i==0 ? ":" : ";");
+ packet.PutCString( features[i].c_str( ) );
+ }
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetData(),
+ response,
+ /*send_async=*/false) == PacketResult::Success)
+ {
+ const char *response_cstr = response.GetStringRef().c_str();
+ if (::strstr (response_cstr, "qXfer:auxv:read+"))
+ m_supports_qXfer_auxv_read = eLazyBoolYes;
+ if (::strstr (response_cstr, "qXfer:libraries-svr4:read+"))
+ m_supports_qXfer_libraries_svr4_read = eLazyBoolYes;
+ if (::strstr (response_cstr, "augmented-libraries-svr4-read"))
+ {
+ m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; // implied
+ m_supports_augmented_libraries_svr4_read = eLazyBoolYes;
+ }
+ if (::strstr (response_cstr, "qXfer:libraries:read+"))
+ m_supports_qXfer_libraries_read = eLazyBoolYes;
+ if (::strstr (response_cstr, "qXfer:features:read+"))
+ m_supports_qXfer_features_read = eLazyBoolYes;
+
+
+ // Look for a list of compressions in the features list e.g.
+ // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-deflate,lzma
+ const char *features_list = ::strstr (response_cstr, "qXfer:features:");
+ if (features_list)
+ {
+ const char *compressions = ::strstr (features_list, "SupportedCompressions=");
+ if (compressions)
+ {
+ std::vector<std::string> supported_compressions;
+ compressions += sizeof ("SupportedCompressions=") - 1;
+ const char *end_of_compressions = strchr (compressions, ';');
+ if (end_of_compressions == NULL)
+ {
+ end_of_compressions = strchr (compressions, '\0');
+ }
+ const char *current_compression = compressions;
+ while (current_compression < end_of_compressions)
+ {
+ const char *next_compression_name = strchr (current_compression, ',');
+ const char *end_of_this_word = next_compression_name;
+ if (next_compression_name == NULL || end_of_compressions < next_compression_name)
+ {
+ end_of_this_word = end_of_compressions;
+ }
+
+ if (end_of_this_word)
+ {
+ if (end_of_this_word == current_compression)
+ {
+ current_compression++;
+ }
+ else
+ {
+ std::string this_compression (current_compression, end_of_this_word - current_compression);
+ supported_compressions.push_back (this_compression);
+ current_compression = end_of_this_word + 1;
+ }
+ }
+ else
+ {
+ supported_compressions.push_back (current_compression);
+ current_compression = end_of_compressions;
+ }
+ }
+
+ if (supported_compressions.size() > 0)
+ {
+ MaybeEnableCompression (supported_compressions);
+ }
+ }
+ }
+
+ if (::strstr (response_cstr, "qEcho"))
+ m_supports_qEcho = eLazyBoolYes;
+ else
+ m_supports_qEcho = eLazyBoolNo;
+
+ const char *packet_size_str = ::strstr (response_cstr, "PacketSize=");
+ if (packet_size_str)
+ {
+ StringExtractorGDBRemote packet_response(packet_size_str + strlen("PacketSize="));
+ m_max_packet_size = packet_response.GetHexMaxU64(/*little_endian=*/false, UINT64_MAX);
+ if (m_max_packet_size == 0)
+ {
+ m_max_packet_size = UINT64_MAX; // Must have been a garbled response
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("Garbled PacketSize spec in qSupported response");
+ }
+ }
+ }
+}
+
+bool
+GDBRemoteCommunicationClient::GetThreadSuffixSupported ()
+{
+ if (m_supports_thread_suffix == eLazyBoolCalculate)
+ {
+ StringExtractorGDBRemote response;
+ m_supports_thread_suffix = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ m_supports_thread_suffix = eLazyBoolYes;
+ }
+ }
+ return m_supports_thread_suffix;
+}
+bool
+GDBRemoteCommunicationClient::GetVContSupported (char flavor)
+{
+ if (m_supports_vCont_c == eLazyBoolCalculate)
+ {
+ StringExtractorGDBRemote response;
+ m_supports_vCont_any = eLazyBoolNo;
+ m_supports_vCont_all = eLazyBoolNo;
+ m_supports_vCont_c = eLazyBoolNo;
+ m_supports_vCont_C = eLazyBoolNo;
+ m_supports_vCont_s = eLazyBoolNo;
+ m_supports_vCont_S = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("vCont?", response, false) == PacketResult::Success)
+ {
+ const char *response_cstr = response.GetStringRef().c_str();
+ if (::strstr (response_cstr, ";c"))
+ m_supports_vCont_c = eLazyBoolYes;
+
+ if (::strstr (response_cstr, ";C"))
+ m_supports_vCont_C = eLazyBoolYes;
+
+ if (::strstr (response_cstr, ";s"))
+ m_supports_vCont_s = eLazyBoolYes;
+
+ if (::strstr (response_cstr, ";S"))
+ m_supports_vCont_S = eLazyBoolYes;
+
+ if (m_supports_vCont_c == eLazyBoolYes &&
+ m_supports_vCont_C == eLazyBoolYes &&
+ m_supports_vCont_s == eLazyBoolYes &&
+ m_supports_vCont_S == eLazyBoolYes)
+ {
+ m_supports_vCont_all = eLazyBoolYes;
+ }
+
+ if (m_supports_vCont_c == eLazyBoolYes ||
+ m_supports_vCont_C == eLazyBoolYes ||
+ m_supports_vCont_s == eLazyBoolYes ||
+ m_supports_vCont_S == eLazyBoolYes)
+ {
+ m_supports_vCont_any = eLazyBoolYes;
+ }
+ }
+ }
+
+ switch (flavor)
+ {
+ case 'a': return m_supports_vCont_any;
+ case 'A': return m_supports_vCont_all;
+ case 'c': return m_supports_vCont_c;
+ case 'C': return m_supports_vCont_C;
+ case 's': return m_supports_vCont_s;
+ case 'S': return m_supports_vCont_S;
+ default: break;
+ }
+ return false;
+}
+
+// Check if the target supports 'p' packet. It sends out a 'p'
+// packet and checks the response. A normal packet will tell us
+// that support is available.
+//
+// Takes a valid thread ID because p needs to apply to a thread.
+bool
+GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid)
+{
+ if (m_supports_p == eLazyBoolCalculate)
+ {
+ StringExtractorGDBRemote response;
+ m_supports_p = eLazyBoolNo;
+ char packet[256];
+ if (GetThreadSuffixSupported())
+ snprintf(packet, sizeof(packet), "p0;thread:%" PRIx64 ";", tid);
+ else
+ snprintf(packet, sizeof(packet), "p0");
+
+ if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success)
+ {
+ if (response.IsNormalResponse())
+ m_supports_p = eLazyBoolYes;
+ }
+ }
+ return m_supports_p;
+}
+
+StructuredData::ObjectSP
+GDBRemoteCommunicationClient::GetThreadsInfo()
+{
+ // Get information on all threads at one using the "jThreadsInfo" packet
+ StructuredData::ObjectSP object_sp;
+
+ if (m_supports_jThreadsInfo)
+ {
+ StringExtractorGDBRemote response;
+ m_supports_jThreadExtendedInfo = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("jThreadsInfo", response, false) == PacketResult::Success)
+ {
+ if (response.IsUnsupportedResponse())
+ {
+ m_supports_jThreadsInfo = false;
+ }
+ else if (!response.Empty())
+ {
+ object_sp = StructuredData::ParseJSON (response.GetStringRef());
+ }
+ }
+ }
+ return object_sp;
+}
+
+
+bool
+GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported ()
+{
+ if (m_supports_jThreadExtendedInfo == eLazyBoolCalculate)
+ {
+ StringExtractorGDBRemote response;
+ m_supports_jThreadExtendedInfo = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ {
+ m_supports_jThreadExtendedInfo = eLazyBoolYes;
+ }
+ }
+ }
+ return m_supports_jThreadExtendedInfo;
+}
+
+bool
+GDBRemoteCommunicationClient::GetLoadedDynamicLibrariesInfosSupported ()
+{
+ if (m_supports_jLoadedDynamicLibrariesInfos == eLazyBoolCalculate)
+ {
+ StringExtractorGDBRemote response;
+ m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("jGetLoadedDynamicLibrariesInfos:", response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ {
+ m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolYes;
+ }
+ }
+ }
+ return m_supports_jLoadedDynamicLibrariesInfos;
+}
+
+bool
+GDBRemoteCommunicationClient::GetxPacketSupported ()
+{
+ if (m_supports_x == eLazyBoolCalculate)
+ {
+ StringExtractorGDBRemote response;
+ m_supports_x = eLazyBoolNo;
+ char packet[256];
+ snprintf (packet, sizeof (packet), "x0,0");
+ if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ m_supports_x = eLazyBoolYes;
+ }
+ }
+ return m_supports_x;
+}
+
+GDBRemoteCommunicationClient::PacketResult
+GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses
+(
+ const char *payload_prefix,
+ std::string &response_string
+)
+{
+ Mutex::Locker locker;
+ if (!GetSequenceMutex(locker,
+ "ProcessGDBRemote::SendPacketsAndConcatenateResponses() failed due to not getting the sequence mutex"))
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS));
+ if (log)
+ log->Printf("error: failed to get packet sequence mutex, not sending packets with prefix '%s'",
+ payload_prefix);
+ return PacketResult::ErrorNoSequenceLock;
+ }
+
+ response_string = "";
+ std::string payload_prefix_str(payload_prefix);
+ unsigned int response_size = 0x1000;
+ if (response_size > GetRemoteMaxPacketSize()) { // May send qSupported packet
+ response_size = GetRemoteMaxPacketSize();
+ }
+
+ for (unsigned int offset = 0; true; offset += response_size)
+ {
+ StringExtractorGDBRemote this_response;
+ // Construct payload
+ char sizeDescriptor[128];
+ snprintf(sizeDescriptor, sizeof(sizeDescriptor), "%x,%x", offset, response_size);
+ PacketResult result = SendPacketAndWaitForResponse((payload_prefix_str + sizeDescriptor).c_str(),
+ this_response,
+ /*send_async=*/false);
+ if (result != PacketResult::Success)
+ return result;
+
+ const std::string &this_string = this_response.GetStringRef();
+
+ // Check for m or l as first character; l seems to mean this is the last chunk
+ char first_char = *this_string.c_str();
+ if (first_char != 'm' && first_char != 'l')
+ {
+ return PacketResult::ErrorReplyInvalid;
+ }
+ // Concatenate the result so far (skipping 'm' or 'l')
+ response_string.append(this_string, 1, std::string::npos);
+ if (first_char == 'l')
+ // We're done
+ return PacketResult::Success;
+ }
+}
+
+GDBRemoteCommunicationClient::PacketResult
+GDBRemoteCommunicationClient::SendPacketAndWaitForResponse
+(
+ const char *payload,
+ StringExtractorGDBRemote &response,
+ bool send_async
+)
+{
+ return SendPacketAndWaitForResponse (payload,
+ ::strlen (payload),
+ response,
+ send_async);
+}
+
+GDBRemoteCommunicationClient::PacketResult
+GDBRemoteCommunicationClient::SendPacketAndWaitForResponseNoLock (const char *payload,
+ size_t payload_length,
+ StringExtractorGDBRemote &response)
+{
+ PacketResult packet_result = SendPacketNoLock (payload, payload_length);
+ if (packet_result == PacketResult::Success)
+ packet_result = ReadPacket (response, GetPacketTimeoutInMicroSeconds (), true);
+ return packet_result;
+}
+
+GDBRemoteCommunicationClient::PacketResult
+GDBRemoteCommunicationClient::SendPacketAndWaitForResponse
+(
+ const char *payload,
+ size_t payload_length,
+ StringExtractorGDBRemote &response,
+ bool send_async
+)
+{
+ PacketResult packet_result = PacketResult::ErrorSendFailed;
+ Mutex::Locker locker;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+
+ // In order to stop async notifications from being processed in the middle of the
+ // send/recieve sequence Hijack the broadcast. Then rebroadcast any events when we are done.
+ static Listener hijack_listener("lldb.NotifyHijacker");
+ HijackBroadcaster(&hijack_listener, eBroadcastBitGdbReadThreadGotNotify);
+
+ if (GetSequenceMutex (locker))
+ {
+ packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response);
+ }
+ else
+ {
+ if (send_async)
+ {
+ if (IsRunning())
+ {
+ Mutex::Locker async_locker (m_async_mutex);
+ m_async_packet.assign(payload, payload_length);
+ m_async_packet_predicate.SetValue (true, eBroadcastNever);
+
+ if (log)
+ log->Printf ("async: async packet = %s", m_async_packet.c_str());
+
+ bool timed_out = false;
+ if (SendInterrupt(locker, 2, timed_out))
+ {
+ if (m_interrupt_sent)
+ {
+ m_interrupt_sent = false;
+ TimeValue timeout_time;
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds (m_packet_timeout);
+
+ if (log)
+ log->Printf ("async: sent interrupt");
+
+ if (m_async_packet_predicate.WaitForValueEqualTo (false, &timeout_time, &timed_out))
+ {
+ if (log)
+ log->Printf ("async: got response");
+
+ // Swap the response buffer to avoid malloc and string copy
+ response.GetStringRef().swap (m_async_response.GetStringRef());
+ packet_result = m_async_result;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("async: timed out waiting for response");
+ }
+
+ // Make sure we wait until the continue packet has been sent again...
+ if (m_private_is_running.WaitForValueEqualTo (true, &timeout_time, &timed_out))
+ {
+ if (log)
+ {
+ if (timed_out)
+ log->Printf ("async: timed out waiting for process to resume, but process was resumed");
+ else
+ log->Printf ("async: async packet sent");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("async: timed out waiting for process to resume");
+ }
+ }
+ else
+ {
+ // We had a racy condition where we went to send the interrupt
+ // yet we were able to get the lock, so the process must have
+ // just stopped?
+ if (log)
+ log->Printf ("async: got lock without sending interrupt");
+ // Send the packet normally since we got the lock
+ packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("async: failed to interrupt");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("async: not running, async is ignored");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("error: failed to get packet sequence mutex, not sending packet '%*s'", (int) payload_length, payload);
+ }
+ }
+
+ // Remove our Hijacking listner from the broadcast.
+ RestoreBroadcaster();
+
+ // If a notification event occured, rebroadcast since it can now be processed safely.
+ EventSP event_sp;
+ if (hijack_listener.GetNextEvent(event_sp))
+ BroadcastEvent(event_sp);
+
+ return packet_result;
+}
+
+static const char *end_delimiter = "--end--;";
+static const int end_delimiter_len = 8;
+
+std::string
+GDBRemoteCommunicationClient::HarmonizeThreadIdsForProfileData
+( ProcessGDBRemote *process,
+ StringExtractorGDBRemote& profileDataExtractor
+)
+{
+ std::map<uint64_t, uint32_t> new_thread_id_to_used_usec_map;
+ std::stringstream final_output;
+ std::string name, value;
+
+ // Going to assuming thread_used_usec comes first, else bail out.
+ while (profileDataExtractor.GetNameColonValue(name, value))
+ {
+ if (name.compare("thread_used_id") == 0)
+ {
+ StringExtractor threadIDHexExtractor(value.c_str());
+ uint64_t thread_id = threadIDHexExtractor.GetHexMaxU64(false, 0);
+
+ bool has_used_usec = false;
+ uint32_t curr_used_usec = 0;
+ std::string usec_name, usec_value;
+ uint32_t input_file_pos = profileDataExtractor.GetFilePos();
+ if (profileDataExtractor.GetNameColonValue(usec_name, usec_value))
+ {
+ if (usec_name.compare("thread_used_usec") == 0)
+ {
+ has_used_usec = true;
+ curr_used_usec = strtoull(usec_value.c_str(), NULL, 0);
+ }
+ else
+ {
+ // We didn't find what we want, it is probably
+ // an older version. Bail out.
+ profileDataExtractor.SetFilePos(input_file_pos);
+ }
+ }
+
+ if (has_used_usec)
+ {
+ uint32_t prev_used_usec = 0;
+ std::map<uint64_t, uint32_t>::iterator iterator = m_thread_id_to_used_usec_map.find(thread_id);
+ if (iterator != m_thread_id_to_used_usec_map.end())
+ {
+ prev_used_usec = m_thread_id_to_used_usec_map[thread_id];
+ }
+
+ uint32_t real_used_usec = curr_used_usec - prev_used_usec;
+ // A good first time record is one that runs for at least 0.25 sec
+ bool good_first_time = (prev_used_usec == 0) && (real_used_usec > 250000);
+ bool good_subsequent_time = (prev_used_usec > 0) &&
+ ((real_used_usec > 0) || (process->HasAssignedIndexIDToThread(thread_id)));
+
+ if (good_first_time || good_subsequent_time)
+ {
+ // We try to avoid doing too many index id reservation,
+ // resulting in fast increase of index ids.
+
+ final_output << name << ":";
+ int32_t index_id = process->AssignIndexIDToThread(thread_id);
+ final_output << index_id << ";";
+
+ final_output << usec_name << ":" << usec_value << ";";
+ }
+ else
+ {
+ // Skip past 'thread_used_name'.
+ std::string local_name, local_value;
+ profileDataExtractor.GetNameColonValue(local_name, local_value);
+ }
+
+ // Store current time as previous time so that they can be compared later.
+ new_thread_id_to_used_usec_map[thread_id] = curr_used_usec;
+ }
+ else
+ {
+ // Bail out and use old string.
+ final_output << name << ":" << value << ";";
+ }
+ }
+ else
+ {
+ final_output << name << ":" << value << ";";
+ }
+ }
+ final_output << end_delimiter;
+ m_thread_id_to_used_usec_map = new_thread_id_to_used_usec_map;
+
+ return final_output.str();
+}
+
+bool
+GDBRemoteCommunicationClient::SendvContPacket
+(
+ ProcessGDBRemote *process,
+ const char *payload,
+ size_t packet_length,
+ StringExtractorGDBRemote &response
+)
+{
+
+ m_curr_tid = LLDB_INVALID_THREAD_ID;
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf("GDBRemoteCommunicationClient::%s ()", __FUNCTION__);
+
+ // we want to lock down packet sending while we continue
+ Mutex::Locker locker(m_sequence_mutex);
+
+ // here we broadcast this before we even send the packet!!
+ // this signals doContinue() to exit
+ BroadcastEvent(eBroadcastBitRunPacketSent, NULL);
+
+ // set the public state to running
+ m_public_is_running.SetValue(true, eBroadcastNever);
+
+ // Set the starting continue packet into "continue_packet". This packet
+ // may change if we are interrupted and we continue after an async packet...
+ std::string continue_packet(payload, packet_length);
+
+ if (log)
+ log->Printf("GDBRemoteCommunicationClient::%s () sending vCont packet: %s", __FUNCTION__, continue_packet.c_str());
+
+ if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success)
+ return false;
+
+ // set the private state to running and broadcast this
+ m_private_is_running.SetValue(true, eBroadcastAlways);
+
+ if (log)
+ log->Printf("GDBRemoteCommunicationClient::%s () ReadPacket(%s)", __FUNCTION__, continue_packet.c_str());
+
+ // wait for the response to the vCont
+ if (ReadPacket(response, UINT32_MAX, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return true;
+ }
+
+ return false;
+}
+
+StateType
+GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse
+(
+ ProcessGDBRemote *process,
+ const char *payload,
+ size_t packet_length,
+ StringExtractorGDBRemote &response
+)
+{
+ m_curr_tid = LLDB_INVALID_THREAD_ID;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s ()", __FUNCTION__);
+
+ Mutex::Locker locker(m_sequence_mutex);
+ StateType state = eStateRunning;
+
+ BroadcastEvent(eBroadcastBitRunPacketSent, NULL);
+ m_public_is_running.SetValue (true, eBroadcastNever);
+ // Set the starting continue packet into "continue_packet". This packet
+ // may change if we are interrupted and we continue after an async packet...
+ std::string continue_packet(payload, packet_length);
+
+ const auto sigstop_signo = process->GetUnixSignals()->GetSignalNumberFromName("SIGSTOP");
+ const auto sigint_signo = process->GetUnixSignals()->GetSignalNumberFromName("SIGINT");
+
+ bool got_async_packet = false;
+
+ while (state == eStateRunning)
+ {
+ if (!got_async_packet)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str());
+ if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success)
+ state = eStateInvalid;
+ else
+ m_interrupt_sent = false;
+
+ m_private_is_running.SetValue (true, eBroadcastAlways);
+ }
+
+ got_async_packet = false;
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () ReadPacket(%s)", __FUNCTION__, continue_packet.c_str());
+
+ if (ReadPacket(response, UINT32_MAX, false) == PacketResult::Success)
+ {
+ if (response.Empty())
+ state = eStateInvalid;
+ else
+ {
+ const char stop_type = response.GetChar();
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () got packet: %s", __FUNCTION__, response.GetStringRef().c_str());
+ switch (stop_type)
+ {
+ case 'T':
+ case 'S':
+ {
+ if (process->GetStopID() == 0)
+ {
+ if (process->GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ lldb::pid_t pid = GetCurrentProcessID ();
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ process->SetID (pid);
+ }
+ process->BuildDynamicRegisterInfo (true);
+ }
+
+ // Privately notify any internal threads that we have stopped
+ // in case we wanted to interrupt our process, yet we might
+ // send a packet and continue without returning control to the
+ // user.
+ m_private_is_running.SetValue (false, eBroadcastAlways);
+
+ const uint8_t signo = response.GetHexU8 (UINT8_MAX);
+
+ bool continue_after_async = m_async_signal != -1 || m_async_packet_predicate.GetValue();
+ if (continue_after_async || m_interrupt_sent)
+ {
+ // We sent an interrupt packet to stop the inferior process
+ // for an async signal or to send an async packet while running
+ // but we might have been single stepping and received the
+ // stop packet for the step instead of for the interrupt packet.
+ // Typically when an interrupt is sent a SIGINT or SIGSTOP
+ // is used, so if we get anything else, we need to try and
+ // get another stop reply packet that may have been sent
+ // due to sending the interrupt when the target is stopped
+ // which will just re-send a copy of the last stop reply
+ // packet. If we don't do this, then the reply for our
+ // async packet will be the repeat stop reply packet and cause
+ // a lot of trouble for us!
+ if (signo != sigint_signo && signo != sigstop_signo)
+ {
+ continue_after_async = false;
+
+ // We didn't get a SIGINT or SIGSTOP, so try for a
+ // very brief time (1 ms) to get another stop reply
+ // packet to make sure it doesn't get in the way
+ StringExtractorGDBRemote extra_stop_reply_packet;
+ uint32_t timeout_usec = 1000;
+ if (ReadPacket (extra_stop_reply_packet, timeout_usec, false) == PacketResult::Success)
+ {
+ switch (extra_stop_reply_packet.GetChar())
+ {
+ case 'T':
+ case 'S':
+ // We did get an extra stop reply, which means
+ // our interrupt didn't stop the target so we
+ // shouldn't continue after the async signal
+ // or packet is sent...
+ continue_after_async = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if (m_async_signal != -1)
+ {
+ if (log)
+ log->Printf ("async: send signo = %s", Host::GetSignalAsCString (m_async_signal));
+
+ // Save off the async signal we are supposed to send
+ const int async_signal = m_async_signal;
+ // Clear the async signal member so we don't end up
+ // sending the signal multiple times...
+ m_async_signal = -1;
+ // Check which signal we stopped with
+ if (signo == async_signal)
+ {
+ if (log)
+ log->Printf ("async: stopped with signal %s, we are done running", Host::GetSignalAsCString (signo));
+
+ // We already stopped with a signal that we wanted
+ // to stop with, so we are done
+ }
+ else
+ {
+ // We stopped with a different signal that the one
+ // we wanted to stop with, so now we must resume
+ // with the signal we want
+ char signal_packet[32];
+ int signal_packet_len = 0;
+ signal_packet_len = ::snprintf (signal_packet,
+ sizeof (signal_packet),
+ "C%2.2x",
+ async_signal);
+
+ if (log)
+ log->Printf ("async: stopped with signal %s, resume with %s",
+ Host::GetSignalAsCString (signo),
+ Host::GetSignalAsCString (async_signal));
+
+ // Set the continue packet to resume even if the
+ // interrupt didn't cause our stop (ignore continue_after_async)
+ continue_packet.assign(signal_packet, signal_packet_len);
+ continue;
+ }
+ }
+ else if (m_async_packet_predicate.GetValue())
+ {
+ Log * packet_log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+
+ // We are supposed to send an asynchronous packet while
+ // we are running.
+ m_async_response.Clear();
+ if (m_async_packet.empty())
+ {
+ m_async_result = PacketResult::ErrorSendFailed;
+ if (packet_log)
+ packet_log->Printf ("async: error: empty async packet");
+
+ }
+ else
+ {
+ if (packet_log)
+ packet_log->Printf ("async: sending packet");
+
+ m_async_result = SendPacketAndWaitForResponse (&m_async_packet[0],
+ m_async_packet.size(),
+ m_async_response,
+ false);
+ }
+ // Let the other thread that was trying to send the async
+ // packet know that the packet has been sent and response is
+ // ready...
+ m_async_packet_predicate.SetValue(false, eBroadcastAlways);
+
+ if (packet_log)
+ packet_log->Printf ("async: sent packet, continue_after_async = %i", continue_after_async);
+
+ // Set the continue packet to resume if our interrupt
+ // for the async packet did cause the stop
+ if (continue_after_async)
+ {
+ // Reverting this for now as it is causing deadlocks
+ // in programs (<rdar://problem/11529853>). In the future
+ // we should check our thread list and "do the right thing"
+ // for new threads that show up while we stop and run async
+ // packets. Setting the packet to 'c' to continue all threads
+ // is the right thing to do 99.99% of the time because if a
+ // thread was single stepping, and we sent an interrupt, we
+ // will notice above that we didn't stop due to an interrupt
+ // but stopped due to stepping and we would _not_ continue.
+ continue_packet.assign (1, 'c');
+ continue;
+ }
+ }
+ // Stop with signal and thread info
+ state = eStateStopped;
+ }
+ break;
+
+ case 'W':
+ case 'X':
+ // process exited
+ state = eStateExited;
+ break;
+
+ case 'O':
+ // STDOUT
+ {
+ got_async_packet = true;
+ std::string inferior_stdout;
+ inferior_stdout.reserve(response.GetBytesLeft () / 2);
+ char ch;
+ while ((ch = response.GetHexU8()) != '\0')
+ inferior_stdout.append(1, ch);
+ process->AppendSTDOUT (inferior_stdout.c_str(), inferior_stdout.size());
+ }
+ break;
+
+ case 'A':
+ // Async miscellaneous reply. Right now, only profile data is coming through this channel.
+ {
+ got_async_packet = true;
+ std::string input = response.GetStringRef().substr(1); // '1' to move beyond 'A'
+ if (m_partial_profile_data.length() > 0)
+ {
+ m_partial_profile_data.append(input);
+ input = m_partial_profile_data;
+ m_partial_profile_data.clear();
+ }
+
+ size_t found, pos = 0, len = input.length();
+ while ((found = input.find(end_delimiter, pos)) != std::string::npos)
+ {
+ StringExtractorGDBRemote profileDataExtractor(input.substr(pos, found).c_str());
+ std::string profile_data = HarmonizeThreadIdsForProfileData(process, profileDataExtractor);
+ process->BroadcastAsyncProfileData (profile_data);
+
+ pos = found + end_delimiter_len;
+ }
+
+ if (pos < len)
+ {
+ // Last incomplete chunk.
+ m_partial_profile_data = input.substr(pos);
+ }
+ }
+ break;
+
+ case 'E':
+ // ERROR
+ state = eStateInvalid;
+ break;
+
+ default:
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () unrecognized async packet", __FUNCTION__);
+ state = eStateInvalid;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () ReadPacket(...) => false", __FUNCTION__);
+ state = eStateInvalid;
+ }
+ }
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () => %s", __FUNCTION__, StateAsCString(state));
+ response.SetFilePos(0);
+ m_private_is_running.SetValue (false, eBroadcastAlways);
+ m_public_is_running.SetValue (false, eBroadcastAlways);
+ return state;
+}
+
+bool
+GDBRemoteCommunicationClient::SendAsyncSignal (int signo)
+{
+ Mutex::Locker async_locker (m_async_mutex);
+ m_async_signal = signo;
+ bool timed_out = false;
+ Mutex::Locker locker;
+ if (SendInterrupt (locker, 1, timed_out))
+ return true;
+ m_async_signal = -1;
+ return false;
+}
+
+// This function takes a mutex locker as a parameter in case the GetSequenceMutex
+// actually succeeds. If it doesn't succeed in acquiring the sequence mutex
+// (the expected result), then it will send the halt packet. If it does succeed
+// then the caller that requested the interrupt will want to keep the sequence
+// locked down so that no one else can send packets while the caller has control.
+// This function usually gets called when we are running and need to stop the
+// target. It can also be used when we are running and we need to do something
+// else (like read/write memory), so we need to interrupt the running process
+// (gdb remote protocol requires this), and do what we need to do, then resume.
+
+bool
+GDBRemoteCommunicationClient::SendInterrupt
+(
+ Mutex::Locker& locker,
+ uint32_t seconds_to_wait_for_stop,
+ bool &timed_out
+)
+{
+ timed_out = false;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS));
+
+ if (IsRunning())
+ {
+ // Only send an interrupt if our debugserver is running...
+ if (GetSequenceMutex (locker))
+ {
+ if (log)
+ log->Printf ("SendInterrupt () - got sequence mutex without having to interrupt");
+ }
+ else
+ {
+ // Someone has the mutex locked waiting for a response or for the
+ // inferior to stop, so send the interrupt on the down low...
+ char ctrl_c = '\x03';
+ ConnectionStatus status = eConnectionStatusSuccess;
+ size_t bytes_written = Write (&ctrl_c, 1, status, NULL);
+ if (log)
+ log->PutCString("send packet: \\x03");
+ if (bytes_written > 0)
+ {
+ m_interrupt_sent = true;
+ if (seconds_to_wait_for_stop)
+ {
+ TimeValue timeout;
+ if (seconds_to_wait_for_stop)
+ {
+ timeout = TimeValue::Now();
+ timeout.OffsetWithSeconds (seconds_to_wait_for_stop);
+ }
+ if (m_private_is_running.WaitForValueEqualTo (false, &timeout, &timed_out))
+ {
+ if (log)
+ log->PutCString ("SendInterrupt () - sent interrupt, private state stopped");
+ return true;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SendInterrupt () - sent interrupt, timed out wating for async thread resume");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SendInterrupt () - sent interrupt, not waiting for stop...");
+ return true;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SendInterrupt () - failed to write interrupt");
+ }
+ return false;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SendInterrupt () - not running");
+ }
+ return true;
+}
+
+lldb::pid_t
+GDBRemoteCommunicationClient::GetCurrentProcessID (bool allow_lazy)
+{
+ if (allow_lazy && m_curr_pid_is_valid == eLazyBoolYes)
+ return m_curr_pid;
+
+ // First try to retrieve the pid via the qProcessInfo request.
+ GetCurrentProcessInfo (allow_lazy);
+ if (m_curr_pid_is_valid == eLazyBoolYes)
+ {
+ // We really got it.
+ return m_curr_pid;
+ }
+ else
+ {
+ // If we don't get a response for qProcessInfo, check if $qC gives us a result.
+ // $qC only returns a real process id on older debugserver and lldb-platform stubs.
+ // The gdb remote protocol documents $qC as returning the thread id, which newer
+ // debugserver and lldb-gdbserver stubs return correctly.
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false) == PacketResult::Success)
+ {
+ if (response.GetChar() == 'Q')
+ {
+ if (response.GetChar() == 'C')
+ {
+ m_curr_pid = response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID);
+ if (m_curr_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ m_curr_pid_is_valid = eLazyBoolYes;
+ return m_curr_pid;
+ }
+ }
+ }
+ }
+
+ // If we don't get a response for $qC, check if $qfThreadID gives us a result.
+ if (m_curr_pid == LLDB_INVALID_PROCESS_ID)
+ {
+ std::vector<lldb::tid_t> thread_ids;
+ bool sequence_mutex_unavailable;
+ size_t size;
+ size = GetCurrentThreadIDs (thread_ids, sequence_mutex_unavailable);
+ if (size && sequence_mutex_unavailable == false)
+ {
+ m_curr_pid = thread_ids.front();
+ m_curr_pid_is_valid = eLazyBoolYes;
+ return m_curr_pid;
+ }
+ }
+ }
+
+ return LLDB_INVALID_PROCESS_ID;
+}
+
+bool
+GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str)
+{
+ error_str.clear();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return true;
+ if (response.GetChar() == 'E')
+ {
+ // A string the describes what failed when launching...
+ error_str = response.GetStringRef().substr(1);
+ }
+ else
+ {
+ error_str.assign ("unknown error occurred launching process");
+ }
+ }
+ else
+ {
+ error_str.assign ("timed out waiting for app to launch");
+ }
+ return false;
+}
+
+int
+GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &launch_info)
+{
+ // Since we don't get the send argv0 separate from the executable path, we need to
+ // make sure to use the actual executable path found in the launch_info...
+ std::vector<const char *> argv;
+ FileSpec exe_file = launch_info.GetExecutableFile();
+ std::string exe_path;
+ const char *arg = NULL;
+ const Args &launch_args = launch_info.GetArguments();
+ if (exe_file)
+ exe_path = exe_file.GetPath(false);
+ else
+ {
+ arg = launch_args.GetArgumentAtIndex(0);
+ if (arg)
+ exe_path = arg;
+ }
+ if (!exe_path.empty())
+ {
+ argv.push_back(exe_path.c_str());
+ for (uint32_t i=1; (arg = launch_args.GetArgumentAtIndex(i)) != NULL; ++i)
+ {
+ if (arg)
+ argv.push_back(arg);
+ }
+ }
+ if (!argv.empty())
+ {
+ StreamString packet;
+ packet.PutChar('A');
+ for (size_t i = 0, n = argv.size(); i < n; ++i)
+ {
+ arg = argv[i];
+ const int arg_len = strlen(arg);
+ if (i > 0)
+ packet.PutChar(',');
+ packet.Printf("%i,%i,", arg_len * 2, (int)i);
+ packet.PutBytesAsRawHex8 (arg, arg_len);
+ }
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_value)
+{
+ if (name_equal_value && name_equal_value[0])
+ {
+ StreamString packet;
+ bool send_hex_encoding = false;
+ for (const char *p = name_equal_value; *p != '\0' && send_hex_encoding == false; ++p)
+ {
+ if (isprint(*p))
+ {
+ switch (*p)
+ {
+ case '$':
+ case '#':
+ send_hex_encoding = true;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // We have non printable characters, lets hex encode this...
+ send_hex_encoding = true;
+ }
+ }
+
+ StringExtractorGDBRemote response;
+ if (send_hex_encoding)
+ {
+ if (m_supports_QEnvironmentHexEncoded)
+ {
+ packet.PutCString("QEnvironmentHexEncoded:");
+ packet.PutBytesAsRawHex8 (name_equal_value, strlen(name_equal_value));
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ if (response.IsUnsupportedResponse())
+ m_supports_QEnvironmentHexEncoded = false;
+ }
+ }
+
+ }
+ else if (m_supports_QEnvironment)
+ {
+ packet.Printf("QEnvironment:%s", name_equal_value);
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ if (response.IsUnsupportedResponse())
+ m_supports_QEnvironment = false;
+ }
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch)
+{
+ if (arch && arch[0])
+ {
+ StreamString packet;
+ packet.Printf("QLaunchArch:%s", arch);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SendLaunchEventDataPacket (char const *data, bool *was_supported)
+{
+ if (data && *data != '\0')
+ {
+ StreamString packet;
+ packet.Printf("QSetProcessEvent:%s", data);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ {
+ if (was_supported)
+ *was_supported = true;
+ return 0;
+ }
+ else if (response.IsUnsupportedResponse())
+ {
+ if (was_supported)
+ *was_supported = false;
+ return -1;
+ }
+ else
+ {
+ uint8_t error = response.GetError();
+ if (was_supported)
+ *was_supported = true;
+ if (error)
+ return error;
+ }
+ }
+ }
+ return -1;
+}
+
+bool
+GDBRemoteCommunicationClient::GetOSVersion (uint32_t &major,
+ uint32_t &minor,
+ uint32_t &update)
+{
+ if (GetHostInfo ())
+ {
+ if (m_os_version_major != UINT32_MAX)
+ {
+ major = m_os_version_major;
+ minor = m_os_version_minor;
+ update = m_os_version_update;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetOSBuildString (std::string &s)
+{
+ if (GetHostInfo ())
+ {
+ if (!m_os_build.empty())
+ {
+ s = m_os_build;
+ return true;
+ }
+ }
+ s.clear();
+ return false;
+}
+
+
+bool
+GDBRemoteCommunicationClient::GetOSKernelDescription (std::string &s)
+{
+ if (GetHostInfo ())
+ {
+ if (!m_os_kernel.empty())
+ {
+ s = m_os_kernel;
+ return true;
+ }
+ }
+ s.clear();
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetHostname (std::string &s)
+{
+ if (GetHostInfo ())
+ {
+ if (!m_hostname.empty())
+ {
+ s = m_hostname;
+ return true;
+ }
+ }
+ s.clear();
+ return false;
+}
+
+ArchSpec
+GDBRemoteCommunicationClient::GetSystemArchitecture ()
+{
+ if (GetHostInfo ())
+ return m_host_arch;
+ return ArchSpec();
+}
+
+const lldb_private::ArchSpec &
+GDBRemoteCommunicationClient::GetProcessArchitecture ()
+{
+ if (m_qProcessInfo_is_valid == eLazyBoolCalculate)
+ GetCurrentProcessInfo ();
+ return m_process_arch;
+}
+
+bool
+GDBRemoteCommunicationClient::GetGDBServerVersion()
+{
+ if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate)
+ {
+ m_gdb_server_name.clear();
+ m_gdb_server_version = 0;
+ m_qGDBServerVersion_is_valid = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse ("qGDBServerVersion", response, false) == PacketResult::Success)
+ {
+ if (response.IsNormalResponse())
+ {
+ std::string name;
+ std::string value;
+ bool success = false;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("name") == 0)
+ {
+ success = true;
+ m_gdb_server_name.swap(value);
+ }
+ else if (name.compare("version") == 0)
+ {
+ size_t dot_pos = value.find('.');
+ if (dot_pos != std::string::npos)
+ value[dot_pos] = '\0';
+ const uint32_t version = StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0);
+ if (version != UINT32_MAX)
+ {
+ success = true;
+ m_gdb_server_version = version;
+ }
+ }
+ }
+ if (success)
+ m_qGDBServerVersion_is_valid = eLazyBoolYes;
+ }
+ }
+ }
+ return m_qGDBServerVersion_is_valid == eLazyBoolYes;
+}
+
+void
+GDBRemoteCommunicationClient::MaybeEnableCompression (std::vector<std::string> supported_compressions)
+{
+ CompressionType avail_type = CompressionType::None;
+ std::string avail_name;
+
+#if defined (HAVE_LIBCOMPRESSION)
+ // libcompression is weak linked so test if compression_decode_buffer() is available
+ if (compression_decode_buffer != NULL && avail_type == CompressionType::None)
+ {
+ for (auto compression : supported_compressions)
+ {
+ if (compression == "lzfse")
+ {
+ avail_type = CompressionType::LZFSE;
+ avail_name = compression;
+ break;
+ }
+ }
+ }
+#endif
+
+#if defined (HAVE_LIBCOMPRESSION)
+ // libcompression is weak linked so test if compression_decode_buffer() is available
+ if (compression_decode_buffer != NULL && avail_type == CompressionType::None)
+ {
+ for (auto compression : supported_compressions)
+ {
+ if (compression == "zlib-deflate")
+ {
+ avail_type = CompressionType::ZlibDeflate;
+ avail_name = compression;
+ break;
+ }
+ }
+ }
+#endif
+
+#if defined (HAVE_LIBZ)
+ if (avail_type == CompressionType::None)
+ {
+ for (auto compression : supported_compressions)
+ {
+ if (compression == "zlib-deflate")
+ {
+ avail_type = CompressionType::ZlibDeflate;
+ avail_name = compression;
+ break;
+ }
+ }
+ }
+#endif
+
+#if defined (HAVE_LIBCOMPRESSION)
+ // libcompression is weak linked so test if compression_decode_buffer() is available
+ if (compression_decode_buffer != NULL && avail_type == CompressionType::None)
+ {
+ for (auto compression : supported_compressions)
+ {
+ if (compression == "lz4")
+ {
+ avail_type = CompressionType::LZ4;
+ avail_name = compression;
+ break;
+ }
+ }
+ }
+#endif
+
+#if defined (HAVE_LIBCOMPRESSION)
+ // libcompression is weak linked so test if compression_decode_buffer() is available
+ if (compression_decode_buffer != NULL && avail_type == CompressionType::None)
+ {
+ for (auto compression : supported_compressions)
+ {
+ if (compression == "lzma")
+ {
+ avail_type = CompressionType::LZMA;
+ avail_name = compression;
+ break;
+ }
+ }
+ }
+#endif
+
+ if (avail_type != CompressionType::None)
+ {
+ StringExtractorGDBRemote response;
+ std::string packet = "QEnableCompression:type:" + avail_name + ";";
+ if (SendPacketAndWaitForResponse (packet.c_str(), response, false) != PacketResult::Success)
+ return;
+
+ if (response.IsOKResponse())
+ {
+ m_compression_type = avail_type;
+ }
+ }
+}
+
+const char *
+GDBRemoteCommunicationClient::GetGDBServerProgramName()
+{
+ if (GetGDBServerVersion())
+ {
+ if (!m_gdb_server_name.empty())
+ return m_gdb_server_name.c_str();
+ }
+ return NULL;
+}
+
+uint32_t
+GDBRemoteCommunicationClient::GetGDBServerProgramVersion()
+{
+ if (GetGDBServerVersion())
+ return m_gdb_server_version;
+ return 0;
+}
+
+bool
+GDBRemoteCommunicationClient::GetDefaultThreadId (lldb::tid_t &tid)
+{
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qC",response,false) != PacketResult::Success)
+ return false;
+
+ if (!response.IsNormalResponse())
+ return false;
+
+ if (response.GetChar() == 'Q' && response.GetChar() == 'C')
+ tid = response.GetHexMaxU32(true, -1);
+
+ return true;
+}
+
+bool
+GDBRemoteCommunicationClient::GetHostInfo (bool force)
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS));
+
+ if (force || m_qHostInfo_is_valid == eLazyBoolCalculate)
+ {
+ m_qHostInfo_is_valid = eLazyBoolNo;
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse ("qHostInfo", response, false) == PacketResult::Success)
+ {
+ if (response.IsNormalResponse())
+ {
+ std::string name;
+ std::string value;
+ uint32_t cpu = LLDB_INVALID_CPUTYPE;
+ uint32_t sub = 0;
+ std::string arch_name;
+ std::string os_name;
+ std::string vendor_name;
+ std::string triple;
+ std::string distribution_id;
+ uint32_t pointer_byte_size = 0;
+ StringExtractor extractor;
+ ByteOrder byte_order = eByteOrderInvalid;
+ uint32_t num_keys_decoded = 0;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("cputype") == 0)
+ {
+ // exception type in big endian hex
+ cpu = StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 0);
+ if (cpu != LLDB_INVALID_CPUTYPE)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("cpusubtype") == 0)
+ {
+ // exception count in big endian hex
+ sub = StringConvert::ToUInt32 (value.c_str(), 0, 0);
+ if (sub != 0)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("arch") == 0)
+ {
+ arch_name.swap (value);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("triple") == 0)
+ {
+ extractor.GetStringRef ().swap (value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (triple);
+ ++num_keys_decoded;
+ }
+ else if (name.compare ("distribution_id") == 0)
+ {
+ extractor.GetStringRef ().swap (value);
+ extractor.SetFilePos (0);
+ extractor.GetHexByteString (distribution_id);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("os_build") == 0)
+ {
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (m_os_build);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("hostname") == 0)
+ {
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (m_hostname);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("os_kernel") == 0)
+ {
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (m_os_kernel);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("ostype") == 0)
+ {
+ os_name.swap (value);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("vendor") == 0)
+ {
+ vendor_name.swap(value);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("endian") == 0)
+ {
+ ++num_keys_decoded;
+ if (value.compare("little") == 0)
+ byte_order = eByteOrderLittle;
+ else if (value.compare("big") == 0)
+ byte_order = eByteOrderBig;
+ else if (value.compare("pdp") == 0)
+ byte_order = eByteOrderPDP;
+ else
+ --num_keys_decoded;
+ }
+ else if (name.compare("ptrsize") == 0)
+ {
+ pointer_byte_size = StringConvert::ToUInt32 (value.c_str(), 0, 0);
+ if (pointer_byte_size != 0)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("os_version") == 0)
+ {
+ Args::StringToVersion (value.c_str(),
+ m_os_version_major,
+ m_os_version_minor,
+ m_os_version_update);
+ if (m_os_version_major != UINT32_MAX)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("watchpoint_exceptions_received") == 0)
+ {
+ ++num_keys_decoded;
+ if (strcmp(value.c_str(),"before") == 0)
+ m_watchpoints_trigger_after_instruction = eLazyBoolNo;
+ else if (strcmp(value.c_str(),"after") == 0)
+ m_watchpoints_trigger_after_instruction = eLazyBoolYes;
+ else
+ --num_keys_decoded;
+ }
+ else if (name.compare("default_packet_timeout") == 0)
+ {
+ m_default_packet_timeout = StringConvert::ToUInt32(value.c_str(), 0);
+ if (m_default_packet_timeout > 0)
+ {
+ SetPacketTimeout(m_default_packet_timeout);
+ ++num_keys_decoded;
+ }
+ }
+
+ }
+
+ if (num_keys_decoded > 0)
+ m_qHostInfo_is_valid = eLazyBoolYes;
+
+ if (triple.empty())
+ {
+ if (arch_name.empty())
+ {
+ if (cpu != LLDB_INVALID_CPUTYPE)
+ {
+ m_host_arch.SetArchitecture (eArchTypeMachO, cpu, sub);
+ if (pointer_byte_size)
+ {
+ assert (pointer_byte_size == m_host_arch.GetAddressByteSize());
+ }
+ if (byte_order != eByteOrderInvalid)
+ {
+ assert (byte_order == m_host_arch.GetByteOrder());
+ }
+
+ if (!os_name.empty() && vendor_name.compare("apple") == 0 && os_name.find("darwin") == 0)
+ {
+ switch (m_host_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ os_name = "ios";
+ break;
+ default:
+ os_name = "macosx";
+ break;
+ }
+ }
+ if (!vendor_name.empty())
+ m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name));
+ if (!os_name.empty())
+ m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name));
+
+ }
+ }
+ else
+ {
+ std::string triple;
+ triple += arch_name;
+ if (!vendor_name.empty() || !os_name.empty())
+ {
+ triple += '-';
+ if (vendor_name.empty())
+ triple += "unknown";
+ else
+ triple += vendor_name;
+ triple += '-';
+ if (os_name.empty())
+ triple += "unknown";
+ else
+ triple += os_name;
+ }
+ m_host_arch.SetTriple (triple.c_str());
+
+ llvm::Triple &host_triple = m_host_arch.GetTriple();
+ if (host_triple.getVendor() == llvm::Triple::Apple && host_triple.getOS() == llvm::Triple::Darwin)
+ {
+ switch (m_host_arch.GetMachine())
+ {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ host_triple.setOS(llvm::Triple::IOS);
+ break;
+ default:
+ host_triple.setOS(llvm::Triple::MacOSX);
+ break;
+ }
+ }
+ if (pointer_byte_size)
+ {
+ assert (pointer_byte_size == m_host_arch.GetAddressByteSize());
+ }
+ if (byte_order != eByteOrderInvalid)
+ {
+ assert (byte_order == m_host_arch.GetByteOrder());
+ }
+
+ }
+ }
+ else
+ {
+ m_host_arch.SetTriple (triple.c_str());
+ if (pointer_byte_size)
+ {
+ assert (pointer_byte_size == m_host_arch.GetAddressByteSize());
+ }
+ if (byte_order != eByteOrderInvalid)
+ {
+ assert (byte_order == m_host_arch.GetByteOrder());
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s parsed host architecture as %s, triple as %s from triple text %s", __FUNCTION__, m_host_arch.GetArchitectureName () ? m_host_arch.GetArchitectureName () : "<null-arch-name>", m_host_arch.GetTriple ().getTriple ().c_str(), triple.c_str ());
+ }
+ if (!distribution_id.empty ())
+ m_host_arch.SetDistributionId (distribution_id.c_str ());
+ }
+ }
+ }
+ return m_qHostInfo_is_valid == eLazyBoolYes;
+}
+
+int
+GDBRemoteCommunicationClient::SendAttach
+(
+ lldb::pid_t pid,
+ StringExtractorGDBRemote& response
+)
+{
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, pid);
+ assert (packet_len < (int)sizeof(packet));
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.IsErrorResponse())
+ return response.GetError();
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SendStdinNotification (const char* data, size_t data_len)
+{
+ StreamString packet;
+ packet.PutCString("I");
+ packet.PutBytesAsRawHex8(data, data_len);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
+ {
+ return 0;
+ }
+ return response.GetError();
+
+}
+
+const lldb_private::ArchSpec &
+GDBRemoteCommunicationClient::GetHostArchitecture ()
+{
+ if (m_qHostInfo_is_valid == eLazyBoolCalculate)
+ GetHostInfo ();
+ return m_host_arch;
+}
+
+uint32_t
+GDBRemoteCommunicationClient::GetHostDefaultPacketTimeout ()
+{
+ if (m_qHostInfo_is_valid == eLazyBoolCalculate)
+ GetHostInfo ();
+ return m_default_packet_timeout;
+}
+
+addr_t
+GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions)
+{
+ if (m_supports_alloc_dealloc_memory != eLazyBoolNo)
+ {
+ m_supports_alloc_dealloc_memory = eLazyBoolYes;
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "_M%" PRIx64 ",%s%s%s",
+ (uint64_t)size,
+ permissions & lldb::ePermissionsReadable ? "r" : "",
+ permissions & lldb::ePermissionsWritable ? "w" : "",
+ permissions & lldb::ePermissionsExecutable ? "x" : "");
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.IsUnsupportedResponse())
+ m_supports_alloc_dealloc_memory = eLazyBoolNo;
+ else if (!response.IsErrorResponse())
+ return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ }
+ else
+ {
+ m_supports_alloc_dealloc_memory = eLazyBoolNo;
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr)
+{
+ if (m_supports_alloc_dealloc_memory != eLazyBoolNo)
+ {
+ m_supports_alloc_dealloc_memory = eLazyBoolYes;
+ char packet[64];
+ const int packet_len = ::snprintf(packet, sizeof(packet), "_m%" PRIx64, (uint64_t)addr);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.IsUnsupportedResponse())
+ m_supports_alloc_dealloc_memory = eLazyBoolNo;
+ else if (response.IsOKResponse())
+ return true;
+ }
+ else
+ {
+ m_supports_alloc_dealloc_memory = eLazyBoolNo;
+ }
+ }
+ return false;
+}
+
+Error
+GDBRemoteCommunicationClient::Detach (bool keep_stopped)
+{
+ Error error;
+
+ if (keep_stopped)
+ {
+ if (m_supports_detach_stay_stopped == eLazyBoolCalculate)
+ {
+ char packet[64];
+ const int packet_len = ::snprintf(packet, sizeof(packet), "qSupportsDetachAndStayStopped:");
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)
+ {
+ m_supports_detach_stay_stopped = eLazyBoolYes;
+ }
+ else
+ {
+ m_supports_detach_stay_stopped = eLazyBoolNo;
+ }
+ }
+
+ if (m_supports_detach_stay_stopped == eLazyBoolNo)
+ {
+ error.SetErrorString("Stays stopped not supported by this target.");
+ return error;
+ }
+ else
+ {
+ StringExtractorGDBRemote response;
+ PacketResult packet_result = SendPacketAndWaitForResponse ("D1", 1, response, false);
+ if (packet_result != PacketResult::Success)
+ error.SetErrorString ("Sending extended disconnect packet failed.");
+ }
+ }
+ else
+ {
+ StringExtractorGDBRemote response;
+ PacketResult packet_result = SendPacketAndWaitForResponse ("D", 1, response, false);
+ if (packet_result != PacketResult::Success)
+ error.SetErrorString ("Sending disconnect packet failed.");
+ }
+ return error;
+}
+
+Error
+GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr,
+ lldb_private::MemoryRegionInfo &region_info)
+{
+ Error error;
+ region_info.Clear();
+
+ if (m_supports_memory_region_info != eLazyBoolNo)
+ {
+ m_supports_memory_region_info = eLazyBoolYes;
+ char packet[64];
+ const int packet_len = ::snprintf(packet, sizeof(packet), "qMemoryRegionInfo:%" PRIx64, (uint64_t)addr);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)
+ {
+ std::string name;
+ std::string value;
+ addr_t addr_value;
+ bool success = true;
+ bool saw_permissions = false;
+ while (success && response.GetNameColonValue(name, value))
+ {
+ if (name.compare ("start") == 0)
+ {
+ addr_value = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_ADDRESS, 16, &success);
+ if (success)
+ region_info.GetRange().SetRangeBase(addr_value);
+ }
+ else if (name.compare ("size") == 0)
+ {
+ addr_value = StringConvert::ToUInt64(value.c_str(), 0, 16, &success);
+ if (success)
+ region_info.GetRange().SetByteSize (addr_value);
+ }
+ else if (name.compare ("permissions") == 0 && region_info.GetRange().IsValid())
+ {
+ saw_permissions = true;
+ if (region_info.GetRange().Contains (addr))
+ {
+ if (value.find('r') != std::string::npos)
+ region_info.SetReadable (MemoryRegionInfo::eYes);
+ else
+ region_info.SetReadable (MemoryRegionInfo::eNo);
+
+ if (value.find('w') != std::string::npos)
+ region_info.SetWritable (MemoryRegionInfo::eYes);
+ else
+ region_info.SetWritable (MemoryRegionInfo::eNo);
+
+ if (value.find('x') != std::string::npos)
+ region_info.SetExecutable (MemoryRegionInfo::eYes);
+ else
+ region_info.SetExecutable (MemoryRegionInfo::eNo);
+ }
+ else
+ {
+ // The reported region does not contain this address -- we're looking at an unmapped page
+ region_info.SetReadable (MemoryRegionInfo::eNo);
+ region_info.SetWritable (MemoryRegionInfo::eNo);
+ region_info.SetExecutable (MemoryRegionInfo::eNo);
+ }
+ }
+ else if (name.compare ("error") == 0)
+ {
+ StringExtractorGDBRemote name_extractor;
+ // Swap "value" over into "name_extractor"
+ name_extractor.GetStringRef().swap(value);
+ // Now convert the HEX bytes into a string value
+ name_extractor.GetHexByteString (value);
+ error.SetErrorString(value.c_str());
+ }
+ }
+
+ // We got a valid address range back but no permissions -- which means this is an unmapped page
+ if (region_info.GetRange().IsValid() && saw_permissions == false)
+ {
+ region_info.SetReadable (MemoryRegionInfo::eNo);
+ region_info.SetWritable (MemoryRegionInfo::eNo);
+ region_info.SetExecutable (MemoryRegionInfo::eNo);
+ }
+ }
+ else
+ {
+ m_supports_memory_region_info = eLazyBoolNo;
+ }
+ }
+
+ if (m_supports_memory_region_info == eLazyBoolNo)
+ {
+ error.SetErrorString("qMemoryRegionInfo is not supported");
+ }
+ if (error.Fail())
+ region_info.Clear();
+ return error;
+
+}
+
+Error
+GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num)
+{
+ Error error;
+
+ if (m_supports_watchpoint_support_info == eLazyBoolYes)
+ {
+ num = m_num_supported_hardware_watchpoints;
+ return error;
+ }
+
+ // 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));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)
+ {
+ m_supports_watchpoint_support_info = eLazyBoolYes;
+ std::string name;
+ std::string value;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare ("num") == 0)
+ {
+ num = StringConvert::ToUInt32(value.c_str(), 0, 0);
+ m_num_supported_hardware_watchpoints = num;
+ }
+ }
+ }
+ else
+ {
+ m_supports_watchpoint_support_info = eLazyBoolNo;
+ }
+ }
+
+ if (m_supports_watchpoint_support_info == eLazyBoolNo)
+ {
+ error.SetErrorString("qWatchpointSupportInfo is not supported");
+ }
+ return error;
+
+}
+
+lldb_private::Error
+GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num, bool& after, const ArchSpec &arch)
+{
+ Error error(GetWatchpointSupportInfo(num));
+ if (error.Success())
+ error = GetWatchpointsTriggerAfterInstruction(after, arch);
+ return error;
+}
+
+lldb_private::Error
+GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction (bool &after, const ArchSpec &arch)
+{
+ Error error;
+ llvm::Triple::ArchType atype = arch.GetMachine();
+
+ // we assume watchpoints will happen after running the relevant opcode
+ // and we only want to override this behavior if we have explicitly
+ // received a qHostInfo telling us otherwise
+ if (m_qHostInfo_is_valid != eLazyBoolYes)
+ {
+ // On targets like MIPS, watchpoint exceptions are always generated
+ // before the instruction is executed. The connected target may not
+ // support qHostInfo or qWatchpointSupportInfo packets.
+ if (atype == llvm::Triple::mips || atype == llvm::Triple::mipsel
+ || atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el)
+ after = false;
+ else
+ after = true;
+ }
+ else
+ {
+ // For MIPS, set m_watchpoints_trigger_after_instruction to eLazyBoolNo
+ // if it is not calculated before.
+ if (m_watchpoints_trigger_after_instruction == eLazyBoolCalculate &&
+ (atype == llvm::Triple::mips || atype == llvm::Triple::mipsel
+ || atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el))
+ m_watchpoints_trigger_after_instruction = eLazyBoolNo;
+
+ after = (m_watchpoints_trigger_after_instruction != eLazyBoolNo);
+ }
+ return error;
+}
+
+int
+GDBRemoteCommunicationClient::SetSTDIN(const FileSpec &file_spec)
+{
+ if (file_spec)
+ {
+ std::string path{file_spec.GetPath(false)};
+ StreamString packet;
+ packet.PutCString("QSetSTDIN:");
+ packet.PutCStringAsRawHex8(path.c_str());
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SetSTDOUT(const FileSpec &file_spec)
+{
+ if (file_spec)
+ {
+ std::string path{file_spec.GetPath(false)};
+ StreamString packet;
+ packet.PutCString("QSetSTDOUT:");
+ packet.PutCStringAsRawHex8(path.c_str());
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SetSTDERR(const FileSpec &file_spec)
+{
+ if (file_spec)
+ {
+ std::string path{file_spec.GetPath(false)};
+ StreamString packet;
+ packet.PutCString("QSetSTDERR:");
+ packet.PutCStringAsRawHex8(path.c_str());
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+bool
+GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir)
+{
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false) == PacketResult::Success)
+ {
+ if (response.IsUnsupportedResponse())
+ return false;
+ if (response.IsErrorResponse())
+ return false;
+ std::string cwd;
+ response.GetHexByteString(cwd);
+ working_dir.SetFile(cwd, false, GetHostArchitecture());
+ return !cwd.empty();
+ }
+ return false;
+}
+
+int
+GDBRemoteCommunicationClient::SetWorkingDir(const FileSpec &working_dir)
+{
+ if (working_dir)
+ {
+ std::string path{working_dir.GetPath(false)};
+ StreamString packet;
+ packet.PutCString("QSetWorkingDir:");
+ packet.PutCStringAsRawHex8(path.c_str());
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SetDisableASLR (bool enable)
+{
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDisableASLR:%i", enable ? 1 : 0);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SetDetachOnError (bool enable)
+{
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDetachOnError:%i", enable ? 1 : 0);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ return -1;
+}
+
+
+bool
+GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info)
+{
+ if (response.IsNormalResponse())
+ {
+ std::string name;
+ std::string value;
+ StringExtractor extractor;
+
+ uint32_t cpu = LLDB_INVALID_CPUTYPE;
+ uint32_t sub = 0;
+ std::string vendor;
+ std::string os_type;
+
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("pid") == 0)
+ {
+ process_info.SetProcessID (StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_PROCESS_ID, 0));
+ }
+ else if (name.compare("ppid") == 0)
+ {
+ process_info.SetParentProcessID (StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_PROCESS_ID, 0));
+ }
+ else if (name.compare("uid") == 0)
+ {
+ process_info.SetUserID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0));
+ }
+ else if (name.compare("euid") == 0)
+ {
+ process_info.SetEffectiveUserID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0));
+ }
+ else if (name.compare("gid") == 0)
+ {
+ process_info.SetGroupID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0));
+ }
+ else if (name.compare("egid") == 0)
+ {
+ process_info.SetEffectiveGroupID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0));
+ }
+ else if (name.compare("triple") == 0)
+ {
+ StringExtractor extractor;
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (value);
+ process_info.GetArchitecture ().SetTriple (value.c_str());
+ }
+ else if (name.compare("name") == 0)
+ {
+ StringExtractor extractor;
+ // The process name from ASCII hex bytes since we can't
+ // control the characters in a process name
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (value);
+ process_info.GetExecutableFile().SetFile (value.c_str(), false);
+ }
+ else if (name.compare("cputype") == 0)
+ {
+ cpu = StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 16);
+ }
+ else if (name.compare("cpusubtype") == 0)
+ {
+ sub = StringConvert::ToUInt32 (value.c_str(), 0, 16);
+ }
+ else if (name.compare("vendor") == 0)
+ {
+ vendor = value;
+ }
+ else if (name.compare("ostype") == 0)
+ {
+ os_type = value;
+ }
+ }
+
+ if (cpu != LLDB_INVALID_CPUTYPE && !vendor.empty() && !os_type.empty())
+ {
+ if (vendor == "apple")
+ {
+ process_info.GetArchitecture().SetArchitecture (eArchTypeMachO, cpu, sub);
+ process_info.GetArchitecture().GetTriple().setVendorName (llvm::StringRef (vendor));
+ process_info.GetArchitecture().GetTriple().setOSName (llvm::StringRef (os_type));
+ }
+ }
+
+ if (process_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ return true;
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ process_info.Clear();
+
+ if (m_supports_qProcessInfoPID)
+ {
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof (packet), "qProcessInfoPID:%" PRIu64, pid);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)
+ {
+ return DecodeProcessInfoResponse (response, process_info);
+ }
+ else
+ {
+ m_supports_qProcessInfoPID = false;
+ return false;
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetCurrentProcessInfo (bool allow_lazy)
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS));
+
+ if (allow_lazy)
+ {
+ if (m_qProcessInfo_is_valid == eLazyBoolYes)
+ return true;
+ if (m_qProcessInfo_is_valid == eLazyBoolNo)
+ return false;
+ }
+
+ GetHostInfo ();
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse ("qProcessInfo", response, false) == PacketResult::Success)
+ {
+ if (response.IsNormalResponse())
+ {
+ std::string name;
+ std::string value;
+ uint32_t cpu = LLDB_INVALID_CPUTYPE;
+ uint32_t sub = 0;
+ std::string arch_name;
+ std::string os_name;
+ std::string vendor_name;
+ std::string triple;
+ uint32_t pointer_byte_size = 0;
+ StringExtractor extractor;
+ ByteOrder byte_order = eByteOrderInvalid;
+ uint32_t num_keys_decoded = 0;
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("cputype") == 0)
+ {
+ cpu = StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 16);
+ if (cpu != LLDB_INVALID_CPUTYPE)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("cpusubtype") == 0)
+ {
+ sub = StringConvert::ToUInt32 (value.c_str(), 0, 16);
+ if (sub != 0)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("triple") == 0)
+ {
+ StringExtractor extractor;
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (triple);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("ostype") == 0)
+ {
+ os_name.swap (value);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("vendor") == 0)
+ {
+ vendor_name.swap(value);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("endian") == 0)
+ {
+ ++num_keys_decoded;
+ if (value.compare("little") == 0)
+ byte_order = eByteOrderLittle;
+ else if (value.compare("big") == 0)
+ byte_order = eByteOrderBig;
+ else if (value.compare("pdp") == 0)
+ byte_order = eByteOrderPDP;
+ else
+ --num_keys_decoded;
+ }
+ else if (name.compare("ptrsize") == 0)
+ {
+ pointer_byte_size = StringConvert::ToUInt32 (value.c_str(), 0, 16);
+ if (pointer_byte_size != 0)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("pid") == 0)
+ {
+ pid = StringConvert::ToUInt64(value.c_str(), 0, 16);
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ ++num_keys_decoded;
+ }
+ }
+ if (num_keys_decoded > 0)
+ m_qProcessInfo_is_valid = eLazyBoolYes;
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ m_curr_pid_is_valid = eLazyBoolYes;
+ m_curr_pid = pid;
+ }
+
+ // Set the ArchSpec from the triple if we have it.
+ if (!triple.empty ())
+ {
+ m_process_arch.SetTriple (triple.c_str ());
+ if (pointer_byte_size)
+ {
+ assert (pointer_byte_size == m_process_arch.GetAddressByteSize());
+ }
+ }
+ else if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty())
+ {
+ llvm::Triple triple(llvm::Twine("-") + vendor_name + "-" + os_name);
+
+ assert(triple.getObjectFormat() != llvm::Triple::UnknownObjectFormat);
+ switch (triple.getObjectFormat()) {
+ case llvm::Triple::MachO:
+ m_process_arch.SetArchitecture (eArchTypeMachO, cpu, sub);
+ break;
+ case llvm::Triple::ELF:
+ m_process_arch.SetArchitecture (eArchTypeELF, cpu, sub);
+ break;
+ case llvm::Triple::COFF:
+ m_process_arch.SetArchitecture (eArchTypeCOFF, cpu, sub);
+ break;
+ case llvm::Triple::UnknownObjectFormat:
+ if (log)
+ log->Printf("error: failed to determine target architecture");
+ return false;
+ }
+
+ if (pointer_byte_size)
+ {
+ assert (pointer_byte_size == m_process_arch.GetAddressByteSize());
+ }
+ if (byte_order != eByteOrderInvalid)
+ {
+ assert (byte_order == m_process_arch.GetByteOrder());
+ }
+ m_process_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name));
+ m_process_arch.GetTriple().setOSName(llvm::StringRef (os_name));
+ m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name));
+ m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name));
+ }
+ return true;
+ }
+ }
+ else
+ {
+ m_qProcessInfo_is_valid = eLazyBoolNo;
+ }
+
+ return false;
+}
+
+
+uint32_t
+GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos)
+{
+ process_infos.Clear();
+
+ if (m_supports_qfProcessInfo)
+ {
+ StreamString packet;
+ packet.PutCString ("qfProcessInfo");
+ if (!match_info.MatchAllProcesses())
+ {
+ packet.PutChar (':');
+ const char *name = match_info.GetProcessInfo().GetName();
+ bool has_name_match = false;
+ if (name && name[0])
+ {
+ has_name_match = true;
+ NameMatchType name_match_type = match_info.GetNameMatchType();
+ switch (name_match_type)
+ {
+ case eNameMatchIgnore:
+ has_name_match = false;
+ break;
+
+ case eNameMatchEquals:
+ packet.PutCString ("name_match:equals;");
+ break;
+
+ case eNameMatchContains:
+ packet.PutCString ("name_match:contains;");
+ break;
+
+ case eNameMatchStartsWith:
+ packet.PutCString ("name_match:starts_with;");
+ break;
+
+ case eNameMatchEndsWith:
+ packet.PutCString ("name_match:ends_with;");
+ break;
+
+ case eNameMatchRegularExpression:
+ packet.PutCString ("name_match:regex;");
+ break;
+ }
+ if (has_name_match)
+ {
+ packet.PutCString ("name:");
+ packet.PutBytesAsRawHex8(name, ::strlen(name));
+ packet.PutChar (';');
+ }
+ }
+
+ if (match_info.GetProcessInfo().ProcessIDIsValid())
+ packet.Printf("pid:%" PRIu64 ";",match_info.GetProcessInfo().GetProcessID());
+ if (match_info.GetProcessInfo().ParentProcessIDIsValid())
+ packet.Printf("parent_pid:%" PRIu64 ";",match_info.GetProcessInfo().GetParentProcessID());
+ if (match_info.GetProcessInfo().UserIDIsValid())
+ packet.Printf("uid:%u;",match_info.GetProcessInfo().GetUserID());
+ if (match_info.GetProcessInfo().GroupIDIsValid())
+ packet.Printf("gid:%u;",match_info.GetProcessInfo().GetGroupID());
+ if (match_info.GetProcessInfo().EffectiveUserIDIsValid())
+ packet.Printf("euid:%u;",match_info.GetProcessInfo().GetEffectiveUserID());
+ if (match_info.GetProcessInfo().EffectiveGroupIDIsValid())
+ packet.Printf("egid:%u;",match_info.GetProcessInfo().GetEffectiveGroupID());
+ if (match_info.GetProcessInfo().EffectiveGroupIDIsValid())
+ packet.Printf("all_users:%u;",match_info.GetMatchAllUsers() ? 1 : 0);
+ if (match_info.GetProcessInfo().GetArchitecture().IsValid())
+ {
+ const ArchSpec &match_arch = match_info.GetProcessInfo().GetArchitecture();
+ const llvm::Triple &triple = match_arch.GetTriple();
+ packet.PutCString("triple:");
+ packet.PutCString(triple.getTriple().c_str());
+ packet.PutChar (';');
+ }
+ }
+ StringExtractorGDBRemote response;
+ // Increase timeout as the first qfProcessInfo packet takes a long time
+ // on Android. The value of 1min was arrived at empirically.
+ GDBRemoteCommunication::ScopedTimeout timeout (*this, 60);
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success)
+ {
+ do
+ {
+ ProcessInstanceInfo process_info;
+ if (!DecodeProcessInfoResponse (response, process_info))
+ break;
+ process_infos.Append(process_info);
+ response.GetStringRef().clear();
+ response.SetFilePos(0);
+ } while (SendPacketAndWaitForResponse ("qsProcessInfo", strlen ("qsProcessInfo"), response, false) == PacketResult::Success);
+ }
+ else
+ {
+ m_supports_qfProcessInfo = false;
+ return 0;
+ }
+ }
+ return process_infos.GetSize();
+
+}
+
+bool
+GDBRemoteCommunicationClient::GetUserName (uint32_t uid, std::string &name)
+{
+ if (m_supports_qUserName)
+ {
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof (packet), "qUserName:%i", uid);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.IsNormalResponse())
+ {
+ // Make sure we parsed the right number of characters. The response is
+ // the hex encoded user name and should make up the entire packet.
+ // If there are any non-hex ASCII bytes, the length won't match below..
+ if (response.GetHexByteString (name) * 2 == response.GetStringRef().size())
+ return true;
+ }
+ }
+ else
+ {
+ m_supports_qUserName = false;
+ return false;
+ }
+ }
+ return false;
+
+}
+
+bool
+GDBRemoteCommunicationClient::GetGroupName (uint32_t gid, std::string &name)
+{
+ if (m_supports_qGroupName)
+ {
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof (packet), "qGroupName:%i", gid);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.IsNormalResponse())
+ {
+ // Make sure we parsed the right number of characters. The response is
+ // the hex encoded group name and should make up the entire packet.
+ // If there are any non-hex ASCII bytes, the length won't match below..
+ if (response.GetHexByteString (name) * 2 == response.GetStringRef().size())
+ return true;
+ }
+ }
+ else
+ {
+ m_supports_qGroupName = false;
+ return false;
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::SetNonStopMode (const bool enable)
+{
+ // Form non-stop packet request
+ char packet[32];
+ const int packet_len = ::snprintf(packet, sizeof(packet), "QNonStop:%1d", (int)enable);
+ assert(packet_len < (int)sizeof(packet));
+
+ StringExtractorGDBRemote response;
+ // Send to target
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ if (response.IsOKResponse())
+ return true;
+
+ // Failed or not supported
+ return false;
+
+}
+
+static void
+MakeSpeedTestPacket(StreamString &packet, uint32_t send_size, uint32_t recv_size)
+{
+ packet.Clear();
+ packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size);
+ uint32_t bytes_left = send_size;
+ while (bytes_left > 0)
+ {
+ if (bytes_left >= 26)
+ {
+ packet.PutCString("abcdefghijklmnopqrstuvwxyz");
+ bytes_left -= 26;
+ }
+ else
+ {
+ packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz");
+ bytes_left = 0;
+ }
+ }
+}
+
+template<typename T>
+T calculate_standard_deviation(const std::vector<T> &v)
+{
+ T sum = std::accumulate(std::begin(v), std::end(v), T(0));
+ T mean = sum / (T)v.size();
+ T accum = T(0);
+ std::for_each (std::begin(v), std::end(v), [&](const T d) {
+ T delta = d - mean;
+ accum += delta * delta;
+ });
+
+ T stdev = sqrt(accum / (v.size()-1));
+ return stdev;
+}
+
+void
+GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets, uint32_t max_send, uint32_t max_recv, bool json, Stream &strm)
+{
+ uint32_t i;
+ TimeValue start_time, end_time;
+ uint64_t total_time_nsec;
+ if (SendSpeedTestPacket (0, 0))
+ {
+ StreamString packet;
+ if (json)
+ strm.Printf("{ \"packet_speeds\" : {\n \"num_packets\" : %u,\n \"results\" : [", num_packets);
+ else
+ strm.Printf("Testing sending %u packets of various sizes:\n", num_packets);
+ strm.Flush();
+
+ uint32_t result_idx = 0;
+ uint32_t send_size;
+ std::vector<float> packet_times;
+
+ for (send_size = 0; send_size <= max_send; send_size ? send_size *= 2 : send_size = 4)
+ {
+ for (uint32_t recv_size = 0; recv_size <= max_recv; recv_size ? recv_size *= 2 : recv_size = 4)
+ {
+ MakeSpeedTestPacket (packet, send_size, recv_size);
+
+ packet_times.clear();
+ // Test how long it takes to send 'num_packets' packets
+ start_time = TimeValue::Now();
+ for (i=0; i<num_packets; ++i)
+ {
+ TimeValue packet_start_time = TimeValue::Now();
+ StringExtractorGDBRemote response;
+ SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false);
+ TimeValue packet_end_time = TimeValue::Now();
+ uint64_t packet_time_nsec = packet_end_time.GetAsNanoSecondsSinceJan1_1970() - packet_start_time.GetAsNanoSecondsSinceJan1_1970();
+ packet_times.push_back((float)packet_time_nsec);
+ }
+ end_time = TimeValue::Now();
+ total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970();
+
+ float packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec;
+ float total_ms = (float)total_time_nsec/(float)TimeValue::NanoSecPerMilliSec;
+ float average_ms_per_packet = total_ms / num_packets;
+ const float standard_deviation = calculate_standard_deviation<float>(packet_times);
+ if (json)
+ {
+ strm.Printf ("%s\n {\"send_size\" : %6" PRIu32 ", \"recv_size\" : %6" PRIu32 ", \"total_time_nsec\" : %12" PRIu64 ", \"standard_deviation_nsec\" : %9" PRIu64 " }", result_idx > 0 ? "," : "", send_size, recv_size, total_time_nsec, (uint64_t)standard_deviation);
+ ++result_idx;
+ }
+ else
+ {
+ strm.Printf ("qSpeedTest(send=%-7u, recv=%-7u) in %" PRIu64 ".%9.9" PRIu64 " sec for %9.2f packets/sec (%10.6f ms per packet) with standard deviation of %10.6f ms\n",
+ send_size,
+ recv_size,
+ total_time_nsec / TimeValue::NanoSecPerSec,
+ total_time_nsec % TimeValue::NanoSecPerSec,
+ packets_per_second,
+ average_ms_per_packet,
+ standard_deviation/(float)TimeValue::NanoSecPerMilliSec);
+ }
+ strm.Flush();
+ }
+ }
+
+ const uint64_t k_recv_amount = 4*1024*1024; // Receive amount in bytes
+
+ const float k_recv_amount_mb = (float)k_recv_amount/(1024.0f*1024.0f);
+ if (json)
+ strm.Printf("\n ]\n },\n \"download_speed\" : {\n \"byte_size\" : %" PRIu64 ",\n \"results\" : [", k_recv_amount);
+ else
+ strm.Printf("Testing receiving %2.1fMB of data using varying receive packet sizes:\n", k_recv_amount_mb);
+ strm.Flush();
+ send_size = 0;
+ result_idx = 0;
+ for (uint32_t recv_size = 32; recv_size <= max_recv; recv_size *= 2)
+ {
+ MakeSpeedTestPacket (packet, send_size, recv_size);
+
+ // If we have a receive size, test how long it takes to receive 4MB of data
+ if (recv_size > 0)
+ {
+ start_time = TimeValue::Now();
+ uint32_t bytes_read = 0;
+ uint32_t packet_count = 0;
+ while (bytes_read < k_recv_amount)
+ {
+ StringExtractorGDBRemote response;
+ SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false);
+ bytes_read += recv_size;
+ ++packet_count;
+ }
+ end_time = TimeValue::Now();
+ total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970();
+ float mb_second = ((((float)k_recv_amount)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec) / (1024.0*1024.0);
+ float packets_per_second = (((float)packet_count)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec;
+ float total_ms = (float)total_time_nsec/(float)TimeValue::NanoSecPerMilliSec;
+ float average_ms_per_packet = total_ms / packet_count;
+
+ if (json)
+ {
+ strm.Printf ("%s\n {\"send_size\" : %6" PRIu32 ", \"recv_size\" : %6" PRIu32 ", \"total_time_nsec\" : %12" PRIu64 " }", result_idx > 0 ? "," : "", send_size, recv_size, total_time_nsec);
+ ++result_idx;
+ }
+ else
+ {
+ strm.Printf ("qSpeedTest(send=%-7u, recv=%-7u) %6u packets needed to receive %2.1fMB in %" PRIu64 ".%9.9" PRIu64 " sec for %f MB/sec for %9.2f packets/sec (%10.6f ms per packet)\n",
+ send_size,
+ recv_size,
+ packet_count,
+ k_recv_amount_mb,
+ total_time_nsec / TimeValue::NanoSecPerSec,
+ total_time_nsec % TimeValue::NanoSecPerSec,
+ mb_second,
+ packets_per_second,
+ average_ms_per_packet);
+ }
+ strm.Flush();
+ }
+ }
+ if (json)
+ strm.Printf("\n ]\n }\n}\n");
+ else
+ strm.EOL();
+ }
+}
+
+bool
+GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t recv_size)
+{
+ StreamString packet;
+ packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size);
+ uint32_t bytes_left = send_size;
+ while (bytes_left > 0)
+ {
+ if (bytes_left >= 26)
+ {
+ packet.PutCString("abcdefghijklmnopqrstuvwxyz");
+ bytes_left -= 26;
+ }
+ else
+ {
+ packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz");
+ bytes_left = 0;
+ }
+ }
+
+ StringExtractorGDBRemote response;
+ return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success;
+}
+
+uint16_t
+GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid, const char *remote_accept_hostname)
+{
+ pid = LLDB_INVALID_PROCESS_ID;
+ StringExtractorGDBRemote response;
+ StreamString stream;
+ stream.PutCString("qLaunchGDBServer;");
+ std::string hostname;
+ if (remote_accept_hostname && remote_accept_hostname[0])
+ hostname = remote_accept_hostname;
+ else
+ {
+ if (HostInfo::GetHostname(hostname))
+ {
+ // Make the GDB server we launch only accept connections from this host
+ stream.Printf("host:%s;", hostname.c_str());
+ }
+ else
+ {
+ // Make the GDB server we launch accept connections from any host since we can't figure out the hostname
+ stream.Printf("host:*;");
+ }
+ }
+ const char *packet = stream.GetData();
+ int packet_len = stream.GetSize();
+
+ // give the process a few seconds to startup
+ GDBRemoteCommunication::ScopedTimeout timeout (*this, 10);
+
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ std::string name;
+ std::string value;
+ uint16_t port = 0;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("port") == 0)
+ port = StringConvert::ToUInt32(value.c_str(), 0, 0);
+ else if (name.compare("pid") == 0)
+ pid = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_PROCESS_ID, 0);
+ }
+ return port;
+ }
+ return 0;
+}
+
+bool
+GDBRemoteCommunicationClient::KillSpawnedProcess (lldb::pid_t pid)
+{
+ StreamString stream;
+ stream.Printf ("qKillSpawnedProcess:%" PRId64 , pid);
+ const char *packet = stream.GetData();
+ int packet_len = stream.GetSize();
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return true;
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid)
+{
+ if (m_curr_tid == tid)
+ return true;
+
+ char packet[32];
+ int packet_len;
+ if (tid == UINT64_MAX)
+ packet_len = ::snprintf (packet, sizeof(packet), "Hg-1");
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "Hg%" PRIx64, tid);
+ assert (packet_len + 1 < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ {
+ m_curr_tid = tid;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::SetCurrentThreadForRun (uint64_t tid)
+{
+ if (m_curr_tid_run == tid)
+ return true;
+
+ char packet[32];
+ int packet_len;
+ if (tid == UINT64_MAX)
+ packet_len = ::snprintf (packet, sizeof(packet), "Hc-1");
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "Hc%" PRIx64, tid);
+
+ assert (packet_len + 1 < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ {
+ m_curr_tid_run = tid;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetStopReply (StringExtractorGDBRemote &response)
+{
+ if (SendPacketAndWaitForResponse("?", 1, response, false) == PacketResult::Success)
+ return response.IsNormalResponse();
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtractorGDBRemote &response)
+{
+ if (m_supports_qThreadStopInfo)
+ {
+ char packet[256];
+ int packet_len = ::snprintf(packet, sizeof(packet), "qThreadStopInfo%" PRIx64, tid);
+ assert (packet_len < (int)sizeof(packet));
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.IsUnsupportedResponse())
+ m_supports_qThreadStopInfo = false;
+ else if (response.IsNormalResponse())
+ return true;
+ else
+ return false;
+ }
+ else
+ {
+ m_supports_qThreadStopInfo = false;
+ }
+ }
+ return false;
+}
+
+
+uint8_t
+GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, bool insert, addr_t addr, uint32_t length)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s() %s at addr = 0x%" PRIx64,
+ __FUNCTION__, insert ? "add" : "remove", addr);
+
+ // Check if the stub is known not to support this breakpoint type
+ if (!SupportsGDBStoppointPacket(type))
+ return UINT8_MAX;
+ // Construct the breakpoint packet
+ char packet[64];
+ const int packet_len = ::snprintf (packet,
+ sizeof(packet),
+ "%c%i,%" PRIx64 ",%x",
+ insert ? 'Z' : 'z',
+ type,
+ addr,
+ length);
+ // Check we haven't overwritten the end of the packet buffer
+ assert (packet_len + 1 < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ // Try to send the breakpoint packet, and check that it was correctly sent
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, true) == PacketResult::Success)
+ {
+ // Receive and OK packet when the breakpoint successfully placed
+ if (response.IsOKResponse())
+ return 0;
+
+ // Error while setting breakpoint, send back specific error
+ if (response.IsErrorResponse())
+ return response.GetError();
+
+ // Empty packet informs us that breakpoint is not supported
+ if (response.IsUnsupportedResponse())
+ {
+ // Disable this breakpoint type since it is unsupported
+ switch (type)
+ {
+ case eBreakpointSoftware: m_supports_z0 = false; break;
+ case eBreakpointHardware: m_supports_z1 = false; break;
+ case eWatchpointWrite: m_supports_z2 = false; break;
+ case eWatchpointRead: m_supports_z3 = false; break;
+ case eWatchpointReadWrite: m_supports_z4 = false; break;
+ case eStoppointInvalid: return UINT8_MAX;
+ }
+ }
+ }
+ // Signal generic failure
+ return UINT8_MAX;
+}
+
+size_t
+GDBRemoteCommunicationClient::GetCurrentThreadIDs (std::vector<lldb::tid_t> &thread_ids,
+ bool &sequence_mutex_unavailable)
+{
+ Mutex::Locker locker;
+ thread_ids.clear();
+
+ if (GetSequenceMutex (locker, "ProcessGDBRemote::UpdateThreadList() failed due to not getting the sequence mutex"))
+ {
+ sequence_mutex_unavailable = false;
+ StringExtractorGDBRemote response;
+
+ PacketResult packet_result;
+ for (packet_result = SendPacketAndWaitForResponseNoLock ("qfThreadInfo", strlen("qfThreadInfo"), response);
+ packet_result == PacketResult::Success && response.IsNormalResponse();
+ packet_result = SendPacketAndWaitForResponseNoLock ("qsThreadInfo", strlen("qsThreadInfo"), response))
+ {
+ char ch = response.GetChar();
+ if (ch == 'l')
+ break;
+ if (ch == 'm')
+ {
+ do
+ {
+ tid_t tid = response.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID);
+
+ if (tid != LLDB_INVALID_THREAD_ID)
+ {
+ thread_ids.push_back (tid);
+ }
+ ch = response.GetChar(); // Skip the command separator
+ } while (ch == ','); // Make sure we got a comma separator
+ }
+ }
+ }
+ else
+ {
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ // assert(!"ProcessGDBRemote::UpdateThreadList() failed due to not getting the sequence mutex");
+#else
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS));
+ if (log)
+ log->Printf("error: failed to get packet sequence mutex, not sending packet 'qfThreadInfo'");
+#endif
+ sequence_mutex_unavailable = true;
+ }
+ return thread_ids.size();
+}
+
+lldb::addr_t
+GDBRemoteCommunicationClient::GetShlibInfoAddr()
+{
+ if (!IsRunning())
+ {
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false) == PacketResult::Success)
+ {
+ if (response.IsNormalResponse())
+ return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+lldb_private::Error
+GDBRemoteCommunicationClient::RunShellCommand(const char *command, // Shouldn't be NULL
+ 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
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish
+{
+ lldb_private::StreamString stream;
+ stream.PutCString("qPlatform_shell:");
+ stream.PutBytesAsRawHex8(command, strlen(command));
+ stream.PutChar(',');
+ stream.PutHex32(timeout_sec);
+ if (working_dir)
+ {
+ std::string path{working_dir.GetPath(false)};
+ stream.PutChar(',');
+ stream.PutCStringAsRawHex8(path.c_str());
+ }
+ const char *packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.GetChar() != 'F')
+ return Error("malformed reply");
+ if (response.GetChar() != ',')
+ return Error("malformed reply");
+ uint32_t exitcode = response.GetHexMaxU32(false, UINT32_MAX);
+ if (exitcode == UINT32_MAX)
+ return Error("unable to run remote process");
+ else if (status_ptr)
+ *status_ptr = exitcode;
+ if (response.GetChar() != ',')
+ return Error("malformed reply");
+ uint32_t signo = response.GetHexMaxU32(false, UINT32_MAX);
+ if (signo_ptr)
+ *signo_ptr = signo;
+ if (response.GetChar() != ',')
+ return Error("malformed reply");
+ std::string output;
+ response.GetEscapedBinaryData(output);
+ if (command_output)
+ command_output->assign(output);
+ return Error();
+ }
+ return Error("unable to send packet");
+}
+
+Error
+GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec,
+ uint32_t file_permissions)
+{
+ std::string path{file_spec.GetPath(false)};
+ lldb_private::StreamString stream;
+ stream.PutCString("qPlatform_mkdir:");
+ stream.PutHex32(file_permissions);
+ stream.PutChar(',');
+ stream.PutCStringAsRawHex8(path.c_str());
+ const char *packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) != PacketResult::Success)
+ return Error("failed to send '%s' packet", packet);
+
+ if (response.GetChar() != 'F')
+ return Error("invalid response to '%s' packet", packet);
+
+ return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX);
+}
+
+Error
+GDBRemoteCommunicationClient::SetFilePermissions(const FileSpec &file_spec,
+ uint32_t file_permissions)
+{
+ std::string path{file_spec.GetPath(false)};
+ lldb_private::StreamString stream;
+ stream.PutCString("qPlatform_chmod:");
+ stream.PutHex32(file_permissions);
+ stream.PutChar(',');
+ stream.PutCStringAsRawHex8(path.c_str());
+ const char *packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) != PacketResult::Success)
+ return Error("failed to send '%s' packet", packet);
+
+ if (response.GetChar() != 'F')
+ return Error("invalid response to '%s' packet", packet);
+
+ return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX);
+}
+
+static uint64_t
+ParseHostIOPacketResponse (StringExtractorGDBRemote &response,
+ uint64_t fail_result,
+ Error &error)
+{
+ response.SetFilePos(0);
+ if (response.GetChar() != 'F')
+ return fail_result;
+ int32_t result = response.GetS32 (-2);
+ if (result == -2)
+ return fail_result;
+ if (response.GetChar() == ',')
+ {
+ int result_errno = response.GetS32 (-2);
+ if (result_errno != -2)
+ error.SetError(result_errno, eErrorTypePOSIX);
+ else
+ error.SetError(-1, eErrorTypeGeneric);
+ }
+ else
+ error.Clear();
+ return result;
+}
+lldb::user_id_t
+GDBRemoteCommunicationClient::OpenFile (const lldb_private::FileSpec& file_spec,
+ uint32_t flags,
+ mode_t mode,
+ Error &error)
+{
+ std::string path(file_spec.GetPath(false));
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:open:");
+ if (path.empty())
+ return UINT64_MAX;
+ stream.PutCStringAsRawHex8(path.c_str());
+ stream.PutChar(',');
+ stream.PutHex32(flags);
+ stream.PutChar(',');
+ stream.PutHex32(mode);
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ return ParseHostIOPacketResponse (response, UINT64_MAX, error);
+ }
+ return UINT64_MAX;
+}
+
+bool
+GDBRemoteCommunicationClient::CloseFile (lldb::user_id_t fd,
+ Error &error)
+{
+ lldb_private::StreamString stream;
+ stream.Printf("vFile:close:%i", (int)fd);
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ return ParseHostIOPacketResponse (response, -1, error) == 0;
+ }
+ return false;
+}
+
+// Extension of host I/O packets to get the file size.
+lldb::user_id_t
+GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_spec)
+{
+ std::string path(file_spec.GetPath(false));
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:size:");
+ stream.PutCStringAsRawHex8(path.c_str());
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.GetChar() != 'F')
+ return UINT64_MAX;
+ uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX);
+ return retcode;
+ }
+ return UINT64_MAX;
+}
+
+Error
+GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec,
+ uint32_t &file_permissions)
+{
+ std::string path{file_spec.GetPath(false)};
+ Error error;
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:mode:");
+ stream.PutCStringAsRawHex8(path.c_str());
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.GetChar() != 'F')
+ {
+ error.SetErrorStringWithFormat ("invalid response to '%s' packet", packet);
+ }
+ else
+ {
+ const uint32_t mode = response.GetS32(-1);
+ if (static_cast<int32_t>(mode) == -1)
+ {
+ if (response.GetChar() == ',')
+ {
+ int response_errno = response.GetS32(-1);
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ else
+ error.SetErrorToGenericError();
+ }
+ else
+ error.SetErrorToGenericError();
+ }
+ else
+ {
+ file_permissions = mode & (S_IRWXU|S_IRWXG|S_IRWXO);
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("failed to send '%s' packet", packet);
+ }
+ return error;
+}
+
+uint64_t
+GDBRemoteCommunicationClient::ReadFile (lldb::user_id_t fd,
+ uint64_t offset,
+ void *dst,
+ uint64_t dst_len,
+ Error &error)
+{
+ lldb_private::StreamString stream;
+ stream.Printf("vFile:pread:%i,%" PRId64 ",%" PRId64, (int)fd, dst_len, offset);
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.GetChar() != 'F')
+ return 0;
+ uint32_t retcode = response.GetHexMaxU32(false, UINT32_MAX);
+ if (retcode == UINT32_MAX)
+ return retcode;
+ const char next = (response.Peek() ? *response.Peek() : 0);
+ if (next == ',')
+ return 0;
+ if (next == ';')
+ {
+ response.GetChar(); // skip the semicolon
+ std::string buffer;
+ if (response.GetEscapedBinaryData(buffer))
+ {
+ const uint64_t data_to_write = std::min<uint64_t>(dst_len, buffer.size());
+ if (data_to_write > 0)
+ memcpy(dst, &buffer[0], data_to_write);
+ return data_to_write;
+ }
+ }
+ }
+ return 0;
+}
+
+uint64_t
+GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd,
+ uint64_t offset,
+ const void* src,
+ uint64_t src_len,
+ Error &error)
+{
+ lldb_private::StreamGDBRemote stream;
+ stream.Printf("vFile:pwrite:%i,%" PRId64 ",", (int)fd, offset);
+ stream.PutEscapedBytes(src, src_len);
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.GetChar() != 'F')
+ {
+ error.SetErrorStringWithFormat("write file failed");
+ return 0;
+ }
+ uint64_t bytes_written = response.GetU64(UINT64_MAX);
+ if (bytes_written == UINT64_MAX)
+ {
+ error.SetErrorToGenericError();
+ if (response.GetChar() == ',')
+ {
+ int response_errno = response.GetS32(-1);
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ }
+ return 0;
+ }
+ return bytes_written;
+ }
+ else
+ {
+ error.SetErrorString ("failed to send vFile:pwrite packet");
+ }
+ return 0;
+}
+
+Error
+GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src, const FileSpec &dst)
+{
+ std::string src_path{src.GetPath(false)},
+ dst_path{dst.GetPath(false)};
+ Error error;
+ lldb_private::StreamGDBRemote stream;
+ stream.PutCString("vFile:symlink:");
+ // the unix symlink() command reverses its parameters where the dst if first,
+ // so we follow suit here
+ stream.PutCStringAsRawHex8(dst_path.c_str());
+ stream.PutChar(',');
+ stream.PutCStringAsRawHex8(src_path.c_str());
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.GetChar() == 'F')
+ {
+ uint32_t result = response.GetU32(UINT32_MAX);
+ if (result != 0)
+ {
+ error.SetErrorToGenericError();
+ if (response.GetChar() == ',')
+ {
+ int response_errno = response.GetS32(-1);
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ }
+ }
+ }
+ else
+ {
+ // Should have returned with 'F<result>[,<errno>]'
+ error.SetErrorStringWithFormat("symlink failed");
+ }
+ }
+ else
+ {
+ error.SetErrorString ("failed to send vFile:symlink packet");
+ }
+ return error;
+}
+
+Error
+GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec)
+{
+ std::string path{file_spec.GetPath(false)};
+ Error error;
+ lldb_private::StreamGDBRemote stream;
+ stream.PutCString("vFile:unlink:");
+ // the unix symlink() command reverses its parameters where the dst if first,
+ // so we follow suit here
+ stream.PutCStringAsRawHex8(path.c_str());
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.GetChar() == 'F')
+ {
+ uint32_t result = response.GetU32(UINT32_MAX);
+ if (result != 0)
+ {
+ error.SetErrorToGenericError();
+ if (response.GetChar() == ',')
+ {
+ int response_errno = response.GetS32(-1);
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ }
+ }
+ }
+ else
+ {
+ // Should have returned with 'F<result>[,<errno>]'
+ error.SetErrorStringWithFormat("unlink failed");
+ }
+ }
+ else
+ {
+ error.SetErrorString ("failed to send vFile:unlink packet");
+ }
+ return error;
+}
+
+// Extension of host I/O packets to get whether a file exists.
+bool
+GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec)
+{
+ std::string path(file_spec.GetPath(false));
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:exists:");
+ stream.PutCStringAsRawHex8(path.c_str());
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.GetChar() != 'F')
+ return false;
+ if (response.GetChar() != ',')
+ return false;
+ bool retcode = (response.GetChar() != '0');
+ return retcode;
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_spec,
+ uint64_t &high,
+ uint64_t &low)
+{
+ std::string path(file_spec.GetPath(false));
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:MD5:");
+ stream.PutCStringAsRawHex8(path.c_str());
+ const char* packet = stream.GetData();
+ int packet_len = stream.GetSize();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success)
+ {
+ if (response.GetChar() != 'F')
+ return false;
+ if (response.GetChar() != ',')
+ return false;
+ if (response.Peek() && *response.Peek() == 'x')
+ return false;
+ low = response.GetHexMaxU64(false, UINT64_MAX);
+ high = response.GetHexMaxU64(false, UINT64_MAX);
+ return true;
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::AvoidGPackets (ProcessGDBRemote *process)
+{
+ // Some targets have issues with g/G packets and we need to avoid using them
+ if (m_avoid_g_packets == eLazyBoolCalculate)
+ {
+ if (process)
+ {
+ m_avoid_g_packets = eLazyBoolNo;
+ const ArchSpec &arch = process->GetTarget().GetArchitecture();
+ if (arch.IsValid()
+ && arch.GetTriple().getVendor() == llvm::Triple::Apple
+ && arch.GetTriple().getOS() == llvm::Triple::IOS
+ && arch.GetTriple().getArch() == llvm::Triple::aarch64)
+ {
+ m_avoid_g_packets = eLazyBoolYes;
+ uint32_t gdb_server_version = GetGDBServerProgramVersion();
+ if (gdb_server_version != 0)
+ {
+ const char *gdb_server_name = GetGDBServerProgramName();
+ if (gdb_server_name && strcmp(gdb_server_name, "debugserver") == 0)
+ {
+ if (gdb_server_version >= 310)
+ m_avoid_g_packets = eLazyBoolNo;
+ }
+ }
+ }
+ }
+ }
+ return m_avoid_g_packets == eLazyBoolYes;
+}
+
+bool
+GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response)
+{
+ Mutex::Locker locker;
+ if (GetSequenceMutex (locker, "Didn't get sequence mutex for p packet."))
+ {
+ const bool thread_suffix_supported = GetThreadSuffixSupported();
+
+ if (thread_suffix_supported || SetCurrentThread(tid))
+ {
+ char packet[64];
+ int packet_len = 0;
+ if (thread_suffix_supported)
+ packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, tid);
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg);
+ assert (packet_len < ((int)sizeof(packet) - 1));
+ return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success;
+ }
+ }
+ return false;
+
+}
+
+
+bool
+GDBRemoteCommunicationClient::ReadAllRegisters (lldb::tid_t tid, StringExtractorGDBRemote &response)
+{
+ Mutex::Locker locker;
+ if (GetSequenceMutex (locker, "Didn't get sequence mutex for g packet."))
+ {
+ const bool thread_suffix_supported = GetThreadSuffixSupported();
+
+ if (thread_suffix_supported || SetCurrentThread(tid))
+ {
+ char packet[64];
+ int packet_len = 0;
+ // Get all registers in one packet
+ if (thread_suffix_supported)
+ packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", tid);
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "g");
+ assert (packet_len < ((int)sizeof(packet) - 1));
+ return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success;
+ }
+ }
+ return false;
+}
+bool
+GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save_id)
+{
+ save_id = 0; // Set to invalid save ID
+ if (m_supports_QSaveRegisterState == eLazyBoolNo)
+ return false;
+
+ m_supports_QSaveRegisterState = eLazyBoolYes;
+ Mutex::Locker locker;
+ if (GetSequenceMutex (locker, "Didn't get sequence mutex for QSaveRegisterState."))
+ {
+ const bool thread_suffix_supported = GetThreadSuffixSupported();
+ if (thread_suffix_supported || SetCurrentThread(tid))
+ {
+ char packet[256];
+ if (thread_suffix_supported)
+ ::snprintf (packet, sizeof(packet), "QSaveRegisterState;thread:%4.4" PRIx64 ";", tid);
+ else
+ ::snprintf(packet, sizeof(packet), "QSaveRegisterState");
+
+ StringExtractorGDBRemote response;
+
+ if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success)
+ {
+ if (response.IsUnsupportedResponse())
+ {
+ // This packet isn't supported, don't try calling it again
+ m_supports_QSaveRegisterState = eLazyBoolNo;
+ }
+
+ const uint32_t response_save_id = response.GetU32(0);
+ if (response_save_id != 0)
+ {
+ save_id = response_save_id;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t save_id)
+{
+ // We use the "m_supports_QSaveRegisterState" variable here because the
+ // QSaveRegisterState and QRestoreRegisterState packets must both be supported in
+ // order to be useful
+ if (m_supports_QSaveRegisterState == eLazyBoolNo)
+ return false;
+
+ Mutex::Locker locker;
+ if (GetSequenceMutex (locker, "Didn't get sequence mutex for QRestoreRegisterState."))
+ {
+ const bool thread_suffix_supported = GetThreadSuffixSupported();
+ if (thread_suffix_supported || SetCurrentThread(tid))
+ {
+ char packet[256];
+ if (thread_suffix_supported)
+ ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u;thread:%4.4" PRIx64 ";", save_id, tid);
+ else
+ ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u" PRIx64 ";", save_id);
+
+ StringExtractorGDBRemote response;
+
+ if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ {
+ return true;
+ }
+ else if (response.IsUnsupportedResponse())
+ {
+ // This packet isn't supported, don't try calling this packet or
+ // QSaveRegisterState again...
+ m_supports_QSaveRegisterState = eLazyBoolNo;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetModuleInfo (const FileSpec& module_file_spec,
+ const lldb_private::ArchSpec& arch_spec,
+ ModuleSpec &module_spec)
+{
+ std::string module_path = module_file_spec.GetPath (false);
+ if (module_path.empty ())
+ return false;
+
+ StreamString packet;
+ packet.PutCString("qModuleInfo:");
+ packet.PutCStringAsRawHex8(module_path.c_str());
+ packet.PutCString(";");
+ const auto& triple = arch_spec.GetTriple().getTriple();
+ packet.PutCStringAsRawHex8(triple.c_str());
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) != PacketResult::Success)
+ return false;
+
+ if (response.IsErrorResponse () || response.IsUnsupportedResponse ())
+ return false;
+
+ std::string name;
+ std::string value;
+ bool success;
+ StringExtractor extractor;
+
+ module_spec.Clear ();
+ module_spec.GetFileSpec () = module_file_spec;
+
+ while (response.GetNameColonValue (name, value))
+ {
+ if (name == "uuid" || name == "md5")
+ {
+ extractor.GetStringRef ().swap (value);
+ extractor.SetFilePos (0);
+ extractor.GetHexByteString (value);
+ module_spec.GetUUID().SetFromCString (value.c_str(), value.size() / 2);
+ }
+ else if (name == "triple")
+ {
+ extractor.GetStringRef ().swap (value);
+ extractor.SetFilePos (0);
+ extractor.GetHexByteString (value);
+ module_spec.GetArchitecture().SetTriple (value.c_str ());
+ }
+ else if (name == "file_offset")
+ {
+ const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success);
+ if (success)
+ module_spec.SetObjectOffset (ival);
+ }
+ else if (name == "file_size")
+ {
+ const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success);
+ if (success)
+ module_spec.SetObjectSize (ival);
+ }
+ else if (name == "file_path")
+ {
+ extractor.GetStringRef ().swap (value);
+ extractor.SetFilePos (0);
+ extractor.GetHexByteString (value);
+ module_spec.GetFileSpec() = FileSpec(value.c_str(), false, arch_spec);
+ }
+ }
+
+ return true;
+}
+
+// query the target remote for extended information using the qXfer packet
+//
+// example: object='features', annex='target.xml', out=<xml output>
+// return: 'true' on success
+// 'false' on failure (err set)
+bool
+GDBRemoteCommunicationClient::ReadExtFeature (const lldb_private::ConstString object,
+ const lldb_private::ConstString annex,
+ std::string & out,
+ lldb_private::Error & err) {
+
+ std::stringstream output;
+ StringExtractorGDBRemote chunk;
+
+ uint64_t size = GetRemoteMaxPacketSize();
+ if (size == 0)
+ size = 0x1000;
+ size = size - 1; // Leave space for the 'm' or 'l' character in the response
+ int offset = 0;
+ bool active = true;
+
+ // loop until all data has been read
+ while ( active ) {
+
+ // send query extended feature packet
+ std::stringstream packet;
+ packet << "qXfer:"
+ << object.AsCString("") << ":read:"
+ << annex.AsCString("") << ":"
+ << std::hex << offset << ","
+ << std::hex << size;
+
+ GDBRemoteCommunication::PacketResult res =
+ SendPacketAndWaitForResponse( packet.str().c_str(),
+ chunk,
+ false );
+
+ if ( res != GDBRemoteCommunication::PacketResult::Success ) {
+ err.SetErrorString( "Error sending $qXfer packet" );
+ return false;
+ }
+
+ const std::string & str = chunk.GetStringRef( );
+ if ( str.length() == 0 ) {
+ // should have some data in chunk
+ err.SetErrorString( "Empty response from $qXfer packet" );
+ return false;
+ }
+
+ // check packet code
+ switch ( str[0] ) {
+ // last chunk
+ case ( 'l' ):
+ active = false;
+ // fall through intentional
+
+ // more chunks
+ case ( 'm' ) :
+ if ( str.length() > 1 )
+ output << &str[1];
+ offset += size;
+ break;
+
+ // unknown chunk
+ default:
+ err.SetErrorString( "Invalid continuation code from $qXfer packet" );
+ return false;
+ }
+ }
+
+ out = output.str( );
+ err.Success( );
+ return true;
+}
+
+// Notify the target that gdb is prepared to serve symbol lookup requests.
+// packet: "qSymbol::"
+// reply:
+// OK The target does not need to look up any (more) symbols.
+// qSymbol:<sym_name> The target requests the value of symbol sym_name (hex encoded).
+// LLDB may provide the value by sending another qSymbol packet
+// in the form of"qSymbol:<sym_value>:<sym_name>".
+
+void
+GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process)
+{
+ if (m_supports_qSymbol)
+ {
+ Mutex::Locker locker;
+ if (GetSequenceMutex(locker, "GDBRemoteCommunicationClient::ServeSymbolLookups() failed due to not getting the sequence mutex"))
+ {
+ StreamString packet;
+ packet.PutCString ("qSymbol::");
+ while (1)
+ {
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponseNoLock(packet.GetData(), packet.GetSize(), response) == PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ {
+ // We are done serving symbols requests
+ return;
+ }
+
+ if (response.IsUnsupportedResponse())
+ {
+ // qSymbol is not supported by the current GDB server we are connected to
+ m_supports_qSymbol = false;
+ return;
+ }
+ else
+ {
+ llvm::StringRef response_str(response.GetStringRef());
+ if (response_str.startswith("qSymbol:"))
+ {
+ response.SetFilePos(strlen("qSymbol:"));
+ std::string symbol_name;
+ if (response.GetHexByteString(symbol_name))
+ {
+ if (symbol_name.empty())
+ return;
+
+ addr_t symbol_load_addr = LLDB_INVALID_ADDRESS;
+ lldb_private::SymbolContextList sc_list;
+ if (process->GetTarget().GetImages().FindSymbolsWithNameAndType(ConstString(symbol_name), eSymbolTypeAny, sc_list))
+ {
+ const size_t num_scs = sc_list.GetSize();
+ for (size_t sc_idx=0; sc_idx<num_scs && symbol_load_addr == LLDB_INVALID_ADDRESS; ++sc_idx)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(sc_idx, sc))
+ {
+ if (sc.symbol)
+ {
+ switch (sc.symbol->GetType())
+ {
+ case eSymbolTypeInvalid:
+ case eSymbolTypeAbsolute:
+ case eSymbolTypeUndefined:
+ case eSymbolTypeSourceFile:
+ case eSymbolTypeHeaderFile:
+ case eSymbolTypeObjectFile:
+ case eSymbolTypeCommonBlock:
+ case eSymbolTypeBlock:
+ case eSymbolTypeLocal:
+ case eSymbolTypeParam:
+ case eSymbolTypeVariable:
+ case eSymbolTypeVariableType:
+ case eSymbolTypeLineEntry:
+ case eSymbolTypeLineHeader:
+ case eSymbolTypeScopeBegin:
+ case eSymbolTypeScopeEnd:
+ case eSymbolTypeAdditional:
+ case eSymbolTypeCompiler:
+ case eSymbolTypeInstrumentation:
+ case eSymbolTypeTrampoline:
+ break;
+
+ case eSymbolTypeCode:
+ case eSymbolTypeResolver:
+ case eSymbolTypeData:
+ case eSymbolTypeRuntime:
+ case eSymbolTypeException:
+ case eSymbolTypeObjCClass:
+ case eSymbolTypeObjCMetaClass:
+ case eSymbolTypeObjCIVar:
+ case eSymbolTypeReExported:
+ symbol_load_addr = sc.symbol->GetLoadAddress(&process->GetTarget());
+ break;
+ }
+ }
+ }
+ }
+ }
+ // This is the normal path where our symbol lookup was successful and we want
+ // to send a packet with the new symbol value and see if another lookup needs to be
+ // done.
+
+ // Change "packet" to contain the requested symbol value and name
+ packet.Clear();
+ packet.PutCString("qSymbol:");
+ if (symbol_load_addr != LLDB_INVALID_ADDRESS)
+ packet.Printf("%" PRIx64, symbol_load_addr);
+ packet.PutCString(":");
+ packet.PutBytesAsRawHex8(symbol_name.data(), symbol_name.size());
+ continue; // go back to the while loop and send "packet" and wait for another response
+ }
+ }
+ }
+ }
+ }
+ // If we make it here, the symbol request packet response wasn't valid or
+ // our symbol lookup failed so we must abort
+ return;
+
+ }
+ }
+}
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
new file mode 100644
index 0000000..b08ff06
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -0,0 +1,684 @@
+//===-- GDBRemoteCommunicationClient.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_GDBRemoteCommunicationClient_h_
+#define liblldb_GDBRemoteCommunicationClient_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/StructuredData.h"
+#include "lldb/Target/Process.h"
+
+#include "GDBRemoteCommunication.h"
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class GDBRemoteCommunicationClient : public GDBRemoteCommunication
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteCommunicationClient();
+
+ ~GDBRemoteCommunicationClient();
+
+ //------------------------------------------------------------------
+ // After connecting, send the handshake to the server to make sure
+ // we are communicating with it.
+ //------------------------------------------------------------------
+ bool
+ HandshakeWithServer (Error *error_ptr);
+
+ PacketResult
+ SendPacketAndWaitForResponse (const char *send_payload,
+ StringExtractorGDBRemote &response,
+ bool send_async);
+
+ PacketResult
+ SendPacketAndWaitForResponse (const char *send_payload,
+ size_t send_length,
+ StringExtractorGDBRemote &response,
+ bool send_async);
+
+ // For packets which specify a range of output to be returned,
+ // return all of the output via a series of request packets of the form
+ // <prefix>0,<size>
+ // <prefix><size>,<size>
+ // <prefix><size>*2,<size>
+ // <prefix><size>*3,<size>
+ // ...
+ // until a "$l..." packet is received, indicating the end.
+ // (size is in hex; this format is used by a standard gdbserver to
+ // return the given portion of the output specified by <prefix>;
+ // for example, "qXfer:libraries-svr4:read::fff,1000" means
+ // "return a chunk of the xml description file for shared
+ // library load addresses, where the chunk starts at offset 0xfff
+ // and continues for 0x1000 bytes").
+ // Concatenate the resulting server response packets together and
+ // return in response_string. If any packet fails, the return value
+ // indicates that failure and the returned string value is undefined.
+ PacketResult
+ SendPacketsAndConcatenateResponses (const char *send_payload_prefix,
+ std::string &response_string);
+
+ lldb::StateType
+ SendContinuePacketAndWaitForResponse (ProcessGDBRemote *process,
+ const char *packet_payload,
+ size_t packet_length,
+ StringExtractorGDBRemote &response);
+ bool
+ SendvContPacket (ProcessGDBRemote *process,
+ const char *payload,
+ size_t packet_length,
+ StringExtractorGDBRemote &response);
+
+ bool
+ GetThreadSuffixSupported () override;
+
+ // This packet is usually sent first and the boolean return value
+ // indicates if the packet was send and any response was received
+ // even in the response is UNIMPLEMENTED. If the packet failed to
+ // get a response, then false is returned. This quickly tells us
+ // if we were able to connect and communicate with the remote GDB
+ // server
+ bool
+ QueryNoAckModeSupported ();
+
+ void
+ GetListThreadsInStopReplySupported ();
+
+ bool
+ SendAsyncSignal (int signo);
+
+ bool
+ SendInterrupt (Mutex::Locker &locker,
+ uint32_t seconds_to_wait_for_stop,
+ bool &timed_out);
+
+ lldb::pid_t
+ GetCurrentProcessID (bool allow_lazy = true);
+
+ bool
+ GetLaunchSuccess (std::string &error_str);
+
+ uint16_t
+ LaunchGDBserverAndGetPort (lldb::pid_t &pid, const char *remote_accept_hostname);
+
+ bool
+ KillSpawnedProcess (lldb::pid_t pid);
+
+ //------------------------------------------------------------------
+ /// Sends a GDB remote protocol 'A' packet that delivers program
+ /// arguments to the remote server.
+ ///
+ /// @param[in] argv
+ /// A NULL terminated array of const C strings to use as the
+ /// arguments.
+ ///
+ /// @return
+ /// Zero if the response was "OK", a positive value if the
+ /// the response was "Exx" where xx are two hex digits, or
+ /// -1 if the call is unsupported or any other unexpected
+ /// response was received.
+ //------------------------------------------------------------------
+ int
+ SendArgumentsPacket (const ProcessLaunchInfo &launch_info);
+
+ //------------------------------------------------------------------
+ /// Sends a "QEnvironment:NAME=VALUE" packet that will build up the
+ /// environment that will get used when launching an application
+ /// in conjunction with the 'A' packet. This function can be called
+ /// multiple times in a row in order to pass on the desired
+ /// environment that the inferior should be launched with.
+ ///
+ /// @param[in] name_equal_value
+ /// A NULL terminated C string that contains a single environment
+ /// in the format "NAME=VALUE".
+ ///
+ /// @return
+ /// Zero if the response was "OK", a positive value if the
+ /// the response was "Exx" where xx are two hex digits, or
+ /// -1 if the call is unsupported or any other unexpected
+ /// response was received.
+ //------------------------------------------------------------------
+ int
+ SendEnvironmentPacket (char const *name_equal_value);
+
+ int
+ SendLaunchArchPacket (const char *arch);
+
+ int
+ SendLaunchEventDataPacket (const char *data, bool *was_supported = NULL);
+
+ //------------------------------------------------------------------
+ /// Sends a "vAttach:PID" where PID is in hex.
+ ///
+ /// @param[in] pid
+ /// A process ID for the remote gdb server to attach to.
+ ///
+ /// @param[out] response
+ /// The response received from the gdb server. If the return
+ /// value is zero, \a response will contain a stop reply
+ /// packet.
+ ///
+ /// @return
+ /// Zero if the attach was successful, or an error indicating
+ /// an error code.
+ //------------------------------------------------------------------
+ int
+ SendAttach (lldb::pid_t pid,
+ StringExtractorGDBRemote& response);
+
+
+ //------------------------------------------------------------------
+ /// Sends a GDB remote protocol 'I' packet that delivers stdin
+ /// data to the remote process.
+ ///
+ /// @param[in] data
+ /// A pointer to stdin data.
+ ///
+ /// @param[in] data_len
+ /// The number of bytes available at \a data.
+ ///
+ /// @return
+ /// Zero if the attach was successful, or an error indicating
+ /// an error code.
+ //------------------------------------------------------------------
+ int
+ SendStdinNotification(const char* data, size_t data_len);
+
+ //------------------------------------------------------------------
+ /// Sets the path to use for stdin/out/err for a process
+ /// that will be launched with the 'A' packet.
+ ///
+ /// @param[in] path
+ /// The path to use for stdin/out/err
+ ///
+ /// @return
+ /// Zero if the for success, or an error code for failure.
+ //------------------------------------------------------------------
+ int
+ SetSTDIN(const FileSpec &file_spec);
+ int
+ SetSTDOUT(const FileSpec &file_spec);
+ int
+ SetSTDERR(const FileSpec &file_spec);
+
+ //------------------------------------------------------------------
+ /// Sets the disable ASLR flag to \a enable for a process that will
+ /// be launched with the 'A' packet.
+ ///
+ /// @param[in] enable
+ /// A boolean value indicating whether to disable ASLR or not.
+ ///
+ /// @return
+ /// Zero if the for success, or an error code for failure.
+ //------------------------------------------------------------------
+ int
+ SetDisableASLR (bool enable);
+
+ //------------------------------------------------------------------
+ /// Sets the DetachOnError flag to \a enable for the process controlled by the stub.
+ ///
+ /// @param[in] enable
+ /// A boolean value indicating whether to detach on error or not.
+ ///
+ /// @return
+ /// Zero if the for success, or an error code for failure.
+ //------------------------------------------------------------------
+ int
+ SetDetachOnError (bool enable);
+
+ //------------------------------------------------------------------
+ /// Sets the working directory to \a path for a process that will
+ /// be launched with the 'A' packet for non platform based
+ /// connections. If this packet is sent to a GDB server that
+ /// implements the platform, it will change the current working
+ /// directory for the platform process.
+ ///
+ /// @param[in] working_dir
+ /// The path to a directory to use when launching our process
+ ///
+ /// @return
+ /// Zero if the for success, or an error code for failure.
+ //------------------------------------------------------------------
+ int
+ SetWorkingDir(const FileSpec &working_dir);
+
+ //------------------------------------------------------------------
+ /// Gets the current working directory of a remote platform GDB
+ /// server.
+ ///
+ /// @param[out] working_dir
+ /// The current working directory on the remote platform.
+ ///
+ /// @return
+ /// Boolean for success
+ //------------------------------------------------------------------
+ bool
+ GetWorkingDir(FileSpec &working_dir);
+
+ lldb::addr_t
+ AllocateMemory (size_t size, uint32_t permissions);
+
+ bool
+ DeallocateMemory (lldb::addr_t addr);
+
+ Error
+ Detach (bool keep_stopped);
+
+ Error
+ GetMemoryRegionInfo (lldb::addr_t addr, MemoryRegionInfo &range_info);
+
+ Error
+ GetWatchpointSupportInfo (uint32_t &num);
+
+ Error
+ GetWatchpointSupportInfo (uint32_t &num, bool& after, const ArchSpec &arch);
+
+ Error
+ GetWatchpointsTriggerAfterInstruction (bool &after, const ArchSpec &arch);
+
+ const ArchSpec &
+ GetHostArchitecture ();
+
+ uint32_t
+ GetHostDefaultPacketTimeout();
+
+ const ArchSpec &
+ GetProcessArchitecture ();
+
+ void
+ GetRemoteQSupported();
+
+ bool
+ GetVContSupported (char flavor);
+
+ bool
+ GetpPacketSupported (lldb::tid_t tid);
+
+ bool
+ GetxPacketSupported ();
+
+ bool
+ GetVAttachOrWaitSupported ();
+
+ bool
+ GetSyncThreadStateSupported();
+
+ void
+ ResetDiscoverableSettings (bool did_exec);
+
+ bool
+ GetHostInfo (bool force = false);
+
+ bool
+ GetDefaultThreadId (lldb::tid_t &tid);
+
+ bool
+ GetOSVersion (uint32_t &major,
+ uint32_t &minor,
+ uint32_t &update);
+
+ bool
+ GetOSBuildString (std::string &s);
+
+ bool
+ GetOSKernelDescription (std::string &s);
+
+ ArchSpec
+ GetSystemArchitecture ();
+
+ bool
+ GetHostname (std::string &s);
+
+ lldb::addr_t
+ GetShlibInfoAddr();
+
+ bool
+ GetSupportsThreadSuffix ();
+
+ bool
+ GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info);
+
+ uint32_t
+ FindProcesses (const ProcessInstanceInfoMatch &process_match_info,
+ ProcessInstanceInfoList &process_infos);
+
+ bool
+ GetUserName (uint32_t uid, std::string &name);
+
+ bool
+ GetGroupName (uint32_t gid, std::string &name);
+
+ bool
+ HasFullVContSupport ()
+ {
+ return GetVContSupported ('A');
+ }
+
+ bool
+ HasAnyVContSupport ()
+ {
+ return GetVContSupported ('a');
+ }
+
+ bool
+ GetStopReply (StringExtractorGDBRemote &response);
+
+ bool
+ GetThreadStopInfo (lldb::tid_t tid,
+ StringExtractorGDBRemote &response);
+
+ bool
+ SupportsGDBStoppointPacket (GDBStoppointType type)
+ {
+ switch (type)
+ {
+ case eBreakpointSoftware: return m_supports_z0;
+ case eBreakpointHardware: return m_supports_z1;
+ case eWatchpointWrite: return m_supports_z2;
+ case eWatchpointRead: return m_supports_z3;
+ case eWatchpointReadWrite: return m_supports_z4;
+ default: return false;
+ }
+ }
+ uint8_t
+ SendGDBStoppointTypePacket (GDBStoppointType type, // Type of breakpoint or watchpoint
+ bool insert, // Insert or remove?
+ lldb::addr_t addr, // Address of breakpoint or watchpoint
+ uint32_t length); // Byte Size of breakpoint or watchpoint
+
+ bool
+ SetNonStopMode (const bool enable);
+
+ void
+ TestPacketSpeed (const uint32_t num_packets, uint32_t max_send, uint32_t max_recv, bool json, Stream &strm);
+
+ // This packet is for testing the speed of the interface only. Both
+ // the client and server need to support it, but this allows us to
+ // measure the packet speed without any other work being done on the
+ // other end and avoids any of that work affecting the packet send
+ // and response times.
+ bool
+ SendSpeedTestPacket (uint32_t send_size,
+ uint32_t recv_size);
+
+ bool
+ SetCurrentThread (uint64_t tid);
+
+ bool
+ SetCurrentThreadForRun (uint64_t tid);
+
+ bool
+ GetQXferAuxvReadSupported ();
+
+ bool
+ GetQXferLibrariesReadSupported ();
+
+ bool
+ GetQXferLibrariesSVR4ReadSupported ();
+
+ uint64_t
+ GetRemoteMaxPacketSize();
+
+ bool
+ GetEchoSupported ();
+
+ bool
+ GetAugmentedLibrariesSVR4ReadSupported ();
+
+ bool
+ GetQXferFeaturesReadSupported ();
+
+ LazyBool
+ SupportsAllocDeallocMemory () // const
+ {
+ // Uncomment this to have lldb pretend the debug server doesn't respond to alloc/dealloc memory packets.
+ // m_supports_alloc_dealloc_memory = lldb_private::eLazyBoolNo;
+ return m_supports_alloc_dealloc_memory;
+ }
+
+ size_t
+ GetCurrentThreadIDs (std::vector<lldb::tid_t> &thread_ids,
+ bool &sequence_mutex_unavailable);
+
+ bool
+ GetInterruptWasSent () const
+ {
+ return m_interrupt_sent;
+ }
+
+ lldb::user_id_t
+ OpenFile (const FileSpec& file_spec, uint32_t flags, mode_t mode, Error &error);
+
+ bool
+ CloseFile (lldb::user_id_t fd, Error &error);
+
+ lldb::user_id_t
+ GetFileSize (const FileSpec& file_spec);
+
+ Error
+ GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions);
+
+ Error
+ SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions);
+
+ uint64_t
+ ReadFile (lldb::user_id_t fd,
+ uint64_t offset,
+ void *dst,
+ uint64_t dst_len,
+ Error &error);
+
+ uint64_t
+ WriteFile (lldb::user_id_t fd,
+ uint64_t offset,
+ const void* src,
+ uint64_t src_len,
+ Error &error);
+
+ Error
+ CreateSymlink(const FileSpec &src,
+ const FileSpec &dst);
+
+ Error
+ Unlink(const FileSpec &file_spec);
+
+ Error
+ MakeDirectory(const FileSpec &file_spec, uint32_t mode);
+
+ bool
+ GetFileExists (const FileSpec& file_spec);
+
+ Error
+ RunShellCommand(const char *command, // Shouldn't be NULL
+ 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
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish
+
+ bool
+ CalculateMD5 (const FileSpec& file_spec, uint64_t &high, uint64_t &low);
+
+ std::string
+ HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process,
+ StringExtractorGDBRemote &inputStringExtractor);
+
+ bool
+ ReadRegister(lldb::tid_t tid,
+ uint32_t reg_num,
+ StringExtractorGDBRemote &response);
+
+ bool
+ ReadAllRegisters (lldb::tid_t tid,
+ StringExtractorGDBRemote &response);
+
+ bool
+ SaveRegisterState (lldb::tid_t tid, uint32_t &save_id);
+
+ bool
+ RestoreRegisterState (lldb::tid_t tid, uint32_t save_id);
+
+ const char *
+ GetGDBServerProgramName();
+
+ uint32_t
+ GetGDBServerProgramVersion();
+
+ bool
+ AvoidGPackets(ProcessGDBRemote *process);
+
+ StructuredData::ObjectSP
+ GetThreadsInfo();
+
+ bool
+ GetThreadExtendedInfoSupported();
+
+ bool
+ GetLoadedDynamicLibrariesInfosSupported();
+
+ bool
+ GetModuleInfo (const FileSpec& module_file_spec,
+ const ArchSpec& arch_spec,
+ ModuleSpec &module_spec);
+
+ bool
+ ReadExtFeature (const lldb_private::ConstString object,
+ const lldb_private::ConstString annex,
+ std::string & out,
+ lldb_private::Error & err);
+
+ void
+ ServeSymbolLookups(lldb_private::Process *process);
+
+protected:
+
+ PacketResult
+ SendPacketAndWaitForResponseNoLock (const char *payload,
+ size_t payload_length,
+ StringExtractorGDBRemote &response);
+
+ bool
+ GetCurrentProcessInfo (bool allow_lazy_pid = true);
+
+ bool
+ GetGDBServerVersion();
+
+ // Given the list of compression types that the remote debug stub can support,
+ // possibly enable compression if we find an encoding we can handle.
+ void
+ MaybeEnableCompression (std::vector<std::string> supported_compressions);
+
+ //------------------------------------------------------------------
+ // Classes that inherit from GDBRemoteCommunicationClient can see and modify these
+ //------------------------------------------------------------------
+ LazyBool m_supports_not_sending_acks;
+ LazyBool m_supports_thread_suffix;
+ LazyBool m_supports_threads_in_stop_reply;
+ LazyBool m_supports_vCont_all;
+ LazyBool m_supports_vCont_any;
+ LazyBool m_supports_vCont_c;
+ LazyBool m_supports_vCont_C;
+ LazyBool m_supports_vCont_s;
+ LazyBool m_supports_vCont_S;
+ LazyBool m_qHostInfo_is_valid;
+ LazyBool m_curr_pid_is_valid;
+ LazyBool m_qProcessInfo_is_valid;
+ LazyBool m_qGDBServerVersion_is_valid;
+ LazyBool m_supports_alloc_dealloc_memory;
+ LazyBool m_supports_memory_region_info;
+ LazyBool m_supports_watchpoint_support_info;
+ LazyBool m_supports_detach_stay_stopped;
+ LazyBool m_watchpoints_trigger_after_instruction;
+ LazyBool m_attach_or_wait_reply;
+ LazyBool m_prepare_for_reg_writing_reply;
+ LazyBool m_supports_p;
+ LazyBool m_supports_x;
+ LazyBool m_avoid_g_packets;
+ LazyBool m_supports_QSaveRegisterState;
+ LazyBool m_supports_qXfer_auxv_read;
+ LazyBool m_supports_qXfer_libraries_read;
+ LazyBool m_supports_qXfer_libraries_svr4_read;
+ LazyBool m_supports_qXfer_features_read;
+ LazyBool m_supports_augmented_libraries_svr4_read;
+ LazyBool m_supports_jThreadExtendedInfo;
+ LazyBool m_supports_jLoadedDynamicLibrariesInfos;
+
+ bool
+ m_supports_qProcessInfoPID:1,
+ m_supports_qfProcessInfo:1,
+ m_supports_qUserName:1,
+ m_supports_qGroupName:1,
+ m_supports_qThreadStopInfo:1,
+ m_supports_z0:1,
+ m_supports_z1:1,
+ m_supports_z2:1,
+ m_supports_z3:1,
+ m_supports_z4:1,
+ m_supports_QEnvironment:1,
+ m_supports_QEnvironmentHexEncoded:1,
+ m_supports_qSymbol:1,
+ m_supports_jThreadsInfo:1;
+
+ lldb::pid_t m_curr_pid;
+ lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all other operations
+ lldb::tid_t m_curr_tid_run; // Current gdb remote protocol thread index for continue, step, etc
+
+
+ uint32_t m_num_supported_hardware_watchpoints;
+
+ // If we need to send a packet while the target is running, the m_async_XXX
+ // member variables take care of making this happen.
+ Mutex m_async_mutex;
+ Predicate<bool> m_async_packet_predicate;
+ std::string m_async_packet;
+ PacketResult m_async_result;
+ StringExtractorGDBRemote m_async_response;
+ int m_async_signal; // We were asked to deliver a signal to the inferior process.
+ bool m_interrupt_sent;
+ std::string m_partial_profile_data;
+ std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map;
+
+ ArchSpec m_host_arch;
+ ArchSpec m_process_arch;
+ uint32_t m_os_version_major;
+ uint32_t m_os_version_minor;
+ uint32_t m_os_version_update;
+ std::string m_os_build;
+ std::string m_os_kernel;
+ std::string m_hostname;
+ std::string m_gdb_server_name; // from reply to qGDBServerVersion, empty if qGDBServerVersion is not supported
+ uint32_t m_gdb_server_version; // from reply to qGDBServerVersion, zero if qGDBServerVersion is not supported
+ uint32_t m_default_packet_timeout;
+ uint64_t m_max_packet_size; // as returned by qSupported
+
+
+ bool
+ DecodeProcessInfoResponse (StringExtractorGDBRemote &response,
+ ProcessInstanceInfo &process_info);
+private:
+ //------------------------------------------------------------------
+ // For GDBRemoteCommunicationClient only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationClient);
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // liblldb_GDBRemoteCommunicationClient_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
new file mode 100644
index 0000000..4ee66b8
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -0,0 +1,138 @@
+//===-- GDBRemoteCommunicationServer.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <errno.h>
+
+#include "lldb/Host/Config.h"
+
+#include "GDBRemoteCommunicationServer.h"
+
+// C Includes
+// C++ Includes
+#include <cstring>
+
+// Project includes
+#include "ProcessGDBRemoteLog.h"
+#include "Utility/StringExtractorGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(const char *comm_name,
+ const char *listener_name) :
+ GDBRemoteCommunication (comm_name, listener_name),
+ m_exit_now (false)
+{
+}
+
+GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer()
+{
+}
+
+void GDBRemoteCommunicationServer::RegisterPacketHandler(
+ StringExtractorGDBRemote::ServerPacketType packet_type,
+ PacketHandler handler)
+{
+ m_packet_handlers[packet_type] = std::move(handler);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
+ Error &error,
+ bool &interrupt,
+ bool &quit)
+{
+ StringExtractorGDBRemote packet;
+
+ PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec, false);
+ if (packet_result == PacketResult::Success)
+ {
+ const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType ();
+ switch (packet_type)
+ {
+ case StringExtractorGDBRemote::eServerPacketType_nack:
+ case StringExtractorGDBRemote::eServerPacketType_ack:
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_invalid:
+ error.SetErrorString("invalid packet");
+ quit = true;
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_unimplemented:
+ packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str());
+ break;
+
+ default:
+ auto handler_it = m_packet_handlers.find(packet_type);
+ if (handler_it == m_packet_handlers.end())
+ packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str());
+ else
+ packet_result = handler_it->second (packet, error, interrupt, quit);
+ break;
+ }
+ }
+ else
+ {
+ if (!IsConnected())
+ {
+ error.SetErrorString("lost connection");
+ quit = true;
+ }
+ else
+ {
+ error.SetErrorString("timeout");
+ }
+ }
+
+ // Check if anything occurred that would force us to want to exit.
+ if (m_exit_now)
+ quit = true;
+
+ return packet_result;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *)
+{
+ // TODO: Log the packet we aren't handling...
+ return SendPacketNoLock ("", 0);
+}
+
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err)
+{
+ char packet[16];
+ int packet_len = ::snprintf (packet, sizeof(packet), "E%2.2x", err);
+ assert (packet_len < (int)sizeof(packet));
+ return SendPacketNoLock (packet, packet_len);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendIllFormedResponse (const StringExtractorGDBRemote &failed_packet, const char *message)
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PACKETS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServer::%s: ILLFORMED: '%s' (%s)", __FUNCTION__, failed_packet.GetStringRef ().c_str (), message ? message : "");
+ return SendErrorResponse (0x03);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServer::SendOKResponse ()
+{
+ return SendPacketNoLock ("OK", 2);
+}
+
+bool
+GDBRemoteCommunicationServer::HandshakeWithClient()
+{
+ return GetAck() == PacketResult::Success;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
new file mode 100644
index 0000000..44c0f6a
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
@@ -0,0 +1,85 @@
+//===-- GDBRemoteCommunicationServer.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_GDBRemoteCommunicationServer_h_
+#define liblldb_GDBRemoteCommunicationServer_h_
+
+// C Includes
+// C++ Includes
+#include <functional>
+#include <map>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-forward.h"
+#include "GDBRemoteCommunication.h"
+
+class StringExtractorGDBRemote;
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class ProcessGDBRemote;
+
+class GDBRemoteCommunicationServer : public GDBRemoteCommunication
+{
+public:
+ using PortMap = std::map<uint16_t, lldb::pid_t>;
+ using PacketHandler = std::function<PacketResult(StringExtractorGDBRemote &packet,
+ Error &error,
+ bool &interrupt,
+ bool &quit)>;
+
+ GDBRemoteCommunicationServer(const char *comm_name,
+ const char *listener_name);
+
+ virtual
+ ~GDBRemoteCommunicationServer();
+
+ void RegisterPacketHandler(StringExtractorGDBRemote::ServerPacketType packet_type,
+ PacketHandler handler);
+
+ PacketResult
+ GetPacketAndSendResponse (uint32_t timeout_usec,
+ Error &error,
+ bool &interrupt,
+ bool &quit);
+
+ // After connecting, do a little handshake with the client to make sure
+ // we are at least communicating
+ bool
+ HandshakeWithClient ();
+
+protected:
+ std::map<StringExtractorGDBRemote::ServerPacketType, PacketHandler> m_packet_handlers;
+ bool m_exit_now; // use in asynchronous handling to indicate process should exit.
+
+ PacketResult
+ SendUnimplementedResponse (const char *packet);
+
+ PacketResult
+ SendErrorResponse (uint8_t error);
+
+ PacketResult
+ SendIllFormedResponse (const StringExtractorGDBRemote &packet, const char *error_message);
+
+ PacketResult
+ SendOKResponse ();
+
+private:
+ //------------------------------------------------------------------
+ // For GDBRemoteCommunicationServer only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServer);
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // liblldb_GDBRemoteCommunicationServer_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
new file mode 100644
index 0000000..698854e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -0,0 +1,1341 @@
+//===-- GDBRemoteCommunicationServerCommon.cpp ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteCommunicationServerCommon.h"
+
+#include <errno.h>
+
+// C Includes
+// C++ Includes
+#include <cstring>
+#include <chrono>
+
+// Other libraries and framework includes
+#include "llvm/ADT/Triple.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/StreamGDBRemote.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/StringConvert.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/FileAction.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+
+// Project includes
+#include "ProcessGDBRemoteLog.h"
+#include "Utility/StringExtractorGDBRemote.h"
+
+#ifdef __ANDROID__
+#include "lldb/Host/android/HostInfoAndroid.h"
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+#ifdef __ANDROID__
+ const static uint32_t g_default_packet_timeout_sec = 20; // seconds
+#else
+ const static uint32_t g_default_packet_timeout_sec = 0; // not specified
+#endif
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunicationServerCommon constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServerCommon::GDBRemoteCommunicationServerCommon(const char *comm_name, const char *listener_name) :
+ GDBRemoteCommunicationServer (comm_name, listener_name),
+ m_spawned_pids (),
+ m_spawned_pids_mutex (Mutex::eMutexTypeRecursive),
+ m_process_launch_info (),
+ m_process_launch_error (),
+ m_proc_infos (),
+ m_proc_infos_index (0),
+ m_thread_suffix_supported (false),
+ m_list_threads_in_stop_reply (false)
+{
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_A,
+ &GDBRemoteCommunicationServerCommon::Handle_A);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QEnvironment,
+ &GDBRemoteCommunicationServerCommon::Handle_QEnvironment);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QEnvironmentHexEncoded,
+ &GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qfProcessInfo,
+ &GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGroupName,
+ &GDBRemoteCommunicationServerCommon::Handle_qGroupName);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qHostInfo,
+ &GDBRemoteCommunicationServerCommon::Handle_qHostInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess,
+ &GDBRemoteCommunicationServerCommon::Handle_qKillSpawnedProcess);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QLaunchArch,
+ &GDBRemoteCommunicationServerCommon::Handle_QLaunchArch);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess,
+ &GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply,
+ &GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qEcho,
+ &GDBRemoteCommunicationServerCommon::Handle_qEcho);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qModuleInfo,
+ &GDBRemoteCommunicationServerCommon::Handle_qModuleInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod,
+ &GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir,
+ &GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_shell,
+ &GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID,
+ &GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetDetachOnError,
+ &GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDERR,
+ &GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDIN,
+ &GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT,
+ &GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qSpeedTest,
+ &GDBRemoteCommunicationServerCommon::Handle_qSpeedTest);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qsProcessInfo,
+ &GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode,
+ &GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qSupported,
+ &GDBRemoteCommunicationServerCommon::Handle_qSupported);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported,
+ &GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qUserName,
+ &GDBRemoteCommunicationServerCommon::Handle_qUserName);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_close,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Close);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_exists,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Exists);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_md5,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_MD5);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_mode,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Mode);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_open,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Open);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_pread,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_pRead);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_pwrite,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_size,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Size);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_stat,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_Stat);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_symlink,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_symlink);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_unlink,
+ &GDBRemoteCommunicationServerCommon::Handle_vFile_unlink);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServerCommon::~GDBRemoteCommunicationServerCommon()
+{
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qHostInfo (StringExtractorGDBRemote &packet)
+{
+ StreamString response;
+
+ // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00
+
+ ArchSpec host_arch(HostInfo::GetArchitecture());
+ const llvm::Triple &host_triple = host_arch.GetTriple();
+ response.PutCString("triple:");
+ response.PutCStringAsRawHex8(host_triple.getTriple().c_str());
+ response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize());
+
+ const char* distribution_id = host_arch.GetDistributionId ().AsCString ();
+ if (distribution_id)
+ {
+ response.PutCString("distribution_id:");
+ response.PutCStringAsRawHex8(distribution_id);
+ response.PutCString(";");
+ }
+
+ // Only send out MachO info when lldb-platform/llgs is running on a MachO host.
+#if defined(__APPLE__)
+ uint32_t cpu = host_arch.GetMachOCPUType();
+ uint32_t sub = host_arch.GetMachOCPUSubType();
+ if (cpu != LLDB_INVALID_CPUTYPE)
+ response.Printf ("cputype:%u;", cpu);
+ if (sub != LLDB_INVALID_CPUTYPE)
+ response.Printf ("cpusubtype:%u;", sub);
+
+ if (cpu == ArchSpec::kCore_arm_any)
+ response.Printf("watchpoint_exceptions_received:before;"); // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes.
+ else
+ response.Printf("watchpoint_exceptions_received:after;");
+#else
+ if (host_arch.GetMachine() == llvm::Triple::mips64 ||
+ host_arch.GetMachine() == llvm::Triple::mips64el)
+ response.Printf("watchpoint_exceptions_received:before;");
+ else
+ response.Printf("watchpoint_exceptions_received:after;");
+#endif
+
+ switch (lldb::endian::InlHostByteOrder())
+ {
+ case eByteOrderBig: response.PutCString ("endian:big;"); break;
+ case eByteOrderLittle: response.PutCString ("endian:little;"); break;
+ case eByteOrderPDP: response.PutCString ("endian:pdp;"); break;
+ default: response.PutCString ("endian:unknown;"); break;
+ }
+
+ uint32_t major = UINT32_MAX;
+ uint32_t minor = UINT32_MAX;
+ uint32_t update = UINT32_MAX;
+ if (HostInfo::GetOSVersion(major, minor, update))
+ {
+ if (major != UINT32_MAX)
+ {
+ response.Printf("os_version:%u", major);
+ if (minor != UINT32_MAX)
+ {
+ response.Printf(".%u", minor);
+ if (update != UINT32_MAX)
+ response.Printf(".%u", update);
+ }
+ response.PutChar(';');
+ }
+ }
+
+ std::string s;
+ if (HostInfo::GetOSBuildString(s))
+ {
+ response.PutCString ("os_build:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+ if (HostInfo::GetOSKernelDescription(s))
+ {
+ response.PutCString ("os_kernel:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+
+#if defined(__APPLE__)
+
+#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
+ // For iOS devices, we are connected through a USB Mux so we never pretend
+ // to actually have a hostname as far as the remote lldb that is connecting
+ // to this lldb-platform is concerned
+ response.PutCString ("hostname:");
+ response.PutCStringAsRawHex8("127.0.0.1");
+ response.PutChar(';');
+#else // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
+ if (HostInfo::GetHostname(s))
+ {
+ response.PutCString ("hostname:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+#endif // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
+
+#else // #if defined(__APPLE__)
+ if (HostInfo::GetHostname(s))
+ {
+ response.PutCString ("hostname:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+#endif // #if defined(__APPLE__)
+
+ if (g_default_packet_timeout_sec > 0)
+ response.Printf ("default_packet_timeout:%u;", g_default_packet_timeout_sec);
+
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet)
+{
+ // Packet format: "qProcessInfoPID:%i" where %i is the pid
+ packet.SetFilePos (::strlen ("qProcessInfoPID:"));
+ lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID);
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ ProcessInstanceInfo proc_info;
+ if (Host::GetProcessInfo (pid, proc_info))
+ {
+ StreamString response;
+ CreateProcessInfoResponse (proc_info, response);
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (1);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo (StringExtractorGDBRemote &packet)
+{
+ m_proc_infos_index = 0;
+ m_proc_infos.Clear();
+
+ ProcessInstanceInfoMatch match_info;
+ packet.SetFilePos(::strlen ("qfProcessInfo"));
+ if (packet.GetChar() == ':')
+ {
+
+ std::string key;
+ std::string value;
+ while (packet.GetNameColonValue(key, value))
+ {
+ bool success = true;
+ if (key.compare("name") == 0)
+ {
+ StringExtractor extractor;
+ extractor.GetStringRef().swap(value);
+ extractor.GetHexByteString (value);
+ match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false);
+ }
+ else if (key.compare("name_match") == 0)
+ {
+ if (value.compare("equals") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchEquals);
+ }
+ else if (value.compare("starts_with") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchStartsWith);
+ }
+ else if (value.compare("ends_with") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchEndsWith);
+ }
+ else if (value.compare("contains") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchContains);
+ }
+ else if (value.compare("regex") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchRegularExpression);
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ else if (key.compare("pid") == 0)
+ {
+ match_info.GetProcessInfo().SetProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
+ }
+ else if (key.compare("parent_pid") == 0)
+ {
+ match_info.GetProcessInfo().SetParentProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
+ }
+ else if (key.compare("uid") == 0)
+ {
+ match_info.GetProcessInfo().SetUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("gid") == 0)
+ {
+ match_info.GetProcessInfo().SetGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("euid") == 0)
+ {
+ match_info.GetProcessInfo().SetEffectiveUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("egid") == 0)
+ {
+ match_info.GetProcessInfo().SetEffectiveGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("all_users") == 0)
+ {
+ match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success));
+ }
+ else if (key.compare("triple") == 0)
+ {
+ match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL);
+ }
+ else
+ {
+ success = false;
+ }
+
+ if (!success)
+ return SendErrorResponse (2);
+ }
+ }
+
+ if (Host::FindProcesses (match_info, m_proc_infos))
+ {
+ // We found something, return the first item by calling the get
+ // subsequent process info packet handler...
+ return Handle_qsProcessInfo (packet);
+ }
+ return SendErrorResponse (3);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo (StringExtractorGDBRemote &packet)
+{
+ if (m_proc_infos_index < m_proc_infos.GetSize())
+ {
+ StreamString response;
+ CreateProcessInfoResponse (m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response);
+ ++m_proc_infos_index;
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse (4);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qUserName (StringExtractorGDBRemote &packet)
+{
+#if !defined(LLDB_DISABLE_POSIX)
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("GDBRemoteCommunicationServerCommon::%s begin", __FUNCTION__);
+
+ // Packet format: "qUserName:%i" where %i is the uid
+ packet.SetFilePos(::strlen ("qUserName:"));
+ uint32_t uid = packet.GetU32 (UINT32_MAX);
+ if (uid != UINT32_MAX)
+ {
+ std::string name;
+ if (HostInfo::LookupUserName(uid, name))
+ {
+ StreamString response;
+ response.PutCStringAsRawHex8 (name.c_str());
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ if (log)
+ log->Printf("GDBRemoteCommunicationServerCommon::%s end", __FUNCTION__);
+#endif
+ return SendErrorResponse (5);
+
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qGroupName (StringExtractorGDBRemote &packet)
+{
+#if !defined(LLDB_DISABLE_POSIX)
+ // Packet format: "qGroupName:%i" where %i is the gid
+ packet.SetFilePos(::strlen ("qGroupName:"));
+ uint32_t gid = packet.GetU32 (UINT32_MAX);
+ if (gid != UINT32_MAX)
+ {
+ std::string name;
+ if (HostInfo::LookupGroupName(gid, name))
+ {
+ StreamString response;
+ response.PutCStringAsRawHex8 (name.c_str());
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+#endif
+ return SendErrorResponse (6);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qSpeedTest (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("qSpeedTest:"));
+
+ std::string key;
+ std::string value;
+ bool success = packet.GetNameColonValue(key, value);
+ if (success && key.compare("response_size") == 0)
+ {
+ uint32_t response_size = StringConvert::ToUInt32(value.c_str(), 0, 0, &success);
+ if (success)
+ {
+ if (response_size == 0)
+ return SendOKResponse();
+ StreamString response;
+ uint32_t bytes_left = response_size;
+ response.PutCString("data:");
+ while (bytes_left > 0)
+ {
+ if (bytes_left >= 26)
+ {
+ response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ bytes_left -= 26;
+ }
+ else
+ {
+ response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ bytes_left = 0;
+ }
+ }
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (7);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("qKillSpawnedProcess:"));
+
+ lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID);
+
+ // verify that we know anything about this pid.
+ // Scope for locker
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ {
+ // not a pid we know about
+ return SendErrorResponse (10);
+ }
+ }
+
+ // go ahead and attempt to kill the spawned process
+ if (KillSpawnedProcess (pid))
+ return SendOKResponse ();
+ else
+ return SendErrorResponse (11);
+}
+
+bool
+GDBRemoteCommunicationServerCommon::KillSpawnedProcess (lldb::pid_t pid)
+{
+ // make sure we know about this process
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return false;
+ }
+
+ // first try a SIGTERM (standard kill)
+ Host::Kill (pid, SIGTERM);
+
+ // check if that worked
+ for (size_t i=0; i<10; ++i)
+ {
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ {
+ // it is now killed
+ return true;
+ }
+ }
+ usleep (10000);
+ }
+
+ // check one more time after the final usleep
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return true;
+ }
+
+ // the launched process still lives. Now try killing it again,
+ // this time with an unblockable signal.
+ Host::Kill (pid, SIGKILL);
+
+ for (size_t i=0; i<10; ++i)
+ {
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ {
+ // it is now killed
+ return true;
+ }
+ }
+ usleep (10000);
+ }
+
+ // check one more time after the final usleep
+ // Scope for locker
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.find(pid) == m_spawned_pids.end())
+ return true;
+ }
+
+ // no luck - the process still lives
+ return false;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Open (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:open:"));
+ std::string path;
+ packet.GetHexByteStringTerminatedBy(path,',');
+ if (!path.empty())
+ {
+ if (packet.GetChar() == ',')
+ {
+ uint32_t flags = File::ConvertOpenOptionsForPOSIXOpen(
+ packet.GetHexMaxU32(false, 0));
+ if (packet.GetChar() == ',')
+ {
+ mode_t mode = packet.GetHexMaxU32(false, 0600);
+ Error error;
+ const FileSpec path_spec{path, true};
+ int fd = ::open(path_spec.GetCString(), flags, mode);
+ const int save_errno = fd == -1 ? errno : 0;
+ StreamString response;
+ response.PutChar('F');
+ response.Printf("%i", fd);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ }
+ }
+ return SendErrorResponse(18);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Close (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:close:"));
+ int fd = packet.GetS32(-1);
+ Error error;
+ int err = -1;
+ int save_errno = 0;
+ if (fd >= 0)
+ {
+ err = close(fd);
+ save_errno = err == -1 ? errno : 0;
+ }
+ else
+ {
+ save_errno = EINVAL;
+ }
+ StreamString response;
+ response.PutChar('F');
+ response.Printf("%i", err);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_pRead (StringExtractorGDBRemote &packet)
+{
+#ifdef _WIN32
+ // Not implemented on Windows
+ return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_pRead() unimplemented");
+#else
+ StreamGDBRemote response;
+ packet.SetFilePos(::strlen("vFile:pread:"));
+ int fd = packet.GetS32(-1);
+ if (packet.GetChar() == ',')
+ {
+ uint64_t count = packet.GetU64(UINT64_MAX);
+ if (packet.GetChar() == ',')
+ {
+ uint64_t offset = packet.GetU64(UINT32_MAX);
+ if (count == UINT64_MAX)
+ {
+ response.Printf("F-1:%i", EINVAL);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+
+ std::string buffer(count, 0);
+ const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset);
+ const int save_errno = bytes_read == -1 ? errno : 0;
+ response.PutChar('F');
+ response.Printf("%zi", bytes_read);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ else
+ {
+ response.PutChar(';');
+ response.PutEscapedBytes(&buffer[0], bytes_read);
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse(21);
+
+#endif
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite (StringExtractorGDBRemote &packet)
+{
+#ifdef _WIN32
+ return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite() unimplemented");
+#else
+ packet.SetFilePos(::strlen("vFile:pwrite:"));
+
+ StreamGDBRemote response;
+ response.PutChar('F');
+
+ int fd = packet.GetU32(UINT32_MAX);
+ if (packet.GetChar() == ',')
+ {
+ off_t offset = packet.GetU64(UINT32_MAX);
+ if (packet.GetChar() == ',')
+ {
+ std::string buffer;
+ if (packet.GetEscapedBinaryData(buffer))
+ {
+ const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset);
+ const int save_errno = bytes_written == -1 ? errno : 0;
+ response.Printf("%zi", bytes_written);
+ if (save_errno)
+ response.Printf(",%i", save_errno);
+ }
+ else
+ {
+ response.Printf ("-1,%i", EINVAL);
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse(27);
+#endif
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Size (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:size:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty())
+ {
+ lldb::user_id_t retcode = FileSystem::GetFileSize(FileSpec(path.c_str(), false));
+ StreamString response;
+ response.PutChar('F');
+ response.PutHex64(retcode);
+ if (retcode == UINT64_MAX)
+ {
+ response.PutChar(',');
+ response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode()
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(22);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Mode (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:mode:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty())
+ {
+ Error error;
+ const uint32_t mode = File::GetPermissions(FileSpec{path, true}, error);
+ StreamString response;
+ response.Printf("F%u", mode);
+ if (mode == 0 || error.Fail())
+ response.Printf(",%i", (int)error.GetError());
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(23);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Exists (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:exists:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty())
+ {
+ bool retcode = FileSystem::GetFileExists(FileSpec(path.c_str(), false));
+ StreamString response;
+ response.PutChar('F');
+ response.PutChar(',');
+ if (retcode)
+ response.PutChar('1');
+ else
+ response.PutChar('0');
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(24);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_symlink (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:symlink:"));
+ std::string dst, src;
+ packet.GetHexByteStringTerminatedBy(dst, ',');
+ packet.GetChar(); // Skip ',' char
+ packet.GetHexByteString(src);
+ Error error = FileSystem::Symlink(FileSpec{src, true}, FileSpec{dst, false});
+ StreamString response;
+ response.Printf("F%u,%u", error.GetError(), error.GetError());
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_unlink (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:unlink:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ Error error = FileSystem::Unlink(FileSpec{path, true});
+ StreamString response;
+ response.Printf("F%u,%u", error.GetError(), error.GetError());
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("qPlatform_shell:"));
+ std::string path;
+ std::string working_dir;
+ packet.GetHexByteStringTerminatedBy(path,',');
+ if (!path.empty())
+ {
+ if (packet.GetChar() == ',')
+ {
+ // FIXME: add timeout to qPlatform_shell packet
+ // uint32_t timeout = packet.GetHexMaxU32(false, 32);
+ uint32_t timeout = 10;
+ if (packet.GetChar() == ',')
+ packet.GetHexByteString(working_dir);
+ int status, signo;
+ std::string output;
+ Error err = Host::RunShellCommand(path.c_str(),
+ FileSpec{working_dir, true},
+ &status, &signo, &output, timeout);
+ StreamGDBRemote response;
+ if (err.Fail())
+ {
+ response.PutCString("F,");
+ response.PutHex32(UINT32_MAX);
+ }
+ else
+ {
+ response.PutCString("F,");
+ response.PutHex32(status);
+ response.PutChar(',');
+ response.PutHex32(signo);
+ response.PutChar(',');
+ response.PutEscapedBytes(output.c_str(), output.size());
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse(24);
+}
+
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_Stat (StringExtractorGDBRemote &packet)
+{
+ return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_Stat() unimplemented");
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_vFile_MD5 (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("vFile:MD5:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ if (!path.empty())
+ {
+ uint64_t a,b;
+ StreamGDBRemote response;
+ if (!FileSystem::CalculateMD5(FileSpec(path.c_str(), false), a, b))
+ {
+ response.PutCString("F,");
+ response.PutCString("x");
+ }
+ else
+ {
+ response.PutCString("F,");
+ response.PutHex64(a);
+ response.PutHex64(b);
+ }
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(25);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("qPlatform_mkdir:"));
+ mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
+ if (packet.GetChar() == ',')
+ {
+ std::string path;
+ packet.GetHexByteString(path);
+ Error error = FileSystem::MakeDirectory(FileSpec{path, false}, mode);
+
+ StreamGDBRemote response;
+ response.Printf("F%u", error.GetError());
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(20);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("qPlatform_chmod:"));
+
+ mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX);
+ if (packet.GetChar() == ',')
+ {
+ std::string path;
+ packet.GetHexByteString(path);
+ Error error = FileSystem::SetFilePermissions(FileSpec{path, true}, mode);
+
+ StreamGDBRemote response;
+ response.Printf("F%u", error.GetError());
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse(19);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qSupported (StringExtractorGDBRemote &packet)
+{
+ StreamGDBRemote response;
+
+ // Features common to lldb-platform and llgs.
+ uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet size--debugger can always use less
+ response.Printf ("PacketSize=%x", max_packet_size);
+
+ response.PutCString (";QStartNoAckMode+");
+ response.PutCString (";QThreadSuffixSupported+");
+ response.PutCString (";QListThreadsInStopReply+");
+ response.PutCString (";qEcho+");
+#if defined(__linux__)
+ response.PutCString (";qXfer:auxv:read+");
+#endif
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet)
+{
+ m_thread_suffix_supported = true;
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet)
+{
+ m_list_threads_in_stop_reply = true;
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetDetachOnError:"));
+ if (packet.GetU32(0))
+ m_process_launch_info.GetFlags().Set (eLaunchFlagDetachOnError);
+ else
+ m_process_launch_info.GetFlags().Clear (eLaunchFlagDetachOnError);
+ return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet)
+{
+ // Send response first before changing m_send_acks to we ack this packet
+ PacketResult packet_result = SendOKResponse ();
+ m_send_acks = false;
+ return packet_result;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDIN:"));
+ FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDIN_FILENO, FileSpec{path, false}, read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (15);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDOUT:"));
+ FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDOUT_FILENO, FileSpec{path, false}, read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (16);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDERR:"));
+ FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDERR_FILENO, FileSpec{path, false}, read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (17);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet)
+{
+ if (m_process_launch_error.Success())
+ return SendOKResponse();
+ StreamString response;
+ response.PutChar('E');
+ response.PutCString(m_process_launch_error.AsCString("<unknown error>"));
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QEnvironment (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QEnvironment:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0)
+ {
+ m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek());
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (12);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen("QEnvironmentHexEncoded:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0)
+ {
+ std::string str;
+ packet.GetHexByteString(str);
+ m_process_launch_info.GetEnvironmentEntries().AppendArgument(str.c_str());
+ return SendOKResponse();
+ }
+ return SendErrorResponse(12);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_QLaunchArch (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QLaunchArch:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0)
+ {
+ const char* arch_triple = packet.Peek();
+ ArchSpec arch_spec(arch_triple,NULL);
+ m_process_launch_info.SetArchitecture(arch_spec);
+ return SendOKResponse();
+ }
+ return SendErrorResponse(13);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_A (StringExtractorGDBRemote &packet)
+{
+ // The 'A' packet is the most over designed packet ever here with
+ // redundant argument indexes, redundant argument lengths and needed hex
+ // encoded argument string values. Really all that is needed is a comma
+ // separated hex encoded argument value list, but we will stay true to the
+ // documented version of the 'A' packet here...
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ int actual_arg_index = 0;
+
+ packet.SetFilePos(1); // Skip the 'A'
+ bool success = true;
+ while (success && packet.GetBytesLeft() > 0)
+ {
+ // Decode the decimal argument string length. This length is the
+ // number of hex nibbles in the argument string value.
+ const uint32_t arg_len = packet.GetU32(UINT32_MAX);
+ if (arg_len == UINT32_MAX)
+ success = false;
+ else
+ {
+ // Make sure the argument hex string length is followed by a comma
+ if (packet.GetChar() != ',')
+ success = false;
+ else
+ {
+ // Decode the argument index. We ignore this really because
+ // who would really send down the arguments in a random order???
+ const uint32_t arg_idx = packet.GetU32(UINT32_MAX);
+ if (arg_idx == UINT32_MAX)
+ success = false;
+ else
+ {
+ // Make sure the argument index is followed by a comma
+ if (packet.GetChar() != ',')
+ success = false;
+ else
+ {
+ // Decode the argument string value from hex bytes
+ // back into a UTF8 string and make sure the length
+ // matches the one supplied in the packet
+ std::string arg;
+ if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2))
+ success = false;
+ else
+ {
+ // If there are any bytes left
+ if (packet.GetBytesLeft())
+ {
+ if (packet.GetChar() != ',')
+ success = false;
+ }
+
+ if (success)
+ {
+ if (arg_idx == 0)
+ m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false);
+ m_process_launch_info.GetArguments().AppendArgument(arg.c_str());
+ if (log)
+ log->Printf ("LLGSPacketHandler::%s added arg %d: \"%s\"", __FUNCTION__, actual_arg_index, arg.c_str ());
+ ++actual_arg_index;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (success)
+ {
+ m_process_launch_error = LaunchProcess ();
+ if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ {
+ return SendOKResponse ();
+ }
+ else
+ {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("LLGSPacketHandler::%s failed to launch exe: %s",
+ __FUNCTION__,
+ m_process_launch_error.AsCString());
+
+ }
+ }
+ return SendErrorResponse (8);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qEcho (StringExtractorGDBRemote &packet)
+{
+ // Just echo back the exact same packet for qEcho...
+ return SendPacketNoLock(packet.GetStringRef().c_str(), packet.GetStringRef().size());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerCommon::Handle_qModuleInfo (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("qModuleInfo:"));
+
+ std::string module_path;
+ packet.GetHexByteStringTerminatedBy(module_path, ';');
+ if (module_path.empty())
+ return SendErrorResponse (1);
+
+ if (packet.GetChar() != ';')
+ return SendErrorResponse (2);
+
+ std::string triple;
+ packet.GetHexByteString(triple);
+ ArchSpec arch(triple.c_str());
+
+ const FileSpec req_module_path_spec(module_path.c_str(), true);
+ const FileSpec module_path_spec = FindModuleFile(req_module_path_spec.GetPath(), arch);
+ const ModuleSpec module_spec(module_path_spec, arch);
+
+ ModuleSpecList module_specs;
+ if (!ObjectFile::GetModuleSpecifications(module_path_spec, 0, 0, module_specs))
+ return SendErrorResponse (3);
+
+ ModuleSpec matched_module_spec;
+ if (!module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
+ return SendErrorResponse (4);
+
+ const auto file_offset = matched_module_spec.GetObjectOffset();
+ const auto file_size = matched_module_spec.GetObjectSize();
+ const auto uuid_str = matched_module_spec.GetUUID().GetAsString("");
+
+ StreamGDBRemote response;
+
+ if (uuid_str.empty())
+ {
+ std::string md5_hash;
+ if (!FileSystem::CalculateMD5AsString(matched_module_spec.GetFileSpec(), file_offset, file_size, md5_hash))
+ return SendErrorResponse (5);
+ response.PutCString ("md5:");
+ response.PutCStringAsRawHex8(md5_hash.c_str());
+ }
+ else{
+ response.PutCString ("uuid:");
+ response.PutCStringAsRawHex8(uuid_str.c_str());
+ }
+ response.PutChar(';');
+
+ const auto &module_arch = matched_module_spec.GetArchitecture();
+ response.PutCString("triple:");
+ response.PutCStringAsRawHex8( module_arch.GetTriple().getTriple().c_str());
+ response.PutChar(';');
+
+ response.PutCString("file_path:");
+ response.PutCStringAsRawHex8(module_path_spec.GetCString());
+ response.PutChar(';');
+ response.PutCString("file_offset:");
+ response.PutHex64(file_offset);
+ response.PutChar(';');
+ response.PutCString("file_size:");
+ response.PutHex64(file_size);
+ response.PutChar(';');
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+void
+GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info,
+ StreamString &response)
+{
+ response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;",
+ proc_info.GetProcessID(),
+ proc_info.GetParentProcessID(),
+ proc_info.GetUserID(),
+ proc_info.GetGroupID(),
+ proc_info.GetEffectiveUserID(),
+ proc_info.GetEffectiveGroupID());
+ response.PutCString ("name:");
+ response.PutCStringAsRawHex8(proc_info.GetExecutableFile().GetCString());
+ response.PutChar(';');
+ const ArchSpec &proc_arch = proc_info.GetArchitecture();
+ if (proc_arch.IsValid())
+ {
+ const llvm::Triple &proc_triple = proc_arch.GetTriple();
+ response.PutCString("triple:");
+ response.PutCStringAsRawHex8(proc_triple.getTriple().c_str());
+ response.PutChar(';');
+ }
+}
+
+void
+GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse_DebugServerStyle (
+ const ProcessInstanceInfo &proc_info, StreamString &response)
+{
+ response.Printf ("pid:%" PRIx64 ";parent-pid:%" PRIx64 ";real-uid:%x;real-gid:%x;effective-uid:%x;effective-gid:%x;",
+ proc_info.GetProcessID(),
+ proc_info.GetParentProcessID(),
+ proc_info.GetUserID(),
+ proc_info.GetGroupID(),
+ proc_info.GetEffectiveUserID(),
+ proc_info.GetEffectiveGroupID());
+
+ const ArchSpec &proc_arch = proc_info.GetArchitecture();
+ if (proc_arch.IsValid())
+ {
+ const llvm::Triple &proc_triple = proc_arch.GetTriple();
+#if defined(__APPLE__)
+ // We'll send cputype/cpusubtype.
+ const uint32_t cpu_type = proc_arch.GetMachOCPUType();
+ if (cpu_type != 0)
+ response.Printf ("cputype:%" PRIx32 ";", cpu_type);
+
+ const uint32_t cpu_subtype = proc_arch.GetMachOCPUSubType();
+ if (cpu_subtype != 0)
+ response.Printf ("cpusubtype:%" PRIx32 ";", cpu_subtype);
+
+ const std::string vendor = proc_triple.getVendorName ();
+ if (!vendor.empty ())
+ response.Printf ("vendor:%s;", vendor.c_str ());
+#else
+ // We'll send the triple.
+ response.PutCString("triple:");
+ response.PutCStringAsRawHex8(proc_triple.getTriple().c_str());
+ response.PutChar(';');
+#endif
+ std::string ostype = proc_triple.getOSName ();
+ // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64.
+ if (proc_triple.getVendor () == llvm::Triple::Apple)
+ {
+ switch (proc_triple.getArch ())
+ {
+ case llvm::Triple::arm:
+ case llvm::Triple::aarch64:
+ ostype = "ios";
+ break;
+ default:
+ // No change.
+ break;
+ }
+ }
+ response.Printf ("ostype:%s;", ostype.c_str ());
+
+
+ switch (proc_arch.GetByteOrder ())
+ {
+ case lldb::eByteOrderLittle: response.PutCString ("endian:little;"); break;
+ case lldb::eByteOrderBig: response.PutCString ("endian:big;"); break;
+ case lldb::eByteOrderPDP: response.PutCString ("endian:pdp;"); break;
+ default:
+ // Nothing.
+ break;
+ }
+
+ if (proc_triple.isArch64Bit ())
+ response.PutCString ("ptrsize:8;");
+ else if (proc_triple.isArch32Bit ())
+ response.PutCString ("ptrsize:4;");
+ else if (proc_triple.isArch16Bit ())
+ response.PutCString ("ptrsize:2;");
+ }
+}
+
+FileSpec
+GDBRemoteCommunicationServerCommon::FindModuleFile(const std::string& module_path,
+ const ArchSpec& arch)
+{
+#ifdef __ANDROID__
+ return HostInfoAndroid::ResolveLibraryPath(module_path, arch);
+#else
+ return FileSpec(module_path.c_str(), true);
+#endif
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
new file mode 100644
index 0000000..62b129b
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h
@@ -0,0 +1,216 @@
+//===-- GDBRemoteCommunicationServerCommon.h --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_GDBRemoteCommunicationServerCommon_h_
+#define liblldb_GDBRemoteCommunicationServerCommon_h_
+
+// C Includes
+// C++ Includes
+#include <set>
+
+// Other libraries and framework includes
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Process.h"
+
+// Project includes
+#include "GDBRemoteCommunicationServer.h"
+#include "GDBRemoteCommunicationServerCommon.h"
+
+class StringExtractorGDBRemote;
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class ProcessGDBRemote;
+
+class GDBRemoteCommunicationServerCommon :
+ public GDBRemoteCommunicationServer
+{
+public:
+ GDBRemoteCommunicationServerCommon(const char *comm_name, const char *listener_name);
+
+ virtual
+ ~GDBRemoteCommunicationServerCommon();
+
+protected:
+ std::set<lldb::pid_t> m_spawned_pids;
+ Mutex m_spawned_pids_mutex;
+ ProcessLaunchInfo m_process_launch_info;
+ Error m_process_launch_error;
+ ProcessInstanceInfoList m_proc_infos;
+ uint32_t m_proc_infos_index;
+ bool m_thread_suffix_supported;
+ bool m_list_threads_in_stop_reply;
+
+ PacketResult
+ Handle_A (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qHostInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qProcessInfoPID (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qfProcessInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qsProcessInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qUserName (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qGroupName (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qSpeedTest (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_Open (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_Close (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_pRead (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_pWrite (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_Size (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_Mode (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_Exists (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_symlink (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_unlink (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_Stat (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vFile_MD5 (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qEcho (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qModuleInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qPlatform_shell (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qPlatform_chmod (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qSupported (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSetDetachOnError (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QStartNoAckMode (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSetSTDIN (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSetSTDOUT (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSetSTDERR (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qLaunchSuccess (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QEnvironment (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QEnvironmentHexEncoded (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QLaunchArch (StringExtractorGDBRemote &packet);
+
+ bool
+ KillSpawnedProcess (lldb::pid_t pid);
+
+ static void
+ CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info,
+ StreamString &response);
+
+ static void
+ CreateProcessInfoResponse_DebugServerStyle (const ProcessInstanceInfo &proc_info,
+ StreamString &response);
+
+ template <typename T>
+ void
+ RegisterMemberFunctionHandler (StringExtractorGDBRemote::ServerPacketType packet_type,
+ PacketResult (T::*handler) (StringExtractorGDBRemote& packet))
+ {
+ RegisterPacketHandler(packet_type,
+ [this, handler] (StringExtractorGDBRemote packet,
+ Error &error,
+ bool &interrupt,
+ bool &quit)
+ {
+ return (static_cast<T*>(this)->*handler) (packet);
+ });
+ }
+
+ bool
+ GetThreadSuffixSupported () override
+ {
+ return true;
+ }
+
+ //------------------------------------------------------------------
+ /// Launch a process with the current launch settings.
+ ///
+ /// This method supports running an lldb-gdbserver or similar
+ /// server in a situation where the startup code has been provided
+ /// with all the information for a child process to be launched.
+ ///
+ /// @return
+ /// An Error object indicating the success or failure of the
+ /// launch.
+ //------------------------------------------------------------------
+ virtual Error
+ LaunchProcess () = 0;
+
+ virtual FileSpec
+ FindModuleFile (const std::string& module_path, const ArchSpec& arch);
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // liblldb_GDBRemoteCommunicationServerCommon_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
new file mode 100644
index 0000000..c452325
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -0,0 +1,2841 @@
+//===-- GDBRemoteCommunicationServerLLGS.cpp --------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <errno.h>
+
+#include "lldb/Host/Config.h"
+
+#include "GDBRemoteCommunicationServerLLGS.h"
+#include "lldb/Core/StreamGDBRemote.h"
+
+// C Includes
+// C++ Includes
+#include <cstring>
+#include <chrono>
+#include <thread>
+
+// Other libraries and framework includes
+#include "llvm/ADT/Triple.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/Debug.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Target/FileAction.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Host/common/NativeRegisterContext.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Host/common/NativeThreadProtocol.h"
+
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+#include "Utility/UriParser.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+using namespace llvm;
+
+//----------------------------------------------------------------------
+// GDBRemote Errors
+//----------------------------------------------------------------------
+
+namespace
+{
+ enum GDBRemoteServerError
+ {
+ // Set to the first unused error number in literal form below
+ eErrorFirst = 29,
+ eErrorNoProcess = eErrorFirst,
+ eErrorResume,
+ eErrorExitStatus
+ };
+}
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunicationServerLLGS constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS(
+ const lldb::PlatformSP& platform_sp,
+ MainLoop &mainloop) :
+ GDBRemoteCommunicationServerCommon ("gdb-remote.server", "gdb-remote.server.rx_packet"),
+ m_platform_sp (platform_sp),
+ m_mainloop (mainloop),
+ m_current_tid (LLDB_INVALID_THREAD_ID),
+ m_continue_tid (LLDB_INVALID_THREAD_ID),
+ m_debugged_process_mutex (Mutex::eMutexTypeRecursive),
+ m_debugged_process_sp (),
+ m_stdio_communication ("process.stdio"),
+ m_inferior_prev_state (StateType::eStateInvalid),
+ m_active_auxv_buffer_sp (),
+ m_saved_registers_mutex (),
+ m_saved_registers_map (),
+ m_next_saved_registers_id (1),
+ m_handshake_completed (false)
+{
+ assert(platform_sp);
+ RegisterPacketHandlers();
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServerLLGS::~GDBRemoteCommunicationServerLLGS()
+{
+ Mutex::Locker locker (m_debugged_process_mutex);
+
+ if (m_debugged_process_sp)
+ {
+ m_debugged_process_sp->Terminate ();
+ m_debugged_process_sp.reset ();
+ }
+}
+
+void
+GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers()
+{
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_C,
+ &GDBRemoteCommunicationServerLLGS::Handle_C);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_c,
+ &GDBRemoteCommunicationServerLLGS::Handle_c);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_D,
+ &GDBRemoteCommunicationServerLLGS::Handle_D);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_H,
+ &GDBRemoteCommunicationServerLLGS::Handle_H);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_I,
+ &GDBRemoteCommunicationServerLLGS::Handle_I);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_interrupt,
+ &GDBRemoteCommunicationServerLLGS::Handle_interrupt);
+ 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,
+ &GDBRemoteCommunicationServerLLGS::Handle_P);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC,
+ &GDBRemoteCommunicationServerLLGS::Handle_qC);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qfThreadInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qFileLoadAddress,
+ &GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir,
+ &GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfoSupported,
+ &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qRegisterInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState,
+ &GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSaveRegisterState,
+ &GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR,
+ &GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
+ &GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qsThreadInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo,
+ &GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read,
+ &GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_s,
+ &GDBRemoteCommunicationServerLLGS::Handle_s);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_stop_reason,
+ &GDBRemoteCommunicationServerLLGS::Handle_stop_reason); // ?
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vAttach,
+ &GDBRemoteCommunicationServerLLGS::Handle_vAttach);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vCont,
+ &GDBRemoteCommunicationServerLLGS::Handle_vCont);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vCont_actions,
+ &GDBRemoteCommunicationServerLLGS::Handle_vCont_actions);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_Z,
+ &GDBRemoteCommunicationServerLLGS::Handle_Z);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z,
+ &GDBRemoteCommunicationServerLLGS::Handle_z);
+
+ RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k,
+ [this](StringExtractorGDBRemote packet,
+ Error &error,
+ bool &interrupt,
+ bool &quit)
+ {
+ quit = true;
+ return this->Handle_k (packet);
+ });
+}
+
+Error
+GDBRemoteCommunicationServerLLGS::SetLaunchArguments (const char *const args[], int argc)
+{
+ if ((argc < 1) || !args || !args[0] || !args[0][0])
+ return Error ("%s: no process command line specified to launch", __FUNCTION__);
+
+ m_process_launch_info.SetArguments (const_cast<const char**> (args), true);
+ return Error ();
+}
+
+Error
+GDBRemoteCommunicationServerLLGS::SetLaunchFlags (unsigned int launch_flags)
+{
+ m_process_launch_info.GetFlags ().Set (launch_flags);
+ return Error ();
+}
+
+Error
+GDBRemoteCommunicationServerLLGS::LaunchProcess ()
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (!m_process_launch_info.GetArguments ().GetArgumentCount ())
+ return Error ("%s: no process command line specified to launch", __FUNCTION__);
+
+ Error error;
+ {
+ Mutex::Locker locker (m_debugged_process_mutex);
+ assert (!m_debugged_process_sp && "lldb-gdbserver creating debugged process but one already exists");
+ error = NativeProcessProtocol::Launch(
+ m_process_launch_info,
+ *this,
+ m_debugged_process_sp);
+ }
+
+ if (!error.Success ())
+ {
+ fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0));
+ return error;
+ }
+
+ // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol
+ // as needed.
+ // llgs local-process debugging may specify PTY paths, which will make these
+ // file actions non-null
+ // process launch -i/e/o will also make these file actions non-null
+ // nullptr means that the traffic is expected to flow over gdb-remote protocol
+ if (
+ m_process_launch_info.GetFileActionForFD(STDIN_FILENO) == nullptr ||
+ m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) == nullptr ||
+ m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr
+ )
+ {
+ // nullptr means it's not redirected to file or pty (in case of LLGS local)
+ // at least one of stdio will be transferred pty<->gdb-remote
+ // we need to give the pty master handle to this object to read and/or write
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " setting up stdout/stderr redirection via $O gdb-remote commands", __FUNCTION__, m_debugged_process_sp->GetID ());
+
+ // Setup stdout/stderr mapping from inferior to $O
+ auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor ();
+ if (terminal_fd >= 0)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd);
+ error = SetSTDIOFileDescriptor (terminal_fd);
+ if (error.Fail ())
+ return error;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " skipping stdout/stderr redirection via $O: inferior will communicate over client-provided file descriptors", __FUNCTION__, m_debugged_process_sp->GetID ());
+ }
+
+ printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID ());
+
+ // Add to list of spawned processes.
+ lldb::pid_t pid;
+ if ((pid = m_process_launch_info.GetProcessID ()) != LLDB_INVALID_PROCESS_ID)
+ {
+ // add to spawned pids
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ // On an lldb-gdbserver, we would expect there to be only one.
+ assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed");
+ m_spawned_pids.insert (pid);
+ }
+
+ return error;
+}
+
+Error
+GDBRemoteCommunicationServerLLGS::AttachToProcess (lldb::pid_t pid)
+{
+ Error error;
+
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64, __FUNCTION__, pid);
+
+ // Scope for mutex locker.
+ {
+ // Before we try to attach, make sure we aren't already monitoring something else.
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (!m_spawned_pids.empty ())
+ {
+ error.SetErrorStringWithFormat ("cannot attach to a process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", pid, *m_spawned_pids.begin());
+ return error;
+ }
+
+ // Try to attach.
+ error = NativeProcessProtocol::Attach(pid, *this, m_debugged_process_sp);
+ if (!error.Success ())
+ {
+ fprintf (stderr, "%s: failed to attach to process %" PRIu64 ": %s", __FUNCTION__, pid, error.AsCString ());
+ return error;
+ }
+
+ // Setup stdout/stderr mapping from inferior.
+ auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor ();
+ if (terminal_fd >= 0)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd);
+ error = SetSTDIOFileDescriptor (terminal_fd);
+ if (error.Fail ())
+ return error;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd);
+ }
+
+ printf ("Attached to process %" PRIu64 "...\n", pid);
+
+ // Add to list of spawned processes.
+ assert (m_spawned_pids.empty () && "lldb-gdbserver adding tracked process but one already existed");
+ m_spawned_pids.insert (pid);
+
+ return error;
+ }
+}
+
+void
+GDBRemoteCommunicationServerLLGS::InitializeDelegate (NativeProcessProtocol *process)
+{
+ assert (process && "process cannot be NULL");
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s called with NativeProcessProtocol pid %" PRIu64 ", current state: %s",
+ __FUNCTION__,
+ process->GetID (),
+ StateAsCString (process->GetState ()));
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::SendWResponse (NativeProcessProtocol *process)
+{
+ assert (process && "process cannot be NULL");
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // send W notification
+ ExitType exit_type = ExitType::eExitTypeInvalid;
+ int return_code = 0;
+ std::string exit_description;
+
+ const bool got_exit_info = process->GetExitStatus (&exit_type, &return_code, exit_description);
+ if (!got_exit_info)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 ", failed to retrieve process exit status", __FUNCTION__, process->GetID ());
+
+ StreamGDBRemote response;
+ response.PutChar ('E');
+ response.PutHex8 (GDBRemoteServerError::eErrorExitStatus);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 ", returning exit type %d, return code %d [%s]", __FUNCTION__, process->GetID (), exit_type, return_code, exit_description.c_str ());
+
+ StreamGDBRemote response;
+
+ char return_type_code;
+ switch (exit_type)
+ {
+ case ExitType::eExitTypeExit:
+ return_type_code = 'W';
+ break;
+ case ExitType::eExitTypeSignal:
+ return_type_code = 'X';
+ break;
+ case ExitType::eExitTypeStop:
+ return_type_code = 'S';
+ break;
+ case ExitType::eExitTypeInvalid:
+ return_type_code = 'E';
+ break;
+ }
+ response.PutChar (return_type_code);
+
+ // POSIX exit status limited to unsigned 8 bits.
+ response.PutHex8 (return_code);
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+}
+
+static void
+AppendHexValue (StreamString &response, const uint8_t* buf, uint32_t buf_size, bool swap)
+{
+ int64_t i;
+ if (swap)
+ {
+ for (i = buf_size-1; i >= 0; i--)
+ response.PutHex8 (buf[i]);
+ }
+ else
+ {
+ for (i = 0; i < buf_size; i++)
+ response.PutHex8 (buf[i]);
+ }
+}
+
+static void
+WriteRegisterValueInHexFixedWidth (StreamString &response,
+ NativeRegisterContextSP &reg_ctx_sp,
+ const RegisterInfo &reg_info,
+ const RegisterValue *reg_value_p)
+{
+ RegisterValue reg_value;
+ if (!reg_value_p)
+ {
+ Error error = reg_ctx_sp->ReadRegister (&reg_info, reg_value);
+ if (error.Success ())
+ reg_value_p = &reg_value;
+ // else log.
+ }
+
+ if (reg_value_p)
+ {
+ AppendHexValue (response, (const uint8_t*) reg_value_p->GetBytes (), reg_value_p->GetByteSize (), false);
+ }
+ else
+ {
+ // Zero-out any unreadable values.
+ if (reg_info.byte_size > 0)
+ {
+ std::basic_string<uint8_t> zeros(reg_info.byte_size, '\0');
+ AppendHexValue (response, zeros.data(), zeros.size(), false);
+ }
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread (lldb::tid_t tid)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
+
+ // Ensure we have a debugged process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse (50);
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s preparing packet for pid %" PRIu64 " tid %" PRIu64,
+ __FUNCTION__, m_debugged_process_sp->GetID (), tid);
+
+ // Ensure we can get info on the given thread.
+ NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid));
+ if (!thread_sp)
+ return SendErrorResponse (51);
+
+ // Grab the reason this thread stopped.
+ struct ThreadStopInfo tid_stop_info;
+ std::string description;
+ if (!thread_sp->GetStopReason (tid_stop_info, description))
+ return SendErrorResponse (52);
+
+ // FIXME implement register handling for exec'd inferiors.
+ // if (tid_stop_info.reason == eStopReasonExec)
+ // {
+ // const bool force = true;
+ // InitializeRegisters(force);
+ // }
+
+ StreamString response;
+ // Output the T packet with the thread
+ response.PutChar ('T');
+ int signum = tid_stop_info.details.signal.signo;
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64,
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ tid,
+ signum,
+ tid_stop_info.reason,
+ tid_stop_info.details.exception.type);
+ }
+
+ // Print the signal number.
+ response.PutHex8 (signum & 0xff);
+
+ // Include the tid.
+ response.Printf ("thread:%" PRIx64 ";", tid);
+
+ // Include the thread name if there is one.
+ const std::string thread_name = thread_sp->GetName ();
+ if (!thread_name.empty ())
+ {
+ size_t thread_name_len = thread_name.length ();
+
+ if (::strcspn (thread_name.c_str (), "$#+-;:") == thread_name_len)
+ {
+ response.PutCString ("name:");
+ response.PutCString (thread_name.c_str ());
+ }
+ else
+ {
+ // The thread name contains special chars, send as hex bytes.
+ response.PutCString ("hexname:");
+ response.PutCStringAsRawHex8 (thread_name.c_str ());
+ }
+ response.PutChar (';');
+ }
+
+ // If a 'QListThreadsInStopReply' was sent to enable this feature, we
+ // will send all thread IDs back in the "threads" key whose value is
+ // a list of hex thread IDs separated by commas:
+ // "threads:10a,10b,10c;"
+ // This will save the debugger from having to send a pair of qfThreadInfo
+ // and qsThreadInfo packets, but it also might take a lot of room in the
+ // stop reply packet, so it must be enabled only on systems where there
+ // are no limits on packet lengths.
+ if (m_list_threads_in_stop_reply)
+ {
+ response.PutCString ("threads:");
+
+ uint32_t thread_index = 0;
+ NativeThreadProtocolSP listed_thread_sp;
+ for (listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); listed_thread_sp; ++thread_index, listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index))
+ {
+ if (thread_index > 0)
+ response.PutChar (',');
+ response.Printf ("%" PRIx64, listed_thread_sp->GetID ());
+ }
+ response.PutChar (';');
+ }
+
+ //
+ // Expedite registers.
+ //
+
+ // Grab the register context.
+ NativeRegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext ();
+ if (reg_ctx_sp)
+ {
+ // 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_sp->GetRegisterSetCount () > 0 && ((reg_set_p = reg_ctx_sp->GetRegisterSet (0)) != nullptr))
+ {
+ if (log)
+ log->Printf ("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);
+
+ 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_sp->GetRegisterInfoAtIndex (*reg_num_p);
+ if (reg_info_p == nullptr)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to get register info for register set '%s', register index %" PRIu32, __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;
+ Error error = reg_ctx_sp->ReadRegister (reg_info_p, reg_value);
+ if (error.Success ())
+ {
+ response.Printf ("%.02x:", *reg_num_p);
+ WriteRegisterValueInHexFixedWidth(response, reg_ctx_sp, *reg_info_p, &reg_value);
+ response.PutChar (';');
+ }
+ else
+ {
+ if (log)
+ log->Printf ("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 ());
+
+ }
+ }
+ }
+ }
+ }
+
+ const char* reason_str = nullptr;
+ switch (tid_stop_info.reason)
+ {
+ case eStopReasonTrace:
+ reason_str = "trace";
+ break;
+ case eStopReasonBreakpoint:
+ reason_str = "breakpoint";
+ break;
+ case eStopReasonWatchpoint:
+ reason_str = "watchpoint";
+ break;
+ case eStopReasonSignal:
+ reason_str = "signal";
+ break;
+ case eStopReasonException:
+ reason_str = "exception";
+ break;
+ case eStopReasonExec:
+ reason_str = "exec";
+ break;
+ case eStopReasonInstrumentation:
+ case eStopReasonInvalid:
+ case eStopReasonPlanComplete:
+ case eStopReasonThreadExiting:
+ case eStopReasonNone:
+ break;
+ }
+ if (reason_str != nullptr)
+ {
+ response.Printf ("reason:%s;", reason_str);
+ }
+
+ if (!description.empty())
+ {
+ // Description may contains special chars, send as hex bytes.
+ response.PutCString ("description:");
+ response.PutCStringAsRawHex8 (description.c_str ());
+ response.PutChar (';');
+ }
+ else if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type)
+ {
+ response.PutCString ("metype:");
+ response.PutHex64 (tid_stop_info.details.exception.type);
+ response.PutCString (";mecount:");
+ response.PutHex32 (tid_stop_info.details.exception.data_count);
+ response.PutChar (';');
+
+ for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i)
+ {
+ response.PutCString ("medata:");
+ response.PutHex64 (tid_stop_info.details.exception.data[i]);
+ response.PutChar (';');
+ }
+ }
+
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+void
+GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited (NativeProcessProtocol *process)
+{
+ assert (process && "process cannot be NULL");
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
+
+ // Send the exit result, and don't flush output.
+ // Note: flushing output here would join the inferior stdio reflection thread, which
+ // would gunk up the waitpid monitor thread that is calling this.
+ PacketResult result = SendStopReasonForState (StateType::eStateExited, false);
+ if (result != PacketResult::Success)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ());
+ }
+
+ // Remove the process from the list of spawned pids.
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ if (m_spawned_pids.erase (process->GetID ()) < 1)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to remove PID %" PRIu64 " from the spawned pids list", __FUNCTION__, process->GetID ());
+
+ }
+ }
+
+ // FIXME can't do this yet - since process state propagation is currently
+ // synchronous, it is running off the NativeProcessProtocol's innards and
+ // will tear down the NPP while it still has code to execute.
+#if 0
+ // Clear the NativeProcessProtocol pointer.
+ {
+ Mutex::Locker locker (m_debugged_process_mutex);
+ m_debugged_process_sp.reset();
+ }
+#endif
+
+ // Close the pipe to the inferior terminal i/o if we launched it
+ // and set one up. Otherwise, 'k' and its flush of stdio could
+ // end up waiting on a thread join that will never end. Consider
+ // adding a timeout to the connection thread join call so we
+ // can avoid that scenario altogether.
+ MaybeCloseInferiorTerminalConnection ();
+
+ // We are ready to exit the debug monitor.
+ m_exit_now = true;
+}
+
+void
+GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped (NativeProcessProtocol *process)
+{
+ assert (process && "process cannot be NULL");
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
+
+ // Send the stop reason unless this is the stop after the
+ // launch or attach.
+ switch (m_inferior_prev_state)
+ {
+ case eStateLaunching:
+ case eStateAttaching:
+ // Don't send anything per debugserver behavior.
+ break;
+ default:
+ // In all other cases, send the stop reason.
+ PacketResult result = SendStopReasonForState (StateType::eStateStopped, false);
+ if (result != PacketResult::Success)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ());
+ }
+ break;
+ }
+}
+
+void
+GDBRemoteCommunicationServerLLGS::ProcessStateChanged (NativeProcessProtocol *process, lldb::StateType state)
+{
+ assert (process && "process cannot be NULL");
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s called with NativeProcessProtocol pid %" PRIu64 ", state: %s",
+ __FUNCTION__,
+ process->GetID (),
+ StateAsCString (state));
+ }
+
+ // Make sure we get all of the pending stdout/stderr from the inferior
+ // and send it to the lldb host before we send the state change
+ // notification
+ m_stdio_communication.SynchronizeWithReadThread();
+
+ switch (state)
+ {
+ case StateType::eStateExited:
+ HandleInferiorState_Exited (process);
+ break;
+
+ case StateType::eStateStopped:
+ HandleInferiorState_Stopped (process);
+ break;
+
+ default:
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s didn't handle state change for pid %" PRIu64 ", new state: %s",
+ __FUNCTION__,
+ process->GetID (),
+ StateAsCString (state));
+ }
+ break;
+ }
+
+ // Remember the previous state reported to us.
+ m_inferior_prev_state = state;
+}
+
+void
+GDBRemoteCommunicationServerLLGS::DidExec (NativeProcessProtocol *process)
+{
+ ClearProcessSpecificData ();
+}
+
+void
+GDBRemoteCommunicationServerLLGS::DataAvailableCallback ()
+{
+ Log *log (GetLogIfAnyCategoriesSet(GDBR_LOG_COMM));
+
+ if (! m_handshake_completed)
+ {
+ if (! HandshakeWithClient())
+ {
+ if(log)
+ log->Printf("GDBRemoteCommunicationServerLLGS::%s handshake with client failed, exiting",
+ __FUNCTION__);
+ m_read_handle_up.reset();
+ m_mainloop.RequestTermination();
+ return;
+ }
+ m_handshake_completed = true;
+ }
+
+ bool interrupt = false;
+ bool done = false;
+ Error error;
+ while (true)
+ {
+ const PacketResult result = GetPacketAndSendResponse (0, error, interrupt, done);
+ if (result == PacketResult::ErrorReplyTimeout)
+ break; // No more packets in the queue
+
+ if ((result != PacketResult::Success))
+ {
+ if(log)
+ log->Printf("GDBRemoteCommunicationServerLLGS::%s processing a packet failed: %s",
+ __FUNCTION__, error.AsCString());
+ m_read_handle_up.reset();
+ m_mainloop.RequestTermination();
+ break;
+ }
+ }
+}
+
+Error
+GDBRemoteCommunicationServerLLGS::InitializeConnection (std::unique_ptr<Connection> &&connection)
+{
+ IOObjectSP read_object_sp = connection->GetReadObject();
+ GDBRemoteCommunicationServer::SetConnection(connection.release());
+
+ Error error;
+ m_read_handle_up = m_mainloop.RegisterReadObject(read_object_sp,
+ [this] (MainLoopBase &) { DataAvailableCallback(); }, error);
+ return error;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::SendONotification (const char *buffer, uint32_t len)
+{
+ if ((buffer == nullptr) || (len == 0))
+ {
+ // Nothing to send.
+ return PacketResult::Success;
+ }
+
+ StreamString response;
+ response.PutChar ('O');
+ response.PutBytesAsRawHex8 (buffer, len);
+
+ return SendPacketNoLock (response.GetData (), response.GetSize ());
+}
+
+Error
+GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor (int fd)
+{
+ Error error;
+
+ // Set up the Read Thread for reading/handling process I/O
+ std::unique_ptr<ConnectionFileDescriptor> conn_up (new ConnectionFileDescriptor (fd, true));
+ if (!conn_up)
+ {
+ error.SetErrorString ("failed to create ConnectionFileDescriptor");
+ return error;
+ }
+
+ m_stdio_communication.SetCloseOnEOF (false);
+ m_stdio_communication.SetConnection (conn_up.release());
+ if (!m_stdio_communication.IsConnected ())
+ {
+ error.SetErrorString ("failed to set connection for inferior I/O communication");
+ return error;
+ }
+
+ // llgs local-process debugging may specify PTY paths, which will make these
+ // file actions non-null
+ // process launch -e/o will also make these file actions non-null
+ // nullptr means that the traffic is expected to flow over gdb-remote protocol
+ if (
+ m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) == nullptr ||
+ m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr
+ )
+ {
+ // output from the process must be forwarded over gdb-remote
+ // create a thread to read the handle and send the data
+ m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this);
+ m_stdio_communication.StartReadThread();
+ }
+
+ return error;
+}
+
+void
+GDBRemoteCommunicationServerLLGS::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len)
+{
+ GDBRemoteCommunicationServerLLGS *server = reinterpret_cast<GDBRemoteCommunicationServerLLGS*> (baton);
+ static_cast<void> (server->SendONotification (static_cast<const char *>(src), src_len));
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo (StringExtractorGDBRemote &packet)
+{
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse (68);
+
+ lldb::pid_t pid = m_debugged_process_sp->GetID ();
+
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return SendErrorResponse (1);
+
+ ProcessInstanceInfo proc_info;
+ if (!Host::GetProcessInfo (pid, proc_info))
+ return SendErrorResponse (1);
+
+ StreamString response;
+ CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
+ return SendPacketNoLock (response.GetData (), response.GetSize ());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qC (StringExtractorGDBRemote &packet)
+{
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse (68);
+
+ // Make sure we set the current thread so g and p packets return
+ // the data the gdb will expect.
+ lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID ();
+ SetCurrentThreadID (tid);
+
+ NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetCurrentThread ();
+ if (!thread_sp)
+ return SendErrorResponse (69);
+
+ StreamString response;
+ response.Printf ("QC%" PRIx64, thread_sp->GetID ());
+
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+bool
+GDBRemoteCommunicationServerLLGS::DebuggedProcessReaped (lldb::pid_t pid)
+{
+ // reap a process that we were debugging (but not debugserver)
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ return m_spawned_pids.erase(pid) > 0;
+}
+
+bool
+GDBRemoteCommunicationServerLLGS::ReapDebuggedProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal, // Zero for no signal
+ int status) // Exit value of process if signal is zero
+{
+ GDBRemoteCommunicationServerLLGS *server = (GDBRemoteCommunicationServerLLGS *)callback_baton;
+ server->DebuggedProcessReaped (pid);
+ return true;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_k (StringExtractorGDBRemote &packet)
+{
+ // shutdown all spawned processes
+ std::set<lldb::pid_t> spawned_pids_copy;
+
+ // copy pids
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ spawned_pids_copy.insert (m_spawned_pids.begin (), m_spawned_pids.end ());
+ }
+
+ // nuke the spawned processes
+ for (auto it = spawned_pids_copy.begin (); it != spawned_pids_copy.end (); ++it)
+ {
+ lldb::pid_t spawned_pid = *it;
+ if (!KillSpawnedProcess (spawned_pid))
+ {
+ fprintf (stderr, "%s: failed to kill spawned pid %" PRIu64 ", ignoring.\n", __FUNCTION__, spawned_pid);
+ }
+ }
+
+ FlushInferiorOutput ();
+
+ // No OK response for kill packet.
+ // return SendOKResponse ();
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetDisableASLR:"));
+ if (packet.GetU32(0))
+ m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
+ else
+ m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR);
+ return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos (::strlen ("QSetWorkingDir:"));
+ std::string path;
+ packet.GetHexByteString (path);
+ m_process_launch_info.SetWorkingDirectory(FileSpec{path, true});
+ return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)
+{
+ FileSpec working_dir{m_process_launch_info.GetWorkingDirectory()};
+ if (working_dir)
+ {
+ StreamString response;
+ response.PutCStringAsRawHex8(working_dir.GetCString());
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+ }
+
+ return SendErrorResponse(14);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_C (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
+
+ // Ensure we have a native process.
+ if (!m_debugged_process_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s no debugged process shared pointer", __FUNCTION__);
+ return SendErrorResponse (0x36);
+ }
+
+ // Pull out the signal number.
+ packet.SetFilePos (::strlen ("C"));
+ if (packet.GetBytesLeft () < 1)
+ {
+ // Shouldn't be using a C without a signal.
+ return SendIllFormedResponse (packet, "C packet specified without signal.");
+ }
+ const uint32_t signo = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (signo == std::numeric_limits<uint32_t>::max ())
+ return SendIllFormedResponse (packet, "failed to parse signal number");
+
+ // Handle optional continue address.
+ if (packet.GetBytesLeft () > 0)
+ {
+ // FIXME add continue at address support for $C{signo}[;{continue-address}].
+ if (*packet.Peek () == ';')
+ return SendUnimplementedResponse (packet.GetStringRef().c_str());
+ else
+ return SendIllFormedResponse (packet, "unexpected content after $C{signal-number}");
+ }
+
+ ResumeActionList resume_actions (StateType::eStateRunning, 0);
+ Error error;
+
+ // We have two branches: what to do if a continue thread is specified (in which case we target
+ // sending the signal to that thread), or when we don't have a continue thread set (in which
+ // case we send a signal to the process).
+
+ // TODO discuss with Greg Clayton, make sure this makes sense.
+
+ lldb::tid_t signal_tid = GetContinueThreadID ();
+ if (signal_tid != LLDB_INVALID_THREAD_ID)
+ {
+ // The resume action for the continue thread (or all threads if a continue thread is not set).
+ ResumeAction action = { GetContinueThreadID (), StateType::eStateRunning, static_cast<int> (signo) };
+
+ // Add the action for the continue thread (or all threads when the continue thread isn't present).
+ resume_actions.Append (action);
+ }
+ else
+ {
+ // Send the signal to the process since we weren't targeting a specific continue thread with the signal.
+ error = m_debugged_process_sp->Signal (signo);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to send signal for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+
+ return SendErrorResponse (0x52);
+ }
+ }
+
+ // Resume the threads.
+ error = m_debugged_process_sp->Resume (resume_actions);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to resume threads for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+
+ return SendErrorResponse (0x38);
+ }
+
+ // Don't send an "OK" packet; response is the stopped/exited message.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_c (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__);
+
+ packet.SetFilePos (packet.GetFilePos() + ::strlen ("c"));
+
+ // For now just support all continue.
+ const bool has_continue_address = (packet.GetBytesLeft () > 0);
+ if (has_continue_address)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s not implemented for c{address} variant [%s remains]", __FUNCTION__, packet.Peek ());
+ return SendUnimplementedResponse (packet.GetStringRef().c_str());
+ }
+
+ // Ensure we have a native process.
+ if (!m_debugged_process_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s no debugged process shared pointer", __FUNCTION__);
+ return SendErrorResponse (0x36);
+ }
+
+ // Build the ResumeActionList
+ ResumeActionList actions (StateType::eStateRunning, 0);
+
+ Error error = m_debugged_process_sp->Resume (actions);
+ if (error.Fail ())
+ {
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s c failed for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ }
+ return SendErrorResponse (GDBRemoteServerError::eErrorResume);
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ());
+
+ // No response required from continue.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vCont_actions (StringExtractorGDBRemote &packet)
+{
+ StreamString response;
+ response.Printf("vCont;c;C;s;S");
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vCont (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s handling vCont packet", __FUNCTION__);
+
+ packet.SetFilePos (::strlen ("vCont"));
+
+ if (packet.GetBytesLeft() == 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s missing action from vCont package", __FUNCTION__);
+ return SendIllFormedResponse (packet, "Missing action from vCont package");
+ }
+
+ // Check if this is all continue (no options or ";c").
+ if (::strcmp (packet.Peek (), ";c") == 0)
+ {
+ // Move past the ';', then do a simple 'c'.
+ packet.SetFilePos (packet.GetFilePos () + 1);
+ return Handle_c (packet);
+ }
+ else if (::strcmp (packet.Peek (), ";s") == 0)
+ {
+ // Move past the ';', then do a simple 's'.
+ packet.SetFilePos (packet.GetFilePos () + 1);
+ return Handle_s (packet);
+ }
+
+ // Ensure we have a native process.
+ if (!m_debugged_process_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s no debugged process shared pointer", __FUNCTION__);
+ return SendErrorResponse (0x36);
+ }
+
+ ResumeActionList thread_actions;
+
+ while (packet.GetBytesLeft () && *packet.Peek () == ';')
+ {
+ // Skip the semi-colon.
+ packet.GetChar ();
+
+ // Build up the thread action.
+ ResumeAction thread_action;
+ thread_action.tid = LLDB_INVALID_THREAD_ID;
+ thread_action.state = eStateInvalid;
+ thread_action.signal = 0;
+
+ const char action = packet.GetChar ();
+ switch (action)
+ {
+ case 'C':
+ thread_action.signal = packet.GetHexMaxU32 (false, 0);
+ if (thread_action.signal == 0)
+ return SendIllFormedResponse (packet, "Could not parse signal in vCont packet C action");
+ // Fall through to next case...
+
+ case 'c':
+ // Continue
+ thread_action.state = eStateRunning;
+ break;
+
+ case 'S':
+ thread_action.signal = packet.GetHexMaxU32 (false, 0);
+ if (thread_action.signal == 0)
+ return SendIllFormedResponse (packet, "Could not parse signal in vCont packet S action");
+ // Fall through to next case...
+
+ case 's':
+ // Step
+ thread_action.state = eStateStepping;
+ break;
+
+ default:
+ return SendIllFormedResponse (packet, "Unsupported vCont action");
+ break;
+ }
+
+ // Parse out optional :{thread-id} value.
+ if (packet.GetBytesLeft () && (*packet.Peek () == ':'))
+ {
+ // Consume the separator.
+ packet.GetChar ();
+
+ thread_action.tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID);
+ if (thread_action.tid == LLDB_INVALID_THREAD_ID)
+ return SendIllFormedResponse (packet, "Could not parse thread number in vCont packet");
+ }
+
+ thread_actions.Append (thread_action);
+ }
+
+ Error error = m_debugged_process_sp->Resume (thread_actions);
+ if (error.Fail ())
+ {
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s vCont failed for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ }
+ return SendErrorResponse (GDBRemoteServerError::eErrorResume);
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ());
+
+ // No response required from vCont.
+ return PacketResult::Success;
+}
+
+void
+GDBRemoteCommunicationServerLLGS::SetCurrentThreadID (lldb::tid_t tid)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s setting current thread id to %" PRIu64, __FUNCTION__, tid);
+
+ m_current_tid = tid;
+ if (m_debugged_process_sp)
+ m_debugged_process_sp->SetCurrentThreadID (m_current_tid);
+}
+
+void
+GDBRemoteCommunicationServerLLGS::SetContinueThreadID (lldb::tid_t tid)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s setting continue thread id to %" PRIu64, __FUNCTION__, tid);
+
+ m_continue_tid = tid;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_stop_reason (StringExtractorGDBRemote &packet)
+{
+ // Handle the $? gdbremote command.
+
+ // If no process, indicate error
+ if (!m_debugged_process_sp)
+ return SendErrorResponse (02);
+
+ return SendStopReasonForState (m_debugged_process_sp->GetState (), true);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ switch (process_state)
+ {
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ // NOTE: gdb protocol doc looks like it should return $OK
+ // when everything is running (i.e. no stopped result).
+ return PacketResult::Success; // Ignore
+
+ case eStateSuspended:
+ case eStateStopped:
+ case eStateCrashed:
+ {
+ lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID ();
+ // Make sure we set the current thread so g and p packets return
+ // the data the gdb will expect.
+ SetCurrentThreadID (tid);
+ return SendStopReplyPacketForThread (tid);
+ }
+
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateExited:
+ if (flush_on_exit)
+ FlushInferiorOutput ();
+ return SendWResponse(m_debugged_process_sp.get());
+
+ default:
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 ", current state reporting not handled: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ StateAsCString (process_state));
+ }
+ break;
+ }
+
+ return SendErrorResponse (0);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo (StringExtractorGDBRemote &packet)
+{
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse (68);
+
+ // Ensure we have a thread.
+ NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadAtIndex (0));
+ if (!thread_sp)
+ return SendErrorResponse (69);
+
+ // Get the register context for the first thread.
+ NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+ if (!reg_context_sp)
+ return SendErrorResponse (69);
+
+ // Parse out the register number from the request.
+ packet.SetFilePos (strlen("qRegisterInfo"));
+ const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (reg_index == std::numeric_limits<uint32_t>::max ())
+ return SendErrorResponse (69);
+
+ // Return the end of registers response if we've iterated one past the end of the register set.
+ if (reg_index >= reg_context_sp->GetUserRegisterCount ())
+ return SendErrorResponse (69);
+
+ const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ return SendErrorResponse (69);
+
+ // Build the reginfos response.
+ StreamGDBRemote response;
+
+ response.PutCString ("name:");
+ response.PutCString (reg_info->name);
+ response.PutChar (';');
+
+ if (reg_info->alt_name && reg_info->alt_name[0])
+ {
+ response.PutCString ("alt-name:");
+ response.PutCString (reg_info->alt_name);
+ response.PutChar (';');
+ }
+
+ response.Printf ("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", reg_info->byte_size * 8, reg_info->byte_offset);
+
+ switch (reg_info->encoding)
+ {
+ case eEncodingUint: response.PutCString ("encoding:uint;"); break;
+ case eEncodingSint: response.PutCString ("encoding:sint;"); break;
+ case eEncodingIEEE754: response.PutCString ("encoding:ieee754;"); break;
+ case eEncodingVector: response.PutCString ("encoding:vector;"); break;
+ default: break;
+ }
+
+ switch (reg_info->format)
+ {
+ case eFormatBinary: response.PutCString ("format:binary;"); break;
+ case eFormatDecimal: response.PutCString ("format:decimal;"); break;
+ case eFormatHex: response.PutCString ("format:hex;"); break;
+ case eFormatFloat: response.PutCString ("format:float;"); break;
+ case eFormatVectorOfSInt8: response.PutCString ("format:vector-sint8;"); break;
+ case eFormatVectorOfUInt8: response.PutCString ("format:vector-uint8;"); break;
+ case eFormatVectorOfSInt16: response.PutCString ("format:vector-sint16;"); break;
+ case eFormatVectorOfUInt16: response.PutCString ("format:vector-uint16;"); break;
+ case eFormatVectorOfSInt32: response.PutCString ("format:vector-sint32;"); break;
+ case eFormatVectorOfUInt32: response.PutCString ("format:vector-uint32;"); break;
+ case eFormatVectorOfFloat32: response.PutCString ("format:vector-float32;"); break;
+ case eFormatVectorOfUInt128: response.PutCString ("format:vector-uint128;"); break;
+ default: break;
+ };
+
+ const char *const register_set_name = reg_context_sp->GetRegisterSetNameForRegisterAtIndex(reg_index);
+ if (register_set_name)
+ {
+ response.PutCString ("set:");
+ response.PutCString (register_set_name);
+ response.PutChar (';');
+ }
+
+ if (reg_info->kinds[RegisterKind::eRegisterKindGCC] != LLDB_INVALID_REGNUM)
+ response.Printf ("gcc:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindGCC]);
+
+ if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != LLDB_INVALID_REGNUM)
+ response.Printf ("dwarf:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindDWARF]);
+
+ switch (reg_info->kinds[RegisterKind::eRegisterKindGeneric])
+ {
+ case LLDB_REGNUM_GENERIC_PC: response.PutCString("generic:pc;"); break;
+ case LLDB_REGNUM_GENERIC_SP: response.PutCString("generic:sp;"); break;
+ case LLDB_REGNUM_GENERIC_FP: response.PutCString("generic:fp;"); break;
+ case LLDB_REGNUM_GENERIC_RA: response.PutCString("generic:ra;"); break;
+ case LLDB_REGNUM_GENERIC_FLAGS: response.PutCString("generic:flags;"); break;
+ case LLDB_REGNUM_GENERIC_ARG1: response.PutCString("generic:arg1;"); break;
+ case LLDB_REGNUM_GENERIC_ARG2: response.PutCString("generic:arg2;"); break;
+ case LLDB_REGNUM_GENERIC_ARG3: response.PutCString("generic:arg3;"); break;
+ case LLDB_REGNUM_GENERIC_ARG4: response.PutCString("generic:arg4;"); break;
+ case LLDB_REGNUM_GENERIC_ARG5: response.PutCString("generic:arg5;"); break;
+ case LLDB_REGNUM_GENERIC_ARG6: response.PutCString("generic:arg6;"); break;
+ case LLDB_REGNUM_GENERIC_ARG7: response.PutCString("generic:arg7;"); break;
+ case LLDB_REGNUM_GENERIC_ARG8: response.PutCString("generic:arg8;"); break;
+ default: break;
+ }
+
+ if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
+ {
+ response.PutCString ("container-regs:");
+ int i = 0;
+ for (const uint32_t *reg_num = reg_info->value_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i)
+ {
+ if (i > 0)
+ response.PutChar (',');
+ response.Printf ("%" PRIx32, *reg_num);
+ }
+ response.PutChar (';');
+ }
+
+ if (reg_info->invalidate_regs && reg_info->invalidate_regs[0])
+ {
+ response.PutCString ("invalidate-regs:");
+ int i = 0;
+ for (const uint32_t *reg_num = reg_info->invalidate_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i)
+ {
+ if (i > 0)
+ response.PutChar (',');
+ response.Printf ("%" PRIx32, *reg_num);
+ }
+ response.PutChar (';');
+ }
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s() no process (%s), returning OK", __FUNCTION__, m_debugged_process_sp ? "invalid process id" : "null m_debugged_process_sp");
+ return SendOKResponse ();
+ }
+
+ StreamGDBRemote response;
+ response.PutChar ('m');
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s() starting thread iteration", __FUNCTION__);
+
+ NativeThreadProtocolSP thread_sp;
+ uint32_t thread_index;
+ for (thread_index = 0, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index);
+ thread_sp;
+ ++thread_index, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s() iterated thread %" PRIu32 "(%s, tid=0x%" PRIx64 ")", __FUNCTION__, thread_index, thread_sp ? "is not null" : "null", thread_sp ? thread_sp->GetID () : LLDB_INVALID_THREAD_ID);
+ if (thread_index > 0)
+ response.PutChar(',');
+ response.Printf ("%" PRIx64, thread_sp->GetID ());
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s() finished thread iteration", __FUNCTION__);
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo (StringExtractorGDBRemote &packet)
+{
+ // FIXME for now we return the full thread list in the initial packet and always do nothing here.
+ return SendPacketNoLock ("l", 1);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_p (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Parse out the register number from the request.
+ packet.SetFilePos (strlen("p"));
+ const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (reg_index == std::numeric_limits<uint32_t>::max ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ());
+ return SendErrorResponse (0x15);
+ }
+
+ // Get the thread to use.
+ NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+ if (!thread_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no thread available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Get the thread's register context.
+ NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+ if (!reg_context_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+ return SendErrorResponse (0x15);
+ }
+
+ // Return the end of registers response if we've iterated one past the end of the register set.
+ if (reg_index >= reg_context_sp->GetUserRegisterCount ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetUserRegisterCount ());
+ return SendErrorResponse (0x15);
+ }
+
+ const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index);
+ return SendErrorResponse (0x15);
+ }
+
+ // Build the reginfos response.
+ StreamGDBRemote response;
+
+ // Retrieve the value
+ RegisterValue reg_value;
+ Error error = reg_context_sp->ReadRegister (reg_info, reg_value);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, read of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ());
+ return SendErrorResponse (0x15);
+ }
+
+ const uint8_t *const data = reinterpret_cast<const uint8_t*> (reg_value.GetBytes ());
+ if (!data)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to get data bytes from requested register %" PRIu32, __FUNCTION__, reg_index);
+ return SendErrorResponse (0x15);
+ }
+
+ // FIXME flip as needed to get data in big/little endian format for this host.
+ for (uint32_t i = 0; i < reg_value.GetByteSize (); ++i)
+ response.PutHex8 (data[i]);
+
+ return SendPacketNoLock (response.GetData (), response.GetSize ());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_P (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Ensure there is more content.
+ if (packet.GetBytesLeft () < 1)
+ return SendIllFormedResponse (packet, "Empty P packet");
+
+ // Parse out the register number from the request.
+ packet.SetFilePos (strlen("P"));
+ const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (reg_index == std::numeric_limits<uint32_t>::max ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ());
+ return SendErrorResponse (0x29);
+ }
+
+ // Note debugserver would send an E30 here.
+ if ((packet.GetBytesLeft () < 1) || (packet.GetChar () != '='))
+ return SendIllFormedResponse (packet, "P packet missing '=' char after register number");
+
+ // Get process architecture.
+ ArchSpec process_arch;
+ if (!m_debugged_process_sp || !m_debugged_process_sp->GetArchitecture (process_arch))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to retrieve inferior architecture", __FUNCTION__);
+ return SendErrorResponse (0x49);
+ }
+
+ // Parse out the value.
+ uint8_t reg_bytes[32]; // big enough to support up to 256 bit ymmN register
+ size_t reg_size = packet.GetHexBytesAvail (reg_bytes, sizeof(reg_bytes));
+
+ // Get the thread to use.
+ NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+ if (!thread_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no thread available (thread index 0)", __FUNCTION__);
+ return SendErrorResponse (0x28);
+ }
+
+ // Get the thread's register context.
+ NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+ if (!reg_context_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+ return SendErrorResponse (0x15);
+ }
+
+ const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex (reg_index);
+ if (!reg_info)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index);
+ return SendErrorResponse (0x48);
+ }
+
+ // Return the end of registers response if we've iterated one past the end of the register set.
+ if (reg_index >= reg_context_sp->GetUserRegisterCount ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetUserRegisterCount ());
+ return SendErrorResponse (0x47);
+ }
+
+ if (reg_size != reg_info->byte_size)
+ {
+ return SendIllFormedResponse (packet, "P packet register size is incorrect");
+ }
+
+ // Build the reginfos response.
+ StreamGDBRemote response;
+
+ RegisterValue reg_value (reg_bytes, reg_size, process_arch.GetByteOrder ());
+ Error error = reg_context_sp->WriteRegister (reg_info, reg_value);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, write of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ());
+ return SendErrorResponse (0x32);
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_H (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Parse out which variant of $H is requested.
+ packet.SetFilePos (strlen("H"));
+ if (packet.GetBytesLeft () < 1)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, H command missing {g,c} variant", __FUNCTION__);
+ return SendIllFormedResponse (packet, "H command missing {g,c} variant");
+ }
+
+ const char h_variant = packet.GetChar ();
+ switch (h_variant)
+ {
+ case 'g':
+ break;
+
+ case 'c':
+ break;
+
+ default:
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, invalid $H variant %c", __FUNCTION__, h_variant);
+ return SendIllFormedResponse (packet, "H variant unsupported, should be c or g");
+ }
+
+ // Parse out the thread number.
+ // FIXME return a parse success/fail value. All values are valid here.
+ const lldb::tid_t tid = packet.GetHexMaxU64 (false, std::numeric_limits<lldb::tid_t>::max ());
+
+ // Ensure we have the given thread when not specifying -1 (all threads) or 0 (any thread).
+ if (tid != LLDB_INVALID_THREAD_ID && tid != 0)
+ {
+ NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid));
+ if (!thread_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, tid %" PRIu64 " not found", __FUNCTION__, tid);
+ return SendErrorResponse (0x15);
+ }
+ }
+
+ // Now switch the given thread type.
+ switch (h_variant)
+ {
+ case 'g':
+ SetCurrentThreadID (tid);
+ break;
+
+ case 'c':
+ SetContinueThreadID (tid);
+ break;
+
+ default:
+ assert (false && "unsupported $H variant - shouldn't get here");
+ return SendIllFormedResponse (packet, "H variant unsupported, should be c or g");
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_I (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ packet.SetFilePos (::strlen("I"));
+ char tmp[4096];
+ for (;;)
+ {
+ size_t read = packet.GetHexBytesAvail(tmp, sizeof(tmp));
+ if (read == 0)
+ {
+ break;
+ }
+ // write directly to stdin *this might block if stdin buffer is full*
+ // TODO: enqueue this block in circular buffer and send window size to remote host
+ ConnectionStatus status;
+ Error error;
+ m_stdio_communication.Write(tmp, read, status, &error);
+ if (error.Fail())
+ {
+ return SendErrorResponse (0x15);
+ }
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_interrupt (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Interrupt the process.
+ Error error = m_debugged_process_sp->Interrupt ();
+ if (error.Fail ())
+ {
+ if (log)
+ {
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed for process %" PRIu64 ": %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ }
+ return SendErrorResponse (GDBRemoteServerError::eErrorResume);
+ }
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s stopped process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ());
+
+ // No response required from stop all.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_m (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("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");
+
+ // Read the address. Punting on validation.
+ // FIXME replace with Hex U64 read with no default value that fails on failed read.
+ const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0);
+
+ // Validate comma.
+ if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ','))
+ return SendIllFormedResponse(packet, "Comma sep missing in m packet");
+
+ // Get # bytes to read.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Length missing in m packet");
+
+ const uint64_t byte_count = packet.GetHexMaxU64(false, 0);
+ if (byte_count == 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s nothing to read: zero-length packet", __FUNCTION__);
+ return PacketResult::Success;
+ }
+
+ // Allocate the response buffer.
+ std::string buf(byte_count, '\0');
+ if (buf.empty())
+ return SendErrorResponse (0x78);
+
+
+ // Retrieve the process memory.
+ size_t bytes_read = 0;
+ Error error = m_debugged_process_sp->ReadMemoryWithoutTrap(read_addr, &buf[0], byte_count, bytes_read);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to read. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, error.AsCString ());
+ return SendErrorResponse (0x08);
+ }
+
+ if (bytes_read == 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": read 0 of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, byte_count);
+ return SendErrorResponse (0x08);
+ }
+
+ StreamGDBRemote response;
+ for (size_t i = 0; i < bytes_read; ++i)
+ response.PutHex8(buf[i]);
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_M (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("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");
+
+ // Read the address. Punting on validation.
+ // FIXME replace with Hex U64 read with no default value that fails on failed read.
+ const lldb::addr_t write_addr = packet.GetHexMaxU64(false, 0);
+
+ // Validate comma.
+ if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ','))
+ return SendIllFormedResponse(packet, "Comma sep missing in M packet");
+
+ // Get # bytes to read.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Length missing in M packet");
+
+ const uint64_t byte_count = packet.GetHexMaxU64(false, 0);
+ if (byte_count == 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s nothing to write: zero-length packet", __FUNCTION__);
+ return PacketResult::Success;
+ }
+
+ // Validate colon.
+ if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ':'))
+ return SendIllFormedResponse(packet, "Comma sep missing in M packet after byte length");
+
+ // Allocate the conversion buffer.
+ std::vector<uint8_t> buf(byte_count, 0);
+ if (buf.empty())
+ return SendErrorResponse (0x78);
+
+ // Convert the hex memory write contents to bytes.
+ StreamGDBRemote response;
+ const uint64_t convert_count = packet.GetHexBytes(&buf[0], byte_count, 0);
+ if (convert_count != byte_count)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": asked to write %" PRIu64 " bytes, but only found %" PRIu64 " to convert.", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, byte_count, convert_count);
+ return SendIllFormedResponse (packet, "M content byte length specified did not match hex-encoded content length");
+ }
+
+ // Write the process memory.
+ size_t bytes_written = 0;
+ Error error = m_debugged_process_sp->WriteMemory (write_addr, &buf[0], byte_count, bytes_written);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to write. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
+
+ if (bytes_written == 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": wrote 0 of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, byte_count);
+ return SendErrorResponse (0x09);
+ }
+
+ return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Currently only the NativeProcessProtocol knows if it can handle a qMemoryRegionInfoSupported
+ // request, but we're not guaranteed to be attached to a process. For now we'll assume the
+ // client only asks this when a process is being debugged.
+
+ // Ensure we have a process running; otherwise, we can't figure this out
+ // since we won't have a NativeProcessProtocol.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Test if we can get any region back when asking for the region around NULL.
+ MemoryRegionInfo region_info;
+ const Error error = m_debugged_process_sp->GetMemoryRegionInfo (0, region_info);
+ if (error.Fail ())
+ {
+ // We don't support memory region info collection for this NativeProcessProtocol.
+ return SendUnimplementedResponse ("");
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos (strlen("qMemoryRegionInfo:"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short qMemoryRegionInfo: packet");
+
+ // Read the address. Punting on validation.
+ const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0);
+
+ StreamGDBRemote response;
+
+ // Get the memory region info for the target address.
+ MemoryRegionInfo region_info;
+ const Error error = m_debugged_process_sp->GetMemoryRegionInfo (read_addr, region_info);
+ if (error.Fail ())
+ {
+ // Return the error message.
+
+ response.PutCString ("error:");
+ response.PutCStringAsRawHex8 (error.AsCString ());
+ response.PutChar (';');
+ }
+ else
+ {
+ // Range start and size.
+ response.Printf ("start:%" PRIx64 ";size:%" PRIx64 ";", region_info.GetRange ().GetRangeBase (), region_info.GetRange ().GetByteSize ());
+
+ // Permissions.
+ if (region_info.GetReadable () ||
+ region_info.GetWritable () ||
+ region_info.GetExecutable ())
+ {
+ // Write permissions info.
+ response.PutCString ("permissions:");
+
+ if (region_info.GetReadable ())
+ response.PutChar ('r');
+ if (region_info.GetWritable ())
+ response.PutChar('w');
+ if (region_info.GetExecutable())
+ response.PutChar ('x');
+
+ response.PutChar (';');
+ }
+ }
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_Z (StringExtractorGDBRemote &packet)
+{
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Parse out software or hardware breakpoint or watchpoint requested.
+ packet.SetFilePos (strlen("Z"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short Z packet, missing software/hardware specifier");
+
+ bool want_breakpoint = true;
+ bool want_hardware = false;
+
+ const GDBStoppointType stoppoint_type =
+ GDBStoppointType(packet.GetS32 (eStoppointInvalid));
+ switch (stoppoint_type)
+ {
+ case eBreakpointSoftware:
+ want_hardware = false; want_breakpoint = true; break;
+ case eBreakpointHardware:
+ want_hardware = true; want_breakpoint = true; break;
+ case eWatchpointWrite:
+ want_hardware = true; want_breakpoint = false; break;
+ case eWatchpointRead:
+ want_hardware = true; want_breakpoint = false; break;
+ case eWatchpointReadWrite:
+ want_hardware = true; want_breakpoint = false; break;
+ case eStoppointInvalid:
+ return SendIllFormedResponse(packet, "Z packet had invalid software/hardware specifier");
+
+ }
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+ return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after stoppoint type");
+
+ // Parse out the stoppoint address.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short Z packet, missing address");
+ const lldb::addr_t addr = packet.GetHexMaxU64(false, 0);
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+ return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after address");
+
+ // Parse out the stoppoint size (i.e. size hint for opcode size).
+ const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (size == std::numeric_limits<uint32_t>::max ())
+ return SendIllFormedResponse(packet, "Malformed Z packet, failed to parse size argument");
+
+ if (want_breakpoint)
+ {
+ // Try to set the breakpoint.
+ const Error error = m_debugged_process_sp->SetBreakpoint (addr, size, want_hardware);
+ if (error.Success ())
+ return SendOKResponse ();
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
+ " failed to set breakpoint: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
+ else
+ {
+ uint32_t watch_flags =
+ stoppoint_type == eWatchpointWrite
+ ? 0x1 // Write
+ : 0x3; // ReadWrite
+
+ // Try to set the watchpoint.
+ const Error error = m_debugged_process_sp->SetWatchpoint (
+ addr, size, watch_flags, want_hardware);
+ if (error.Success ())
+ return SendOKResponse ();
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
+ " failed to set watchpoint: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_z (StringExtractorGDBRemote &packet)
+{
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ // Parse out software or hardware breakpoint or watchpoint requested.
+ packet.SetFilePos (strlen("z"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short z packet, missing software/hardware specifier");
+
+ bool want_breakpoint = true;
+
+ const GDBStoppointType stoppoint_type =
+ GDBStoppointType(packet.GetS32 (eStoppointInvalid));
+ switch (stoppoint_type)
+ {
+ case eBreakpointHardware: want_breakpoint = true; break;
+ case eBreakpointSoftware: want_breakpoint = true; break;
+ case eWatchpointWrite: want_breakpoint = false; break;
+ case eWatchpointRead: want_breakpoint = false; break;
+ case eWatchpointReadWrite: want_breakpoint = false; break;
+ default:
+ return SendIllFormedResponse(packet, "z packet had invalid software/hardware specifier");
+
+ }
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+ return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after stoppoint type");
+
+ // Parse out the stoppoint address.
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short z packet, missing address");
+ const lldb::addr_t addr = packet.GetHexMaxU64(false, 0);
+
+ if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',')
+ return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after address");
+
+ /*
+ // Parse out the stoppoint size (i.e. size hint for opcode size).
+ const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits<uint32_t>::max ());
+ if (size == std::numeric_limits<uint32_t>::max ())
+ return SendIllFormedResponse(packet, "Malformed z packet, failed to parse size argument");
+ */
+
+ if (want_breakpoint)
+ {
+ // Try to clear the breakpoint.
+ const Error error = m_debugged_process_sp->RemoveBreakpoint (addr);
+ if (error.Success ())
+ return SendOKResponse ();
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
+ " failed to remove breakpoint: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
+ else
+ {
+ // Try to clear the watchpoint.
+ const Error error = m_debugged_process_sp->RemoveWatchpoint (addr);
+ if (error.Success ())
+ return SendOKResponse ();
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
+ " failed to remove watchpoint: %s",
+ __FUNCTION__,
+ m_debugged_process_sp->GetID (),
+ error.AsCString ());
+ return SendErrorResponse (0x09);
+ }
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_s (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD));
+
+ // Ensure we have a process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x32);
+ }
+
+ // We first try to use a continue thread id. If any one or any all set, use the current thread.
+ // Bail out if we don't have a thread id.
+ lldb::tid_t tid = GetContinueThreadID ();
+ if (tid == 0 || tid == LLDB_INVALID_THREAD_ID)
+ tid = GetCurrentThreadID ();
+ if (tid == LLDB_INVALID_THREAD_ID)
+ return SendErrorResponse (0x33);
+
+ // Double check that we have such a thread.
+ // TODO investigate: on MacOSX we might need to do an UpdateThreads () here.
+ NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetThreadByID (tid);
+ if (!thread_sp || thread_sp->GetID () != tid)
+ return SendErrorResponse (0x33);
+
+ // Create the step action for the given thread.
+ ResumeAction action = { tid, eStateStepping, 0 };
+
+ // Setup the actions list.
+ ResumeActionList actions;
+ actions.Append (action);
+
+ // All other threads stop while we're single stepping a thread.
+ actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0);
+ Error error = m_debugged_process_sp->Resume (actions);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " Resume() failed with error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), tid, error.AsCString ());
+ return SendErrorResponse(0x49);
+ }
+
+ // No response here - the stop or exit will come from the resulting action.
+ return PacketResult::Success;
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet)
+{
+ // *BSD impls should be able to do this too.
+#if defined(__linux__)
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Parse out the offset.
+ packet.SetFilePos (strlen("qXfer:auxv:read::"));
+ if (packet.GetBytesLeft () < 1)
+ return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset");
+
+ const uint64_t auxv_offset = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ());
+ if (auxv_offset == std::numeric_limits<uint64_t>::max ())
+ return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset");
+
+ // Parse out comma.
+ if (packet.GetBytesLeft () < 1 || packet.GetChar () != ',')
+ return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing comma after offset");
+
+ // Parse out the length.
+ const uint64_t auxv_length = packet.GetHexMaxU64 (false, std::numeric_limits<uint64_t>::max ());
+ if (auxv_length == std::numeric_limits<uint64_t>::max ())
+ return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing length");
+
+ // Grab the auxv data if we need it.
+ if (!m_active_auxv_buffer_sp)
+ {
+ // Make sure we have a valid process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x10);
+ }
+
+ // Grab the auxv data.
+ m_active_auxv_buffer_sp = Host::GetAuxvData (m_debugged_process_sp->GetID ());
+ if (!m_active_auxv_buffer_sp || m_active_auxv_buffer_sp->GetByteSize () == 0)
+ {
+ // Hmm, no auxv data, call that an error.
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no auxv data retrieved", __FUNCTION__);
+ m_active_auxv_buffer_sp.reset ();
+ return SendErrorResponse (0x11);
+ }
+ }
+
+ // FIXME find out if/how I lock the stream here.
+
+ StreamGDBRemote response;
+ bool done_with_buffer = false;
+
+ if (auxv_offset >= m_active_auxv_buffer_sp->GetByteSize ())
+ {
+ // We have nothing left to send. Mark the buffer as complete.
+ response.PutChar ('l');
+ done_with_buffer = true;
+ }
+ else
+ {
+ // Figure out how many bytes are available starting at the given offset.
+ const uint64_t bytes_remaining = m_active_auxv_buffer_sp->GetByteSize () - auxv_offset;
+
+ // Figure out how many bytes we're going to read.
+ const uint64_t bytes_to_read = (auxv_length > bytes_remaining) ? bytes_remaining : auxv_length;
+
+ // Mark the response type according to whether we're reading the remainder of the auxv data.
+ if (bytes_to_read >= bytes_remaining)
+ {
+ // There will be nothing left to read after this
+ response.PutChar ('l');
+ done_with_buffer = true;
+ }
+ else
+ {
+ // There will still be bytes to read after this request.
+ response.PutChar ('m');
+ }
+
+ // Now write the data in encoded binary form.
+ response.PutEscapedBytes (m_active_auxv_buffer_sp->GetBytes () + auxv_offset, bytes_to_read);
+ }
+
+ if (done_with_buffer)
+ m_active_auxv_buffer_sp.reset ();
+
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+#else
+ return SendUnimplementedResponse ("not implemented on this platform");
+#endif
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Move past packet name.
+ packet.SetFilePos (strlen ("QSaveRegisterState"));
+
+ // Get the thread to use.
+ NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+ if (!thread_sp)
+ {
+ if (m_thread_suffix_supported)
+ return SendIllFormedResponse (packet, "No thread specified in QSaveRegisterState packet");
+ else
+ return SendIllFormedResponse (packet, "No thread was is set with the Hg packet");
+ }
+
+ // Grab the register context for the thread.
+ NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+ if (!reg_context_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+ return SendErrorResponse (0x15);
+ }
+
+ // Save registers to a buffer.
+ DataBufferSP register_data_sp;
+ Error error = reg_context_sp->ReadAllRegisterValues (register_data_sp);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " failed to save all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+ return SendErrorResponse (0x75);
+ }
+
+ // Allocate a new save id.
+ const uint32_t save_id = GetNextSavedRegistersID ();
+ assert ((m_saved_registers_map.find (save_id) == m_saved_registers_map.end ()) && "GetNextRegisterSaveID() returned an existing register save id");
+
+ // Save the register data buffer under the save id.
+ {
+ Mutex::Locker locker (m_saved_registers_mutex);
+ m_saved_registers_map[save_id] = register_data_sp;
+ }
+
+ // Write the response.
+ StreamGDBRemote response;
+ response.Printf ("%" PRIu32, save_id);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Parse out save id.
+ packet.SetFilePos (strlen ("QRestoreRegisterState:"));
+ if (packet.GetBytesLeft () < 1)
+ return SendIllFormedResponse (packet, "QRestoreRegisterState packet missing register save id");
+
+ const uint32_t save_id = packet.GetU32 (0);
+ if (save_id == 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s QRestoreRegisterState packet has malformed save id, expecting decimal uint32_t", __FUNCTION__);
+ return SendErrorResponse (0x76);
+ }
+
+ // Get the thread to use.
+ NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet);
+ if (!thread_sp)
+ {
+ if (m_thread_suffix_supported)
+ return SendIllFormedResponse (packet, "No thread specified in QRestoreRegisterState packet");
+ else
+ return SendIllFormedResponse (packet, "No thread was is set with the Hg packet");
+ }
+
+ // Grab the register context for the thread.
+ NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ());
+ if (!reg_context_sp)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ());
+ return SendErrorResponse (0x15);
+ }
+
+ // Retrieve register state buffer, then remove from the list.
+ DataBufferSP register_data_sp;
+ {
+ Mutex::Locker locker (m_saved_registers_mutex);
+
+ // Find the register set buffer for the given save id.
+ auto it = m_saved_registers_map.find (save_id);
+ if (it == m_saved_registers_map.end ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " does not have a register set save buffer for id %" PRIu32, __FUNCTION__, m_debugged_process_sp->GetID (), save_id);
+ return SendErrorResponse (0x77);
+ }
+ register_data_sp = it->second;
+
+ // Remove it from the map.
+ m_saved_registers_map.erase (it);
+ }
+
+ Error error = reg_context_sp->WriteAllRegisterValues (register_data_sp);
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " failed to restore all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+ return SendErrorResponse (0x77);
+ }
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vAttach (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Consume the ';' after vAttach.
+ packet.SetFilePos (strlen ("vAttach"));
+ if (!packet.GetBytesLeft () || packet.GetChar () != ';')
+ return SendIllFormedResponse (packet, "vAttach missing expected ';'");
+
+ // Grab the PID to which we will attach (assume hex encoding).
+ lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16);
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return SendIllFormedResponse (packet, "vAttach failed to parse the process id");
+
+ // Attempt to attach.
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s attempting to attach to pid %" PRIu64, __FUNCTION__, pid);
+
+ Error error = AttachToProcess (pid);
+
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to attach to pid %" PRIu64 ": %s\n", __FUNCTION__, pid, error.AsCString());
+ return SendErrorResponse (0x01);
+ }
+
+ // Notify we attached by sending a stop packet.
+ return SendStopReasonForState (m_debugged_process_sp->GetState (), true);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_D (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ // Scope for mutex locker.
+ Mutex::Locker locker (m_spawned_pids_mutex);
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID))
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__);
+ return SendErrorResponse (0x15);
+ }
+
+ if (m_spawned_pids.find(m_debugged_process_sp->GetID ()) == m_spawned_pids.end())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to find PID %" PRIu64 " in spawned pids list",
+ __FUNCTION__, m_debugged_process_sp->GetID ());
+ return SendErrorResponse (0x1);
+ }
+
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ // Consume the ';' after D.
+ packet.SetFilePos (1);
+ if (packet.GetBytesLeft ())
+ {
+ if (packet.GetChar () != ';')
+ return SendIllFormedResponse (packet, "D missing expected ';'");
+
+ // Grab the PID from which we will detach (assume hex encoding).
+ pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16);
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return SendIllFormedResponse (packet, "D failed to parse the process id");
+ }
+
+ if (pid != LLDB_INVALID_PROCESS_ID &&
+ m_debugged_process_sp->GetID () != pid)
+ {
+ return SendIllFormedResponse (packet, "Invalid pid");
+ }
+
+ if (m_stdio_communication.IsConnected ())
+ {
+ m_stdio_communication.StopReadThread ();
+ }
+
+ const Error error = m_debugged_process_sp->Detach ();
+ if (error.Fail ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to detach from pid %" PRIu64 ": %s\n",
+ __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ());
+ return SendErrorResponse (0x01);
+ }
+
+ m_spawned_pids.erase (m_debugged_process_sp->GetID ());
+ return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo (StringExtractorGDBRemote &packet)
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ packet.SetFilePos (strlen("qThreadStopInfo"));
+ const lldb::tid_t tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID);
+ if (tid == LLDB_INVALID_THREAD_ID)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse thread id from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ());
+ return SendErrorResponse (0x15);
+ }
+ return SendStopReplyPacketForThread (tid);
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet)
+{
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp ||
+ m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)
+ return SendErrorResponse (68);
+
+ packet.SetFilePos(strlen("qWatchpointSupportInfo"));
+ if (packet.GetBytesLeft() == 0)
+ return SendOKResponse();
+ if (packet.GetChar() != ':')
+ return SendErrorResponse(67);
+
+ uint32_t num = m_debugged_process_sp->GetMaxWatchpoints();
+ StreamGDBRemote response;
+ response.Printf ("num:%d;", num);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress (StringExtractorGDBRemote &packet)
+{
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_sp ||
+ m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)
+ return SendErrorResponse(67);
+
+ packet.SetFilePos(strlen("qFileLoadAddress:"));
+ if (packet.GetBytesLeft() == 0)
+ return SendErrorResponse(68);
+
+ std::string file_name;
+ packet.GetHexByteString(file_name);
+
+ lldb::addr_t file_load_address = LLDB_INVALID_ADDRESS;
+ Error error = m_debugged_process_sp->GetFileLoadAddress(file_name, file_load_address);
+ if (error.Fail())
+ return SendErrorResponse(69);
+
+ if (file_load_address == LLDB_INVALID_ADDRESS)
+ return SendErrorResponse(1); // File not loaded
+
+ StreamGDBRemote response;
+ response.PutHex64(file_load_address);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+void
+GDBRemoteCommunicationServerLLGS::FlushInferiorOutput ()
+{
+ // If we're not monitoring an inferior's terminal, ignore this.
+ if (!m_stdio_communication.IsConnected())
+ return;
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s() called", __FUNCTION__);
+
+ // FIXME implement a timeout on the join.
+ m_stdio_communication.JoinReadThread();
+}
+
+void
+GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection ()
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Tell the stdio connection to shut down.
+ if (m_stdio_communication.IsConnected())
+ {
+ auto connection = m_stdio_communication.GetConnection();
+ if (connection)
+ {
+ Error error;
+ connection->Disconnect (&error);
+
+ if (error.Success ())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s disconnect process terminal stdio - SUCCESS", __FUNCTION__);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s disconnect process terminal stdio - FAIL: %s", __FUNCTION__, error.AsCString ());
+ }
+ }
+ }
+}
+
+
+NativeThreadProtocolSP
+GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix (StringExtractorGDBRemote &packet)
+{
+ NativeThreadProtocolSP thread_sp;
+
+ // We have no thread if we don't have a process.
+ if (!m_debugged_process_sp || m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)
+ return thread_sp;
+
+ // If the client hasn't asked for thread suffix support, there will not be a thread suffix.
+ // Use the current thread in that case.
+ if (!m_thread_suffix_supported)
+ {
+ const lldb::tid_t current_tid = GetCurrentThreadID ();
+ if (current_tid == LLDB_INVALID_THREAD_ID)
+ return thread_sp;
+ else if (current_tid == 0)
+ {
+ // Pick a thread.
+ return m_debugged_process_sp->GetThreadAtIndex (0);
+ }
+ else
+ return m_debugged_process_sp->GetThreadByID (current_tid);
+ }
+
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
+
+ // Parse out the ';'.
+ if (packet.GetBytesLeft () < 1 || packet.GetChar () != ';')
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse error: expected ';' prior to start of thread suffix: packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ());
+ return thread_sp;
+ }
+
+ if (!packet.GetBytesLeft ())
+ return thread_sp;
+
+ // Parse out thread: portion.
+ if (strncmp (packet.Peek (), "thread:", strlen("thread:")) != 0)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse error: expected 'thread:' but not found, packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ());
+ return thread_sp;
+ }
+ packet.SetFilePos (packet.GetFilePos () + strlen("thread:"));
+ const lldb::tid_t tid = packet.GetHexMaxU64(false, 0);
+ if (tid != 0)
+ return m_debugged_process_sp->GetThreadByID (tid);
+
+ return thread_sp;
+}
+
+lldb::tid_t
+GDBRemoteCommunicationServerLLGS::GetCurrentThreadID () const
+{
+ if (m_current_tid == 0 || m_current_tid == LLDB_INVALID_THREAD_ID)
+ {
+ // Use whatever the debug process says is the current thread id
+ // since the protocol either didn't specify or specified we want
+ // any/all threads marked as the current thread.
+ if (!m_debugged_process_sp)
+ return LLDB_INVALID_THREAD_ID;
+ return m_debugged_process_sp->GetCurrentThreadID ();
+ }
+ // Use the specific current thread id set by the gdb remote protocol.
+ return m_current_tid;
+}
+
+uint32_t
+GDBRemoteCommunicationServerLLGS::GetNextSavedRegistersID ()
+{
+ Mutex::Locker locker (m_saved_registers_mutex);
+ return m_next_saved_registers_id++;
+}
+
+void
+GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData ()
+{
+ Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s()", __FUNCTION__);
+
+ // Clear any auxv cached data.
+ // *BSD impls should be able to do this too.
+#if defined(__linux__)
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerLLGS::%s clearing auxv buffer (previously %s)",
+ __FUNCTION__,
+ m_active_auxv_buffer_sp ? "was set" : "was not set");
+ m_active_auxv_buffer_sp.reset ();
+#endif
+}
+
+FileSpec
+GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string& module_path,
+ const ArchSpec& arch)
+{
+ if (m_debugged_process_sp)
+ {
+ FileSpec file_spec;
+ if (m_debugged_process_sp->GetLoadedModuleFileSpec(module_path.c_str(), file_spec).Success())
+ {
+ if (file_spec.Exists())
+ return file_spec;
+ }
+ }
+
+ return GDBRemoteCommunicationServerCommon::FindModuleFile(module_path, arch);
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
new file mode 100644
index 0000000..29f3fde
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -0,0 +1,317 @@
+//===-- GDBRemoteCommunicationServerLLGS.h ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_GDBRemoteCommunicationServerLLGS_h_
+#define liblldb_GDBRemoteCommunicationServerLLGS_h_
+
+// C Includes
+// C++ Includes
+#include <unordered_map>
+
+// Other libraries and framework includes
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/common/NativeProcessProtocol.h"
+#include "lldb/Host/MainLoop.h"
+
+// Project includes
+#include "GDBRemoteCommunicationServerCommon.h"
+
+class StringExtractorGDBRemote;
+
+namespace lldb_private {
+
+namespace process_gdb_remote {
+
+class ProcessGDBRemote;
+
+class GDBRemoteCommunicationServerLLGS :
+ public GDBRemoteCommunicationServerCommon,
+ public NativeProcessProtocol::NativeDelegate
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteCommunicationServerLLGS(const lldb::PlatformSP& platform_sp, MainLoop &mainloop);
+
+ virtual
+ ~GDBRemoteCommunicationServerLLGS();
+
+ //------------------------------------------------------------------
+ /// Specify the program to launch and its arguments.
+ ///
+ /// @param[in] args
+ /// The command line to launch.
+ ///
+ /// @param[in] argc
+ /// The number of elements in the args array of cstring pointers.
+ ///
+ /// @return
+ /// An Error object indicating the success or failure of making
+ /// the setting.
+ //------------------------------------------------------------------
+ Error
+ SetLaunchArguments (const char *const args[], int argc);
+
+ //------------------------------------------------------------------
+ /// Specify the launch flags for the process.
+ ///
+ /// @param[in] launch_flags
+ /// The launch flags to use when launching this process.
+ ///
+ /// @return
+ /// An Error object indicating the success or failure of making
+ /// the setting.
+ //------------------------------------------------------------------
+ Error
+ SetLaunchFlags (unsigned int launch_flags);
+
+ //------------------------------------------------------------------
+ /// Launch a process with the current launch settings.
+ ///
+ /// This method supports running an lldb-gdbserver or similar
+ /// server in a situation where the startup code has been provided
+ /// with all the information for a child process to be launched.
+ ///
+ /// @return
+ /// An Error object indicating the success or failure of the
+ /// launch.
+ //------------------------------------------------------------------
+ Error
+ LaunchProcess () override;
+
+ //------------------------------------------------------------------
+ /// Attach to a process.
+ ///
+ /// This method supports attaching llgs to a process accessible via the
+ /// configured Platform.
+ ///
+ /// @return
+ /// An Error object indicating the success or failure of the
+ /// attach operation.
+ //------------------------------------------------------------------
+ Error
+ AttachToProcess (lldb::pid_t pid);
+
+ //------------------------------------------------------------------
+ // NativeProcessProtocol::NativeDelegate overrides
+ //------------------------------------------------------------------
+ void
+ InitializeDelegate (NativeProcessProtocol *process) override;
+
+ void
+ ProcessStateChanged (NativeProcessProtocol *process, lldb::StateType state) override;
+
+ void
+ DidExec (NativeProcessProtocol *process) override;
+
+ Error
+ InitializeConnection (std::unique_ptr<Connection> &&connection);
+
+protected:
+ lldb::PlatformSP m_platform_sp;
+ MainLoop &m_mainloop;
+ MainLoop::ReadHandleUP m_read_handle_up;
+ lldb::tid_t m_current_tid;
+ lldb::tid_t m_continue_tid;
+ Mutex m_debugged_process_mutex;
+ NativeProcessProtocolSP m_debugged_process_sp;
+ Communication m_stdio_communication;
+ lldb::StateType m_inferior_prev_state;
+ lldb::DataBufferSP m_active_auxv_buffer_sp;
+ Mutex m_saved_registers_mutex;
+ std::unordered_map<uint32_t, lldb::DataBufferSP> m_saved_registers_map;
+ uint32_t m_next_saved_registers_id;
+ bool m_handshake_completed : 1;
+
+ PacketResult
+ SendONotification (const char *buffer, uint32_t len);
+
+ PacketResult
+ SendWResponse (NativeProcessProtocol *process);
+
+ PacketResult
+ SendStopReplyPacketForThread (lldb::tid_t tid);
+
+ PacketResult
+ SendStopReasonForState (lldb::StateType process_state, bool flush_on_exit);
+
+ PacketResult
+ Handle_k (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qProcessInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qC (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSetDisableASLR (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSetWorkingDir (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qGetWorkingDir (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_C (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_c (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vCont (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vCont_actions (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_stop_reason (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qRegisterInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qfThreadInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qsThreadInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_p (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_P (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_H (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_I (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_interrupt (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_m (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_M (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_Z (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_z (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_s (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSaveRegisterState (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_vAttach (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_D (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qThreadStopInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qFileLoadAddress (StringExtractorGDBRemote &packet);
+
+ void
+ SetCurrentThreadID (lldb::tid_t tid);
+
+ lldb::tid_t
+ GetCurrentThreadID () const;
+
+ void
+ SetContinueThreadID (lldb::tid_t tid);
+
+ lldb::tid_t
+ GetContinueThreadID () const { return m_continue_tid; }
+
+ Error
+ SetSTDIOFileDescriptor (int fd);
+
+ static void
+ STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len);
+
+ FileSpec
+ FindModuleFile (const std::string& module_path, const ArchSpec& arch) override;
+
+private:
+ bool
+ DebuggedProcessReaped (lldb::pid_t pid);
+
+ static bool
+ ReapDebuggedProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal,
+ int status);
+
+ void
+ HandleInferiorState_Exited (NativeProcessProtocol *process);
+
+ void
+ HandleInferiorState_Stopped (NativeProcessProtocol *process);
+
+ void
+ FlushInferiorOutput ();
+
+ NativeThreadProtocolSP
+ GetThreadFromSuffix (StringExtractorGDBRemote &packet);
+
+ uint32_t
+ GetNextSavedRegistersID ();
+
+ void
+ MaybeCloseInferiorTerminalConnection ();
+
+ void
+ ClearProcessSpecificData ();
+
+ void
+ RegisterPacketHandlers ();
+
+ void
+ DataAvailableCallback ();
+
+ //------------------------------------------------------------------
+ // For GDBRemoteCommunicationServerLLGS only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServerLLGS);
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // liblldb_GDBRemoteCommunicationServerLLGS_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
new file mode 100644
index 0000000..1205049
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
@@ -0,0 +1,409 @@
+//===-- GDBRemoteCommunicationServerPlatform.cpp ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteCommunicationServerPlatform.h"
+
+#include <errno.h>
+
+// C Includes
+// C++ Includes
+#include <cstring>
+#include <chrono>
+
+// Other libraries and framework includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/StructuredData.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/StringConvert.h"
+#include "lldb/Target/FileAction.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/UnixSignals.h"
+
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+#include "Utility/UriParser.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunicationServerPlatform constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform() :
+ GDBRemoteCommunicationServerCommon ("gdb-remote.server", "gdb-remote.server.rx_packet"),
+ m_platform_sp (Platform::GetHostPlatform ()),
+ m_port_map (),
+ m_port_offset(0)
+{
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC,
+ &GDBRemoteCommunicationServerPlatform::Handle_qC);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir,
+ &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer,
+ &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
+ &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
+ &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_jSignalsInfo,
+ &GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo);
+
+ RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_interrupt,
+ [this](StringExtractorGDBRemote packet,
+ Error &error,
+ bool &interrupt,
+ bool &quit)
+ {
+ error.SetErrorString("interrupt received");
+ interrupt = true;
+ return PacketResult::Success;
+ });
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform()
+{
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
+{
+#ifdef _WIN32
+ return SendErrorResponse(9);
+#else
+ // Spawn a local debugserver as a platform so we can then attach or launch
+ // a process...
+
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__);
+
+ // Sleep and wait a bit for debugserver to start to listen...
+ ConnectionFileDescriptor file_conn;
+ std::string hostname;
+ // TODO: /tmp/ should not be hardcoded. User might want to override /tmp
+ // with the TMPDIR environment variable
+ packet.SetFilePos(::strlen ("qLaunchGDBServer;"));
+ std::string name;
+ std::string value;
+ uint16_t port = UINT16_MAX;
+ while (packet.GetNameColonValue(name, value))
+ {
+ if (name.compare ("host") == 0)
+ hostname.swap(value);
+ else if (name.compare ("port") == 0)
+ port = StringConvert::ToUInt32(value.c_str(), 0, 0);
+ }
+ if (port == UINT16_MAX)
+ port = GetNextAvailablePort();
+
+ // Spawn a new thread to accept the port that gets bound after
+ // binding to port 0 (zero).
+
+ // ignore the hostname send from the remote end, just use the ip address
+ // that we're currently communicating with as the hostname
+
+ // Spawn a debugserver and try to get the port it listens to.
+ ProcessLaunchInfo debugserver_launch_info;
+ if (hostname.empty())
+ hostname = "127.0.0.1";
+ if (log)
+ log->Printf("Launching debugserver with: %s:%u...", hostname.c_str(), port);
+
+ // Do not run in a new session so that it can not linger after the
+ // platform closes.
+ debugserver_launch_info.SetLaunchInSeparateProcessGroup(false);
+ debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
+
+ std::string platform_scheme;
+ std::string platform_ip;
+ int platform_port;
+ std::string platform_path;
+ bool ok = UriParser::Parse(GetConnection()->GetURI().c_str(), platform_scheme, platform_ip, platform_port, platform_path);
+ assert(ok);
+ Error error = StartDebugserverProcess (
+ platform_ip.c_str(),
+ port,
+ debugserver_launch_info,
+ port);
+
+ lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
+
+
+ if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ m_spawned_pids.insert(debugserver_pid);
+ if (port > 0)
+ AssociatePortWithProcess(port, debugserver_pid);
+ }
+ else
+ {
+ if (port > 0)
+ FreePort (port);
+ }
+
+ if (error.Success())
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid);
+
+ char response[256];
+ const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset);
+ assert (response_len < (int)sizeof(response));
+ PacketResult packet_result = SendPacketNoLock (response, response_len);
+
+ if (packet_result != PacketResult::Success)
+ {
+ if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ ::kill (debugserver_pid, SIGINT);
+ }
+ return packet_result;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ());
+ }
+ return SendErrorResponse (9);
+#endif
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo (StringExtractorGDBRemote &packet)
+{
+ lldb::pid_t pid = m_process_launch_info.GetProcessID ();
+ m_process_launch_info.Clear ();
+
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ return SendErrorResponse (1);
+
+ ProcessInstanceInfo proc_info;
+ if (!Host::GetProcessInfo (pid, proc_info))
+ return SendErrorResponse (1);
+
+ StreamString response;
+ CreateProcessInfoResponse_DebugServerStyle(proc_info, response);
+ return SendPacketNoLock (response.GetData (), response.GetSize ());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet)
+{
+ // If this packet is sent to a platform, then change the current working directory
+
+ char cwd[PATH_MAX];
+ if (getcwd(cwd, sizeof(cwd)) == NULL)
+ return SendErrorResponse(errno);
+
+ StreamString response;
+ response.PutBytesAsRawHex8(cwd, strlen(cwd));
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos (::strlen ("QSetWorkingDir:"));
+ std::string path;
+ packet.GetHexByteString (path);
+
+ // If this packet is sent to a platform, then change the current working directory
+ if (::chdir(path.c_str()) != 0)
+ return SendErrorResponse (errno);
+ return SendOKResponse ();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qC (StringExtractorGDBRemote &packet)
+{
+ // NOTE: lldb should now be using qProcessInfo for process IDs. This path here
+ // should not be used. It is reporting process id instead of thread id. The
+ // correct answer doesn't seem to make much sense for lldb-platform.
+ // CONSIDER: flip to "unsupported".
+ lldb::pid_t pid = m_process_launch_info.GetProcessID();
+
+ StreamString response;
+ response.Printf("QC%" PRIx64, pid);
+
+ // If we launch a process and this GDB server is acting as a platform,
+ // then we need to clear the process launch state so we can start
+ // launching another process. In order to launch a process a bunch or
+ // packets need to be sent: environment packets, working directory,
+ // disable ASLR, and many more settings. When we launch a process we
+ // then need to know when to clear this information. Currently we are
+ // selecting the 'qC' packet as that packet which seems to make the most
+ // sense.
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ m_process_launch_info.Clear();
+ }
+
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo(StringExtractorGDBRemote &packet)
+{
+ StructuredData::Array signal_array;
+
+ const auto &signals = Host::GetUnixSignals();
+ for (auto signo = signals->GetFirstSignalNumber();
+ signo != LLDB_INVALID_SIGNAL_NUMBER;
+ signo = signals->GetNextSignalNumber(signo))
+ {
+ auto dictionary = std::make_shared<StructuredData::Dictionary>();
+
+ dictionary->AddIntegerItem("signo", signo);
+ dictionary->AddStringItem("name", signals->GetSignalAsCString(signo));
+
+ bool suppress, stop, notify;
+ signals->GetSignalInfo(signo, suppress, stop, notify);
+ dictionary->AddBooleanItem("suppress", suppress);
+ dictionary->AddBooleanItem("stop", stop);
+ dictionary->AddBooleanItem("notify", notify);
+
+ signal_array.Push(dictionary);
+ }
+
+ StreamString response;
+ signal_array.Dump(response);
+ return SendPacketNoLock(response.GetData(), response.GetSize());
+}
+
+bool
+GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped (lldb::pid_t pid)
+{
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ FreePortForProcess(pid);
+ return m_spawned_pids.erase(pid) > 0;
+}
+
+bool
+GDBRemoteCommunicationServerPlatform::ReapDebugserverProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal, // Zero for no signal
+ int status) // Exit value of process if signal is zero
+{
+ GDBRemoteCommunicationServerPlatform *server = (GDBRemoteCommunicationServerPlatform *)callback_baton;
+ server->DebugserverProcessReaped (pid);
+ return true;
+}
+
+Error
+GDBRemoteCommunicationServerPlatform::LaunchProcess ()
+{
+ if (!m_process_launch_info.GetArguments ().GetArgumentCount ())
+ return Error ("%s: no process command line specified to launch", __FUNCTION__);
+
+ // specify the process monitor if not already set. This should
+ // generally be what happens since we need to reap started
+ // processes.
+ if (!m_process_launch_info.GetMonitorProcessCallback ())
+ m_process_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
+
+ Error error = m_platform_sp->LaunchProcess (m_process_launch_info);
+ if (!error.Success ())
+ {
+ fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0));
+ return error;
+ }
+
+ printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID());
+
+ // add to list of spawned processes. On an lldb-gdbserver, we
+ // would expect there to be only one.
+ const auto pid = m_process_launch_info.GetProcessID();
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ // add to spawned pids
+ Mutex::Locker locker (m_spawned_pids_mutex);
+ m_spawned_pids.insert(pid);
+ }
+
+ return error;
+}
+
+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;
+}
+
+void
+GDBRemoteCommunicationServerPlatform::SetPortOffset (uint16_t port_offset)
+{
+ m_port_offset = port_offset;
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
new file mode 100644
index 0000000..5c01137
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
@@ -0,0 +1,105 @@
+//===-- GDBRemoteCommunicationServerPlatform.h ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_GDBRemoteCommunicationServerPlatform_h_
+#define liblldb_GDBRemoteCommunicationServerPlatform_h_
+
+#include "GDBRemoteCommunicationServerCommon.h"
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class GDBRemoteCommunicationServerPlatform :
+ public GDBRemoteCommunicationServerCommon
+{
+public:
+ typedef std::map<uint16_t, lldb::pid_t> PortMap;
+
+ GDBRemoteCommunicationServerPlatform();
+
+ virtual
+ ~GDBRemoteCommunicationServerPlatform();
+
+ Error
+ LaunchProcess () override;
+
+ // Set both ports to zero to let the platform automatically bind to
+ // 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);
+
+protected:
+ lldb::PlatformSP m_platform_sp;
+
+ PortMap m_port_map;
+ uint16_t m_port_offset;
+
+ PacketResult
+ Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qProcessInfo (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qGetWorkingDir (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_QSetWorkingDir (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_qC (StringExtractorGDBRemote &packet);
+
+ PacketResult
+ Handle_jSignalsInfo(StringExtractorGDBRemote &packet);
+
+private:
+ bool
+ DebugserverProcessReaped (lldb::pid_t pid);
+
+ static bool
+ ReapDebugserverProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal,
+ int status);
+
+ //------------------------------------------------------------------
+ // For GDBRemoteCommunicationServerPlatform only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServerPlatform);
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // liblldb_GDBRemoteCommunicationServerPlatform_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
new file mode 100644
index 0000000..f5f134e
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -0,0 +1,1170 @@
+//===-- GDBRemoteRegisterContext.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteRegisterContext.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#ifndef LLDB_DISABLE_PYTHON
+#include "lldb/Interpreter/PythonDataObjects.h"
+#endif
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/Utils.h"
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "ThreadGDBRemote.h"
+#include "Utility/ARM_GCC_Registers.h"
+#include "Utility/ARM_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+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
+) :
+ 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)
+{
+ // 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());
+
+ // Make a heap based buffer that is big enough to store all registers
+ DataBufferSP reg_data_sp(new DataBufferHeap (reg_info.GetRegisterDataByteSize(), 0));
+ m_reg_data.SetData (reg_data_sp);
+ m_reg_data.SetByteOrder(thread.GetProcess()->GetByteOrder());
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteRegisterContext::~GDBRemoteRegisterContext()
+{
+}
+
+void
+GDBRemoteRegisterContext::InvalidateAllRegisters ()
+{
+ SetAllRegisterValid (false);
+}
+
+void
+GDBRemoteRegisterContext::SetAllRegisterValid (bool b)
+{
+ std::vector<bool>::iterator pos, end = m_reg_valid.end();
+ for (pos = m_reg_valid.begin(); pos != end; ++pos)
+ *pos = b;
+}
+
+size_t
+GDBRemoteRegisterContext::GetRegisterCount ()
+{
+ return m_reg_info.GetNumRegisters ();
+}
+
+const RegisterInfo *
+GDBRemoteRegisterContext::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_reg_info.GetRegisterInfoAtIndex (reg);
+}
+
+size_t
+GDBRemoteRegisterContext::GetRegisterSetCount ()
+{
+ return m_reg_info.GetNumRegisterSets ();
+}
+
+
+
+const RegisterSet *
+GDBRemoteRegisterContext::GetRegisterSet (size_t reg_set)
+{
+ return m_reg_info.GetRegisterSet (reg_set);
+}
+
+
+
+bool
+GDBRemoteRegisterContext::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
+{
+ // Read the register
+ if (ReadRegisterBytes (reg_info, m_reg_data))
+ {
+ const bool partial_data_ok = false;
+ Error error (value.SetValueFromData(reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok));
+ return error.Success();
+ }
+ return false;
+}
+
+bool
+GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response)
+{
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL)
+ return false;
+
+ // Invalidate if needed
+ InvalidateIfNeeded(false);
+
+ const uint32_t reg_byte_size = reg_info->byte_size;
+ const size_t bytes_copied = response.GetHexBytes (const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_byte_size)), reg_byte_size, '\xcc');
+ bool success = bytes_copied == reg_byte_size;
+ if (success)
+ {
+ SetRegisterIsValid(reg, true);
+ }
+ else if (bytes_copied > 0)
+ {
+ // Only set register is valid to false if we copied some bytes, else
+ // leave it as it was.
+ SetRegisterIsValid(reg, false);
+ }
+ return success;
+}
+
+// Helper function for GDBRemoteRegisterContext::ReadRegisterBytes().
+bool
+GDBRemoteRegisterContext::GetPrimordialRegister(const RegisterInfo *reg_info,
+ GDBRemoteCommunicationClient &gdb_comm)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ StringExtractorGDBRemote response;
+ if (gdb_comm.ReadRegister(m_thread.GetProtocolID(), reg, response))
+ return PrivateSetRegisterValue (reg, response);
+ return false;
+}
+
+bool
+GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data)
+{
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ InvalidateIfNeeded(false);
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (!GetRegisterIsValid(reg))
+ {
+ if (m_read_all_at_once)
+ {
+ StringExtractorGDBRemote response;
+ if (!gdb_comm.ReadAllRegisters(m_thread.GetProtocolID(), response))
+ return false;
+ if (response.IsNormalResponse())
+ if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize())
+ SetAllRegisterValid (true);
+ }
+ else if (reg_info->value_regs)
+ {
+ // Process this composite register request by delegating to the constituent
+ // primordial registers.
+
+ // Index of the primordial register.
+ bool success = true;
+ for (uint32_t idx = 0; success; ++idx)
+ {
+ const uint32_t prim_reg = reg_info->value_regs[idx];
+ if (prim_reg == LLDB_INVALID_REGNUM)
+ break;
+ // We have a valid primordial register as our constituent.
+ // Grab the corresponding register info.
+ const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg);
+ if (prim_reg_info == NULL)
+ success = false;
+ else
+ {
+ // Read the containing register if it hasn't already been read
+ if (!GetRegisterIsValid(prim_reg))
+ success = GetPrimordialRegister(prim_reg_info, gdb_comm);
+ }
+ }
+
+ if (success)
+ {
+ // If we reach this point, all primordial register requests have succeeded.
+ // Validate this composite register.
+ SetRegisterIsValid (reg_info, true);
+ }
+ }
+ else
+ {
+ // Get each register individually
+ GetPrimordialRegister(reg_info, gdb_comm);
+ }
+
+ // Make sure we got a valid register value after reading it
+ if (!GetRegisterIsValid(reg))
+ return false;
+ }
+
+ if (&data != &m_reg_data)
+ {
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ assert (m_reg_data.GetByteSize() >= reg_info->byte_offset + reg_info->byte_size);
+#endif
+ // If our register context and our register info disagree, which should never happen, don't
+ // read past the end of the buffer.
+ if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size)
+ return false;
+
+ // If we aren't extracting into our own buffer (which
+ // only happens when this function is called from
+ // ReadRegisterValue(uint32_t, Scalar&)) then
+ // we transfer bytes from our buffer into the data
+ // buffer that was passed in
+
+ data.SetByteOrder (m_reg_data.GetByteOrder());
+ data.SetData (m_reg_data, reg_info->byte_offset, reg_info->byte_size);
+ }
+ return true;
+}
+
+bool
+GDBRemoteRegisterContext::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ DataExtractor data;
+ if (value.GetData (data))
+ return WriteRegisterBytes (reg_info, data, 0);
+ return false;
+}
+
+// Helper function for GDBRemoteRegisterContext::WriteRegisterBytes().
+bool
+GDBRemoteRegisterContext::SetPrimordialRegister(const RegisterInfo *reg_info,
+ GDBRemoteCommunicationClient &gdb_comm)
+{
+ StreamString packet;
+ StringExtractorGDBRemote response;
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ packet.Printf ("P%x=", reg);
+ packet.PutBytesAsRawHex8 (m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size),
+ reg_info->byte_size,
+ lldb::endian::InlHostByteOrder(),
+ lldb::endian::InlHostByteOrder());
+
+ if (gdb_comm.GetThreadSuffixSupported())
+ packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+
+ // Invalidate just this register
+ SetRegisterIsValid(reg, false);
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return true;
+ }
+ return false;
+}
+
+void
+GDBRemoteRegisterContext::SyncThreadState(Process *process)
+{
+ // NB. We assume our caller has locked the sequence mutex.
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *) process)->GetGDBRemote());
+ if (!gdb_comm.GetSyncThreadStateSupported())
+ return;
+
+ StreamString packet;
+ StringExtractorGDBRemote response;
+ packet.Printf ("QSyncThreadState:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ InvalidateAllRegisters();
+ }
+}
+
+bool
+GDBRemoteRegisterContext::WriteRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data, uint32_t data_offset)
+{
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+// FIXME: This check isn't right because IsRunning checks the Public state, but this
+// is work you need to do - for instance in ShouldStop & friends - before the public
+// state has been changed.
+// if (gdb_comm.IsRunning())
+// return false;
+
+
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ assert (m_reg_data.GetByteSize() >= reg_info->byte_offset + reg_info->byte_size);
+#endif
+
+ // If our register context and our register info disagree, which should never happen, don't
+ // overwrite past the end of the buffer.
+ if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size)
+ return false;
+
+ // Grab a pointer to where we are going to put this register
+ uint8_t *dst = const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size));
+
+ if (dst == NULL)
+ return false;
+
+
+ if (data.CopyByteOrderedData (data_offset, // src offset
+ reg_info->byte_size, // src length
+ dst, // dst
+ reg_info->byte_size, // dst length
+ m_reg_data.GetByteOrder())) // dst byte order
+ {
+ Mutex::Locker locker;
+ if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write register."))
+ {
+ const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID()))
+ {
+ StreamString packet;
+ StringExtractorGDBRemote response;
+
+ if (m_read_all_at_once)
+ {
+ // Set all registers in one packet
+ packet.PutChar ('G');
+ packet.PutBytesAsRawHex8 (m_reg_data.GetDataStart(),
+ m_reg_data.GetByteSize(),
+ lldb::endian::InlHostByteOrder(),
+ lldb::endian::InlHostByteOrder());
+
+ if (thread_suffix_supported)
+ packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+
+ // Invalidate all register values
+ InvalidateIfNeeded (true);
+
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ SetAllRegisterValid (false);
+ if (response.IsOKResponse())
+ {
+ return true;
+ }
+ }
+ }
+ else
+ {
+ bool success = true;
+
+ if (reg_info->value_regs)
+ {
+ // This register is part of another register. In this case we read the actual
+ // register data for any "value_regs", and once all that data is read, we will
+ // have enough data in our register context bytes for the value of this register
+
+ // Invalidate this composite register first.
+
+ for (uint32_t idx = 0; success; ++idx)
+ {
+ const uint32_t reg = reg_info->value_regs[idx];
+ if (reg == LLDB_INVALID_REGNUM)
+ break;
+ // We have a valid primordial register as our constituent.
+ // Grab the corresponding register info.
+ const RegisterInfo *value_reg_info = GetRegisterInfoAtIndex(reg);
+ if (value_reg_info == NULL)
+ success = false;
+ else
+ success = SetPrimordialRegister(value_reg_info, gdb_comm);
+ }
+ }
+ else
+ {
+ // This is an actual register, write it
+ success = SetPrimordialRegister(reg_info, gdb_comm);
+ }
+
+ // Check if writing this register will invalidate any other register values?
+ // If so, invalidate them
+ if (reg_info->invalidate_regs)
+ {
+ for (uint32_t idx = 0, reg = reg_info->invalidate_regs[0];
+ reg != LLDB_INVALID_REGNUM;
+ reg = reg_info->invalidate_regs[++idx])
+ {
+ SetRegisterIsValid(reg, false);
+ }
+ }
+
+ return success;
+ }
+ }
+ }
+ else
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
+ if (log)
+ {
+ if (log->GetVerbose())
+ {
+ StreamString strm;
+ gdb_comm.DumpHistory(strm);
+ log->Printf("error: failed to get packet sequence mutex, not sending write register for \"%s\":\n%s", reg_info->name, strm.GetData());
+ }
+ else
+ log->Printf("error: failed to get packet sequence mutex, not sending write register for \"%s\"", reg_info->name);
+ }
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteRegisterContext::ReadAllRegisterValues (RegisterCheckpoint &reg_checkpoint)
+{
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ uint32_t save_id = 0;
+ if (gdb_comm.SaveRegisterState(thread->GetProtocolID(), save_id))
+ {
+ reg_checkpoint.SetID(save_id);
+ reg_checkpoint.GetData().reset();
+ return true;
+ }
+ else
+ {
+ reg_checkpoint.SetID(0); // Invalid save ID is zero
+ return ReadAllRegisterValues(reg_checkpoint.GetData());
+ }
+}
+
+bool
+GDBRemoteRegisterContext::WriteAllRegisterValues (const RegisterCheckpoint &reg_checkpoint)
+{
+ uint32_t save_id = reg_checkpoint.GetID();
+ if (save_id != 0)
+ {
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ return gdb_comm.RestoreRegisterState(m_thread.GetProtocolID(), save_id);
+ }
+ else
+ {
+ return WriteAllRegisterValues(reg_checkpoint.GetData());
+ }
+}
+
+bool
+GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ StringExtractorGDBRemote response;
+
+ const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false;
+
+ Mutex::Locker locker;
+ if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers."))
+ {
+ SyncThreadState(process);
+
+ char packet[32];
+ const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID()))
+ {
+ int packet_len = 0;
+ if (thread_suffix_supported)
+ packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID());
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "g");
+ assert (packet_len < ((int)sizeof(packet) - 1));
+
+ if (use_g_packet && gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ int packet_len = 0;
+ if (thread_suffix_supported)
+ packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID());
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "g");
+ assert (packet_len < ((int)sizeof(packet) - 1));
+
+ if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ if (response.IsErrorResponse())
+ return false;
+
+ std::string &response_str = response.GetStringRef();
+ if (isxdigit(response_str[0]))
+ {
+ response_str.insert(0, 1, 'G');
+ if (thread_suffix_supported)
+ {
+ char thread_id_cstr[64];
+ ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+ response_str.append (thread_id_cstr);
+ }
+ data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size()));
+ return true;
+ }
+ }
+ }
+ else
+ {
+ // For the use_g_packet == false case, we're going to read each register
+ // individually and store them as binary data in a buffer instead of as ascii
+ // characters.
+ const RegisterInfo *reg_info;
+
+ // data_sp will take ownership of this DataBufferHeap pointer soon.
+ DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0));
+
+ for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++)
+ {
+ if (reg_info->value_regs) // skip registers that are slices of real registers
+ continue;
+ ReadRegisterBytes (reg_info, m_reg_data);
+ // ReadRegisterBytes saves the contents of the register in to the m_reg_data buffer
+ }
+ memcpy (reg_ctx->GetBytes(), m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize());
+
+ data_sp = reg_ctx;
+ return true;
+ }
+ }
+ }
+ else
+ {
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
+ if (log)
+ {
+ if (log->GetVerbose())
+ {
+ StreamString strm;
+ gdb_comm.DumpHistory(strm);
+ log->Printf("error: failed to get packet sequence mutex, not sending read all registers:\n%s", strm.GetData());
+ }
+ else
+ log->Printf("error: failed to get packet sequence mutex, not sending read all registers");
+ }
+ }
+
+ data_sp.reset();
+ return false;
+}
+
+bool
+GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (!data_sp || data_sp->GetBytes() == NULL || data_sp->GetByteSize() == 0)
+ return false;
+
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false;
+
+ StringExtractorGDBRemote response;
+ Mutex::Locker locker;
+ if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write all registers."))
+ {
+ const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID()))
+ {
+ // The data_sp contains the entire G response packet including the
+ // G, and if the thread suffix is supported, it has the thread suffix
+ // as well.
+ const char *G_packet = (const char *)data_sp->GetBytes();
+ size_t G_packet_len = data_sp->GetByteSize();
+ if (use_g_packet
+ && gdb_comm.SendPacketAndWaitForResponse (G_packet,
+ G_packet_len,
+ response,
+ false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ // The data_sp contains the entire G response packet including the
+ // G, and if the thread suffix is supported, it has the thread suffix
+ // as well.
+ const char *G_packet = (const char *)data_sp->GetBytes();
+ size_t G_packet_len = data_sp->GetByteSize();
+ if (gdb_comm.SendPacketAndWaitForResponse (G_packet,
+ G_packet_len,
+ response,
+ false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ return true;
+ else if (response.IsErrorResponse())
+ {
+ uint32_t num_restored = 0;
+ // We need to manually go through all of the registers and
+ // restore them manually
+
+ response.GetStringRef().assign (G_packet, G_packet_len);
+ response.SetFilePos(1); // Skip the leading 'G'
+
+ // G_packet_len is hex-ascii characters plus prefix 'G' plus suffix thread specifier.
+ // This means buffer will be a little more than 2x larger than necessary but we resize
+ // it down once we've extracted all hex ascii chars from the packet.
+ DataBufferHeap buffer (G_packet_len, 0);
+
+ const uint32_t bytes_extracted = response.GetHexBytes (buffer.GetBytes(),
+ buffer.GetByteSize(),
+ '\xcc');
+
+ DataExtractor restore_data (buffer.GetBytes(),
+ buffer.GetByteSize(),
+ m_reg_data.GetByteOrder(),
+ m_reg_data.GetAddressByteSize());
+
+ if (bytes_extracted < restore_data.GetByteSize())
+ restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder());
+
+ const RegisterInfo *reg_info;
+
+ // The g packet contents may either include the slice registers (registers defined in
+ // terms of other registers, e.g. eax is a subset of rax) or not. The slice registers
+ // should NOT be in the g packet, but some implementations may incorrectly include them.
+ //
+ // If the slice registers are included in the packet, we must step over the slice registers
+ // when parsing the packet -- relying on the RegisterInfo byte_offset field would be incorrect.
+ // If the slice registers are not included, then using the byte_offset values into the
+ // data buffer is the best way to find individual register values.
+
+ uint64_t size_including_slice_registers = 0;
+ uint64_t size_not_including_slice_registers = 0;
+ uint64_t size_by_highest_offset = 0;
+
+ for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx)
+ {
+ size_including_slice_registers += reg_info->byte_size;
+ if (reg_info->value_regs == NULL)
+ size_not_including_slice_registers += reg_info->byte_size;
+ if (reg_info->byte_offset >= size_by_highest_offset)
+ size_by_highest_offset = reg_info->byte_offset + reg_info->byte_size;
+ }
+
+ bool use_byte_offset_into_buffer;
+ if (size_by_highest_offset == restore_data.GetByteSize())
+ {
+ // The size of the packet agrees with the highest offset: + size in the register file
+ use_byte_offset_into_buffer = true;
+ }
+ else if (size_not_including_slice_registers == restore_data.GetByteSize())
+ {
+ // The size of the packet is the same as concatenating all of the registers sequentially,
+ // skipping the slice registers
+ use_byte_offset_into_buffer = true;
+ }
+ else if (size_including_slice_registers == restore_data.GetByteSize())
+ {
+ // The slice registers are present in the packet (when they shouldn't be).
+ // Don't try to use the RegisterInfo byte_offset into the restore_data, it will
+ // point to the wrong place.
+ use_byte_offset_into_buffer = false;
+ }
+ else {
+ // None of our expected sizes match the actual g packet data we're looking at.
+ // The most conservative approach here is to use the running total byte offset.
+ use_byte_offset_into_buffer = false;
+ }
+
+ // In case our register definitions don't include the correct offsets,
+ // keep track of the size of each reg & compute offset based on that.
+ uint32_t running_byte_offset = 0;
+ for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, running_byte_offset += reg_info->byte_size)
+ {
+ // Skip composite aka slice registers (e.g. eax is a slice of rax).
+ if (reg_info->value_regs)
+ continue;
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ uint32_t register_offset;
+ if (use_byte_offset_into_buffer)
+ {
+ register_offset = reg_info->byte_offset;
+ }
+ else
+ {
+ register_offset = running_byte_offset;
+ }
+
+ // Only write down the registers that need to be written
+ // if we are going to be doing registers individually.
+ bool write_reg = true;
+ const uint32_t reg_byte_size = reg_info->byte_size;
+
+ const char *restore_src = (const char *)restore_data.PeekData(register_offset, reg_byte_size);
+ if (restore_src)
+ {
+ StreamString packet;
+ packet.Printf ("P%x=", reg);
+ packet.PutBytesAsRawHex8 (restore_src,
+ reg_byte_size,
+ lldb::endian::InlHostByteOrder(),
+ lldb::endian::InlHostByteOrder());
+
+ if (thread_suffix_supported)
+ packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+
+ SetRegisterIsValid(reg, false);
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ const char *current_src = (const char *)m_reg_data.PeekData(register_offset, reg_byte_size);
+ if (current_src)
+ write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0;
+ }
+
+ if (write_reg)
+ {
+ StreamString packet;
+ packet.Printf ("P%x=", reg);
+ packet.PutBytesAsRawHex8 (restore_src,
+ reg_byte_size,
+ lldb::endian::InlHostByteOrder(),
+ lldb::endian::InlHostByteOrder());
+
+ if (thread_suffix_supported)
+ packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+
+ SetRegisterIsValid(reg, false);
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ ++num_restored;
+ }
+ }
+ }
+ }
+ return num_restored > 0;
+ }
+ }
+ }
+ else
+ {
+ // For the use_g_packet == false case, we're going to write each register
+ // individually. The data buffer is binary data in this case, instead of
+ // ascii characters.
+
+ bool arm64_debugserver = false;
+ if (m_thread.GetProcess().get())
+ {
+ const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture();
+ if (arch.IsValid()
+ && arch.GetMachine() == llvm::Triple::aarch64
+ && arch.GetTriple().getVendor() == llvm::Triple::Apple
+ && arch.GetTriple().getOS() == llvm::Triple::IOS)
+ {
+ arm64_debugserver = true;
+ }
+ }
+ uint32_t num_restored = 0;
+ const RegisterInfo *reg_info;
+ for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++)
+ {
+ if (reg_info->value_regs) // skip registers that are slices of real registers
+ continue;
+ // Skip the fpsr and fpcr floating point status/control register writing to
+ // work around a bug in an older version of debugserver that would lead to
+ // register context corruption when writing fpsr/fpcr.
+ if (arm64_debugserver &&
+ (strcmp (reg_info->name, "fpsr") == 0 || strcmp (reg_info->name, "fpcr") == 0))
+ {
+ continue;
+ }
+ StreamString packet;
+ packet.Printf ("P%x=", reg_info->kinds[eRegisterKindLLDB]);
+ packet.PutBytesAsRawHex8 (data_sp->GetBytes() + reg_info->byte_offset, reg_info->byte_size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder());
+ if (thread_suffix_supported)
+ packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+
+ SetRegisterIsValid(reg_info, false);
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ ++num_restored;
+ }
+ }
+ return num_restored > 0;
+ }
+ }
+ }
+ else
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
+ if (log)
+ {
+ if (log->GetVerbose())
+ {
+ StreamString strm;
+ gdb_comm.DumpHistory(strm);
+ log->Printf("error: failed to get packet sequence mutex, not sending write all registers:\n%s", strm.GetData());
+ }
+ else
+ log->Printf("error: failed to get packet sequence mutex, not sending write all registers");
+ }
+ }
+ return false;
+}
+
+
+uint32_t
+GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num)
+{
+ return m_reg_info.ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
+
+void
+GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch)
+{
+ // For Advanced SIMD and VFP register mapping.
+ static uint32_t g_d0_regs[] = { 26, 27, LLDB_INVALID_REGNUM }; // (s0, s1)
+ static uint32_t g_d1_regs[] = { 28, 29, LLDB_INVALID_REGNUM }; // (s2, s3)
+ static uint32_t g_d2_regs[] = { 30, 31, LLDB_INVALID_REGNUM }; // (s4, s5)
+ static uint32_t g_d3_regs[] = { 32, 33, LLDB_INVALID_REGNUM }; // (s6, s7)
+ static uint32_t g_d4_regs[] = { 34, 35, LLDB_INVALID_REGNUM }; // (s8, s9)
+ static uint32_t g_d5_regs[] = { 36, 37, LLDB_INVALID_REGNUM }; // (s10, s11)
+ static uint32_t g_d6_regs[] = { 38, 39, LLDB_INVALID_REGNUM }; // (s12, s13)
+ static uint32_t g_d7_regs[] = { 40, 41, LLDB_INVALID_REGNUM }; // (s14, s15)
+ static uint32_t g_d8_regs[] = { 42, 43, LLDB_INVALID_REGNUM }; // (s16, s17)
+ static uint32_t g_d9_regs[] = { 44, 45, LLDB_INVALID_REGNUM }; // (s18, s19)
+ static uint32_t g_d10_regs[] = { 46, 47, LLDB_INVALID_REGNUM }; // (s20, s21)
+ static uint32_t g_d11_regs[] = { 48, 49, LLDB_INVALID_REGNUM }; // (s22, s23)
+ static uint32_t g_d12_regs[] = { 50, 51, LLDB_INVALID_REGNUM }; // (s24, s25)
+ static uint32_t g_d13_regs[] = { 52, 53, LLDB_INVALID_REGNUM }; // (s26, s27)
+ static uint32_t g_d14_regs[] = { 54, 55, LLDB_INVALID_REGNUM }; // (s28, s29)
+ static uint32_t g_d15_regs[] = { 56, 57, LLDB_INVALID_REGNUM }; // (s30, s31)
+ static uint32_t g_q0_regs[] = { 26, 27, 28, 29, LLDB_INVALID_REGNUM }; // (d0, d1) -> (s0, s1, s2, s3)
+ static uint32_t g_q1_regs[] = { 30, 31, 32, 33, LLDB_INVALID_REGNUM }; // (d2, d3) -> (s4, s5, s6, s7)
+ static uint32_t g_q2_regs[] = { 34, 35, 36, 37, LLDB_INVALID_REGNUM }; // (d4, d5) -> (s8, s9, s10, s11)
+ static uint32_t g_q3_regs[] = { 38, 39, 40, 41, LLDB_INVALID_REGNUM }; // (d6, d7) -> (s12, s13, s14, s15)
+ static uint32_t g_q4_regs[] = { 42, 43, 44, 45, LLDB_INVALID_REGNUM }; // (d8, d9) -> (s16, s17, s18, s19)
+ static uint32_t g_q5_regs[] = { 46, 47, 48, 49, LLDB_INVALID_REGNUM }; // (d10, d11) -> (s20, s21, s22, s23)
+ static uint32_t g_q6_regs[] = { 50, 51, 52, 53, LLDB_INVALID_REGNUM }; // (d12, d13) -> (s24, s25, s26, s27)
+ static uint32_t g_q7_regs[] = { 54, 55, 56, 57, LLDB_INVALID_REGNUM }; // (d14, d15) -> (s28, s29, s30, s31)
+ static uint32_t g_q8_regs[] = { 59, 60, LLDB_INVALID_REGNUM }; // (d16, d17)
+ static uint32_t g_q9_regs[] = { 61, 62, LLDB_INVALID_REGNUM }; // (d18, d19)
+ static uint32_t g_q10_regs[] = { 63, 64, LLDB_INVALID_REGNUM }; // (d20, d21)
+ static uint32_t g_q11_regs[] = { 65, 66, LLDB_INVALID_REGNUM }; // (d22, d23)
+ static uint32_t g_q12_regs[] = { 67, 68, LLDB_INVALID_REGNUM }; // (d24, d25)
+ static uint32_t g_q13_regs[] = { 69, 70, LLDB_INVALID_REGNUM }; // (d26, d27)
+ static uint32_t g_q14_regs[] = { 71, 72, LLDB_INVALID_REGNUM }; // (d28, d29)
+ static uint32_t g_q15_regs[] = { 73, 74, LLDB_INVALID_REGNUM }; // (d30, d31)
+
+ // This is our array of composite registers, with each element coming from the above register mappings.
+ static uint32_t *g_composites[] = {
+ g_d0_regs, g_d1_regs, g_d2_regs, g_d3_regs, g_d4_regs, g_d5_regs, g_d6_regs, g_d7_regs,
+ g_d8_regs, g_d9_regs, g_d10_regs, g_d11_regs, g_d12_regs, g_d13_regs, g_d14_regs, g_d15_regs,
+ g_q0_regs, g_q1_regs, g_q2_regs, g_q3_regs, g_q4_regs, g_q5_regs, g_q6_regs, g_q7_regs,
+ g_q8_regs, g_q9_regs, g_q10_regs, g_q11_regs, g_q12_regs, g_q13_regs, g_q14_regs, g_q15_regs
+ };
+
+ static RegisterInfo g_register_infos[] = {
+// NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS
+// ====== ====== === === ============= ============ =================== =================== ====================== === ==== ========== ===============
+ { "r0", "arg1", 4, 0, eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1,0, 0 }, NULL, NULL},
+ { "r1", "arg2", 4, 0, eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2,1, 1 }, NULL, NULL},
+ { "r2", "arg3", 4, 0, eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3,2, 2 }, NULL, NULL},
+ { "r3", "arg4", 4, 0, eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4,3, 3 }, NULL, NULL},
+ { "r4", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, 4, 4 }, NULL, NULL},
+ { "r5", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, 5, 5 }, NULL, NULL},
+ { "r6", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, 6, 6 }, NULL, NULL},
+ { "r7", "fp", 4, 0, eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, 7, 7 }, NULL, NULL},
+ { "r8", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, 8, 8 }, NULL, NULL},
+ { "r9", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, 9, 9 }, NULL, NULL},
+ { "r10", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, 10, 10 }, NULL, NULL},
+ { "r11", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM, 11, 11 }, NULL, NULL},
+ { "r12", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, 12, 12 }, NULL, NULL},
+ { "sp", "r13", 4, 0, eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, 13, 13 }, NULL, NULL},
+ { "lr", "r14", 4, 0, eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, 14, 14 }, NULL, NULL},
+ { "pc", "r15", 4, 0, eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, 15, 15 }, NULL, NULL},
+ { "f0", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 16, 16 }, NULL, NULL},
+ { "f1", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 17, 17 }, NULL, NULL},
+ { "f2", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 18, 18 }, NULL, NULL},
+ { "f3", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 19, 19 }, NULL, NULL},
+ { "f4", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 20, 20 }, NULL, NULL},
+ { "f5", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 21, 21 }, NULL, NULL},
+ { "f6", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 22, 22 }, NULL, NULL},
+ { "f7", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 23, 23 }, NULL, NULL},
+ { "fps", NULL, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 24, 24 }, NULL, NULL},
+ { "cpsr","flags", 4, 0, eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_INVALID_REGNUM, 25, 25 }, NULL, NULL},
+ { "s0", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, 26, 26 }, NULL, NULL},
+ { "s1", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, 27, 27 }, NULL, NULL},
+ { "s2", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, 28, 28 }, NULL, NULL},
+ { "s3", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, 29, 29 }, NULL, NULL},
+ { "s4", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, 30, 30 }, NULL, NULL},
+ { "s5", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, 31, 31 }, NULL, NULL},
+ { "s6", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, 32, 32 }, NULL, NULL},
+ { "s7", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, 33, 33 }, NULL, NULL},
+ { "s8", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, 34, 34 }, NULL, NULL},
+ { "s9", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, 35, 35 }, NULL, NULL},
+ { "s10", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, 36, 36 }, NULL, NULL},
+ { "s11", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, 37, 37 }, NULL, NULL},
+ { "s12", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, 38, 38 }, NULL, NULL},
+ { "s13", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, 39, 39 }, NULL, NULL},
+ { "s14", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, 40, 40 }, NULL, NULL},
+ { "s15", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, 41, 41 }, NULL, NULL},
+ { "s16", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, 42, 42 }, NULL, NULL},
+ { "s17", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, 43, 43 }, NULL, NULL},
+ { "s18", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, 44, 44 }, NULL, NULL},
+ { "s19", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, 45, 45 }, NULL, NULL},
+ { "s20", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, 46, 46 }, NULL, NULL},
+ { "s21", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, 47, 47 }, NULL, NULL},
+ { "s22", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, 48, 48 }, NULL, NULL},
+ { "s23", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, 49, 49 }, NULL, NULL},
+ { "s24", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, 50, 50 }, NULL, NULL},
+ { "s25", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, 51, 51 }, NULL, NULL},
+ { "s26", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, 52, 52 }, NULL, NULL},
+ { "s27", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, 53, 53 }, NULL, NULL},
+ { "s28", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, 54, 54 }, NULL, NULL},
+ { "s29", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, 55, 55 }, NULL, NULL},
+ { "s30", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, 56, 56 }, NULL, NULL},
+ { "s31", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, 57, 57 }, NULL, NULL},
+ { "fpscr",NULL, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 58, 58 }, NULL, NULL},
+ { "d16", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, 59, 59 }, NULL, NULL},
+ { "d17", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, 60, 60 }, NULL, NULL},
+ { "d18", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, 61, 61 }, NULL, NULL},
+ { "d19", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, 62, 62 }, NULL, NULL},
+ { "d20", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, 63, 63 }, NULL, NULL},
+ { "d21", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, 64, 64 }, NULL, NULL},
+ { "d22", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, 65, 65 }, NULL, NULL},
+ { "d23", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, 66, 66 }, NULL, NULL},
+ { "d24", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, 67, 67 }, NULL, NULL},
+ { "d25", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, 68, 68 }, NULL, NULL},
+ { "d26", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, 69, 69 }, NULL, NULL},
+ { "d27", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, 70, 70 }, NULL, NULL},
+ { "d28", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, 71, 71 }, NULL, NULL},
+ { "d29", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, 72, 72 }, NULL, NULL},
+ { "d30", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, 73, 73 }, NULL, NULL},
+ { "d31", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, 74, 74 }, NULL, NULL},
+ { "d0", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d0, LLDB_INVALID_REGNUM, 75, 75 }, g_d0_regs, NULL},
+ { "d1", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d1, LLDB_INVALID_REGNUM, 76, 76 }, g_d1_regs, NULL},
+ { "d2", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d2, LLDB_INVALID_REGNUM, 77, 77 }, g_d2_regs, NULL},
+ { "d3", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d3, LLDB_INVALID_REGNUM, 78, 78 }, g_d3_regs, NULL},
+ { "d4", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d4, LLDB_INVALID_REGNUM, 79, 79 }, g_d4_regs, NULL},
+ { "d5", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d5, LLDB_INVALID_REGNUM, 80, 80 }, g_d5_regs, NULL},
+ { "d6", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d6, LLDB_INVALID_REGNUM, 81, 81 }, g_d6_regs, NULL},
+ { "d7", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d7, LLDB_INVALID_REGNUM, 82, 82 }, g_d7_regs, NULL},
+ { "d8", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d8, LLDB_INVALID_REGNUM, 83, 83 }, g_d8_regs, NULL},
+ { "d9", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d9, LLDB_INVALID_REGNUM, 84, 84 }, g_d9_regs, NULL},
+ { "d10", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d10, LLDB_INVALID_REGNUM, 85, 85 }, g_d10_regs, NULL},
+ { "d11", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d11, LLDB_INVALID_REGNUM, 86, 86 }, g_d11_regs, NULL},
+ { "d12", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d12, LLDB_INVALID_REGNUM, 87, 87 }, g_d12_regs, NULL},
+ { "d13", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d13, LLDB_INVALID_REGNUM, 88, 88 }, g_d13_regs, NULL},
+ { "d14", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d14, LLDB_INVALID_REGNUM, 89, 89 }, g_d14_regs, NULL},
+ { "d15", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d15, LLDB_INVALID_REGNUM, 90, 90 }, g_d15_regs, NULL},
+ { "q0", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q0, LLDB_INVALID_REGNUM, 91, 91 }, g_q0_regs, NULL},
+ { "q1", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q1, LLDB_INVALID_REGNUM, 92, 92 }, g_q1_regs, NULL},
+ { "q2", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q2, LLDB_INVALID_REGNUM, 93, 93 }, g_q2_regs, NULL},
+ { "q3", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q3, LLDB_INVALID_REGNUM, 94, 94 }, g_q3_regs, NULL},
+ { "q4", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q4, LLDB_INVALID_REGNUM, 95, 95 }, g_q4_regs, NULL},
+ { "q5", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q5, LLDB_INVALID_REGNUM, 96, 96 }, g_q5_regs, NULL},
+ { "q6", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q6, LLDB_INVALID_REGNUM, 97, 97 }, g_q6_regs, NULL},
+ { "q7", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q7, LLDB_INVALID_REGNUM, 98, 98 }, g_q7_regs, NULL},
+ { "q8", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q8, LLDB_INVALID_REGNUM, 99, 99 }, g_q8_regs, NULL},
+ { "q9", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q9, LLDB_INVALID_REGNUM, 100, 100 }, g_q9_regs, NULL},
+ { "q10", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q10, LLDB_INVALID_REGNUM, 101, 101 }, g_q10_regs, NULL},
+ { "q11", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q11, LLDB_INVALID_REGNUM, 102, 102 }, g_q11_regs, NULL},
+ { "q12", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q12, LLDB_INVALID_REGNUM, 103, 103 }, g_q12_regs, NULL},
+ { "q13", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q13, LLDB_INVALID_REGNUM, 104, 104 }, g_q13_regs, NULL},
+ { "q14", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q14, LLDB_INVALID_REGNUM, 105, 105 }, g_q14_regs, NULL},
+ { "q15", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q15, LLDB_INVALID_REGNUM, 106, 106 }, g_q15_regs, NULL}
+ };
+
+ static const uint32_t num_registers = llvm::array_lengthof(g_register_infos);
+ static ConstString gpr_reg_set ("General Purpose Registers");
+ static ConstString sfp_reg_set ("Software Floating Point Registers");
+ static ConstString vfp_reg_set ("Floating Point Registers");
+ size_t i;
+ if (from_scratch)
+ {
+ // Calculate the offsets of the registers
+ // Note that the layout of the "composite" registers (d0-d15 and q0-q15) which comes after the
+ // "primordial" registers is important. This enables us to calculate the offset of the composite
+ // register by using the offset of its first primordial register. For example, to calculate the
+ // offset of q0, use s0's offset.
+ if (g_register_infos[2].byte_offset == 0)
+ {
+ uint32_t byte_offset = 0;
+ for (i=0; i<num_registers; ++i)
+ {
+ // For primordial registers, increment the byte_offset by the byte_size to arrive at the
+ // byte_offset for the next register. Otherwise, we have a composite register whose
+ // offset can be calculated by consulting the offset of its first primordial register.
+ if (!g_register_infos[i].value_regs)
+ {
+ g_register_infos[i].byte_offset = byte_offset;
+ byte_offset += g_register_infos[i].byte_size;
+ }
+ else
+ {
+ const uint32_t first_primordial_reg = g_register_infos[i].value_regs[0];
+ g_register_infos[i].byte_offset = g_register_infos[first_primordial_reg].byte_offset;
+ }
+ }
+ }
+ for (i=0; i<num_registers; ++i)
+ {
+ ConstString name;
+ ConstString alt_name;
+ if (g_register_infos[i].name && g_register_infos[i].name[0])
+ name.SetCString(g_register_infos[i].name);
+ if (g_register_infos[i].alt_name && g_register_infos[i].alt_name[0])
+ alt_name.SetCString(g_register_infos[i].alt_name);
+
+ if (i <= 15 || i == 25)
+ AddRegister (g_register_infos[i], name, alt_name, gpr_reg_set);
+ else if (i <= 24)
+ AddRegister (g_register_infos[i], name, alt_name, sfp_reg_set);
+ else
+ AddRegister (g_register_infos[i], name, alt_name, vfp_reg_set);
+ }
+ }
+ else
+ {
+ // Add composite registers to our primordial registers, then.
+ const size_t num_composites = llvm::array_lengthof(g_composites);
+ const size_t num_dynamic_regs = GetNumRegisters();
+ const size_t num_common_regs = num_registers - num_composites;
+ RegisterInfo *g_comp_register_infos = g_register_infos + num_common_regs;
+
+ // First we need to validate that all registers that we already have match the non composite regs.
+ // If so, then we can add the registers, else we need to bail
+ bool match = true;
+ if (num_dynamic_regs == num_common_regs)
+ {
+ for (i=0; match && i<num_dynamic_regs; ++i)
+ {
+ // Make sure all register names match
+ if (m_regs[i].name && g_register_infos[i].name)
+ {
+ if (strcmp(m_regs[i].name, g_register_infos[i].name))
+ {
+ match = false;
+ break;
+ }
+ }
+
+ // Make sure all register byte sizes match
+ if (m_regs[i].byte_size != g_register_infos[i].byte_size)
+ {
+ match = false;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Wrong number of registers.
+ match = false;
+ }
+ // If "match" is true, then we can add extra registers.
+ if (match)
+ {
+ for (i=0; i<num_composites; ++i)
+ {
+ ConstString name;
+ ConstString alt_name;
+ const uint32_t first_primordial_reg = g_comp_register_infos[i].value_regs[0];
+ const char *reg_name = g_register_infos[first_primordial_reg].name;
+ if (reg_name && reg_name[0])
+ {
+ for (uint32_t j = 0; j < num_dynamic_regs; ++j)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(j);
+ // Find a matching primordial register info entry.
+ if (reg_info && reg_info->name && ::strcasecmp(reg_info->name, reg_name) == 0)
+ {
+ // The name matches the existing primordial entry.
+ // Find and assign the offset, and then add this composite register entry.
+ g_comp_register_infos[i].byte_offset = reg_info->byte_offset;
+ name.SetCString(g_comp_register_infos[i].name);
+ AddRegister(g_comp_register_infos[i], name, alt_name, vfp_reg_set);
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
new file mode 100644
index 0000000..117d280
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -0,0 +1,178 @@
+//===-- GDBRemoteRegisterContext.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_GDBRemoteRegisterContext_h_
+#define lldb_GDBRemoteRegisterContext_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/RegisterContext.h"
+#include "Plugins/Process/Utility/DynamicRegisterInfo.h"
+
+#include "GDBRemoteCommunicationClient.h"
+
+class StringExtractor;
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class ThreadGDBRemote;
+class ProcessGDBRemote;
+
+class GDBRemoteDynamicRegisterInfo :
+ public DynamicRegisterInfo
+{
+public:
+ GDBRemoteDynamicRegisterInfo () :
+ DynamicRegisterInfo()
+ {
+ }
+
+ ~GDBRemoteDynamicRegisterInfo ()
+ {
+ }
+
+ void
+ HardcodeARMRegisters(bool from_scratch);
+
+};
+
+class GDBRemoteRegisterContext : public RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteRegisterContext (ThreadGDBRemote &thread,
+ uint32_t concrete_frame_idx,
+ GDBRemoteDynamicRegisterInfo &reg_info,
+ bool read_all_at_once);
+
+ virtual
+ ~GDBRemoteRegisterContext ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ void
+ InvalidateAllRegisters () override;
+
+ size_t
+ GetRegisterCount () override;
+
+ const RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg) override;
+
+ size_t
+ GetRegisterSetCount () override;
+
+ const RegisterSet *
+ GetRegisterSet (size_t reg_set) override;
+
+ bool
+ ReadRegister (const RegisterInfo *reg_info, RegisterValue &value) override;
+
+ bool
+ WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value) override;
+
+ bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp) override;
+
+ bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override;
+
+ bool
+ ReadAllRegisterValues (RegisterCheckpoint &reg_checkpoint) override;
+
+ bool
+ WriteAllRegisterValues (const RegisterCheckpoint &reg_checkpoint) override;
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) override;
+
+protected:
+ friend class ThreadGDBRemote;
+
+ bool
+ ReadRegisterBytes (const RegisterInfo *reg_info,
+ DataExtractor &data);
+
+ bool
+ WriteRegisterBytes (const RegisterInfo *reg_info,
+ DataExtractor &data,
+ uint32_t data_offset);
+
+ bool
+ PrivateSetRegisterValue (uint32_t reg, StringExtractor &response);
+
+ void
+ SetAllRegisterValid (bool b);
+
+ bool
+ GetRegisterIsValid (uint32_t reg) const
+ {
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ assert (reg < m_reg_valid.size());
+#endif
+ if (reg < m_reg_valid.size())
+ return m_reg_valid[reg];
+ return false;
+ }
+
+ void
+ SetRegisterIsValid (const RegisterInfo *reg_info, bool valid)
+ {
+ if (reg_info)
+ return SetRegisterIsValid (reg_info->kinds[lldb::eRegisterKindLLDB], valid);
+ }
+
+ void
+ SetRegisterIsValid (uint32_t reg, bool valid)
+ {
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ assert (reg < m_reg_valid.size());
+#endif
+ if (reg < m_reg_valid.size())
+ m_reg_valid[reg] = valid;
+ }
+
+ void
+ SyncThreadState(Process *process); // Assumes the sequence mutex has already been acquired.
+
+ GDBRemoteDynamicRegisterInfo &m_reg_info;
+ std::vector<bool> m_reg_valid;
+ DataExtractor m_reg_data;
+ bool m_read_all_at_once;
+
+private:
+ // Helper function for ReadRegisterBytes().
+ bool GetPrimordialRegister(const RegisterInfo *reg_info,
+ GDBRemoteCommunicationClient &gdb_comm);
+ // Helper function for WriteRegisterBytes().
+ bool SetPrimordialRegister(const RegisterInfo *reg_info,
+ GDBRemoteCommunicationClient &gdb_comm);
+
+ //------------------------------------------------------------------
+ // For GDBRemoteRegisterContext only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteRegisterContext);
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // lldb_GDBRemoteRegisterContext_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
new file mode 100644
index 0000000..0a8d559
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -0,0 +1,5038 @@
+//===-- ProcessGDBRemote.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/Config.h"
+
+// C Includes
+#include <errno.h>
+#include <stdlib.h>
+#ifndef LLDB_DISABLE_POSIX
+#include <netinet/in.h>
+#include <sys/mman.h> // for mmap
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+
+// C++ Includes
+#include <algorithm>
+#include <map>
+#include <mutex>
+
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/Value.h"
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/Host/StringConvert.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Host/XML.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionGroupBoolean.h"
+#include "lldb/Interpreter/OptionGroupUInt64.h"
+#include "lldb/Interpreter/Property.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/TargetList.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Target/SystemRuntime.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+// Project includes
+#include "lldb/Host/Host.h"
+#include "Plugins/Process/Utility/GDBRemoteSignals.h"
+#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "Plugins/Process/Utility/StopInfoMachException.h"
+#include "Utility/StringExtractorGDBRemote.h"
+#include "GDBRemoteRegisterContext.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "ThreadGDBRemote.h"
+
+#define DEBUGSERVER_BASENAME "debugserver"
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+namespace lldb
+{
+ // Provide a function that can easily dump the packet history if we know a
+ // ProcessGDBRemote * value (which we can get from logs or from debugging).
+ // We need the function in the lldb namespace so it makes it into the final
+ // executable since the LLDB shared library only exports stuff in the lldb
+ // namespace. This allows you to attach with a debugger and call this
+ // function and get the packet history dumped to a file.
+ void
+ DumpProcessGDBRemotePacketHistory (void *p, const char *path)
+ {
+ StreamFile strm;
+ Error error (strm.GetFile().Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate));
+ if (error.Success())
+ ((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory (strm);
+ }
+}
+
+namespace {
+
+ static PropertyDefinition
+ g_properties[] =
+ {
+ { "packet-timeout" , OptionValue::eTypeUInt64 , true , 1, NULL, NULL, "Specify the default packet timeout in seconds." },
+ { "target-definition-file" , OptionValue::eTypeFileSpec , true, 0 , NULL, NULL, "The file that provides the description for remote target registers." },
+ { NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL }
+ };
+
+ enum
+ {
+ ePropertyPacketTimeout,
+ ePropertyTargetDefinitionFile
+ };
+
+ class PluginProperties : public Properties
+ {
+ public:
+
+ static ConstString
+ GetSettingName ()
+ {
+ return ProcessGDBRemote::GetPluginNameStatic();
+ }
+
+ PluginProperties() :
+ Properties ()
+ {
+ m_collection_sp.reset (new OptionValueProperties(GetSettingName()));
+ m_collection_sp->Initialize(g_properties);
+ }
+
+ virtual
+ ~PluginProperties()
+ {
+ }
+
+ uint64_t
+ GetPacketTimeout()
+ {
+ const uint32_t idx = ePropertyPacketTimeout;
+ return m_collection_sp->GetPropertyAtIndexAsUInt64(NULL, idx, g_properties[idx].default_uint_value);
+ }
+
+ bool
+ SetPacketTimeout(uint64_t timeout)
+ {
+ const uint32_t idx = ePropertyPacketTimeout;
+ return m_collection_sp->SetPropertyAtIndexAsUInt64(NULL, idx, timeout);
+ }
+
+ FileSpec
+ GetTargetDefinitionFile () const
+ {
+ const uint32_t idx = ePropertyTargetDefinitionFile;
+ return m_collection_sp->GetPropertyAtIndexAsFileSpec (NULL, idx);
+ }
+ };
+
+ typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP;
+
+ static const ProcessKDPPropertiesSP &
+ GetGlobalPluginProperties()
+ {
+ static ProcessKDPPropertiesSP g_settings_sp;
+ if (!g_settings_sp)
+ g_settings_sp.reset (new PluginProperties ());
+ return g_settings_sp;
+ }
+
+} // anonymous namespace end
+
+class ProcessGDBRemote::GDBLoadedModuleInfoList
+{
+public:
+
+ class LoadedModuleInfo
+ {
+ public:
+
+ enum e_data_point
+ {
+ e_has_name = 0,
+ e_has_base ,
+ e_has_dynamic ,
+ e_has_link_map ,
+ e_num
+ };
+
+ LoadedModuleInfo ()
+ {
+ for (uint32_t i = 0; i < e_num; ++i)
+ m_has[i] = false;
+ };
+
+ void set_name (const std::string & name)
+ {
+ m_name = name;
+ m_has[e_has_name] = true;
+ }
+ bool get_name (std::string & out) const
+ {
+ out = m_name;
+ return m_has[e_has_name];
+ }
+
+ void set_base (const lldb::addr_t base)
+ {
+ m_base = base;
+ m_has[e_has_base] = true;
+ }
+ bool get_base (lldb::addr_t & out) const
+ {
+ out = m_base;
+ return m_has[e_has_base];
+ }
+
+ void set_link_map (const lldb::addr_t addr)
+ {
+ m_link_map = addr;
+ m_has[e_has_link_map] = true;
+ }
+ bool get_link_map (lldb::addr_t & out) const
+ {
+ out = m_link_map;
+ return m_has[e_has_link_map];
+ }
+
+ void set_dynamic (const lldb::addr_t addr)
+ {
+ m_dynamic = addr;
+ m_has[e_has_dynamic] = true;
+ }
+ bool get_dynamic (lldb::addr_t & out) const
+ {
+ out = m_dynamic;
+ return m_has[e_has_dynamic];
+ }
+
+ bool has_info (e_data_point datum)
+ {
+ assert (datum < e_num);
+ return m_has[datum];
+ }
+
+ protected:
+
+ bool m_has[e_num];
+ std::string m_name;
+ lldb::addr_t m_link_map;
+ lldb::addr_t m_base;
+ lldb::addr_t m_dynamic;
+ };
+
+ GDBLoadedModuleInfoList ()
+ : m_list ()
+ , m_link_map (LLDB_INVALID_ADDRESS)
+ {}
+
+ void add (const LoadedModuleInfo & mod)
+ {
+ m_list.push_back (mod);
+ }
+
+ void clear ()
+ {
+ m_list.clear ();
+ }
+
+ std::vector<LoadedModuleInfo> m_list;
+ lldb::addr_t m_link_map;
+};
+
+// TODO Randomly assigning a port is unsafe. We should get an unused
+// ephemeral port from the kernel and make sure we reserve it before passing
+// it to debugserver.
+
+#if defined (__APPLE__)
+#define LOW_PORT (IPPORT_RESERVED)
+#define HIGH_PORT (IPPORT_HIFIRSTAUTO)
+#else
+#define LOW_PORT (1024u)
+#define HIGH_PORT (49151u)
+#endif
+
+#if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__) || defined(__aarch64__))
+static bool rand_initialized = false;
+
+static inline uint16_t
+get_random_port ()
+{
+ if (!rand_initialized)
+ {
+ time_t seed = time(NULL);
+
+ rand_initialized = true;
+ srand(seed);
+ }
+ return (rand() % (HIGH_PORT - LOW_PORT)) + LOW_PORT;
+}
+#endif
+
+ConstString
+ProcessGDBRemote::GetPluginNameStatic()
+{
+ static ConstString g_name("gdb-remote");
+ return g_name;
+}
+
+const char *
+ProcessGDBRemote::GetPluginDescriptionStatic()
+{
+ return "GDB Remote protocol based debugging plug-in.";
+}
+
+void
+ProcessGDBRemote::Terminate()
+{
+ PluginManager::UnregisterPlugin (ProcessGDBRemote::CreateInstance);
+}
+
+
+lldb::ProcessSP
+ProcessGDBRemote::CreateInstance (Target &target, Listener &listener, const FileSpec *crash_file_path)
+{
+ lldb::ProcessSP process_sp;
+ if (crash_file_path == NULL)
+ process_sp.reset (new ProcessGDBRemote (target, listener));
+ return process_sp;
+}
+
+bool
+ProcessGDBRemote::CanDebug (Target &target, bool plugin_specified_by_name)
+{
+ if (plugin_specified_by_name)
+ return true;
+
+ // For now we are just making sure the file exists for a given module
+ Module *exe_module = target.GetExecutableModulePointer();
+ if (exe_module)
+ {
+ ObjectFile *exe_objfile = exe_module->GetObjectFile();
+ // We can't debug core files...
+ switch (exe_objfile->GetType())
+ {
+ case ObjectFile::eTypeInvalid:
+ case ObjectFile::eTypeCoreFile:
+ case ObjectFile::eTypeDebugInfo:
+ case ObjectFile::eTypeObjectFile:
+ case ObjectFile::eTypeSharedLibrary:
+ case ObjectFile::eTypeStubLibrary:
+ case ObjectFile::eTypeJIT:
+ return false;
+ case ObjectFile::eTypeExecutable:
+ case ObjectFile::eTypeDynamicLinker:
+ case ObjectFile::eTypeUnknown:
+ break;
+ }
+ return exe_module->GetFileSpec().Exists();
+ }
+ // However, if there is no executable module, we return true since we might be preparing to attach.
+ return true;
+}
+
+//----------------------------------------------------------------------
+// ProcessGDBRemote constructor
+//----------------------------------------------------------------------
+ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) :
+ Process (target, listener),
+ m_flags (0),
+ m_gdb_comm (),
+ m_debugserver_pid (LLDB_INVALID_PROCESS_ID),
+ m_last_stop_packet_mutex (Mutex::eMutexTypeRecursive),
+ m_register_info (),
+ m_async_broadcaster (NULL, "lldb.process.gdb-remote.async-broadcaster"),
+ m_async_thread_state_mutex(Mutex::eMutexTypeRecursive),
+ m_thread_ids (),
+ m_threads_info_sp (),
+ m_continue_c_tids (),
+ m_continue_C_tids (),
+ m_continue_s_tids (),
+ m_continue_S_tids (),
+ m_max_memory_size (0),
+ m_remote_stub_max_memory_size (0),
+ m_addr_to_mmap_size (),
+ m_thread_create_bp_sp (),
+ m_waiting_for_attach (false),
+ m_destroy_tried_resuming (false),
+ m_command_sp (),
+ m_breakpoint_pc_offset (0),
+ m_initial_tid (LLDB_INVALID_THREAD_ID)
+{
+ m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit, "async thread should exit");
+ m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue, "async thread continue");
+ m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadDidExit, "async thread did exit");
+ const uint64_t timeout_seconds = GetGlobalPluginProperties()->GetPacketTimeout();
+ if (timeout_seconds > 0)
+ m_gdb_comm.SetPacketTimeout(timeout_seconds);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessGDBRemote::~ProcessGDBRemote()
+{
+ // m_mach_process.UnregisterNotificationCallbacks (this);
+ Clear();
+ // We need to call finalize on the process before destroying ourselves
+ // to make sure all of the broadcaster cleanup goes as planned. If we
+ // destruct this class, then Process::~Process() might have problems
+ // trying to fully destroy the broadcaster.
+ Finalize();
+
+ // The general Finalize is going to try to destroy the process and that SHOULD
+ // shut down the async thread. However, if we don't kill it it will get stranded and
+ // its connection will go away so when it wakes up it will crash. So kill it for sure here.
+ StopAsyncThread();
+ KillDebugserverProcess();
+}
+
+//----------------------------------------------------------------------
+// PluginInterface
+//----------------------------------------------------------------------
+ConstString
+ProcessGDBRemote::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessGDBRemote::GetPluginVersion()
+{
+ return 1;
+}
+
+bool
+ProcessGDBRemote::ParsePythonTargetDefinition(const FileSpec &target_definition_fspec)
+{
+ ScriptInterpreter *interpreter = GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ Error error;
+ StructuredData::ObjectSP module_object_sp(interpreter->LoadPluginModule(target_definition_fspec, error));
+ if (module_object_sp)
+ {
+ StructuredData::DictionarySP target_definition_sp(
+ interpreter->GetDynamicSettings(module_object_sp, &GetTarget(), "gdb-server-target-definition", error));
+
+ if (target_definition_sp)
+ {
+ StructuredData::ObjectSP target_object(target_definition_sp->GetValueForKey("host-info"));
+ if (target_object)
+ {
+ if (auto host_info_dict = target_object->GetAsDictionary())
+ {
+ StructuredData::ObjectSP triple_value = host_info_dict->GetValueForKey("triple");
+ if (auto triple_string_value = triple_value->GetAsString())
+ {
+ std::string triple_string = triple_string_value->GetValue();
+ ArchSpec host_arch(triple_string.c_str());
+ if (!host_arch.IsCompatibleMatch(GetTarget().GetArchitecture()))
+ {
+ GetTarget().SetArchitecture(host_arch);
+ }
+ }
+ }
+ }
+ m_breakpoint_pc_offset = 0;
+ StructuredData::ObjectSP breakpoint_pc_offset_value = target_definition_sp->GetValueForKey("breakpoint-pc-offset");
+ if (breakpoint_pc_offset_value)
+ {
+ if (auto breakpoint_pc_int_value = breakpoint_pc_offset_value->GetAsInteger())
+ m_breakpoint_pc_offset = breakpoint_pc_int_value->GetValue();
+ }
+
+ if (m_register_info.SetRegisterInfo(*target_definition_sp, GetTarget().GetArchitecture()) > 0)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static size_t
+SplitCommaSeparatedRegisterNumberString(const llvm::StringRef &comma_separated_regiter_numbers, std::vector<uint32_t> &regnums, int base)
+{
+ regnums.clear();
+ std::pair<llvm::StringRef, llvm::StringRef> value_pair;
+ value_pair.second = comma_separated_regiter_numbers;
+ do
+ {
+ value_pair = value_pair.second.split(',');
+ if (!value_pair.first.empty())
+ {
+ uint32_t reg = StringConvert::ToUInt32 (value_pair.first.str().c_str(), LLDB_INVALID_REGNUM, base);
+ if (reg != LLDB_INVALID_REGNUM)
+ regnums.push_back (reg);
+ }
+ } while (!value_pair.second.empty());
+ return regnums.size();
+}
+
+
+void
+ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
+{
+ if (!force && m_register_info.GetNumRegisters() > 0)
+ return;
+
+ m_register_info.Clear();
+
+ // Check if qHostInfo specified a specific packet timeout for this connection.
+ // If so then lets update our setting so the user knows what the timeout is
+ // and can see it.
+ const uint32_t host_packet_timeout = m_gdb_comm.GetHostDefaultPacketTimeout();
+ if (host_packet_timeout)
+ {
+ GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout);
+ }
+
+ // Register info search order:
+ // 1 - Use the target definition python file if one is specified.
+ // 2 - If the target definition doesn't have any of the info from the target.xml (registers) then proceed to read the target.xml.
+ // 3 - Fall back on the qRegisterInfo packets.
+
+ FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile ();
+ if (target_definition_fspec)
+ {
+ // See if we can get register definitions from a python file
+ if (ParsePythonTargetDefinition (target_definition_fspec))
+ return;
+ }
+
+ if (GetGDBServerRegisterInfo ())
+ return;
+
+ char packet[128];
+ uint32_t reg_offset = 0;
+ uint32_t reg_num = 0;
+ for (StringExtractorGDBRemote::ResponseType response_type = StringExtractorGDBRemote::eResponse;
+ response_type == StringExtractorGDBRemote::eResponse;
+ ++reg_num)
+ {
+ const int packet_len = ::snprintf (packet, sizeof(packet), "qRegisterInfo%x", reg_num);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ response_type = response.GetResponseType();
+ if (response_type == StringExtractorGDBRemote::eResponse)
+ {
+ std::string name;
+ std::string value;
+ ConstString reg_name;
+ ConstString alt_name;
+ ConstString set_name;
+ std::vector<uint32_t> value_regs;
+ std::vector<uint32_t> invalidate_regs;
+ RegisterInfo reg_info = { NULL, // Name
+ NULL, // Alt name
+ 0, // byte size
+ reg_offset, // offset
+ eEncodingUint, // encoding
+ eFormatHex, // formate
+ {
+ LLDB_INVALID_REGNUM, // GCC reg num
+ LLDB_INVALID_REGNUM, // DWARF reg num
+ LLDB_INVALID_REGNUM, // generic reg num
+ reg_num, // GDB reg num
+ reg_num // native register number
+ },
+ NULL,
+ NULL
+ };
+
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("name") == 0)
+ {
+ reg_name.SetCString(value.c_str());
+ }
+ else if (name.compare("alt-name") == 0)
+ {
+ alt_name.SetCString(value.c_str());
+ }
+ else if (name.compare("bitsize") == 0)
+ {
+ reg_info.byte_size = StringConvert::ToUInt32(value.c_str(), 0, 0) / CHAR_BIT;
+ }
+ else if (name.compare("offset") == 0)
+ {
+ uint32_t offset = StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0);
+ if (reg_offset != offset)
+ {
+ reg_offset = offset;
+ }
+ }
+ else if (name.compare("encoding") == 0)
+ {
+ const Encoding encoding = Args::StringToEncoding (value.c_str());
+ if (encoding != eEncodingInvalid)
+ reg_info.encoding = encoding;
+ }
+ else if (name.compare("format") == 0)
+ {
+ Format format = eFormatInvalid;
+ if (Args::StringToFormat (value.c_str(), format, NULL).Success())
+ reg_info.format = format;
+ else if (value.compare("binary") == 0)
+ reg_info.format = eFormatBinary;
+ else if (value.compare("decimal") == 0)
+ reg_info.format = eFormatDecimal;
+ else if (value.compare("hex") == 0)
+ reg_info.format = eFormatHex;
+ else if (value.compare("float") == 0)
+ reg_info.format = eFormatFloat;
+ else if (value.compare("vector-sint8") == 0)
+ reg_info.format = eFormatVectorOfSInt8;
+ else if (value.compare("vector-uint8") == 0)
+ reg_info.format = eFormatVectorOfUInt8;
+ else if (value.compare("vector-sint16") == 0)
+ reg_info.format = eFormatVectorOfSInt16;
+ else if (value.compare("vector-uint16") == 0)
+ reg_info.format = eFormatVectorOfUInt16;
+ else if (value.compare("vector-sint32") == 0)
+ reg_info.format = eFormatVectorOfSInt32;
+ else if (value.compare("vector-uint32") == 0)
+ reg_info.format = eFormatVectorOfUInt32;
+ else if (value.compare("vector-float32") == 0)
+ reg_info.format = eFormatVectorOfFloat32;
+ else if (value.compare("vector-uint128") == 0)
+ reg_info.format = eFormatVectorOfUInt128;
+ }
+ else if (name.compare("set") == 0)
+ {
+ set_name.SetCString(value.c_str());
+ }
+ else if (name.compare("gcc") == 0)
+ {
+ reg_info.kinds[eRegisterKindGCC] = StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0);
+ }
+ else if (name.compare("dwarf") == 0)
+ {
+ reg_info.kinds[eRegisterKindDWARF] = StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0);
+ }
+ else if (name.compare("generic") == 0)
+ {
+ reg_info.kinds[eRegisterKindGeneric] = Args::StringToGenericRegister (value.c_str());
+ }
+ else if (name.compare("container-regs") == 0)
+ {
+ SplitCommaSeparatedRegisterNumberString(value, value_regs, 16);
+ }
+ else if (name.compare("invalidate-regs") == 0)
+ {
+ SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 16);
+ }
+ }
+
+ reg_info.byte_offset = reg_offset;
+ assert (reg_info.byte_size != 0);
+ reg_offset += reg_info.byte_size;
+ if (!value_regs.empty())
+ {
+ value_regs.push_back(LLDB_INVALID_REGNUM);
+ reg_info.value_regs = value_regs.data();
+ }
+ if (!invalidate_regs.empty())
+ {
+ invalidate_regs.push_back(LLDB_INVALID_REGNUM);
+ reg_info.invalidate_regs = invalidate_regs.data();
+ }
+
+ m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name);
+ }
+ else
+ {
+ break; // ensure exit before reg_num is incremented
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (m_register_info.GetNumRegisters() > 0)
+ {
+ m_register_info.Finalize(GetTarget().GetArchitecture());
+ return;
+ }
+
+ // We didn't get anything if the accumulated reg_num is zero. See if we are
+ // debugging ARM and fill with a hard coded register set until we can get an
+ // 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);
+
+ const ArchSpec &target_arch = GetTarget().GetArchitecture();
+ const ArchSpec &remote_host_arch = m_gdb_comm.GetHostArchitecture();
+ const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture();
+
+ // Use the process' architecture instead of the host arch, if available
+ ArchSpec remote_arch;
+ if (remote_process_arch.IsValid ())
+ remote_arch = remote_process_arch;
+ else
+ remote_arch = remote_host_arch;
+
+ if (!target_arch.IsValid())
+ {
+ if (remote_arch.IsValid()
+ && remote_arch.GetMachine() == llvm::Triple::arm
+ && remote_arch.GetTriple().getVendor() == llvm::Triple::Apple)
+ m_register_info.HardcodeARMRegisters(from_scratch);
+ }
+ else if (target_arch.GetMachine() == llvm::Triple::arm)
+ {
+ m_register_info.HardcodeARMRegisters(from_scratch);
+ }
+
+ // At this point, we can finalize our register info.
+ m_register_info.Finalize (GetTarget().GetArchitecture());
+}
+
+Error
+ProcessGDBRemote::WillLaunch (Module* module)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::WillAttachToProcessWithID (lldb::pid_t pid)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::WillAttachToProcessWithName (const char *process_name, bool wait_for_launch)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ Error error (WillLaunchOrAttach ());
+
+ if (error.Fail())
+ return error;
+
+ error = ConnectToDebugserver (remote_url);
+
+ if (error.Fail())
+ return error;
+ StartAsyncThread ();
+
+ lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID ();
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ // We don't have a valid process ID, so note that we are connected
+ // and could now request to launch or attach, or get remote process
+ // listings...
+ SetPrivateState (eStateConnected);
+ }
+ else
+ {
+ // We have a valid process
+ SetID (pid);
+ GetThreadList();
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.GetStopReply(response))
+ {
+ SetLastStopPacket(response);
+
+ // '?' Packets must be handled differently in non-stop mode
+ if (GetTarget().GetNonStopModeEnabled())
+ HandleStopReplySequence();
+
+ if (!m_target.GetArchitecture().IsValid())
+ {
+ if (m_gdb_comm.GetProcessArchitecture().IsValid())
+ {
+ m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture());
+ }
+ else
+ {
+ m_target.SetArchitecture(m_gdb_comm.GetHostArchitecture());
+ }
+ }
+
+ const StateType state = SetThreadStopInfo (response);
+ if (state == eStateStopped)
+ {
+ SetPrivateState (state);
+ }
+ else
+ error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but state was not stopped: %s", pid, remote_url, StateAsCString (state));
+ }
+ else
+ error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but no stop reply packet was received", pid, remote_url);
+ }
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalizing target architecture initial triple: %s (GetTarget().GetArchitecture().IsValid() %s, m_gdb_comm.GetHostArchitecture().IsValid(): %s)", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str (), GetTarget ().GetArchitecture ().IsValid () ? "true" : "false", m_gdb_comm.GetHostArchitecture ().IsValid () ? "true" : "false");
+
+
+ if (error.Success()
+ && !GetTarget().GetArchitecture().IsValid()
+ && m_gdb_comm.GetHostArchitecture().IsValid())
+ {
+ // Prefer the *process'* architecture over that of the *host*, if available.
+ if (m_gdb_comm.GetProcessArchitecture().IsValid())
+ GetTarget().SetArchitecture(m_gdb_comm.GetProcessArchitecture());
+ else
+ GetTarget().SetArchitecture(m_gdb_comm.GetHostArchitecture());
+ }
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalized target architecture triple: %s", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str ());
+
+ if (error.Success())
+ {
+ PlatformSP platform_sp = GetTarget().GetPlatform();
+ if (platform_sp && platform_sp->IsConnected())
+ SetUnixSignals(platform_sp->GetUnixSignals());
+ else
+ SetUnixSignals(UnixSignals::Create(GetTarget().GetArchitecture()));
+ }
+
+ return error;
+}
+
+Error
+ProcessGDBRemote::WillLaunchOrAttach ()
+{
+ Error error;
+ m_stdio_communication.Clear ();
+ return error;
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+Error
+ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info)
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ Error error;
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s() entered", __FUNCTION__);
+
+ uint32_t launch_flags = launch_info.GetFlags().Get();
+ FileSpec stdin_file_spec{};
+ FileSpec stdout_file_spec{};
+ FileSpec stderr_file_spec{};
+ FileSpec working_dir = launch_info.GetWorkingDirectory();
+
+ const FileAction *file_action;
+ file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
+ if (file_action)
+ {
+ if (file_action->GetAction() == FileAction::eFileActionOpen)
+ stdin_file_spec = file_action->GetFileSpec();
+ }
+ file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
+ if (file_action)
+ {
+ if (file_action->GetAction() == FileAction::eFileActionOpen)
+ stdout_file_spec = file_action->GetFileSpec();
+ }
+ file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
+ if (file_action)
+ {
+ if (file_action->GetAction() == FileAction::eFileActionOpen)
+ stderr_file_spec = file_action->GetFileSpec();
+ }
+
+ if (log)
+ {
+ if (stdin_file_spec || stdout_file_spec || stderr_file_spec)
+ log->Printf ("ProcessGDBRemote::%s provided with STDIO paths via launch_info: stdin=%s, stdout=%s, stderr=%s",
+ __FUNCTION__,
+ stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
+ stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
+ stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
+ else
+ log->Printf ("ProcessGDBRemote::%s no STDIO paths given via launch_info", __FUNCTION__);
+ }
+
+ const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
+ if (stdin_file_spec || disable_stdio)
+ {
+ // the inferior will be reading stdin from the specified file
+ // or stdio is completely disabled
+ m_stdin_forward = false;
+ }
+ else
+ {
+ m_stdin_forward = true;
+ }
+
+ // ::LogSetBitMask (GDBR_LOG_DEFAULT);
+ // ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD);
+ // ::LogSetLogFile ("/dev/stdout");
+
+ ObjectFile * object_file = exe_module->GetObjectFile();
+ if (object_file)
+ {
+ // Make sure we aren't already connected?
+ if (!m_gdb_comm.IsConnected())
+ {
+ error = LaunchAndConnectToDebugserver (launch_info);
+ }
+
+ if (error.Success())
+ {
+ lldb_utility::PseudoTerminal pty;
+ const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
+
+ PlatformSP platform_sp (m_target.GetPlatform());
+ if (disable_stdio)
+ {
+ // set to /dev/null unless redirected to a file above
+ if (!stdin_file_spec)
+ stdin_file_spec.SetFile("/dev/null", false);
+ if (!stdout_file_spec)
+ stdout_file_spec.SetFile("/dev/null", false);
+ if (!stderr_file_spec)
+ stderr_file_spec.SetFile("/dev/null", false);
+ }
+ else if (platform_sp && platform_sp->IsHost())
+ {
+ // If the debugserver is local and we aren't disabling STDIO, lets use
+ // a pseudo terminal to instead of relying on the 'O' packets for stdio
+ // 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.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, NULL, 0))
+ {
+ FileSpec slave_name{pty.GetSlaveName(NULL, 0), false};
+
+ if (!stdin_file_spec)
+ stdin_file_spec = slave_name;
+
+ if (!stdout_file_spec)
+ stdout_file_spec = slave_name;
+
+ if (!stderr_file_spec)
+ stderr_file_spec = slave_name;
+ }
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s adjusted STDIO paths for local platform (IsHost() is true) using slave: stdin=%s, stdout=%s, stderr=%s",
+ __FUNCTION__,
+ stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
+ stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
+ stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
+ }
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s final STDIO paths after all adjustments: stdin=%s, stdout=%s, stderr=%s",
+ __FUNCTION__,
+ stdin_file_spec ? stdin_file_spec.GetCString() : "<null>",
+ stdout_file_spec ? stdout_file_spec.GetCString() : "<null>",
+ stderr_file_spec ? stderr_file_spec.GetCString() : "<null>");
+
+ if (stdin_file_spec)
+ m_gdb_comm.SetSTDIN(stdin_file_spec);
+ if (stdout_file_spec)
+ m_gdb_comm.SetSTDOUT(stdout_file_spec);
+ if (stderr_file_spec)
+ m_gdb_comm.SetSTDERR(stderr_file_spec);
+
+ m_gdb_comm.SetDisableASLR (launch_flags & eLaunchFlagDisableASLR);
+ m_gdb_comm.SetDetachOnError (launch_flags & eLaunchFlagDetachOnError);
+
+ m_gdb_comm.SendLaunchArchPacket (m_target.GetArchitecture().GetArchitectureName());
+
+ const char * launch_event_data = launch_info.GetLaunchEventData();
+ if (launch_event_data != NULL && *launch_event_data != '\0')
+ m_gdb_comm.SendLaunchEventDataPacket (launch_event_data);
+
+ if (working_dir)
+ {
+ m_gdb_comm.SetWorkingDir (working_dir);
+ }
+
+ // Send the environment and the program + arguments after we connect
+ const Args &environment = launch_info.GetEnvironmentEntries();
+ if (environment.GetArgumentCount())
+ {
+ size_t num_environment_entries = environment.GetArgumentCount();
+ for (size_t i=0; i<num_environment_entries; ++i)
+ {
+ const char *env_entry = environment.GetArgumentAtIndex(i);
+ if (env_entry == NULL || m_gdb_comm.SendEnvironmentPacket(env_entry) != 0)
+ break;
+ }
+ }
+
+ {
+ // Scope for the scoped timeout object
+ GDBRemoteCommunication::ScopedTimeout timeout (m_gdb_comm, 10);
+
+ int arg_packet_err = m_gdb_comm.SendArgumentsPacket (launch_info);
+ if (arg_packet_err == 0)
+ {
+ std::string error_str;
+ if (m_gdb_comm.GetLaunchSuccess (error_str))
+ {
+ SetID (m_gdb_comm.GetCurrentProcessID ());
+ }
+ else
+ {
+ error.SetErrorString (error_str.c_str());
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'A' packet returned an error: %i", arg_packet_err);
+ }
+ }
+
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ if (log)
+ log->Printf("failed to connect to debugserver: %s", error.AsCString());
+ KillDebugserverProcess ();
+ return error;
+ }
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.GetStopReply(response))
+ {
+ SetLastStopPacket(response);
+ // '?' Packets must be handled differently in non-stop mode
+ if (GetTarget().GetNonStopModeEnabled())
+ HandleStopReplySequence();
+
+ const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture();
+
+ if (process_arch.IsValid())
+ {
+ m_target.MergeArchitecture(process_arch);
+ }
+ else
+ {
+ const ArchSpec &host_arch = m_gdb_comm.GetHostArchitecture();
+ if (host_arch.IsValid())
+ m_target.MergeArchitecture(host_arch);
+ }
+
+ SetPrivateState (SetThreadStopInfo (response));
+
+ if (!disable_stdio)
+ {
+ if (pty.GetMasterFileDescriptor() != lldb_utility::PseudoTerminal::invalid_fd)
+ SetSTDIOFileDescriptor (pty.ReleaseMasterFileDescriptor());
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("failed to connect to debugserver: %s", error.AsCString());
+ }
+ }
+ else
+ {
+ // Set our user ID to an invalid process ID.
+ SetID(LLDB_INVALID_PROCESS_ID);
+ error.SetErrorStringWithFormat ("failed to get object file from '%s' for arch %s",
+ exe_module->GetFileSpec().GetFilename().AsCString(),
+ exe_module->GetArchitecture().GetArchitectureName());
+ }
+ return error;
+
+}
+
+
+Error
+ProcessGDBRemote::ConnectToDebugserver (const char *connect_url)
+{
+ Error error;
+ // Only connect if we have a valid connect URL
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+
+ if (connect_url && connect_url[0])
+ {
+ if (log)
+ log->Printf("ProcessGDBRemote::%s Connecting to %s", __FUNCTION__, connect_url);
+ std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+ if (conn_ap.get())
+ {
+ const uint32_t max_retry_count = 50;
+ uint32_t retry_count = 0;
+ while (!m_gdb_comm.IsConnected())
+ {
+ if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess)
+ {
+ m_gdb_comm.SetConnection (conn_ap.release());
+ break;
+ }
+ else if (error.WasInterrupted())
+ {
+ // If we were interrupted, don't keep retrying.
+ break;
+ }
+
+ retry_count++;
+
+ if (retry_count >= max_retry_count)
+ break;
+
+ usleep (100000);
+ }
+ }
+ }
+
+ if (!m_gdb_comm.IsConnected())
+ {
+ if (error.Success())
+ error.SetErrorString("not connected to remote gdb server");
+ return error;
+ }
+
+
+ // Start the communications read thread so all incoming data can be
+ // parsed into packets and queued as they arrive.
+ if (GetTarget().GetNonStopModeEnabled())
+ m_gdb_comm.StartReadThread();
+
+ // We always seem to be able to open a connection to a local port
+ // so we need to make sure we can then send data to it. If we can't
+ // then we aren't actually connected to anything, so try and do the
+ // handshake with the remote GDB server and make sure that goes
+ // alright.
+ if (!m_gdb_comm.HandshakeWithServer (&error))
+ {
+ m_gdb_comm.Disconnect();
+ if (error.Success())
+ error.SetErrorString("not connected to remote gdb server");
+ return error;
+ }
+
+ // Send $QNonStop:1 packet on startup if required
+ if (GetTarget().GetNonStopModeEnabled())
+ GetTarget().SetNonStopModeEnabled (m_gdb_comm.SetNonStopMode(true));
+
+ m_gdb_comm.GetEchoSupported ();
+ m_gdb_comm.GetThreadSuffixSupported ();
+ m_gdb_comm.GetListThreadsInStopReplySupported ();
+ m_gdb_comm.GetHostInfo ();
+ m_gdb_comm.GetVContSupported ('c');
+ m_gdb_comm.GetVAttachOrWaitSupported();
+
+ // Ask the remote server for the default thread id
+ if (GetTarget().GetNonStopModeEnabled())
+ m_gdb_comm.GetDefaultThreadId(m_initial_tid);
+
+
+ size_t num_cmds = GetExtraStartupCommands().GetArgumentCount();
+ for (size_t idx = 0; idx < num_cmds; idx++)
+ {
+ StringExtractorGDBRemote response;
+ m_gdb_comm.SendPacketAndWaitForResponse (GetExtraStartupCommands().GetArgumentAtIndex(idx), response, false);
+ }
+ return error;
+}
+
+void
+ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch)
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::DidLaunch()");
+ if (GetID() != LLDB_INVALID_PROCESS_ID)
+ {
+ BuildDynamicRegisterInfo (false);
+
+ // See if the GDB server supports the qHostInfo information
+
+
+ // See if the GDB server supports the qProcessInfo packet, if so
+ // prefer that over the Host information as it will be more specific
+ // to our process.
+
+ const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture();
+ if (remote_process_arch.IsValid())
+ {
+ process_arch = remote_process_arch;
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s gdb-remote had process architecture, using %s %s",
+ __FUNCTION__,
+ process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "<null>",
+ process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : "<null>");
+ }
+ else
+ {
+ process_arch = m_gdb_comm.GetHostArchitecture();
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s gdb-remote did not have process architecture, using gdb-remote host architecture %s %s",
+ __FUNCTION__,
+ process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "<null>",
+ process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : "<null>");
+ }
+
+ if (process_arch.IsValid())
+ {
+ const ArchSpec &target_arch = GetTarget().GetArchitecture();
+ if (target_arch.IsValid())
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s analyzing target arch, currently %s %s",
+ __FUNCTION__,
+ target_arch.GetArchitectureName () ? target_arch.GetArchitectureName () : "<null>",
+ target_arch.GetTriple().getTriple ().c_str() ? target_arch.GetTriple().getTriple ().c_str() : "<null>");
+
+ // If the remote host is ARM and we have apple as the vendor, then
+ // ARM executables and shared libraries can have mixed ARM architectures.
+ // You can have an armv6 executable, and if the host is armv7, then the
+ // system will load the best possible architecture for all shared libraries
+ // it has, so we really need to take the remote host architecture as our
+ // defacto architecture in this case.
+
+ if (process_arch.GetMachine() == llvm::Triple::arm &&
+ process_arch.GetTriple().getVendor() == llvm::Triple::Apple)
+ {
+ GetTarget().SetArchitecture (process_arch);
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s remote process is ARM/Apple, setting target arch to %s %s",
+ __FUNCTION__,
+ process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "<null>",
+ process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : "<null>");
+ }
+ else
+ {
+ // Fill in what is missing in the triple
+ const llvm::Triple &remote_triple = process_arch.GetTriple();
+ llvm::Triple new_target_triple = target_arch.GetTriple();
+ if (new_target_triple.getVendorName().size() == 0)
+ {
+ new_target_triple.setVendor (remote_triple.getVendor());
+
+ if (new_target_triple.getOSName().size() == 0)
+ {
+ new_target_triple.setOS (remote_triple.getOS());
+
+ if (new_target_triple.getEnvironmentName().size() == 0)
+ new_target_triple.setEnvironment (remote_triple.getEnvironment());
+ }
+
+ ArchSpec new_target_arch = target_arch;
+ new_target_arch.SetTriple(new_target_triple);
+ GetTarget().SetArchitecture(new_target_arch);
+ }
+ }
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s final target arch after adjustments for remote architecture: %s %s",
+ __FUNCTION__,
+ target_arch.GetArchitectureName () ? target_arch.GetArchitectureName () : "<null>",
+ target_arch.GetTriple().getTriple ().c_str() ? target_arch.GetTriple().getTriple ().c_str() : "<null>");
+ }
+ else
+ {
+ // The target doesn't have a valid architecture yet, set it from
+ // the architecture we got from the remote GDB server
+ GetTarget().SetArchitecture (process_arch);
+ }
+ }
+ }
+}
+
+void
+ProcessGDBRemote::DidLaunch ()
+{
+ ArchSpec process_arch;
+ DidLaunchOrAttach (process_arch);
+}
+
+Error
+ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info)
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ Error error;
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s()", __FUNCTION__);
+
+ // Clear out and clean up from any current state
+ Clear();
+ if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ // Make sure we aren't already connected?
+ if (!m_gdb_comm.IsConnected())
+ {
+ error = LaunchAndConnectToDebugserver (attach_info);
+
+ if (error.Fail())
+ {
+ const char *error_string = error.AsCString();
+ if (error_string == NULL)
+ error_string = "unable to launch " DEBUGSERVER_BASENAME;
+
+ SetExitStatus (-1, error_string);
+ }
+ }
+
+ if (error.Success())
+ {
+ m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError());
+
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, attach_pid);
+ SetID (attach_pid);
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet, packet_len));
+ }
+ }
+
+ return error;
+}
+
+Error
+ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const ProcessAttachInfo &attach_info)
+{
+ Error error;
+ // Clear out and clean up from any current state
+ Clear();
+
+ if (process_name && process_name[0])
+ {
+ // Make sure we aren't already connected?
+ if (!m_gdb_comm.IsConnected())
+ {
+ error = LaunchAndConnectToDebugserver (attach_info);
+
+ if (error.Fail())
+ {
+ const char *error_string = error.AsCString();
+ if (error_string == NULL)
+ error_string = "unable to launch " DEBUGSERVER_BASENAME;
+
+ SetExitStatus (-1, error_string);
+ }
+ }
+
+ if (error.Success())
+ {
+ StreamString packet;
+
+ m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError());
+
+ if (attach_info.GetWaitForLaunch())
+ {
+ if (!m_gdb_comm.GetVAttachOrWaitSupported())
+ {
+ packet.PutCString ("vAttachWait");
+ }
+ else
+ {
+ if (attach_info.GetIgnoreExisting())
+ packet.PutCString("vAttachWait");
+ else
+ packet.PutCString ("vAttachOrWait");
+ }
+ }
+ else
+ packet.PutCString("vAttachName");
+ packet.PutChar(';');
+ packet.PutBytesAsRawHex8(process_name, strlen(process_name), lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder());
+
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet.GetData(), packet.GetSize()));
+
+ }
+ }
+ return error;
+}
+
+void
+ProcessGDBRemote::DidExit ()
+{
+ // When we exit, disconnect from the GDB server communications
+ m_gdb_comm.Disconnect();
+}
+
+void
+ProcessGDBRemote::DidAttach (ArchSpec &process_arch)
+{
+ // If you can figure out what the architecture is, fill it in here.
+ process_arch.Clear();
+ DidLaunchOrAttach (process_arch);
+}
+
+
+Error
+ProcessGDBRemote::WillResume ()
+{
+ m_continue_c_tids.clear();
+ m_continue_C_tids.clear();
+ m_continue_s_tids.clear();
+ m_continue_S_tids.clear();
+ return Error();
+}
+
+Error
+ProcessGDBRemote::DoResume ()
+{
+ Error error;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::Resume()");
+
+ Listener listener ("gdb-remote.resume-packet-sent");
+ if (listener.StartListeningForEvents (&m_gdb_comm, GDBRemoteCommunication::eBroadcastBitRunPacketSent))
+ {
+ listener.StartListeningForEvents (&m_async_broadcaster, ProcessGDBRemote::eBroadcastBitAsyncThreadDidExit);
+
+ const size_t num_threads = GetThreadList().GetSize();
+
+ StreamString continue_packet;
+ bool continue_packet_error = false;
+ if (m_gdb_comm.HasAnyVContSupport ())
+ {
+ if (!GetTarget().GetNonStopModeEnabled() &&
+ (m_continue_c_tids.size() == num_threads ||
+ (m_continue_c_tids.empty() &&
+ m_continue_C_tids.empty() &&
+ m_continue_s_tids.empty() &&
+ m_continue_S_tids.empty())))
+ {
+ // All threads are continuing, just send a "c" packet
+ continue_packet.PutCString ("c");
+ }
+ else
+ {
+ continue_packet.PutCString ("vCont");
+
+ if (!m_continue_c_tids.empty())
+ {
+ if (m_gdb_comm.GetVContSupported ('c'))
+ {
+ for (tid_collection::const_iterator t_pos = m_continue_c_tids.begin(), t_end = m_continue_c_tids.end(); t_pos != t_end; ++t_pos)
+ continue_packet.Printf(";c:%4.4" PRIx64, *t_pos);
+ }
+ else
+ continue_packet_error = true;
+ }
+
+ if (!continue_packet_error && !m_continue_C_tids.empty())
+ {
+ if (m_gdb_comm.GetVContSupported ('C'))
+ {
+ for (tid_sig_collection::const_iterator s_pos = m_continue_C_tids.begin(), s_end = m_continue_C_tids.end(); s_pos != s_end; ++s_pos)
+ continue_packet.Printf(";C%2.2x:%4.4" PRIx64, s_pos->second, s_pos->first);
+ }
+ else
+ continue_packet_error = true;
+ }
+
+ if (!continue_packet_error && !m_continue_s_tids.empty())
+ {
+ if (m_gdb_comm.GetVContSupported ('s'))
+ {
+ for (tid_collection::const_iterator t_pos = m_continue_s_tids.begin(), t_end = m_continue_s_tids.end(); t_pos != t_end; ++t_pos)
+ continue_packet.Printf(";s:%4.4" PRIx64, *t_pos);
+ }
+ else
+ continue_packet_error = true;
+ }
+
+ if (!continue_packet_error && !m_continue_S_tids.empty())
+ {
+ if (m_gdb_comm.GetVContSupported ('S'))
+ {
+ for (tid_sig_collection::const_iterator s_pos = m_continue_S_tids.begin(), s_end = m_continue_S_tids.end(); s_pos != s_end; ++s_pos)
+ continue_packet.Printf(";S%2.2x:%4.4" PRIx64, s_pos->second, s_pos->first);
+ }
+ else
+ continue_packet_error = true;
+ }
+
+ if (continue_packet_error)
+ continue_packet.GetString().clear();
+ }
+ }
+ else
+ continue_packet_error = true;
+
+ if (continue_packet_error)
+ {
+ // Either no vCont support, or we tried to use part of the vCont
+ // packet that wasn't supported by the remote GDB server.
+ // We need to try and make a simple packet that can do our continue
+ const size_t num_continue_c_tids = m_continue_c_tids.size();
+ const size_t num_continue_C_tids = m_continue_C_tids.size();
+ const size_t num_continue_s_tids = m_continue_s_tids.size();
+ const size_t num_continue_S_tids = m_continue_S_tids.size();
+ if (num_continue_c_tids > 0)
+ {
+ if (num_continue_c_tids == num_threads)
+ {
+ // All threads are resuming...
+ m_gdb_comm.SetCurrentThreadForRun (-1);
+ continue_packet.PutChar ('c');
+ continue_packet_error = false;
+ }
+ else if (num_continue_c_tids == 1 &&
+ num_continue_C_tids == 0 &&
+ num_continue_s_tids == 0 &&
+ num_continue_S_tids == 0 )
+ {
+ // Only one thread is continuing
+ m_gdb_comm.SetCurrentThreadForRun (m_continue_c_tids.front());
+ continue_packet.PutChar ('c');
+ continue_packet_error = false;
+ }
+ }
+
+ if (continue_packet_error && num_continue_C_tids > 0)
+ {
+ if ((num_continue_C_tids + num_continue_c_tids) == num_threads &&
+ num_continue_C_tids > 0 &&
+ num_continue_s_tids == 0 &&
+ num_continue_S_tids == 0 )
+ {
+ const int continue_signo = m_continue_C_tids.front().second;
+ // Only one thread is continuing
+ if (num_continue_C_tids > 1)
+ {
+ // More that one thread with a signal, yet we don't have
+ // vCont support and we are being asked to resume each
+ // thread with a signal, we need to make sure they are
+ // all the same signal, or we can't issue the continue
+ // accurately with the current support...
+ if (num_continue_C_tids > 1)
+ {
+ continue_packet_error = false;
+ for (size_t i=1; i<m_continue_C_tids.size(); ++i)
+ {
+ if (m_continue_C_tids[i].second != continue_signo)
+ continue_packet_error = true;
+ }
+ }
+ if (!continue_packet_error)
+ m_gdb_comm.SetCurrentThreadForRun (-1);
+ }
+ else
+ {
+ // Set the continue thread ID
+ continue_packet_error = false;
+ m_gdb_comm.SetCurrentThreadForRun (m_continue_C_tids.front().first);
+ }
+ if (!continue_packet_error)
+ {
+ // Add threads continuing with the same signo...
+ continue_packet.Printf("C%2.2x", continue_signo);
+ }
+ }
+ }
+
+ if (continue_packet_error && num_continue_s_tids > 0)
+ {
+ if (num_continue_s_tids == num_threads)
+ {
+ // All threads are resuming...
+ m_gdb_comm.SetCurrentThreadForRun (-1);
+
+ // If in Non-Stop-Mode use vCont when stepping
+ if (GetTarget().GetNonStopModeEnabled())
+ {
+ if (m_gdb_comm.GetVContSupported('s'))
+ continue_packet.PutCString("vCont;s");
+ else
+ continue_packet.PutChar('s');
+ }
+ else
+ continue_packet.PutChar('s');
+
+ continue_packet_error = false;
+ }
+ else if (num_continue_c_tids == 0 &&
+ num_continue_C_tids == 0 &&
+ num_continue_s_tids == 1 &&
+ num_continue_S_tids == 0 )
+ {
+ // Only one thread is stepping
+ m_gdb_comm.SetCurrentThreadForRun (m_continue_s_tids.front());
+ continue_packet.PutChar ('s');
+ continue_packet_error = false;
+ }
+ }
+
+ if (!continue_packet_error && num_continue_S_tids > 0)
+ {
+ if (num_continue_S_tids == num_threads)
+ {
+ const int step_signo = m_continue_S_tids.front().second;
+ // Are all threads trying to step with the same signal?
+ continue_packet_error = false;
+ if (num_continue_S_tids > 1)
+ {
+ for (size_t i=1; i<num_threads; ++i)
+ {
+ if (m_continue_S_tids[i].second != step_signo)
+ continue_packet_error = true;
+ }
+ }
+ if (!continue_packet_error)
+ {
+ // Add threads stepping with the same signo...
+ m_gdb_comm.SetCurrentThreadForRun (-1);
+ continue_packet.Printf("S%2.2x", step_signo);
+ }
+ }
+ else if (num_continue_c_tids == 0 &&
+ num_continue_C_tids == 0 &&
+ num_continue_s_tids == 0 &&
+ num_continue_S_tids == 1 )
+ {
+ // Only one thread is stepping with signal
+ m_gdb_comm.SetCurrentThreadForRun (m_continue_S_tids.front().first);
+ continue_packet.Printf("S%2.2x", m_continue_S_tids.front().second);
+ continue_packet_error = false;
+ }
+ }
+ }
+
+ if (continue_packet_error)
+ {
+ error.SetErrorString ("can't make continue packet for this resume");
+ }
+ else
+ {
+ EventSP event_sp;
+ TimeValue timeout;
+ timeout = TimeValue::Now();
+ timeout.OffsetWithSeconds (5);
+ if (!m_async_thread.IsJoinable())
+ {
+ error.SetErrorString ("Trying to resume but the async thread is dead.");
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoResume: Trying to resume but the async thread is dead.");
+ return error;
+ }
+
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (continue_packet.GetData(), continue_packet.GetSize()));
+
+ if (listener.WaitForEvent (&timeout, event_sp) == false)
+ {
+ error.SetErrorString("Resume timed out.");
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoResume: Resume timed out.");
+ }
+ else if (event_sp->BroadcasterIs (&m_async_broadcaster))
+ {
+ error.SetErrorString ("Broadcast continue, but the async thread was killed before we got an ack back.");
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoResume: Broadcast continue, but the async thread was killed before we got an ack back.");
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+
+void
+ProcessGDBRemote::HandleStopReplySequence ()
+{
+ while(true)
+ {
+ // Send vStopped
+ StringExtractorGDBRemote response;
+ m_gdb_comm.SendPacketAndWaitForResponse("vStopped", response, false);
+
+ // OK represents end of signal list
+ if (response.IsOKResponse())
+ break;
+
+ // If not OK or a normal packet we have a problem
+ if (!response.IsNormalResponse())
+ break;
+
+ SetLastStopPacket(response);
+ }
+}
+
+void
+ProcessGDBRemote::ClearThreadIDList ()
+{
+ Mutex::Locker locker(m_thread_list_real.GetMutex());
+ m_thread_ids.clear();
+}
+
+size_t
+ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue (std::string &value)
+{
+ m_thread_ids.clear();
+ size_t comma_pos;
+ lldb::tid_t tid;
+ while ((comma_pos = value.find(',')) != std::string::npos)
+ {
+ value[comma_pos] = '\0';
+ // thread in big endian hex
+ tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
+ if (tid != LLDB_INVALID_THREAD_ID)
+ m_thread_ids.push_back (tid);
+ value.erase(0, comma_pos + 1);
+ }
+ tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
+ if (tid != LLDB_INVALID_THREAD_ID)
+ m_thread_ids.push_back (tid);
+ return m_thread_ids.size();
+}
+
+bool
+ProcessGDBRemote::UpdateThreadIDList ()
+{
+ Mutex::Locker locker(m_thread_list_real.GetMutex());
+
+ if (m_threads_info_sp)
+ {
+ // If we have the JSON threads info, we can get the thread list from that
+ StructuredData::Array *thread_infos = m_threads_info_sp->GetAsArray();
+ if (thread_infos && thread_infos->GetSize() > 0)
+ {
+ m_thread_ids.clear();
+ thread_infos->ForEach([this](StructuredData::Object* object) -> bool {
+ StructuredData::Dictionary *thread_dict = object->GetAsDictionary();
+ if (thread_dict)
+ {
+ // Set the thread stop info from the JSON dictionary
+ SetThreadStopInfo (thread_dict);
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+ if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>("tid", tid))
+ m_thread_ids.push_back(tid);
+ }
+ return true; // Keep iterating through all thread_info objects
+ });
+ }
+ if (!m_thread_ids.empty())
+ return true;
+ }
+ else
+ {
+ // See if we can get the thread IDs from the current stop reply packets
+ // that might contain a "threads" key/value pair
+
+ // Lock the thread stack while we access it
+ Mutex::Locker stop_stack_lock(m_last_stop_packet_mutex);
+ // Get the number of stop packets on the stack
+ int nItems = m_stop_packet_stack.size();
+ // Iterate over them
+ for (int i = 0; i < nItems; i++)
+ {
+ // Get the thread stop info
+ StringExtractorGDBRemote &stop_info = m_stop_packet_stack[i];
+ const std::string &stop_info_str = stop_info.GetStringRef();
+ const size_t threads_pos = stop_info_str.find(";threads:");
+ if (threads_pos != std::string::npos)
+ {
+ const size_t start = threads_pos + strlen(";threads:");
+ const size_t end = stop_info_str.find(';', start);
+ if (end != std::string::npos)
+ {
+ std::string value = stop_info_str.substr(start, end - start);
+ if (UpdateThreadIDsFromStopReplyThreadsValue(value))
+ return true;
+ }
+ }
+ }
+ }
+
+ bool sequence_mutex_unavailable = false;
+ m_gdb_comm.GetCurrentThreadIDs (m_thread_ids, sequence_mutex_unavailable);
+ if (sequence_mutex_unavailable)
+ {
+ return false; // We just didn't get the list
+ }
+ return true;
+}
+
+bool
+ProcessGDBRemote::UpdateThreadList (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));
+ if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
+ log->Printf ("ProcessGDBRemote::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID());
+
+ size_t num_thread_ids = m_thread_ids.size();
+ // The "m_thread_ids" thread ID list should always be updated after each stop
+ // reply packet, but in case it isn't, update it here.
+ if (num_thread_ids == 0)
+ {
+ if (!UpdateThreadIDList ())
+ return false;
+ num_thread_ids = m_thread_ids.size();
+ }
+
+ ThreadList old_thread_list_copy(old_thread_list);
+ if (num_thread_ids > 0)
+ {
+ for (size_t i=0; i<num_thread_ids; ++i)
+ {
+ tid_t tid = m_thread_ids[i];
+ ThreadSP thread_sp (old_thread_list_copy.RemoveThreadByProtocolID(tid, false));
+ if (!thread_sp)
+ {
+ thread_sp.reset (new ThreadGDBRemote (*this, tid));
+ if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
+ log->Printf(
+ "ProcessGDBRemote::%s Making new thread: %p for thread ID: 0x%" PRIx64 ".\n",
+ __FUNCTION__, static_cast<void*>(thread_sp.get()),
+ thread_sp->GetID());
+ }
+ else
+ {
+ if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
+ log->Printf(
+ "ProcessGDBRemote::%s Found old thread: %p for thread ID: 0x%" PRIx64 ".\n",
+ __FUNCTION__, static_cast<void*>(thread_sp.get()),
+ thread_sp->GetID());
+ }
+ new_thread_list.AddThread(thread_sp);
+ }
+ }
+
+ // Whatever that is left in old_thread_list_copy are not
+ // present in new_thread_list. Remove non-existent threads from internal id table.
+ size_t old_num_thread_ids = old_thread_list_copy.GetSize(false);
+ for (size_t i=0; i<old_num_thread_ids; i++)
+ {
+ ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex (i, false));
+ if (old_thread_sp)
+ {
+ lldb::tid_t old_thread_id = old_thread_sp->GetProtocolID();
+ m_thread_id_to_index_id_map.erase(old_thread_id);
+ }
+ }
+
+ return true;
+}
+
+bool
+ProcessGDBRemote::CalculateThreadStopInfo (ThreadGDBRemote *thread)
+{
+ // See if we got thread stop infos for all threads via the "jThreadsInfo" packet
+ if (m_threads_info_sp)
+ {
+ StructuredData::Array *thread_infos = m_threads_info_sp->GetAsArray();
+ if (thread_infos)
+ {
+ lldb::tid_t tid;
+ const size_t n = thread_infos->GetSize();
+ for (size_t i=0; i<n; ++i)
+ {
+ StructuredData::Dictionary *thread_dict = thread_infos->GetItemAtIndex(i)->GetAsDictionary();
+ if (thread_dict)
+ {
+ if (thread_dict->GetValueForKeyAsInteger<lldb::tid_t>("tid", tid, LLDB_INVALID_THREAD_ID))
+ {
+ if (tid == thread->GetID())
+ return SetThreadStopInfo(thread_dict);
+ }
+ }
+ }
+ }
+ }
+
+ // Fall back to using the qThreadStopInfo packet
+ StringExtractorGDBRemote stop_packet;
+ if (GetGDBRemote().GetThreadStopInfo(thread->GetProtocolID(), stop_packet))
+ return SetThreadStopInfo (stop_packet) == eStateStopped;
+ return false;
+}
+
+
+ThreadSP
+ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid,
+ ExpeditedRegisterMap &expedited_register_map,
+ uint8_t signo,
+ const std::string &thread_name,
+ const std::string &reason,
+ const std::string &description,
+ uint32_t exc_type,
+ const std::vector<addr_t> &exc_data,
+ addr_t thread_dispatch_qaddr,
+ bool queue_vars_valid, // Set to true if queue_name, queue_kind and queue_serial are valid
+ std::string &queue_name,
+ QueueKind queue_kind,
+ uint64_t queue_serial)
+{
+ ThreadSP thread_sp;
+ if (tid != LLDB_INVALID_THREAD_ID)
+ {
+ // Scope for "locker" below
+ {
+ // m_thread_list_real does have its own mutex, but we need to
+ // hold onto the mutex between the call to m_thread_list_real.FindThreadByID(...)
+ // and the m_thread_list_real.AddThread(...) so it doesn't change on us
+ Mutex::Locker locker (m_thread_list_real.GetMutex ());
+ thread_sp = m_thread_list_real.FindThreadByProtocolID(tid, false);
+
+ if (!thread_sp)
+ {
+ // Create the thread if we need to
+ thread_sp.reset (new ThreadGDBRemote (*this, tid));
+ m_thread_list_real.AddThread(thread_sp);
+ }
+ }
+
+ if (thread_sp)
+ {
+ ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get());
+ gdb_thread->GetRegisterContext()->InvalidateIfNeeded(true);
+
+ for (const auto &pair : expedited_register_map)
+ {
+ StringExtractor reg_value_extractor;
+ reg_value_extractor.GetStringRef() = pair.second;
+ gdb_thread->PrivateSetRegisterValue (pair.first, reg_value_extractor);
+ }
+
+ // Clear the stop info just in case we don't set it to anything
+ thread_sp->SetStopInfo (StopInfoSP());
+ thread_sp->SetName (thread_name.empty() ? NULL : thread_name.c_str());
+
+ gdb_thread->SetThreadDispatchQAddr (thread_dispatch_qaddr);
+ // Check if the GDB server was able to provide the queue name, kind and serial number
+ if (queue_vars_valid)
+ gdb_thread->SetQueueInfo(std::move(queue_name), queue_kind, queue_serial);
+ else
+ gdb_thread->ClearQueueInfo();
+
+
+ if (exc_type != 0)
+ {
+ const size_t exc_data_size = exc_data.size();
+
+ thread_sp->SetStopInfo (StopInfoMachException::CreateStopReasonWithMachException (*thread_sp,
+ exc_type,
+ exc_data_size,
+ exc_data_size >= 1 ? exc_data[0] : 0,
+ exc_data_size >= 2 ? exc_data[1] : 0,
+ exc_data_size >= 3 ? exc_data[2] : 0));
+ }
+ else
+ {
+ bool handled = false;
+ bool did_exec = false;
+ if (!reason.empty())
+ {
+ if (reason.compare("trace") == 0)
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp));
+ handled = true;
+ }
+ else if (reason.compare("breakpoint") == 0)
+ {
+ addr_t pc = thread_sp->GetRegisterContext()->GetPC();
+ lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
+ if (bp_site_sp)
+ {
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ handled = true;
+ if (bp_site_sp->ValidForThisThread (thread_sp.get()))
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID()));
+ }
+ else
+ {
+ StopInfoSP invalid_stop_info_sp;
+ thread_sp->SetStopInfo (invalid_stop_info_sp);
+ }
+ }
+ }
+ else if (reason.compare("trap") == 0)
+ {
+ // Let the trap just use the standard signal stop reason below...
+ }
+ else if (reason.compare("watchpoint") == 0)
+ {
+ StringExtractor desc_extractor(description.c_str());
+ addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);
+ uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32);
+ addr_t wp_hit_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);
+ watch_id_t watch_id = LLDB_INVALID_WATCH_ID;
+ if (wp_addr != LLDB_INVALID_ADDRESS)
+ {
+ WatchpointSP wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr);
+ if (wp_sp)
+ {
+ wp_sp->SetHardwareIndex(wp_index);
+ watch_id = wp_sp->GetID();
+ }
+ }
+ if (watch_id == LLDB_INVALID_WATCH_ID)
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_WATCHPOINTS));
+ if (log) log->Printf ("failed to find watchpoint");
+ }
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID (*thread_sp, watch_id, wp_hit_addr));
+ handled = true;
+ }
+ else if (reason.compare("exception") == 0)
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException(*thread_sp, description.c_str()));
+ handled = true;
+ }
+ else if (reason.compare("exec") == 0)
+ {
+ did_exec = true;
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithExec(*thread_sp));
+ handled = true;
+ }
+ }
+
+ if (!handled && signo && did_exec == false)
+ {
+ if (signo == SIGTRAP)
+ {
+ // Currently we are going to assume SIGTRAP means we are either
+ // hitting a breakpoint or hardware single stepping.
+ handled = true;
+ addr_t pc = thread_sp->GetRegisterContext()->GetPC() + m_breakpoint_pc_offset;
+ lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
+
+ if (bp_site_sp)
+ {
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ if (bp_site_sp->ValidForThisThread (thread_sp.get()))
+ {
+ if(m_breakpoint_pc_offset != 0)
+ thread_sp->GetRegisterContext()->SetPC(pc);
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID()));
+ }
+ else
+ {
+ StopInfoSP invalid_stop_info_sp;
+ thread_sp->SetStopInfo (invalid_stop_info_sp);
+ }
+ }
+ else
+ {
+ // If we were stepping then assume the stop was the result of the trace. If we were
+ // not stepping then report the SIGTRAP.
+ // FIXME: We are still missing the case where we single step over a trap instruction.
+ if (thread_sp->GetTemporaryResumeState() == eStateStepping)
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp));
+ else
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal(*thread_sp, signo, description.c_str()));
+ }
+ }
+ if (!handled)
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal (*thread_sp, signo, description.c_str()));
+ }
+
+ if (!description.empty())
+ {
+ lldb::StopInfoSP stop_info_sp (thread_sp->GetStopInfo ());
+ if (stop_info_sp)
+ {
+ const char *stop_info_desc = stop_info_sp->GetDescription();
+ if (!stop_info_desc || !stop_info_desc[0])
+ stop_info_sp->SetDescription (description.c_str());
+ }
+ else
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException (*thread_sp, description.c_str()));
+ }
+ }
+ }
+ }
+ }
+ return thread_sp;
+}
+
+StateType
+ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict)
+{
+ static ConstString g_key_tid("tid");
+ static ConstString g_key_name("name");
+ static ConstString g_key_reason("reason");
+ static ConstString g_key_metype("metype");
+ static ConstString g_key_medata("medata");
+ static ConstString g_key_qaddr("qaddr");
+ static ConstString g_key_queue_name("qname");
+ static ConstString g_key_queue_kind("qkind");
+ static ConstString g_key_queue_serial("qserial");
+ static ConstString g_key_registers("registers");
+ static ConstString g_key_memory("memory");
+ static ConstString g_key_address("address");
+ static ConstString g_key_bytes("bytes");
+ static ConstString g_key_description("description");
+
+ // Stop with signal and thread info
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+ uint8_t signo = 0;
+ std::string value;
+ std::string thread_name;
+ std::string reason;
+ std::string description;
+ uint32_t exc_type = 0;
+ std::vector<addr_t> exc_data;
+ addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS;
+ ExpeditedRegisterMap expedited_register_map;
+ bool queue_vars_valid = false;
+ std::string queue_name;
+ QueueKind queue_kind = eQueueKindUnknown;
+ uint64_t queue_serial = 0;
+ // Iterate through all of the thread dictionary key/value pairs from the structured data dictionary
+
+ thread_dict->ForEach([this,
+ &tid,
+ &expedited_register_map,
+ &thread_name,
+ &signo,
+ &reason,
+ &description,
+ &exc_type,
+ &exc_data,
+ &thread_dispatch_qaddr,
+ &queue_vars_valid,
+ &queue_name,
+ &queue_kind,
+ &queue_serial]
+ (ConstString key, StructuredData::Object* object) -> bool
+ {
+ if (key == g_key_tid)
+ {
+ // thread in big endian hex
+ tid = object->GetIntegerValue(LLDB_INVALID_THREAD_ID);
+ }
+ else if (key == g_key_metype)
+ {
+ // exception type in big endian hex
+ exc_type = object->GetIntegerValue(0);
+ }
+ else if (key == g_key_medata)
+ {
+ // exception data in big endian hex
+ StructuredData::Array *array = object->GetAsArray();
+ if (array)
+ {
+ array->ForEach([&exc_data](StructuredData::Object* object) -> bool {
+ exc_data.push_back(object->GetIntegerValue());
+ return true; // Keep iterating through all array items
+ });
+ }
+ }
+ else if (key == g_key_name)
+ {
+ thread_name = std::move(object->GetStringValue());
+ }
+ else if (key == g_key_qaddr)
+ {
+ thread_dispatch_qaddr = object->GetIntegerValue(LLDB_INVALID_ADDRESS);
+ }
+ else if (key == g_key_queue_name)
+ {
+ queue_vars_valid = true;
+ queue_name = std::move(object->GetStringValue());
+ }
+ else if (key == g_key_queue_kind)
+ {
+ std::string queue_kind_str = object->GetStringValue();
+ if (queue_kind_str == "serial")
+ {
+ queue_vars_valid = true;
+ queue_kind = eQueueKindSerial;
+ }
+ else if (queue_kind_str == "concurrent")
+ {
+ queue_vars_valid = true;
+ queue_kind = eQueueKindConcurrent;
+ }
+ }
+ else if (key == g_key_queue_serial)
+ {
+ queue_serial = object->GetIntegerValue(0);
+ if (queue_serial != 0)
+ queue_vars_valid = true;
+ }
+ else if (key == g_key_reason)
+ {
+ reason = std::move(object->GetStringValue());
+ }
+ else if (key == g_key_description)
+ {
+ description = std::move(object->GetStringValue());
+ }
+ else if (key == g_key_registers)
+ {
+ StructuredData::Dictionary *registers_dict = object->GetAsDictionary();
+
+ if (registers_dict)
+ {
+ registers_dict->ForEach([&expedited_register_map](ConstString key, StructuredData::Object* object) -> bool {
+ const uint32_t reg = StringConvert::ToUInt32 (key.GetCString(), UINT32_MAX, 10);
+ if (reg != UINT32_MAX)
+ expedited_register_map[reg] = std::move(object->GetStringValue());
+ return true; // Keep iterating through all array items
+ });
+ }
+ }
+ else if (key == g_key_memory)
+ {
+ StructuredData::Array *array = object->GetAsArray();
+ if (array)
+ {
+ array->ForEach([this](StructuredData::Object* object) -> bool {
+ StructuredData::Dictionary *mem_cache_dict = object->GetAsDictionary();
+ if (mem_cache_dict)
+ {
+ lldb::addr_t mem_cache_addr = LLDB_INVALID_ADDRESS;
+ if (mem_cache_dict->GetValueForKeyAsInteger<lldb::addr_t>("address", mem_cache_addr))
+ {
+ if (mem_cache_addr != LLDB_INVALID_ADDRESS)
+ {
+ StringExtractor bytes;
+ if (mem_cache_dict->GetValueForKeyAsString("bytes", bytes.GetStringRef()))
+ {
+ bytes.SetFilePos(0);
+
+ const size_t byte_size = bytes.GetStringRef().size()/2;
+ DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0));
+ const size_t bytes_copied = bytes.GetHexBytes (data_buffer_sp->GetBytes(), byte_size, 0);
+ if (bytes_copied == byte_size)
+ m_memory_cache.AddL1CacheData(mem_cache_addr, data_buffer_sp);
+ }
+ }
+ }
+ }
+ return true; // Keep iterating through all array items
+ });
+ }
+
+ }
+ return true; // Keep iterating through all dictionary key/value pairs
+ });
+
+ SetThreadStopInfo (tid,
+ expedited_register_map,
+ signo,
+ thread_name,
+ reason,
+ description,
+ exc_type,
+ exc_data,
+ thread_dispatch_qaddr,
+ queue_vars_valid,
+ queue_name,
+ queue_kind,
+ queue_serial);
+
+ return eStateExited;
+}
+
+StateType
+ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
+{
+ stop_packet.SetFilePos (0);
+ const char stop_type = stop_packet.GetChar();
+ switch (stop_type)
+ {
+ case 'T':
+ case 'S':
+ {
+ // This is a bit of a hack, but is is required. If we did exec, we
+ // need to clear our thread lists and also know to rebuild our dynamic
+ // register info before we lookup and threads and populate the expedited
+ // register values so we need to know this right away so we can cleanup
+ // and update our registers.
+ const uint32_t stop_id = GetStopID();
+ if (stop_id == 0)
+ {
+ // Our first stop, make sure we have a process ID, and also make
+ // sure we know about our registers
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID ();
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ SetID (pid);
+ }
+ BuildDynamicRegisterInfo (true);
+ }
+ // Stop with signal and thread info
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+ const uint8_t signo = stop_packet.GetHexU8();
+ std::string key;
+ std::string value;
+ std::string thread_name;
+ std::string reason;
+ std::string description;
+ uint32_t exc_type = 0;
+ std::vector<addr_t> exc_data;
+ addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS;
+ bool queue_vars_valid = false; // says if locals below that start with "queue_" are valid
+ std::string queue_name;
+ QueueKind queue_kind = eQueueKindUnknown;
+ uint64_t queue_serial = 0;
+ ExpeditedRegisterMap expedited_register_map;
+ while (stop_packet.GetNameColonValue(key, value))
+ {
+ if (key.compare("metype") == 0)
+ {
+ // exception type in big endian hex
+ exc_type = StringConvert::ToUInt32 (value.c_str(), 0, 16);
+ }
+ else if (key.compare("medata") == 0)
+ {
+ // exception data in big endian hex
+ exc_data.push_back(StringConvert::ToUInt64 (value.c_str(), 0, 16));
+ }
+ else if (key.compare("thread") == 0)
+ {
+ // thread in big endian hex
+ tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
+ }
+ else if (key.compare("threads") == 0)
+ {
+ Mutex::Locker locker(m_thread_list_real.GetMutex());
+ m_thread_ids.clear();
+ // A comma separated list of all threads in the current
+ // process that includes the thread for this stop reply
+ // packet
+ size_t comma_pos;
+ lldb::tid_t tid;
+ while ((comma_pos = value.find(',')) != std::string::npos)
+ {
+ value[comma_pos] = '\0';
+ // thread in big endian hex
+ tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
+ if (tid != LLDB_INVALID_THREAD_ID)
+ m_thread_ids.push_back (tid);
+ value.erase(0, comma_pos + 1);
+ }
+ tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
+ if (tid != LLDB_INVALID_THREAD_ID)
+ m_thread_ids.push_back (tid);
+ }
+ else if (key.compare("hexname") == 0)
+ {
+ StringExtractor name_extractor;
+ // Swap "value" over into "name_extractor"
+ name_extractor.GetStringRef().swap(value);
+ // Now convert the HEX bytes into a string value
+ name_extractor.GetHexByteString (value);
+ thread_name.swap (value);
+ }
+ else if (key.compare("name") == 0)
+ {
+ thread_name.swap (value);
+ }
+ else if (key.compare("qaddr") == 0)
+ {
+ thread_dispatch_qaddr = StringConvert::ToUInt64 (value.c_str(), 0, 16);
+ }
+ else if (key.compare("qname") == 0)
+ {
+ queue_vars_valid = true;
+ StringExtractor name_extractor;
+ // Swap "value" over into "name_extractor"
+ name_extractor.GetStringRef().swap(value);
+ // Now convert the HEX bytes into a string value
+ name_extractor.GetHexByteString (value);
+ queue_name.swap (value);
+ }
+ else if (key.compare("qkind") == 0)
+ {
+ if (value == "serial")
+ {
+ queue_vars_valid = true;
+ queue_kind = eQueueKindSerial;
+ }
+ else if (value == "concurrent")
+ {
+ queue_vars_valid = true;
+ queue_kind = eQueueKindConcurrent;
+ }
+ }
+ else if (key.compare("qserial") == 0)
+ {
+ queue_serial = StringConvert::ToUInt64 (value.c_str(), 0, 0);
+ if (queue_serial != 0)
+ queue_vars_valid = true;
+ }
+ else if (key.compare("reason") == 0)
+ {
+ reason.swap(value);
+ }
+ else if (key.compare("description") == 0)
+ {
+ StringExtractor desc_extractor;
+ // Swap "value" over into "name_extractor"
+ desc_extractor.GetStringRef().swap(value);
+ // Now convert the HEX bytes into a string value
+ desc_extractor.GetHexByteString (value);
+ description.swap(value);
+ }
+ else if (key.compare("memory") == 0)
+ {
+ // Expedited memory. GDB servers can choose to send back expedited memory
+ // that can populate the L1 memory cache in the process so that things like
+ // the frame pointer backchain can be expedited. This will help stack
+ // backtracing be more efficient by not having to send as many memory read
+ // requests down the remote GDB server.
+
+ // Key/value pair format: memory:<addr>=<bytes>;
+ // <addr> is a number whose base will be interpreted by the prefix:
+ // "0x[0-9a-fA-F]+" for hex
+ // "0[0-7]+" for octal
+ // "[1-9]+" for decimal
+ // <bytes> is native endian ASCII hex bytes just like the register values
+ llvm::StringRef value_ref(value);
+ std::pair<llvm::StringRef, llvm::StringRef> pair;
+ pair = value_ref.split('=');
+ if (!pair.first.empty() && !pair.second.empty())
+ {
+ std::string addr_str(pair.first.str());
+ const lldb::addr_t mem_cache_addr = StringConvert::ToUInt64(addr_str.c_str(), LLDB_INVALID_ADDRESS, 0);
+ if (mem_cache_addr != LLDB_INVALID_ADDRESS)
+ {
+ StringExtractor bytes;
+ bytes.GetStringRef() = std::move(pair.second.str());
+ const size_t byte_size = bytes.GetStringRef().size()/2;
+ DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0));
+ const size_t bytes_copied = bytes.GetHexBytes (data_buffer_sp->GetBytes(), byte_size, 0);
+ if (bytes_copied == byte_size)
+ m_memory_cache.AddL1CacheData(mem_cache_addr, data_buffer_sp);
+ }
+ }
+ }
+ else if (key.compare("watch") == 0 || key.compare("rwatch") == 0 || key.compare("awatch") == 0)
+ {
+ // Support standard GDB remote stop reply packet 'TAAwatch:addr'
+ lldb::addr_t wp_addr = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16);
+ WatchpointSP wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr);
+ uint32_t wp_index = LLDB_INVALID_INDEX32;
+
+ if (wp_sp)
+ wp_index = wp_sp->GetHardwareIndex();
+
+ reason = "watchpoint";
+ StreamString ostr;
+ ostr.Printf("%" PRIu64 " %" PRIu32, wp_addr, wp_index);
+ description = ostr.GetString().c_str();
+ }
+ else if (key.size() == 2 && ::isxdigit(key[0]) && ::isxdigit(key[1]))
+ {
+ uint32_t reg = StringConvert::ToUInt32 (key.c_str(), UINT32_MAX, 16);
+ if (reg != UINT32_MAX)
+ expedited_register_map[reg] = std::move(value);
+ }
+ }
+
+ if (tid == LLDB_INVALID_THREAD_ID)
+ {
+ // A thread id may be invalid if the response is old style 'S' packet which does not provide the
+ // thread information. So update the thread list and choose the first one.
+ UpdateThreadIDList ();
+
+ if (!m_thread_ids.empty ())
+ {
+ tid = m_thread_ids.front ();
+ }
+ }
+
+ ThreadSP thread_sp = SetThreadStopInfo (tid,
+ expedited_register_map,
+ signo,
+ thread_name,
+ reason,
+ description,
+ exc_type,
+ exc_data,
+ thread_dispatch_qaddr,
+ queue_vars_valid,
+ queue_name,
+ queue_kind,
+ queue_serial);
+
+ return eStateStopped;
+ }
+ break;
+
+ case 'W':
+ case 'X':
+ // process exited
+ return eStateExited;
+
+ default:
+ break;
+ }
+ return eStateInvalid;
+}
+
+void
+ProcessGDBRemote::RefreshStateAfterStop ()
+{
+ Mutex::Locker locker(m_thread_list_real.GetMutex());
+ m_thread_ids.clear();
+ // Set the thread stop info. It might have a "threads" key whose value is
+ // a list of all thread IDs in the current process, so m_thread_ids might
+ // get set.
+
+ // Scope for the lock
+ {
+ // Lock the thread stack while we access it
+ Mutex::Locker stop_stack_lock(m_last_stop_packet_mutex);
+ // Get the number of stop packets on the stack
+ int nItems = m_stop_packet_stack.size();
+ // Iterate over them
+ for (int i = 0; i < nItems; i++)
+ {
+ // Get the thread stop info
+ StringExtractorGDBRemote stop_info = m_stop_packet_stack[i];
+ // Process thread stop info
+ SetThreadStopInfo(stop_info);
+ }
+ // Clear the thread stop stack
+ m_stop_packet_stack.clear();
+ }
+
+ // Check to see if SetThreadStopInfo() filled in m_thread_ids?
+ if (m_thread_ids.empty())
+ {
+ // No, we need to fetch the thread list manually
+ UpdateThreadIDList();
+ }
+
+ // If we have queried for a default thread id
+ if (m_initial_tid != LLDB_INVALID_THREAD_ID)
+ {
+ m_thread_list.SetSelectedThreadByID(m_initial_tid);
+ m_initial_tid = LLDB_INVALID_THREAD_ID;
+ }
+
+ // Fetch the threads via an efficient packet that gets stop infos for all threads
+ // only if we have more than one thread
+ if (m_thread_ids.size() > 1)
+ m_threads_info_sp = m_gdb_comm.GetThreadsInfo();
+
+ // Let all threads recover from stopping and do any clean up based
+ // on the previous thread state (if any).
+ m_thread_list_real.RefreshStateAfterStop();
+
+}
+
+Error
+ProcessGDBRemote::DoHalt (bool &caused_stop)
+{
+ Error error;
+
+ bool timed_out = false;
+ Mutex::Locker locker;
+
+ if (m_public_state.GetValue() == eStateAttaching)
+ {
+ // We are being asked to halt during an attach. We need to just close
+ // our file handle and debugserver will go away, and we can be done...
+ m_gdb_comm.Disconnect();
+ }
+ else
+ {
+ if (!m_gdb_comm.SendInterrupt (locker, 2, timed_out))
+ {
+ if (timed_out)
+ error.SetErrorString("timed out sending interrupt packet");
+ else
+ error.SetErrorString("unknown error sending interrupt packet");
+ }
+
+ caused_stop = m_gdb_comm.GetInterruptWasSent ();
+ }
+ return error;
+}
+
+Error
+ProcessGDBRemote::DoDetach(bool keep_stopped)
+{
+ Error error;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDetach(keep_stopped: %i)", keep_stopped);
+
+ error = m_gdb_comm.Detach (keep_stopped);
+ if (log)
+ {
+ if (error.Success())
+ log->PutCString ("ProcessGDBRemote::DoDetach() detach packet sent successfully");
+ else
+ log->Printf ("ProcessGDBRemote::DoDetach() detach packet send failed: %s", error.AsCString() ? error.AsCString() : "<unknown error>");
+ }
+
+ if (!error.Success())
+ return error;
+
+ // Sleep for one second to let the process get all detached...
+ StopAsyncThread ();
+
+ SetPrivateState (eStateDetached);
+ ResumePrivateStateThread();
+
+ //KillDebugserverProcess ();
+ return error;
+}
+
+
+Error
+ProcessGDBRemote::DoDestroy ()
+{
+ Error error;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy()");
+
+#if 0 // XXX Currently no iOS target support on FreeBSD
+ // There is a bug in older iOS debugservers where they don't shut down the process
+ // they are debugging properly. If the process is sitting at a breakpoint or an exception,
+ // this can cause problems with restarting. So we check to see if any of our threads are stopped
+ // at a breakpoint, and if so we remove all the breakpoints, resume the process, and THEN
+ // destroy it again.
+ //
+ // Note, we don't have a good way to test the version of debugserver, but I happen to know that
+ // the set of all the iOS debugservers which don't support GetThreadSuffixSupported() and that of
+ // the debugservers with this bug are equal. There really should be a better way to test this!
+ //
+ // We also use m_destroy_tried_resuming to make sure we only do this once, if we resume and then halt and
+ // get called here to destroy again and we're still at a breakpoint or exception, then we should
+ // just do the straight-forward kill.
+ //
+ // And of course, if we weren't able to stop the process by the time we get here, it isn't
+ // necessary (or helpful) to do any of this.
+
+ if (!m_gdb_comm.GetThreadSuffixSupported() && m_public_state.GetValue() != eStateRunning)
+ {
+ PlatformSP platform_sp = GetTarget().GetPlatform();
+
+ // FIXME: These should be ConstStrings so we aren't doing strcmp'ing.
+ if (platform_sp
+ && platform_sp->GetName()
+ && platform_sp->GetName() == PlatformRemoteiOS::GetPluginNameStatic())
+ {
+ if (m_destroy_tried_resuming)
+ {
+ if (log)
+ log->PutCString ("ProcessGDBRemote::DoDestroy() - Tried resuming to destroy once already, not doing it again.");
+ }
+ else
+ {
+ // At present, the plans are discarded and the breakpoints disabled Process::Destroy,
+ // but we really need it to happen here and it doesn't matter if we do it twice.
+ m_thread_list.DiscardThreadPlans();
+ DisableAllBreakpointSites();
+
+ bool stop_looks_like_crash = false;
+ ThreadList &threads = GetThreadList();
+
+ {
+ Mutex::Locker locker(threads.GetMutex());
+
+ size_t num_threads = threads.GetSize();
+ for (size_t i = 0; i < num_threads; i++)
+ {
+ ThreadSP thread_sp = threads.GetThreadAtIndex(i);
+ StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo();
+ StopReason reason = eStopReasonInvalid;
+ if (stop_info_sp)
+ reason = stop_info_sp->GetStopReason();
+ if (reason == eStopReasonBreakpoint
+ || reason == eStopReasonException)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy() - thread: 0x%4.4" PRIx64 " stopped with reason: %s.",
+ thread_sp->GetProtocolID(),
+ stop_info_sp->GetDescription());
+ stop_looks_like_crash = true;
+ break;
+ }
+ }
+ }
+
+ if (stop_looks_like_crash)
+ {
+ if (log)
+ log->PutCString ("ProcessGDBRemote::DoDestroy() - Stopped at a breakpoint, continue and then kill.");
+ m_destroy_tried_resuming = true;
+
+ // If we are going to run again before killing, it would be good to suspend all the threads
+ // before resuming so they won't get into more trouble. Sadly, for the threads stopped with
+ // the breakpoint or exception, the exception doesn't get cleared if it is suspended, so we do
+ // have to run the risk of letting those threads proceed a bit.
+
+ {
+ Mutex::Locker locker(threads.GetMutex());
+
+ size_t num_threads = threads.GetSize();
+ for (size_t i = 0; i < num_threads; i++)
+ {
+ ThreadSP thread_sp = threads.GetThreadAtIndex(i);
+ StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo();
+ StopReason reason = eStopReasonInvalid;
+ if (stop_info_sp)
+ reason = stop_info_sp->GetStopReason();
+ if (reason != eStopReasonBreakpoint
+ && reason != eStopReasonException)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy() - Suspending thread: 0x%4.4" PRIx64 " before running.",
+ thread_sp->GetProtocolID());
+ thread_sp->SetResumeState(eStateSuspended);
+ }
+ }
+ }
+ Resume ();
+ return Destroy(false);
+ }
+ }
+ }
+ }
+#endif
+
+ // Interrupt if our inferior is running...
+ int exit_status = SIGABRT;
+ std::string exit_string;
+
+ if (m_gdb_comm.IsConnected())
+ {
+ if (m_public_state.GetValue() != eStateAttaching)
+ {
+ StringExtractorGDBRemote response;
+ bool send_async = true;
+ GDBRemoteCommunication::ScopedTimeout (m_gdb_comm, 3);
+
+ if (m_gdb_comm.SendPacketAndWaitForResponse("k", 1, response, send_async) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ char packet_cmd = response.GetChar(0);
+
+ if (packet_cmd == 'W' || packet_cmd == 'X')
+ {
+#if defined(__APPLE__)
+ // For Native processes on Mac OS X, we launch through the Host Platform, then hand the process off
+ // to debugserver, which becomes the parent process through "PT_ATTACH". Then when we go to kill
+ // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then we call waitpid which returns
+ // with no error and the correct status. But amusingly enough that doesn't seem to actually reap
+ // the process, but instead it is left around as a Zombie. Probably the kernel is in the process of
+ // switching ownership back to lldb which was the original parent, and gets confused in the handoff.
+ // Anyway, so call waitpid here to finally reap it.
+ PlatformSP platform_sp(GetTarget().GetPlatform());
+ if (platform_sp && platform_sp->IsHost())
+ {
+ int status;
+ ::pid_t reap_pid;
+ reap_pid = waitpid (GetID(), &status, WNOHANG);
+ if (log)
+ log->Printf ("Reaped pid: %d, status: %d.\n", reap_pid, status);
+ }
+#endif
+ SetLastStopPacket (response);
+ ClearThreadIDList ();
+ exit_status = response.GetHexU8();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy - got unexpected response to k packet: %s", response.GetStringRef().c_str());
+ exit_string.assign("got unexpected response to k packet: ");
+ exit_string.append(response.GetStringRef());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy - failed to send k packet");
+ exit_string.assign("failed to send the k packet");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy - killed or interrupted while attaching");
+ exit_string.assign ("killed or interrupted while attaching.");
+ }
+ }
+ else
+ {
+ // If we missed setting the exit status on the way out, do it here.
+ // NB set exit status can be called multiple times, the first one sets the status.
+ exit_string.assign("destroying when not connected to debugserver");
+ }
+
+ SetExitStatus(exit_status, exit_string.c_str());
+
+ StopAsyncThread ();
+ KillDebugserverProcess ();
+ return error;
+}
+
+void
+ProcessGDBRemote::SetLastStopPacket (const StringExtractorGDBRemote &response)
+{
+ const bool did_exec = response.GetStringRef().find(";reason:exec;") != std::string::npos;
+ if (did_exec)
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::SetLastStopPacket () - detected exec");
+
+ m_thread_list_real.Clear();
+ m_thread_list.Clear();
+ BuildDynamicRegisterInfo (true);
+ m_gdb_comm.ResetDiscoverableSettings (did_exec);
+ }
+
+ // Scope the lock
+ {
+ // Lock the thread stack while we access it
+ Mutex::Locker stop_stack_lock(m_last_stop_packet_mutex);
+ // Add this stop packet to the stop packet stack
+ // This stack will get popped and examined when we switch to the
+ // Stopped state
+ m_stop_packet_stack.push_back(response);
+ }
+}
+
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessGDBRemote::IsAlive ()
+{
+ return m_gdb_comm.IsConnected() && m_private_state.GetValue() != eStateExited;
+}
+
+addr_t
+ProcessGDBRemote::GetImageInfoAddress()
+{
+ // request the link map address via the $qShlibInfoAddr packet
+ lldb::addr_t addr = m_gdb_comm.GetShlibInfoAddr();
+
+ // the loaded module list can also provides a link map address
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ GDBLoadedModuleInfoList list;
+ if (GetLoadedModuleList (list).Success())
+ addr = list.m_link_map;
+ }
+
+ return addr;
+}
+
+//------------------------------------------------------------------
+// Process Memory
+//------------------------------------------------------------------
+size_t
+ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error)
+{
+ GetMaxMemorySize ();
+ if (size > m_max_memory_size)
+ {
+ // Keep memory read sizes down to a sane limit. This function will be
+ // called multiple times in order to complete the task by
+ // lldb_private::Process so it is ok to do this.
+ size = m_max_memory_size;
+ }
+
+ char packet[64];
+ int packet_len;
+ bool binary_memory_read = m_gdb_comm.GetxPacketSupported();
+ if (binary_memory_read)
+ {
+ packet_len = ::snprintf (packet, sizeof(packet), "x0x%" PRIx64 ",0x%" PRIx64, (uint64_t)addr, (uint64_t)size);
+ }
+ else
+ {
+ packet_len = ::snprintf (packet, sizeof(packet), "m%" PRIx64 ",%" PRIx64, (uint64_t)addr, (uint64_t)size);
+ }
+ assert (packet_len + 1 < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ if (response.IsNormalResponse())
+ {
+ error.Clear();
+ if (binary_memory_read)
+ {
+ // The lower level GDBRemoteCommunication packet receive layer has already de-quoted any
+ // 0x7d character escaping that was present in the packet
+
+ size_t data_received_size = response.GetBytesLeft();
+ if (data_received_size > size)
+ {
+ // Don't write past the end of BUF if the remote debug server gave us too
+ // much data for some reason.
+ data_received_size = size;
+ }
+ memcpy (buf, response.GetStringRef().data(), data_received_size);
+ return data_received_size;
+ }
+ else
+ {
+ return response.GetHexBytes(buf, size, '\xdd');
+ }
+ }
+ else if (response.IsErrorResponse())
+ error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, addr);
+ else if (response.IsUnsupportedResponse())
+ error.SetErrorStringWithFormat("GDB server does not support reading memory");
+ else
+ error.SetErrorStringWithFormat("unexpected response to GDB server memory read packet '%s': '%s'", packet, response.GetStringRef().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("failed to send packet: '%s'", packet);
+ }
+ return 0;
+}
+
+size_t
+ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
+{
+ GetMaxMemorySize ();
+ if (size > m_max_memory_size)
+ {
+ // Keep memory read sizes down to a sane limit. This function will be
+ // called multiple times in order to complete the task by
+ // lldb_private::Process so it is ok to do this.
+ size = m_max_memory_size;
+ }
+
+ StreamString packet;
+ packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size);
+ packet.PutBytesAsRawHex8(buf, size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder());
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, true) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ if (response.IsOKResponse())
+ {
+ error.Clear();
+ return size;
+ }
+ else if (response.IsErrorResponse())
+ error.SetErrorStringWithFormat("memory write failed for 0x%" PRIx64, addr);
+ else if (response.IsUnsupportedResponse())
+ error.SetErrorStringWithFormat("GDB server does not support writing memory");
+ else
+ error.SetErrorStringWithFormat("unexpected response to GDB server memory write packet '%s': '%s'", packet.GetString().c_str(), response.GetStringRef().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("failed to send packet: '%s'", packet.GetString().c_str());
+ }
+ return 0;
+}
+
+lldb::addr_t
+ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &error)
+{
+ Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_EXPRESSIONS));
+ addr_t allocated_addr = LLDB_INVALID_ADDRESS;
+
+ LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory();
+ switch (supported)
+ {
+ case eLazyBoolCalculate:
+ case eLazyBoolYes:
+ allocated_addr = m_gdb_comm.AllocateMemory (size, permissions);
+ if (allocated_addr != LLDB_INVALID_ADDRESS || supported == eLazyBoolYes)
+ return allocated_addr;
+
+ case eLazyBoolNo:
+ // Call mmap() to create memory in the inferior..
+ unsigned prot = 0;
+ if (permissions & lldb::ePermissionsReadable)
+ prot |= eMmapProtRead;
+ if (permissions & lldb::ePermissionsWritable)
+ prot |= eMmapProtWrite;
+ if (permissions & lldb::ePermissionsExecutable)
+ prot |= eMmapProtExec;
+
+ if (InferiorCallMmap(this, allocated_addr, 0, size, prot,
+ eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0))
+ m_addr_to_mmap_size[allocated_addr] = size;
+ else
+ {
+ allocated_addr = LLDB_INVALID_ADDRESS;
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s no direct stub support for memory allocation, and InferiorCallMmap also failed - is stub missing register context save/restore capability?", __FUNCTION__);
+ }
+ break;
+ }
+
+ if (allocated_addr == LLDB_INVALID_ADDRESS)
+ error.SetErrorStringWithFormat("unable to allocate %" PRIu64 " bytes of memory with permissions %s", (uint64_t)size, GetPermissionsAsCString (permissions));
+ else
+ error.Clear();
+ return allocated_addr;
+}
+
+Error
+ProcessGDBRemote::GetMemoryRegionInfo (addr_t load_addr,
+ MemoryRegionInfo &region_info)
+{
+
+ Error error (m_gdb_comm.GetMemoryRegionInfo (load_addr, region_info));
+ return error;
+}
+
+Error
+ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num)
+{
+
+ Error error (m_gdb_comm.GetWatchpointSupportInfo (num));
+ return error;
+}
+
+Error
+ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num, bool& after)
+{
+ Error error (m_gdb_comm.GetWatchpointSupportInfo (num, after, GetTarget().GetArchitecture()));
+ return error;
+}
+
+Error
+ProcessGDBRemote::DoDeallocateMemory (lldb::addr_t addr)
+{
+ Error error;
+ LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory();
+
+ switch (supported)
+ {
+ case eLazyBoolCalculate:
+ // We should never be deallocating memory without allocating memory
+ // first so we should never get eLazyBoolCalculate
+ error.SetErrorString ("tried to deallocate memory without ever allocating memory");
+ break;
+
+ case eLazyBoolYes:
+ if (!m_gdb_comm.DeallocateMemory (addr))
+ error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr);
+ break;
+
+ case eLazyBoolNo:
+ // Call munmap() to deallocate memory in the inferior..
+ {
+ MMapMap::iterator pos = m_addr_to_mmap_size.find(addr);
+ if (pos != m_addr_to_mmap_size.end() &&
+ InferiorCallMunmap(this, addr, pos->second))
+ m_addr_to_mmap_size.erase (pos);
+ else
+ error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr);
+ }
+ break;
+ }
+
+ return error;
+}
+
+
+//------------------------------------------------------------------
+// Process STDIO
+//------------------------------------------------------------------
+size_t
+ProcessGDBRemote::PutSTDIN (const char *src, size_t src_len, Error &error)
+{
+ if (m_stdio_communication.IsConnected())
+ {
+ ConnectionStatus status;
+ m_stdio_communication.Write(src, src_len, status, NULL);
+ }
+ else if (m_stdin_forward)
+ {
+ m_gdb_comm.SendStdinNotification(src, src_len);
+ }
+ return 0;
+}
+
+Error
+ProcessGDBRemote::EnableBreakpointSite (BreakpointSite *bp_site)
+{
+ Error error;
+ assert(bp_site != NULL);
+
+ // Get logging info
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS));
+ user_id_t site_id = bp_site->GetID();
+
+ // Get the breakpoint address
+ const addr_t addr = bp_site->GetLoadAddress();
+
+ // Log that a breakpoint was requested
+ if (log)
+ log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64, site_id, (uint64_t)addr);
+
+ // Breakpoint already exists and is enabled
+ if (bp_site->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64 " -- SUCCESS (already enabled)", site_id, (uint64_t)addr);
+ return error;
+ }
+
+ // Get the software breakpoint trap opcode size
+ const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode(bp_site);
+
+ // SupportsGDBStoppointPacket() simply checks a boolean, indicating if this breakpoint type
+ // is supported by the remote stub. These are set to true by default, and later set to false
+ // only after we receive an unimplemented response when sending a breakpoint packet. This means
+ // initially that unless we were specifically instructed to use a hardware breakpoint, LLDB will
+ // attempt to set a software breakpoint. HardwareRequired() also queries a boolean variable which
+ // indicates if the user specifically asked for hardware breakpoints. If true then we will
+ // skip over software breakpoints.
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware) && (!bp_site->HardwareRequired()))
+ {
+ // Try to send off a software breakpoint packet ($Z0)
+ if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, true, addr, bp_op_size) == 0)
+ {
+ // The breakpoint was placed successfully
+ bp_site->SetEnabled(true);
+ bp_site->SetType(BreakpointSite::eExternal);
+ return error;
+ }
+
+ // SendGDBStoppointTypePacket() will return an error if it was unable to set this
+ // breakpoint. We need to differentiate between a error specific to placing this breakpoint
+ // or if we have learned that this breakpoint type is unsupported. To do this, we
+ // must test the support boolean for this breakpoint type to see if it now indicates that
+ // this breakpoint type is unsupported. If they are still supported then we should return
+ // with the error code. If they are now unsupported, then we would like to fall through
+ // and try another form of breakpoint.
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware))
+ return error;
+
+ // We reach here when software breakpoints have been found to be unsupported. For future
+ // calls to set a breakpoint, we will not attempt to set a breakpoint with a type that is
+ // known not to be supported.
+ if (log)
+ log->Printf("Software breakpoints are unsupported");
+
+ // So we will fall through and try a hardware breakpoint
+ }
+
+ // The process of setting a hardware breakpoint is much the same as above. We check the
+ // supported boolean for this breakpoint type, and if it is thought to be supported then we
+ // will try to set this breakpoint with a hardware breakpoint.
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware))
+ {
+ // Try to send off a hardware breakpoint packet ($Z1)
+ if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, true, addr, bp_op_size) == 0)
+ {
+ // The breakpoint was placed successfully
+ bp_site->SetEnabled(true);
+ bp_site->SetType(BreakpointSite::eHardware);
+ return error;
+ }
+
+ // Check if the error was something other then an unsupported breakpoint type
+ if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware))
+ {
+ // Unable to set this hardware breakpoint
+ error.SetErrorString("failed to set hardware breakpoint (hardware breakpoint resources might be exhausted or unavailable)");
+ return error;
+ }
+
+ // We will reach here when the stub gives an unsupported response to a hardware breakpoint
+ if (log)
+ log->Printf("Hardware breakpoints are unsupported");
+
+ // Finally we will falling through to a #trap style breakpoint
+ }
+
+ // Don't fall through when hardware breakpoints were specifically requested
+ if (bp_site->HardwareRequired())
+ {
+ error.SetErrorString("hardware breakpoints are not supported");
+ return error;
+ }
+
+ // As a last resort we want to place a manual breakpoint. An instruction
+ // is placed into the process memory using memory write packets.
+ return EnableSoftwareBreakpoint(bp_site);
+}
+
+Error
+ProcessGDBRemote::DisableBreakpointSite (BreakpointSite *bp_site)
+{
+ Error error;
+ assert (bp_site != NULL);
+ addr_t addr = bp_site->GetLoadAddress();
+ user_id_t site_id = bp_site->GetID();
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 ") addr = 0x%8.8" PRIx64, site_id, (uint64_t)addr);
+
+ if (bp_site->IsEnabled())
+ {
+ const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site);
+
+ BreakpointSite::Type bp_type = bp_site->GetType();
+ switch (bp_type)
+ {
+ case BreakpointSite::eSoftware:
+ error = DisableSoftwareBreakpoint (bp_site);
+ break;
+
+ case BreakpointSite::eHardware:
+ if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, false, addr, bp_op_size))
+ error.SetErrorToGenericError();
+ 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))
+ error.SetErrorToGenericError();
+ }
+ break;
+ }
+ if (error.Success())
+ bp_site->SetEnabled(false);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", site_id, (uint64_t)addr);
+ return error;
+ }
+
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+// Pre-requisite: wp != NULL.
+static GDBStoppointType
+GetGDBStoppointType (Watchpoint *wp)
+{
+ assert(wp);
+ bool watch_read = wp->WatchpointRead();
+ bool watch_write = wp->WatchpointWrite();
+
+ // watch_read and watch_write cannot both be false.
+ assert(watch_read || watch_write);
+ if (watch_read && watch_write)
+ return eWatchpointReadWrite;
+ else if (watch_read)
+ return eWatchpointRead;
+ else // Must be watch_write, then.
+ return eWatchpointWrite;
+}
+
+Error
+ProcessGDBRemote::EnableWatchpoint (Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+ addr_t addr = wp->GetLoadAddress();
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")", watchID);
+ if (wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", watchID, (uint64_t)addr);
+ return error;
+ }
+
+ GDBStoppointType type = GetGDBStoppointType(wp);
+ // Pass down an appropriate z/Z packet...
+ if (m_gdb_comm.SupportsGDBStoppointPacket (type))
+ {
+ if (m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, wp->GetByteSize()) == 0)
+ {
+ wp->SetEnabled(true, notify);
+ return error;
+ }
+ else
+ error.SetErrorString("sending gdb watchpoint packet failed");
+ }
+ else
+ error.SetErrorString("watchpoints not supported");
+ }
+ else
+ {
+ error.SetErrorString("Watchpoint argument was NULL.");
+ }
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+Error
+ProcessGDBRemote::DisableWatchpoint (Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS));
+
+ addr_t addr = wp->GetLoadAddress();
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64, watchID, (uint64_t)addr);
+
+ if (!wp->IsEnabled())
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", watchID, (uint64_t)addr);
+ // See also 'class WatchpointSentry' within StopInfo.cpp.
+ // This disabling attempt might come from the user-supplied actions, we'll route it in order for
+ // the watchpoint object to intelligently process this action.
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+
+ if (wp->IsHardware())
+ {
+ GDBStoppointType type = GetGDBStoppointType(wp);
+ // Pass down an appropriate z/Z packet...
+ if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, wp->GetByteSize()) == 0)
+ {
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+ else
+ error.SetErrorString("sending gdb watchpoint packet failed");
+ }
+ // TODO: clear software watchpoints if we implement them
+ }
+ else
+ {
+ error.SetErrorString("Watchpoint argument was NULL.");
+ }
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+void
+ProcessGDBRemote::Clear()
+{
+ m_flags = 0;
+ m_thread_list_real.Clear();
+ m_thread_list.Clear();
+}
+
+Error
+ProcessGDBRemote::DoSignal (int signo)
+{
+ Error error;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoSignal (signal = %d)", signo);
+
+ if (!m_gdb_comm.SendAsyncSignal (signo))
+ error.SetErrorStringWithFormat("failed to send signal %i", signo);
+ return error;
+}
+
+Error
+ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info)
+{
+ Error error;
+ if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID)
+ {
+ // If we locate debugserver, keep that located version around
+ static FileSpec g_debugserver_file_spec;
+
+ ProcessLaunchInfo debugserver_launch_info;
+ // Make debugserver run in its own session so signals generated by
+ // special terminal key sequences (^C) don't affect debugserver.
+ debugserver_launch_info.SetLaunchInSeparateProcessGroup(true);
+
+ debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false);
+ debugserver_launch_info.SetUserID(process_info.GetUserID());
+
+#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__))
+ // On iOS, still do a local connection using a random port
+ const char *hostname = "127.0.0.1";
+ uint16_t port = get_random_port ();
+#else
+ // Set hostname being NULL to do the reverse connect where debugserver
+ // will bind to port zero and it will communicate back to us the port
+ // that we will connect to
+ const char *hostname = NULL;
+ uint16_t port = 0;
+#endif
+
+ error = m_gdb_comm.StartDebugserverProcess (hostname,
+ port,
+ debugserver_launch_info,
+ port);
+
+ if (error.Success ())
+ m_debugserver_pid = debugserver_launch_info.GetProcessID();
+ else
+ m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+
+ if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ StartAsyncThread ();
+
+ if (error.Fail())
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+
+ if (log)
+ log->Printf("failed to start debugserver process: %s", error.AsCString());
+ return error;
+ }
+
+ if (m_gdb_comm.IsConnected())
+ {
+ // Finish the connection process by doing the handshake without connecting (send NULL URL)
+ ConnectToDebugserver (NULL);
+ }
+ else
+ {
+ StreamString connect_url;
+ connect_url.Printf("connect://%s:%u", hostname, port);
+ error = ConnectToDebugserver (connect_url.GetString().c_str());
+ }
+
+ }
+ return error;
+}
+
+bool
+ProcessGDBRemote::MonitorDebugserverProcess
+(
+ void *callback_baton,
+ lldb::pid_t debugserver_pid,
+ bool exited, // True if the process did exit
+ int signo, // Zero for no signal
+ int exit_status // Exit value of process if signal is zero
+)
+{
+ // The baton is a "ProcessGDBRemote *". Now this class might be gone
+ // and might not exist anymore, so we need to carefully try to get the
+ // target for this process first since we have a race condition when
+ // we are done running between getting the notice that the inferior
+ // process has died and the debugserver that was debugging this process.
+ // In our test suite, we are also continually running process after
+ // process, so we must be very careful to make sure:
+ // 1 - process object hasn't been deleted already
+ // 2 - that a new process object hasn't been recreated in its place
+
+ // "debugserver_pid" argument passed in is the process ID for
+ // debugserver that we are tracking...
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+
+ ProcessGDBRemote *process = (ProcessGDBRemote *)callback_baton;
+
+ // Get a shared pointer to the target that has a matching process pointer.
+ // This target could be gone, or the target could already have a new process
+ // object inside of it
+ TargetSP target_sp (Debugger::FindTargetWithProcess(process));
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::MonitorDebugserverProcess (baton=%p, pid=%" PRIu64 ", signo=%i (0x%x), exit_status=%i)", callback_baton, debugserver_pid, signo, signo, exit_status);
+
+ if (target_sp)
+ {
+ // We found a process in a target that matches, but another thread
+ // might be in the process of launching a new process that will
+ // soon replace it, so get a shared pointer to the process so we
+ // can keep it alive.
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ // Now we have a shared pointer to the process that can't go away on us
+ // so we now make sure it was the same as the one passed in, and also make
+ // sure that our previous "process *" didn't get deleted and have a new
+ // "process *" created in its place with the same pointer. To verify this
+ // we make sure the process has our debugserver process ID. If we pass all
+ // of these tests, then we are sure that this process is the one we were
+ // looking for.
+ if (process_sp && process == process_sp.get() && process->m_debugserver_pid == debugserver_pid)
+ {
+ // Sleep for a half a second to make sure our inferior process has
+ // time to set its exit status before we set it incorrectly when
+ // both the debugserver and the inferior process shut down.
+ usleep (500000);
+ // If our process hasn't yet exited, debugserver might have died.
+ // If the process did exit, the we are reaping it.
+ const StateType state = process->GetState();
+
+ if (process->m_debugserver_pid != LLDB_INVALID_PROCESS_ID &&
+ state != eStateInvalid &&
+ state != eStateUnloaded &&
+ state != eStateExited &&
+ state != eStateDetached)
+ {
+ char error_str[1024];
+ if (signo)
+ {
+ const char *signal_cstr = process->GetUnixSignals()->GetSignalAsCString(signo);
+ if (signal_cstr)
+ ::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with signal %s", signal_cstr);
+ else
+ ::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with signal %i", signo);
+ }
+ else
+ {
+ ::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with an exit status of 0x%8.8x", exit_status);
+ }
+
+ process->SetExitStatus (-1, error_str);
+ }
+ // Debugserver has exited we need to let our ProcessGDBRemote
+ // know that it no longer has a debugserver instance
+ process->m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+ }
+ }
+ return true;
+}
+
+void
+ProcessGDBRemote::KillDebugserverProcess ()
+{
+ m_gdb_comm.Disconnect();
+ if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ Host::Kill (m_debugserver_pid, SIGINT);
+ m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+ }
+}
+
+void
+ProcessGDBRemote::Initialize()
+{
+ static std::once_flag g_once_flag;
+
+ std::call_once(g_once_flag, []()
+ {
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance,
+ DebuggerInitialize);
+ });
+}
+
+void
+ProcessGDBRemote::DebuggerInitialize (Debugger &debugger)
+{
+ if (!PluginManager::GetSettingForProcessPlugin(debugger, PluginProperties::GetSettingName()))
+ {
+ const bool is_global_setting = true;
+ PluginManager::CreateSettingForProcessPlugin (debugger,
+ GetGlobalPluginProperties()->GetValueProperties(),
+ ConstString ("Properties for the gdb-remote process plug-in."),
+ is_global_setting);
+ }
+}
+
+bool
+ProcessGDBRemote::StartAsyncThread ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__);
+
+ Mutex::Locker start_locker(m_async_thread_state_mutex);
+ if (!m_async_thread.IsJoinable())
+ {
+ // Create a thread that watches our internal state and controls which
+ // events make it to clients (into the DCProcess event queue).
+
+ m_async_thread = ThreadLauncher::LaunchThread("<lldb.process.gdb-remote.async>", ProcessGDBRemote::AsyncThread, this, NULL);
+ }
+ else if (log)
+ log->Printf("ProcessGDBRemote::%s () - Called when Async thread was already running.", __FUNCTION__);
+
+ return m_async_thread.IsJoinable();
+}
+
+void
+ProcessGDBRemote::StopAsyncThread ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__);
+
+ Mutex::Locker start_locker(m_async_thread_state_mutex);
+ if (m_async_thread.IsJoinable())
+ {
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit);
+
+ // This will shut down the async thread.
+ m_gdb_comm.Disconnect(); // Disconnect from the debug server.
+
+ // Stop the stdio thread
+ m_async_thread.Join(nullptr);
+ m_async_thread.Reset();
+ }
+ else if (log)
+ log->Printf("ProcessGDBRemote::%s () - Called when Async thread was not running.", __FUNCTION__);
+}
+
+bool
+ProcessGDBRemote::HandleNotifyPacket (StringExtractorGDBRemote &packet)
+{
+ // get the packet at a string
+ const std::string &pkt = packet.GetStringRef();
+ // skip %stop:
+ StringExtractorGDBRemote stop_info(pkt.c_str() + 5);
+
+ // pass as a thread stop info packet
+ SetLastStopPacket(stop_info);
+
+ // check for more stop reasons
+ HandleStopReplySequence();
+
+ // if the process is stopped then we need to fake a resume
+ // so that we can stop properly with the new break. This
+ // is possible due to SetPrivateState() broadcasting the
+ // state change as a side effect.
+ if (GetPrivateState() == lldb::StateType::eStateStopped)
+ {
+ SetPrivateState(lldb::StateType::eStateRunning);
+ }
+
+ // since we have some stopped packets we can halt the process
+ SetPrivateState(lldb::StateType::eStateStopped);
+
+ return true;
+}
+
+thread_result_t
+ProcessGDBRemote::AsyncThread (void *arg)
+{
+ ProcessGDBRemote *process = (ProcessGDBRemote*) arg;
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread starting...", __FUNCTION__, arg, process->GetID());
+
+ Listener listener ("ProcessGDBRemote::AsyncThread");
+ EventSP event_sp;
+ const uint32_t desired_event_mask = eBroadcastBitAsyncContinue |
+ eBroadcastBitAsyncThreadShouldExit;
+
+ if (listener.StartListeningForEvents (&process->m_async_broadcaster, desired_event_mask) == desired_event_mask)
+ {
+ listener.StartListeningForEvents (&process->m_gdb_comm, Communication::eBroadcastBitReadThreadDidExit |
+ GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify);
+
+ bool done = false;
+ while (!done)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp)...", __FUNCTION__, arg, process->GetID());
+ if (listener.WaitForEvent (NULL, event_sp))
+ {
+ const uint32_t event_type = event_sp->GetType();
+ if (event_sp->BroadcasterIs (&process->m_async_broadcaster))
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") Got an event of type: %d...", __FUNCTION__, arg, process->GetID(), event_type);
+
+ switch (event_type)
+ {
+ case eBroadcastBitAsyncContinue:
+ {
+ const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event_sp.get());
+
+ if (continue_packet)
+ {
+ const char *continue_cstr = (const char *)continue_packet->GetBytes ();
+ const size_t continue_cstr_len = continue_packet->GetByteSize ();
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got eBroadcastBitAsyncContinue: %s", __FUNCTION__, arg, process->GetID(), continue_cstr);
+
+ if (::strstr (continue_cstr, "vAttach") == NULL)
+ process->SetPrivateState(eStateRunning);
+ StringExtractorGDBRemote response;
+
+ // If in Non-Stop-Mode
+ if (process->GetTarget().GetNonStopModeEnabled())
+ {
+ // send the vCont packet
+ if (!process->GetGDBRemote().SendvContPacket(process, continue_cstr, continue_cstr_len, response))
+ {
+ // Something went wrong
+ done = true;
+ break;
+ }
+ }
+ // If in All-Stop-Mode
+ else
+ {
+ StateType stop_state = process->GetGDBRemote().SendContinuePacketAndWaitForResponse (process, continue_cstr, continue_cstr_len, response);
+
+ // We need to immediately clear the thread ID list so we are sure to get a valid list of threads.
+ // The thread ID list might be contained within the "response", or the stop reply packet that
+ // caused the stop. So clear it now before we give the stop reply packet to the process
+ // using the process->SetLastStopPacket()...
+ process->ClearThreadIDList ();
+
+ switch (stop_state)
+ {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ process->SetLastStopPacket (response);
+ process->SetPrivateState (stop_state);
+ break;
+
+ case eStateExited:
+ {
+ process->SetLastStopPacket (response);
+ process->ClearThreadIDList();
+ response.SetFilePos(1);
+
+ int exit_status = response.GetHexU8();
+ const char *desc_cstr = NULL;
+ StringExtractor extractor;
+ std::string desc_string;
+ if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';')
+ {
+ std::string desc_token;
+ while (response.GetNameColonValue (desc_token, desc_string))
+ {
+ if (desc_token == "description")
+ {
+ extractor.GetStringRef().swap(desc_string);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (desc_string);
+ desc_cstr = desc_string.c_str();
+ }
+ }
+ }
+ process->SetExitStatus(exit_status, desc_cstr);
+ done = true;
+ break;
+ }
+ case eStateInvalid:
+ process->SetExitStatus(-1, "lost connection");
+ break;
+
+ default:
+ process->SetPrivateState (stop_state);
+ break;
+ } // switch(stop_state)
+ } // else // if in All-stop-mode
+ } // if (continue_packet)
+ } // case eBroadcastBitAysncContinue
+ break;
+
+ case eBroadcastBitAsyncThreadShouldExit:
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got eBroadcastBitAsyncThreadShouldExit...", __FUNCTION__, arg, process->GetID());
+ done = true;
+ break;
+
+ default:
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got unknown event 0x%8.8x", __FUNCTION__, arg, process->GetID(), event_type);
+ done = true;
+ break;
+ }
+ }
+ else if (event_sp->BroadcasterIs (&process->m_gdb_comm))
+ {
+ switch (event_type)
+ {
+ case Communication::eBroadcastBitReadThreadDidExit:
+ process->SetExitStatus (-1, "lost connection");
+ done = true;
+ break;
+
+ case GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify:
+ {
+ lldb_private::Event *event = event_sp.get();
+ const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event);
+ StringExtractorGDBRemote notify((const char*)continue_packet->GetBytes());
+ // Hand this over to the process to handle
+ process->HandleNotifyPacket(notify);
+ break;
+ }
+
+ default:
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got unknown event 0x%8.8x", __FUNCTION__, arg, process->GetID(), event_type);
+ done = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp) => false", __FUNCTION__, arg, process->GetID());
+ done = true;
+ }
+ }
+ }
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", __FUNCTION__, arg, process->GetID());
+
+ return NULL;
+}
+
+//uint32_t
+//ProcessGDBRemote::ListProcessesMatchingName (const char *name, StringList &matches, std::vector<lldb::pid_t> &pids)
+//{
+// // If we are planning to launch the debugserver remotely, then we need to fire up a debugserver
+// // process and ask it for the list of processes. But if we are local, we can let the Host do it.
+// if (m_local_debugserver)
+// {
+// return Host::ListProcessesMatchingName (name, matches, pids);
+// }
+// else
+// {
+// // FIXME: Implement talking to the remote debugserver.
+// return 0;
+// }
+//
+//}
+//
+bool
+ProcessGDBRemote::NewThreadNotifyBreakpointHit (void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id)
+{
+ // I don't think I have to do anything here, just make sure I notice the new thread when it starts to
+ // run so I can stop it if that's what I want to do.
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf("Hit New Thread Notification breakpoint.");
+ return false;
+}
+
+
+bool
+ProcessGDBRemote::StartNoticingNewThreads()
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (m_thread_create_bp_sp)
+ {
+ if (log && log->GetVerbose())
+ log->Printf("Enabled noticing new thread breakpoint.");
+ m_thread_create_bp_sp->SetEnabled(true);
+ }
+ else
+ {
+ PlatformSP platform_sp (m_target.GetPlatform());
+ if (platform_sp)
+ {
+ m_thread_create_bp_sp = platform_sp->SetThreadCreationBreakpoint(m_target);
+ if (m_thread_create_bp_sp)
+ {
+ if (log && log->GetVerbose())
+ log->Printf("Successfully created new thread notification breakpoint %i", m_thread_create_bp_sp->GetID());
+ m_thread_create_bp_sp->SetCallback (ProcessGDBRemote::NewThreadNotifyBreakpointHit, this, true);
+ }
+ else
+ {
+ if (log)
+ log->Printf("Failed to create new thread notification breakpoint.");
+ }
+ }
+ }
+ return m_thread_create_bp_sp.get() != NULL;
+}
+
+bool
+ProcessGDBRemote::StopNoticingNewThreads()
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose())
+ log->Printf ("Disabling new thread notification breakpoint.");
+
+ if (m_thread_create_bp_sp)
+ m_thread_create_bp_sp->SetEnabled(false);
+
+ return true;
+}
+
+DynamicLoader *
+ProcessGDBRemote::GetDynamicLoader ()
+{
+ if (m_dyld_ap.get() == NULL)
+ m_dyld_ap.reset (DynamicLoader::FindPlugin(this, NULL));
+ return m_dyld_ap.get();
+}
+
+Error
+ProcessGDBRemote::SendEventData(const char *data)
+{
+ int return_value;
+ bool was_supported;
+
+ Error error;
+
+ return_value = m_gdb_comm.SendLaunchEventDataPacket (data, &was_supported);
+ if (return_value != 0)
+ {
+ if (!was_supported)
+ error.SetErrorString("Sending events is not supported for this process.");
+ else
+ error.SetErrorStringWithFormat("Error sending event data: %d.", return_value);
+ }
+ return error;
+}
+
+const DataBufferSP
+ProcessGDBRemote::GetAuxvData()
+{
+ DataBufferSP buf;
+ if (m_gdb_comm.GetQXferAuxvReadSupported())
+ {
+ std::string response_string;
+ if (m_gdb_comm.SendPacketsAndConcatenateResponses("qXfer:auxv:read::", response_string) == GDBRemoteCommunication::PacketResult::Success)
+ buf.reset(new DataBufferHeap(response_string.c_str(), response_string.length()));
+ }
+ return buf;
+}
+
+StructuredData::ObjectSP
+ProcessGDBRemote::GetExtendedInfoForThread (lldb::tid_t tid)
+{
+ StructuredData::ObjectSP object_sp;
+
+ if (m_gdb_comm.GetThreadExtendedInfoSupported())
+ {
+ StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
+ SystemRuntime *runtime = GetSystemRuntime();
+ if (runtime)
+ {
+ runtime->AddThreadExtendedInfoPacketHints (args_dict);
+ }
+ args_dict->GetAsDictionary()->AddIntegerItem ("thread", tid);
+
+ StreamString packet;
+ packet << "jThreadExtendedInfo:";
+ args_dict->Dump (packet);
+
+ // FIXME the final character of a JSON dictionary, '}', is the escape
+ // character in gdb-remote binary mode. lldb currently doesn't escape
+ // these characters in its packet output -- so we add the quoted version
+ // of the } character here manually in case we talk to a debugserver which
+ // un-escapes the characters at packet read time.
+ packet << (char) (0x7d ^ 0x20);
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType();
+ if (response_type == StringExtractorGDBRemote::eResponse)
+ {
+ if (!response.Empty())
+ {
+ object_sp = StructuredData::ParseJSON (response.GetStringRef());
+ }
+ }
+ }
+ }
+ return object_sp;
+}
+
+StructuredData::ObjectSP
+ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count)
+{
+ StructuredData::ObjectSP object_sp;
+
+ if (m_gdb_comm.GetLoadedDynamicLibrariesInfosSupported())
+ {
+ StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
+ args_dict->GetAsDictionary()->AddIntegerItem ("image_list_address", image_list_address);
+ args_dict->GetAsDictionary()->AddIntegerItem ("image_count", image_count);
+
+ StreamString packet;
+ packet << "jGetLoadedDynamicLibrariesInfos:";
+ args_dict->Dump (packet);
+
+ // FIXME the final character of a JSON dictionary, '}', is the escape
+ // character in gdb-remote binary mode. lldb currently doesn't escape
+ // these characters in its packet output -- so we add the quoted version
+ // of the } character here manually in case we talk to a debugserver which
+ // un-escapes the characters at packet read time.
+ packet << (char) (0x7d ^ 0x20);
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == GDBRemoteCommunication::PacketResult::Success)
+ {
+ StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType();
+ if (response_type == StringExtractorGDBRemote::eResponse)
+ {
+ if (!response.Empty())
+ {
+ // The packet has already had the 0x7d xor quoting stripped out at the
+ // GDBRemoteCommunication packet receive level.
+ object_sp = StructuredData::ParseJSON (response.GetStringRef());
+ }
+ }
+ }
+ }
+ return object_sp;
+}
+
+
+// Establish the largest memory read/write payloads we should use.
+// If the remote stub has a max packet size, stay under that size.
+//
+// If the remote stub's max packet size is crazy large, use a
+// reasonable largeish default.
+//
+// If the remote stub doesn't advertise a max packet size, use a
+// conservative default.
+
+void
+ProcessGDBRemote::GetMaxMemorySize()
+{
+ const uint64_t reasonable_largeish_default = 128 * 1024;
+ const uint64_t conservative_default = 512;
+
+ if (m_max_memory_size == 0)
+ {
+ uint64_t stub_max_size = m_gdb_comm.GetRemoteMaxPacketSize();
+ if (stub_max_size != UINT64_MAX && stub_max_size != 0)
+ {
+ // Save the stub's claimed maximum packet size
+ m_remote_stub_max_memory_size = stub_max_size;
+
+ // Even if the stub says it can support ginormous packets,
+ // don't exceed our reasonable largeish default packet size.
+ if (stub_max_size > reasonable_largeish_default)
+ {
+ stub_max_size = reasonable_largeish_default;
+ }
+
+ m_max_memory_size = stub_max_size;
+ }
+ else
+ {
+ m_max_memory_size = conservative_default;
+ }
+ }
+}
+
+void
+ProcessGDBRemote::SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max)
+{
+ if (user_specified_max != 0)
+ {
+ GetMaxMemorySize ();
+
+ if (m_remote_stub_max_memory_size != 0)
+ {
+ if (m_remote_stub_max_memory_size < user_specified_max)
+ {
+ m_max_memory_size = m_remote_stub_max_memory_size; // user specified a packet size too big, go as big
+ // as the remote stub says we can go.
+ }
+ else
+ {
+ m_max_memory_size = user_specified_max; // user's packet size is good
+ }
+ }
+ else
+ {
+ m_max_memory_size = user_specified_max; // user's packet size is probably fine
+ }
+ }
+}
+
+bool
+ProcessGDBRemote::GetModuleSpec(const FileSpec& module_file_spec,
+ const ArchSpec& arch,
+ ModuleSpec &module_spec)
+{
+ Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PLATFORM);
+
+ if (!m_gdb_comm.GetModuleInfo (module_file_spec, arch, module_spec))
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s - failed to get module info for %s:%s",
+ __FUNCTION__, module_file_spec.GetPath ().c_str (),
+ arch.GetTriple ().getTriple ().c_str ());
+ return false;
+ }
+
+ if (log)
+ {
+ StreamString stream;
+ module_spec.Dump (stream);
+ log->Printf ("ProcessGDBRemote::%s - got module info for (%s:%s) : %s",
+ __FUNCTION__, module_file_spec.GetPath ().c_str (),
+ arch.GetTriple ().getTriple ().c_str (), stream.GetString ().c_str ());
+ }
+
+ return true;
+}
+
+namespace {
+
+typedef std::vector<std::string> stringVec;
+
+typedef std::vector<struct GdbServerRegisterInfo> GDBServerRegisterVec;
+struct RegisterSetInfo
+{
+ ConstString name;
+};
+
+typedef std::map<uint32_t, RegisterSetInfo> RegisterSetMap;
+
+struct GdbServerTargetInfo
+{
+ std::string arch;
+ std::string osabi;
+ stringVec includes;
+ RegisterSetMap reg_set_map;
+ XMLNode feature_node;
+};
+
+bool
+ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemoteDynamicRegisterInfo &dyn_reg_info)
+{
+ if (!feature_node)
+ return false;
+
+ uint32_t prev_reg_num = 0;
+ uint32_t reg_offset = 0;
+
+ feature_node.ForEachChildElementWithName("reg", [&target_info, &dyn_reg_info, &prev_reg_num, &reg_offset](const XMLNode &reg_node) -> bool {
+ std::string gdb_group;
+ std::string gdb_type;
+ ConstString reg_name;
+ ConstString alt_name;
+ ConstString set_name;
+ std::vector<uint32_t> value_regs;
+ std::vector<uint32_t> invalidate_regs;
+ bool encoding_set = false;
+ bool format_set = false;
+ RegisterInfo reg_info = { NULL, // Name
+ NULL, // Alt name
+ 0, // byte size
+ reg_offset, // offset
+ eEncodingUint, // encoding
+ eFormatHex, // formate
+ {
+ LLDB_INVALID_REGNUM, // GCC reg num
+ LLDB_INVALID_REGNUM, // DWARF reg num
+ LLDB_INVALID_REGNUM, // generic reg num
+ prev_reg_num, // GDB reg num
+ prev_reg_num // native register number
+ },
+ NULL,
+ NULL
+ };
+
+ reg_node.ForEachAttribute([&target_info, &gdb_group, &gdb_type, &reg_name, &alt_name, &set_name, &value_regs, &invalidate_regs, &encoding_set, &format_set, &reg_info, &prev_reg_num, &reg_offset](const llvm::StringRef &name, const llvm::StringRef &value) -> bool {
+ if (name == "name")
+ {
+ reg_name.SetString(value);
+ }
+ else if (name == "bitsize")
+ {
+ reg_info.byte_size = StringConvert::ToUInt32(value.data(), 0, 0) / CHAR_BIT;
+ }
+ else if (name == "type")
+ {
+ gdb_type = value.str();
+ }
+ else if (name == "group")
+ {
+ gdb_group = value.str();
+ }
+ else if (name == "regnum")
+ {
+ const uint32_t regnum = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0);
+ if (regnum != LLDB_INVALID_REGNUM)
+ {
+ reg_info.kinds[eRegisterKindGDB] = regnum;
+ reg_info.kinds[eRegisterKindLLDB] = regnum;
+ prev_reg_num = regnum;
+ }
+ }
+ else if (name == "offset")
+ {
+ reg_offset = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0);
+ }
+ else if (name == "altname")
+ {
+ alt_name.SetString(value);
+ }
+ else if (name == "encoding")
+ {
+ encoding_set = true;
+ reg_info.encoding = Args::StringToEncoding (value.data(), eEncodingUint);
+ }
+ else if (name == "format")
+ {
+ format_set = true;
+ Format format = eFormatInvalid;
+ if (Args::StringToFormat (value.data(), format, NULL).Success())
+ reg_info.format = format;
+ else if (value == "vector-sint8")
+ reg_info.format = eFormatVectorOfSInt8;
+ else if (value == "vector-uint8")
+ reg_info.format = eFormatVectorOfUInt8;
+ else if (value == "vector-sint16")
+ reg_info.format = eFormatVectorOfSInt16;
+ else if (value == "vector-uint16")
+ reg_info.format = eFormatVectorOfUInt16;
+ else if (value == "vector-sint32")
+ reg_info.format = eFormatVectorOfSInt32;
+ else if (value == "vector-uint32")
+ reg_info.format = eFormatVectorOfUInt32;
+ else if (value == "vector-float32")
+ reg_info.format = eFormatVectorOfFloat32;
+ else if (value == "vector-uint128")
+ reg_info.format = eFormatVectorOfUInt128;
+ }
+ else if (name == "group_id")
+ {
+ const uint32_t set_id = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0);
+ RegisterSetMap::const_iterator pos = target_info.reg_set_map.find(set_id);
+ if (pos != target_info.reg_set_map.end())
+ set_name = pos->second.name;
+ }
+ else if (name == "gcc_regnum")
+ {
+ reg_info.kinds[eRegisterKindGCC] = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0);
+ }
+ else if (name == "dwarf_regnum")
+ {
+ reg_info.kinds[eRegisterKindDWARF] = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0);
+ }
+ else if (name == "generic")
+ {
+ reg_info.kinds[eRegisterKindGeneric] = Args::StringToGenericRegister(value.data());
+ }
+ else if (name == "value_regnums")
+ {
+ SplitCommaSeparatedRegisterNumberString(value, value_regs, 0);
+ }
+ else if (name == "invalidate_regnums")
+ {
+ SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 0);
+ }
+ else
+ {
+ printf("unhandled attribute %s = %s\n", name.data(), value.data());
+ }
+ return true; // Keep iterating through all attributes
+ });
+
+ if (!gdb_type.empty() && !(encoding_set || format_set))
+ {
+ if (gdb_type.find("int") == 0)
+ {
+ reg_info.format = eFormatHex;
+ reg_info.encoding = eEncodingUint;
+ }
+ else if (gdb_type == "data_ptr" || gdb_type == "code_ptr")
+ {
+ reg_info.format = eFormatAddressInfo;
+ reg_info.encoding = eEncodingUint;
+ }
+ else if (gdb_type == "i387_ext" || gdb_type == "float")
+ {
+ reg_info.format = eFormatFloat;
+ reg_info.encoding = eEncodingIEEE754;
+ }
+ }
+
+ // Only update the register set name if we didn't get a "reg_set" attribute.
+ // "set_name" will be empty if we didn't have a "reg_set" attribute.
+ if (!set_name && !gdb_group.empty())
+ set_name.SetCString(gdb_group.c_str());
+
+ reg_info.byte_offset = reg_offset;
+ assert (reg_info.byte_size != 0);
+ reg_offset += reg_info.byte_size;
+ if (!value_regs.empty())
+ {
+ value_regs.push_back(LLDB_INVALID_REGNUM);
+ reg_info.value_regs = value_regs.data();
+ }
+ if (!invalidate_regs.empty())
+ {
+ invalidate_regs.push_back(LLDB_INVALID_REGNUM);
+ reg_info.invalidate_regs = invalidate_regs.data();
+ }
+
+ ++prev_reg_num;
+ dyn_reg_info.AddRegister(reg_info, reg_name, alt_name, set_name);
+
+ return true; // Keep iterating through all "reg" elements
+ });
+ return true;
+}
+
+} // namespace {}
+
+
+// query the target of gdb-remote for extended target information
+// return: 'true' on success
+// 'false' on failure
+bool
+ProcessGDBRemote::GetGDBServerRegisterInfo ()
+{
+ // Make sure LLDB has an XML parser it can use first
+ if (!XMLDocument::XMLEnabled())
+ return false;
+
+ // redirect libxml2's error handler since the default prints to stdout
+
+ GDBRemoteCommunicationClient & comm = m_gdb_comm;
+
+ // check that we have extended feature read support
+ if ( !comm.GetQXferFeaturesReadSupported( ) )
+ return false;
+
+ // request the target xml file
+ std::string raw;
+ lldb_private::Error lldberr;
+ if (!comm.ReadExtFeature(ConstString("features"),
+ ConstString("target.xml"),
+ raw,
+ lldberr))
+ {
+ return false;
+ }
+
+
+ XMLDocument xml_document;
+
+ if (xml_document.ParseMemory(raw.c_str(), raw.size(), "target.xml"))
+ {
+ GdbServerTargetInfo target_info;
+
+ XMLNode target_node = xml_document.GetRootElement("target");
+ if (target_node)
+ {
+ XMLNode feature_node;
+ target_node.ForEachChildElement([&target_info, this, &feature_node](const XMLNode &node) -> bool
+ {
+ llvm::StringRef name = node.GetName();
+ if (name == "architecture")
+ {
+ node.GetElementText(target_info.arch);
+ }
+ else if (name == "osabi")
+ {
+ node.GetElementText(target_info.osabi);
+ }
+ else if (name == "xi:include" || name == "include")
+ {
+ llvm::StringRef href = node.GetAttributeValue("href");
+ if (!href.empty())
+ target_info.includes.push_back(href.str());
+ }
+ else if (name == "feature")
+ {
+ feature_node = node;
+ }
+ else if (name == "groups")
+ {
+ node.ForEachChildElementWithName("group", [&target_info](const XMLNode &node) -> bool {
+ uint32_t set_id = UINT32_MAX;
+ RegisterSetInfo set_info;
+
+ node.ForEachAttribute([&set_id, &set_info](const llvm::StringRef &name, const llvm::StringRef &value) -> bool {
+ if (name == "id")
+ set_id = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0);
+ if (name == "name")
+ set_info.name = ConstString(value);
+ return true; // Keep iterating through all attributes
+ });
+
+ if (set_id != UINT32_MAX)
+ target_info.reg_set_map[set_id] = set_info;
+ return true; // Keep iterating through all "group" elements
+ });
+ }
+ return true; // Keep iterating through all children of the target_node
+ });
+
+ if (feature_node)
+ {
+ ParseRegisters(feature_node, target_info, this->m_register_info);
+ }
+
+ for (const auto &include : target_info.includes)
+ {
+ // request register file
+ std::string xml_data;
+ if (!comm.ReadExtFeature(ConstString("features"),
+ ConstString(include),
+ xml_data,
+ lldberr))
+ continue;
+
+ XMLDocument include_xml_document;
+ include_xml_document.ParseMemory(xml_data.data(), xml_data.size(), include.c_str());
+ XMLNode include_feature_node = include_xml_document.GetRootElement("feature");
+ if (include_feature_node)
+ {
+ ParseRegisters(include_feature_node, target_info, this->m_register_info);
+ }
+ }
+ this->m_register_info.Finalize(GetTarget().GetArchitecture());
+ }
+ }
+
+ return m_register_info.GetNumRegisters() > 0;
+}
+
+Error
+ProcessGDBRemote::GetLoadedModuleList (GDBLoadedModuleInfoList & list)
+{
+ // Make sure LLDB has an XML parser it can use first
+ if (!XMLDocument::XMLEnabled())
+ return Error (0, ErrorType::eErrorTypeGeneric);
+
+ Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS);
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s", __FUNCTION__);
+
+ GDBRemoteCommunicationClient & comm = m_gdb_comm;
+
+ // check that we have extended feature read support
+ if (comm.GetQXferLibrariesSVR4ReadSupported ()) {
+ list.clear ();
+
+ // request the loaded library list
+ std::string raw;
+ lldb_private::Error lldberr;
+
+ if (!comm.ReadExtFeature (ConstString ("libraries-svr4"), ConstString (""), raw, lldberr))
+ return Error (0, ErrorType::eErrorTypeGeneric);
+
+ // parse the xml file in memory
+ if (log)
+ log->Printf ("parsing: %s", raw.c_str());
+ XMLDocument doc;
+
+ if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml"))
+ return Error (0, ErrorType::eErrorTypeGeneric);
+
+ XMLNode root_element = doc.GetRootElement("library-list-svr4");
+ if (!root_element)
+ return Error();
+
+ // main link map structure
+ llvm::StringRef main_lm = root_element.GetAttributeValue("main-lm");
+ if (!main_lm.empty())
+ {
+ list.m_link_map = StringConvert::ToUInt64(main_lm.data(), LLDB_INVALID_ADDRESS, 0);
+ }
+
+ root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool {
+
+ GDBLoadedModuleInfoList::LoadedModuleInfo module;
+
+ library.ForEachAttribute([log, &module](const llvm::StringRef &name, const llvm::StringRef &value) -> bool {
+
+ if (name == "name")
+ module.set_name (value.str());
+ else if (name == "lm")
+ {
+ // the address of the link_map struct.
+ module.set_link_map(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0));
+ }
+ else if (name == "l_addr")
+ {
+ // the displacement as read from the field 'l_addr' of the link_map struct.
+ module.set_base(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0));
+
+ }
+ else if (name == "l_ld")
+ {
+ // the memory address of the libraries PT_DYAMIC section.
+ module.set_dynamic(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0));
+ }
+
+ return true; // Keep iterating over all properties of "library"
+ });
+
+ if (log)
+ {
+ std::string name;
+ lldb::addr_t lm=0, base=0, ld=0;
+
+ module.get_name (name);
+ module.get_link_map (lm);
+ module.get_base (base);
+ module.get_dynamic (ld);
+
+ log->Printf ("found (link_map:0x08%" PRIx64 ", base:0x08%" PRIx64 ", ld:0x08%" PRIx64 ", name:'%s')", lm, base, ld, name.c_str());
+ }
+
+ list.add (module);
+ return true; // Keep iterating over all "library" elements in the root node
+ });
+
+ if (log)
+ log->Printf ("found %" PRId32 " modules in total", (int) list.m_list.size());
+ } else if (comm.GetQXferLibrariesReadSupported ()) {
+ list.clear ();
+
+ // request the loaded library list
+ std::string raw;
+ lldb_private::Error lldberr;
+
+ if (!comm.ReadExtFeature (ConstString ("libraries"), ConstString (""), raw, lldberr))
+ return Error (0, ErrorType::eErrorTypeGeneric);
+
+ if (log)
+ log->Printf ("parsing: %s", raw.c_str());
+ XMLDocument doc;
+
+ if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml"))
+ return Error (0, ErrorType::eErrorTypeGeneric);
+
+ XMLNode root_element = doc.GetRootElement("library-list");
+ if (!root_element)
+ return Error();
+
+ root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool {
+ GDBLoadedModuleInfoList::LoadedModuleInfo module;
+
+ llvm::StringRef name = library.GetAttributeValue("name");
+ module.set_name(name.str());
+
+ // The base address of a given library will be the address of its
+ // first section. Most remotes send only one section for Windows
+ // targets for example.
+ const XMLNode &section = library.FindFirstChildElementWithName("section");
+ llvm::StringRef address = section.GetAttributeValue("address");
+ module.set_base(StringConvert::ToUInt64(address.data(), LLDB_INVALID_ADDRESS, 0));
+
+ if (log)
+ {
+ std::string name;
+ lldb::addr_t base = 0;
+ module.get_name (name);
+ module.get_base (base);
+
+ log->Printf ("found (base:0x%" PRIx64 ", name:'%s')", base, name.c_str());
+ }
+
+ list.add (module);
+ return true; // Keep iterating over all "library" elements in the root node
+ });
+
+ if (log)
+ log->Printf ("found %" PRId32 " modules in total", (int) list.m_list.size());
+ } else {
+ return Error (0, ErrorType::eErrorTypeGeneric);
+ }
+
+ return Error();
+}
+
+lldb::ModuleSP
+ProcessGDBRemote::LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_addr)
+{
+ Target &target = m_process->GetTarget();
+ ModuleList &modules = target.GetImages();
+ ModuleSP module_sp;
+
+ bool changed = false;
+
+ ModuleSpec module_spec (file, target.GetArchitecture());
+ if ((module_sp = modules.FindFirstModule (module_spec)))
+ {
+ module_sp->SetLoadAddress (target, base_addr, true, changed);
+ }
+ else if ((module_sp = target.GetSharedModule (module_spec)))
+ {
+ module_sp->SetLoadAddress (target, base_addr, true, changed);
+ }
+
+ return module_sp;
+}
+
+size_t
+ProcessGDBRemote::LoadModules ()
+{
+ using lldb_private::process_gdb_remote::ProcessGDBRemote;
+
+ // request a list of loaded libraries from GDBServer
+ GDBLoadedModuleInfoList module_list;
+ if (GetLoadedModuleList (module_list).Fail())
+ return 0;
+
+ // get a list of all the modules
+ ModuleList new_modules;
+
+ for (GDBLoadedModuleInfoList::LoadedModuleInfo & modInfo : module_list.m_list)
+ {
+ std::string mod_name;
+ lldb::addr_t mod_base;
+
+ bool valid = true;
+ valid &= modInfo.get_name (mod_name);
+ valid &= modInfo.get_base (mod_base);
+ if (!valid)
+ continue;
+
+ // hack (cleaner way to get file name only?) (win/unix compat?)
+ size_t marker = mod_name.rfind ('/');
+ if (marker == std::string::npos)
+ marker = 0;
+ else
+ marker += 1;
+
+ FileSpec file (mod_name.c_str()+marker, true);
+ lldb::ModuleSP module_sp = LoadModuleAtAddress (file, mod_base);
+
+ if (module_sp.get())
+ new_modules.Append (module_sp);
+ }
+
+ if (new_modules.GetSize() > 0)
+ {
+ Target & target = m_target;
+
+ new_modules.ForEach ([&target](const lldb::ModuleSP module_sp) -> bool
+ {
+ lldb_private::ObjectFile * obj = module_sp->GetObjectFile ();
+ if (!obj)
+ return true;
+
+ if (obj->GetType () != ObjectFile::Type::eTypeExecutable)
+ return true;
+
+ lldb::ModuleSP module_copy_sp = module_sp;
+ target.SetExecutableModule (module_copy_sp, false);
+ return false;
+ });
+
+ ModuleList &loaded_modules = m_process->GetTarget().GetImages();
+ loaded_modules.AppendIfNeeded (new_modules);
+ m_process->GetTarget().ModulesDidLoad (new_modules);
+ }
+
+ return new_modules.GetSize();
+}
+
+Error
+ProcessGDBRemote::GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr)
+{
+ is_loaded = false;
+ load_addr = LLDB_INVALID_ADDRESS;
+
+ std::string file_path = file.GetPath(false);
+ if (file_path.empty ())
+ return Error("Empty file name specified");
+
+ StreamString packet;
+ packet.PutCString("qFileLoadAddress:");
+ packet.PutCStringAsRawHex8(file_path.c_str());
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), response, false) != GDBRemoteCommunication::PacketResult::Success)
+ return Error("Sending qFileLoadAddress packet failed");
+
+ if (response.IsErrorResponse())
+ {
+ if (response.GetError() == 1)
+ {
+ // The file is not loaded into the inferior
+ is_loaded = false;
+ load_addr = LLDB_INVALID_ADDRESS;
+ return Error();
+ }
+
+ return Error("Fetching file load address from remote server returned an error");
+ }
+
+ if (response.IsNormalResponse())
+ {
+ is_loaded = true;
+ load_addr = response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ return Error();
+ }
+
+ return Error("Unknown error happened during sending the load address packet");
+}
+
+
+void
+ProcessGDBRemote::ModulesDidLoad (ModuleList &module_list)
+{
+ // We must call the lldb_private::Process::ModulesDidLoad () first before we do anything
+ Process::ModulesDidLoad (module_list);
+
+ // After loading shared libraries, we can ask our remote GDB server if
+ // it needs any symbols.
+ m_gdb_comm.ServeSymbolLookups(this);
+}
+
+
+class CommandObjectProcessGDBRemoteSpeedTest: public CommandObjectParsed
+{
+public:
+ CommandObjectProcessGDBRemoteSpeedTest(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process plugin packet speed-test",
+ "Tests packet speeds of various sizes to determine the performance characteristics of the GDB remote connection. ",
+ NULL),
+ m_option_group (interpreter),
+ m_num_packets (LLDB_OPT_SET_1, false, "count", 'c', 0, eArgTypeCount, "The number of packets to send of each varying size (default is 1000).", 1000),
+ m_max_send (LLDB_OPT_SET_1, false, "max-send", 's', 0, eArgTypeCount, "The maximum number of bytes to send in a packet. Sizes increase in powers of 2 while the size is less than or equal to this option value. (default 1024).", 1024),
+ m_max_recv (LLDB_OPT_SET_1, false, "max-receive", 'r', 0, eArgTypeCount, "The maximum number of bytes to receive in a packet. Sizes increase in powers of 2 while the size is less than or equal to this option value. (default 1024).", 1024),
+ m_json (LLDB_OPT_SET_1, false, "json", 'j', "Print the output as JSON data for easy parsing.", false, true)
+ {
+ m_option_group.Append (&m_num_packets, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_max_send, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_max_recv, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_json, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ ~CommandObjectProcessGDBRemoteSpeedTest ()
+ {
+ }
+
+
+ Options *
+ GetOptions () override
+ {
+ return &m_option_group;
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result) override
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ {
+ StreamSP output_stream_sp (m_interpreter.GetDebugger().GetAsyncOutputStream());
+ result.SetImmediateOutputStream (output_stream_sp);
+
+ const uint32_t num_packets = (uint32_t)m_num_packets.GetOptionValue().GetCurrentValue();
+ const uint64_t max_send = m_max_send.GetOptionValue().GetCurrentValue();
+ const uint64_t max_recv = m_max_recv.GetOptionValue().GetCurrentValue();
+ const bool json = m_json.GetOptionValue().GetCurrentValue();
+ if (output_stream_sp)
+ process->GetGDBRemote().TestPacketSpeed (num_packets, max_send, max_recv, json, *output_stream_sp);
+ else
+ {
+ process->GetGDBRemote().TestPacketSpeed (num_packets, max_send, max_recv, json, result.GetOutputStream());
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' takes no arguments", m_cmd_name.c_str());
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+protected:
+ OptionGroupOptions m_option_group;
+ OptionGroupUInt64 m_num_packets;
+ OptionGroupUInt64 m_max_send;
+ OptionGroupUInt64 m_max_recv;
+ OptionGroupBoolean m_json;
+
+};
+
+class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed
+{
+private:
+
+public:
+ CommandObjectProcessGDBRemotePacketHistory(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process plugin packet history",
+ "Dumps the packet history buffer. ",
+ NULL)
+ {
+ }
+
+ ~CommandObjectProcessGDBRemotePacketHistory ()
+ {
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result) override
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ {
+ process->GetGDBRemote().DumpHistory(result.GetOutputStream());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' takes no arguments", m_cmd_name.c_str());
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+};
+
+class CommandObjectProcessGDBRemotePacketXferSize : public CommandObjectParsed
+{
+private:
+
+public:
+ CommandObjectProcessGDBRemotePacketXferSize(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process plugin packet xfer-size",
+ "Maximum size that lldb will try to read/write one one chunk.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectProcessGDBRemotePacketXferSize ()
+ {
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result) override
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ result.AppendErrorWithFormat ("'%s' takes an argument to specify the max amount to be transferred when reading/writing", m_cmd_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ {
+ const char *packet_size = command.GetArgumentAtIndex(0);
+ errno = 0;
+ uint64_t user_specified_max = strtoul (packet_size, NULL, 10);
+ if (errno == 0 && user_specified_max != 0)
+ {
+ process->SetUserSpecifiedMaxMemoryTransferSize (user_specified_max);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+};
+
+
+class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed
+{
+private:
+
+public:
+ CommandObjectProcessGDBRemotePacketSend(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process plugin packet send",
+ "Send a custom packet through the GDB remote protocol and print the answer. "
+ "The packet header and footer will automatically be added to the packet prior to sending and stripped from the result.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectProcessGDBRemotePacketSend ()
+ {
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result) override
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ result.AppendErrorWithFormat ("'%s' takes a one or more packet content arguments", m_cmd_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ {
+ for (size_t i=0; i<argc; ++ i)
+ {
+ const char *packet_cstr = command.GetArgumentAtIndex(0);
+ bool send_async = true;
+ StringExtractorGDBRemote response;
+ process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ Stream &output_strm = result.GetOutputStream();
+ output_strm.Printf (" packet: %s\n", packet_cstr);
+ std::string &response_str = response.GetStringRef();
+
+ if (strstr(packet_cstr, "qGetProfileData") != NULL)
+ {
+ response_str = process->GetGDBRemote().HarmonizeThreadIdsForProfileData(process, response);
+ }
+
+ if (response_str.empty())
+ output_strm.PutCString ("response: \nerror: UNIMPLEMENTED\n");
+ else
+ output_strm.Printf ("response: %s\n", response.GetStringRef().c_str());
+ }
+ }
+ return true;
+ }
+};
+
+class CommandObjectProcessGDBRemotePacketMonitor : public CommandObjectRaw
+{
+private:
+
+public:
+ CommandObjectProcessGDBRemotePacketMonitor(CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "process plugin packet monitor",
+ "Send a qRcmd packet through the GDB remote protocol and print the response."
+ "The argument passed to this command will be hex encoded into a valid 'qRcmd' packet, sent and the response will be printed.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectProcessGDBRemotePacketMonitor ()
+ {
+ }
+
+ bool
+ DoExecute (const char *command, CommandReturnObject &result) override
+ {
+ if (command == NULL || command[0] == '\0')
+ {
+ result.AppendErrorWithFormat ("'%s' takes a command string argument", m_cmd_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ {
+ StreamString packet;
+ packet.PutCString("qRcmd,");
+ packet.PutBytesAsRawHex8(command, strlen(command));
+ const char *packet_cstr = packet.GetString().c_str();
+
+ bool send_async = true;
+ StringExtractorGDBRemote response;
+ process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ Stream &output_strm = result.GetOutputStream();
+ output_strm.Printf (" packet: %s\n", packet_cstr);
+ const std::string &response_str = response.GetStringRef();
+
+ if (response_str.empty())
+ output_strm.PutCString ("response: \nerror: UNIMPLEMENTED\n");
+ else
+ output_strm.Printf ("response: %s\n", response.GetStringRef().c_str());
+ }
+ return true;
+ }
+};
+
+class CommandObjectProcessGDBRemotePacket : public CommandObjectMultiword
+{
+private:
+
+public:
+ CommandObjectProcessGDBRemotePacket(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "process plugin packet",
+ "Commands that deal with GDB remote packets.",
+ NULL)
+ {
+ LoadSubCommand ("history", CommandObjectSP (new CommandObjectProcessGDBRemotePacketHistory (interpreter)));
+ LoadSubCommand ("send", CommandObjectSP (new CommandObjectProcessGDBRemotePacketSend (interpreter)));
+ LoadSubCommand ("monitor", CommandObjectSP (new CommandObjectProcessGDBRemotePacketMonitor (interpreter)));
+ LoadSubCommand ("xfer-size", CommandObjectSP (new CommandObjectProcessGDBRemotePacketXferSize (interpreter)));
+ LoadSubCommand ("speed-test", CommandObjectSP (new CommandObjectProcessGDBRemoteSpeedTest (interpreter)));
+ }
+
+ ~CommandObjectProcessGDBRemotePacket ()
+ {
+ }
+};
+
+class CommandObjectMultiwordProcessGDBRemote : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordProcessGDBRemote (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "process plugin",
+ "A set of commands for operating on a ProcessGDBRemote process.",
+ "process plugin <subcommand> [<subcommand-options>]")
+ {
+ LoadSubCommand ("packet", CommandObjectSP (new CommandObjectProcessGDBRemotePacket (interpreter)));
+ }
+
+ ~CommandObjectMultiwordProcessGDBRemote ()
+ {
+ }
+};
+
+CommandObject *
+ProcessGDBRemote::GetPluginCommandObject()
+{
+ if (!m_command_sp)
+ m_command_sp.reset (new CommandObjectMultiwordProcessGDBRemote (GetTarget().GetDebugger().GetCommandInterpreter()));
+ return m_command_sp.get();
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
new file mode 100644
index 0000000..45c74ea
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -0,0 +1,467 @@
+//===-- ProcessGDBRemote.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessGDBRemote_h_
+#define liblldb_ProcessGDBRemote_h_
+
+// C Includes
+
+// C++ Includes
+#include <list>
+#include <vector>
+
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/StructuredData.h"
+#include "lldb/Core/ThreadSafeValue.h"
+#include "lldb/Host/HostThread.h"
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Utility/StringExtractor.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+#include "GDBRemoteCommunicationClient.h"
+#include "GDBRemoteRegisterContext.h"
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class ThreadGDBRemote;
+
+class ProcessGDBRemote : public Process
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ static lldb::ProcessSP
+ CreateInstance (Target& target,
+ Listener &listener,
+ const FileSpec *crash_file_path);
+
+ static void
+ Initialize();
+
+ static void
+ DebuggerInitialize (Debugger &debugger);
+
+ static void
+ Terminate();
+
+ static ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ProcessGDBRemote(Target& target, Listener &listener);
+
+ virtual
+ ~ProcessGDBRemote();
+
+ //------------------------------------------------------------------
+ // Check if a given Process
+ //------------------------------------------------------------------
+ bool
+ CanDebug (Target &target, bool plugin_specified_by_name) override;
+
+ CommandObject *
+ GetPluginCommandObject() override;
+
+ //------------------------------------------------------------------
+ // Creating a new process, or attaching to an existing one
+ //------------------------------------------------------------------
+ Error
+ WillLaunch (Module* module) override;
+
+ Error
+ DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) override;
+
+ void
+ DidLaunch () override;
+
+ Error
+ WillAttachToProcessWithID (lldb::pid_t pid) override;
+
+ Error
+ WillAttachToProcessWithName (const char *process_name, bool wait_for_launch) override;
+
+ Error
+ DoConnectRemote (Stream *strm, const char *remote_url) override;
+
+ Error
+ WillLaunchOrAttach ();
+
+ Error
+ DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info) override;
+
+ Error
+ DoAttachToProcessWithName (const char *process_name,
+ const ProcessAttachInfo &attach_info) override;
+
+ void
+ DidAttach (ArchSpec &process_arch) override;
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ ConstString
+ GetPluginName() override;
+
+ uint32_t
+ GetPluginVersion() override;
+
+ //------------------------------------------------------------------
+ // Process Control
+ //------------------------------------------------------------------
+ Error
+ WillResume () override;
+
+ Error
+ DoResume () override;
+
+ Error
+ DoHalt (bool &caused_stop) override;
+
+ Error
+ DoDetach (bool keep_stopped) override;
+
+ bool
+ DetachRequiresHalt() override { return true; }
+
+ Error
+ DoSignal (int signal) override;
+
+ Error
+ DoDestroy () override;
+
+ void
+ RefreshStateAfterStop() override;
+
+ //------------------------------------------------------------------
+ // Process Queries
+ //------------------------------------------------------------------
+ bool
+ IsAlive () override;
+
+ lldb::addr_t
+ GetImageInfoAddress() override;
+
+ //------------------------------------------------------------------
+ // Process Memory
+ //------------------------------------------------------------------
+ size_t
+ DoReadMemory (lldb::addr_t addr, void *buf, size_t size, Error &error) override;
+
+ size_t
+ DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, Error &error) override;
+
+ lldb::addr_t
+ DoAllocateMemory (size_t size, uint32_t permissions, Error &error) override;
+
+ Error
+ GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &region_info) override;
+
+ Error
+ DoDeallocateMemory (lldb::addr_t ptr) override;
+
+ //------------------------------------------------------------------
+ // Process STDIO
+ //------------------------------------------------------------------
+ size_t
+ PutSTDIN (const char *buf, size_t buf_size, Error &error) override;
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ Error
+ EnableBreakpointSite (BreakpointSite *bp_site) override;
+
+ Error
+ DisableBreakpointSite (BreakpointSite *bp_site) override;
+
+ //----------------------------------------------------------------------
+ // Process Watchpoints
+ //----------------------------------------------------------------------
+ Error
+ EnableWatchpoint (Watchpoint *wp, bool notify = true) override;
+
+ Error
+ DisableWatchpoint (Watchpoint *wp, bool notify = true) override;
+
+ Error
+ GetWatchpointSupportInfo (uint32_t &num) override;
+
+ Error
+ GetWatchpointSupportInfo (uint32_t &num, bool& after) override;
+
+ bool
+ StartNoticingNewThreads() override;
+
+ bool
+ StopNoticingNewThreads() override;
+
+ GDBRemoteCommunicationClient &
+ GetGDBRemote()
+ {
+ return m_gdb_comm;
+ }
+
+ Error
+ SendEventData(const char *data) override;
+
+ //----------------------------------------------------------------------
+ // Override DidExit so we can disconnect from the remote GDB server
+ //----------------------------------------------------------------------
+ void
+ DidExit () override;
+
+ void
+ SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max);
+
+ bool
+ GetModuleSpec(const FileSpec& module_file_spec,
+ const ArchSpec& arch,
+ ModuleSpec &module_spec) override;
+
+ size_t
+ LoadModules() override;
+
+ Error
+ GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr) override;
+
+ void
+ ModulesDidLoad (ModuleList &module_list) override;
+
+ StructuredData::ObjectSP
+ GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count) override;
+
+protected:
+ friend class ThreadGDBRemote;
+ friend class GDBRemoteCommunicationClient;
+ friend class GDBRemoteRegisterContext;
+
+ class GDBLoadedModuleInfoList;
+
+ //----------------------------------------------------------------------
+ // Accessors
+ //----------------------------------------------------------------------
+ bool
+ IsRunning ( lldb::StateType state )
+ {
+ return state == lldb::eStateRunning || IsStepping(state);
+ }
+
+ bool
+ IsStepping ( lldb::StateType state)
+ {
+ return state == lldb::eStateStepping;
+ }
+ bool
+ CanResume ( lldb::StateType state)
+ {
+ return state == lldb::eStateStopped;
+ }
+
+ bool
+ HasExited (lldb::StateType state)
+ {
+ return state == lldb::eStateExited;
+ }
+
+ bool
+ ProcessIDIsValid ( ) const;
+
+ void
+ Clear ( );
+
+ Flags &
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const Flags &
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+ bool
+ UpdateThreadList (ThreadList &old_thread_list,
+ ThreadList &new_thread_list) override;
+
+ Error
+ LaunchAndConnectToDebugserver (const ProcessInfo &process_info);
+
+ void
+ KillDebugserverProcess ();
+
+ void
+ BuildDynamicRegisterInfo (bool force);
+
+ void
+ SetLastStopPacket (const StringExtractorGDBRemote &response);
+
+ bool
+ ParsePythonTargetDefinition(const FileSpec &target_definition_fspec);
+
+ const lldb::DataBufferSP
+ GetAuxvData() override;
+
+ StructuredData::ObjectSP
+ GetExtendedInfoForThread (lldb::tid_t tid);
+
+ void
+ GetMaxMemorySize();
+
+ bool
+ CalculateThreadStopInfo (ThreadGDBRemote *thread);
+
+ size_t
+ UpdateThreadIDsFromStopReplyThreadsValue (std::string &value);
+
+ //------------------------------------------------------------------
+ /// Broadcaster event bits definitions.
+ //------------------------------------------------------------------
+ enum
+ {
+ eBroadcastBitAsyncContinue = (1 << 0),
+ eBroadcastBitAsyncThreadShouldExit = (1 << 1),
+ eBroadcastBitAsyncThreadDidExit = (1 << 2)
+ };
+
+ Flags m_flags; // Process specific flags (see eFlags enums)
+ GDBRemoteCommunicationClient m_gdb_comm;
+ std::atomic<lldb::pid_t> m_debugserver_pid;
+ std::vector<StringExtractorGDBRemote> m_stop_packet_stack; // The stop packet stack replaces the last stop packet variable
+ Mutex m_last_stop_packet_mutex;
+ GDBRemoteDynamicRegisterInfo m_register_info;
+ Broadcaster m_async_broadcaster;
+ HostThread m_async_thread;
+ Mutex m_async_thread_state_mutex;
+ typedef std::vector<lldb::tid_t> tid_collection;
+ typedef std::vector< std::pair<lldb::tid_t,int> > tid_sig_collection;
+ typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
+ typedef std::map<uint32_t, std::string> ExpeditedRegisterMap;
+ tid_collection m_thread_ids; // Thread IDs for all threads. This list gets updated after stopping
+ StructuredData::ObjectSP m_threads_info_sp; // Stop info for all threads if "jThreadsInfo" packet is supported
+ tid_collection m_continue_c_tids; // 'c' for continue
+ tid_sig_collection m_continue_C_tids; // 'C' for continue with signal
+ tid_collection m_continue_s_tids; // 's' for step
+ tid_sig_collection m_continue_S_tids; // 'S' for step with signal
+ uint64_t m_max_memory_size; // The maximum number of bytes to read/write when reading and writing memory
+ uint64_t m_remote_stub_max_memory_size; // The maximum memory size the remote gdb stub can handle
+ MMapMap m_addr_to_mmap_size;
+ lldb::BreakpointSP m_thread_create_bp_sp;
+ bool m_waiting_for_attach;
+ bool m_destroy_tried_resuming;
+ lldb::CommandObjectSP m_command_sp;
+ int64_t m_breakpoint_pc_offset;
+ lldb::tid_t m_initial_tid; // The inital thread ID, given by stub on attach
+
+ bool
+ HandleNotifyPacket(StringExtractorGDBRemote &packet);
+
+ bool
+ StartAsyncThread ();
+
+ void
+ StopAsyncThread ();
+
+ static lldb::thread_result_t
+ AsyncThread (void *arg);
+
+ static bool
+ MonitorDebugserverProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signo,
+ int exit_status);
+
+ lldb::StateType
+ SetThreadStopInfo (StringExtractor& stop_packet);
+
+ lldb::StateType
+ SetThreadStopInfo (StructuredData::Dictionary *thread_dict);
+
+ lldb::ThreadSP
+ SetThreadStopInfo (lldb::tid_t tid,
+ ExpeditedRegisterMap &expedited_register_map,
+ uint8_t signo,
+ const std::string &thread_name,
+ const std::string &reason,
+ const std::string &description,
+ uint32_t exc_type,
+ const std::vector<lldb::addr_t> &exc_data,
+ lldb::addr_t thread_dispatch_qaddr,
+ bool queue_vars_valid,
+ std::string &queue_name,
+ lldb::QueueKind queue_kind,
+ uint64_t queue_serial);
+
+ void
+ HandleStopReplySequence ();
+
+ void
+ ClearThreadIDList ();
+
+ bool
+ UpdateThreadIDList ();
+
+ void
+ DidLaunchOrAttach (ArchSpec& process_arch);
+
+ Error
+ ConnectToDebugserver (const char *host_port);
+
+ const char *
+ GetDispatchQueueNameForThread (lldb::addr_t thread_dispatch_qaddr,
+ std::string &dispatch_queue_name);
+
+ DynamicLoader *
+ GetDynamicLoader () override;
+
+ // Query remote GDBServer for register information
+ bool
+ GetGDBServerRegisterInfo ();
+
+ // Query remote GDBServer for a detailed loaded library list
+ Error
+ GetLoadedModuleList (GDBLoadedModuleInfoList &);
+
+ lldb::ModuleSP
+ LoadModuleAtAddress (const FileSpec &file, lldb::addr_t base_addr);
+
+private:
+ //------------------------------------------------------------------
+ // For ProcessGDBRemote only
+ //------------------------------------------------------------------
+ static bool
+ NewThreadNotifyBreakpointHit (void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ DISALLOW_COPY_AND_ASSIGN (ProcessGDBRemote);
+
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // liblldb_ProcessGDBRemote_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
new file mode 100644
index 0000000..d4726ad
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
@@ -0,0 +1,215 @@
+//===-- ProcessGDBRemoteLog.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessGDBRemoteLog.h"
+
+#include <mutex>
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/StreamFile.h"
+
+#include "ProcessGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+
+// We want to avoid global constructors where code needs to be run so here we
+// control access to our static g_log_sp by hiding it in a singleton function
+// that will construct the static g_lob_sp the first time this function is
+// called.
+static bool g_log_enabled = false;
+static Log * g_log = NULL;
+static Log *
+GetLog ()
+{
+ if (!g_log_enabled)
+ return NULL;
+ return g_log;
+}
+
+void
+ProcessGDBRemoteLog::Initialize()
+{
+ static ConstString g_name("gdb-remote");
+ static std::once_flag g_once_flag;
+
+ std::call_once(g_once_flag, [](){
+ Log::Callbacks log_callbacks = {
+ DisableLog,
+ EnableLog,
+ ListLogCategories
+ };
+
+ Log::RegisterLogChannel (g_name, log_callbacks);
+ });
+}
+
+Log *
+ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().Get();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+Log *
+ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && log->GetMask().Get() & mask)
+ return log;
+ return NULL;
+}
+
+void
+ProcessGDBRemoteLog::DisableLog (const char **categories, Stream *feedback_strm)
+{
+ Log *log (GetLog ());
+ if (log)
+ {
+ uint32_t flag_bits = 0;
+
+ if (categories[0] != NULL)
+ {
+ flag_bits = log->GetMask().Get();
+ for (size_t i = 0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+
+ if (::strcasecmp (arg, "all") == 0 ) flag_bits &= ~GDBR_LOG_ALL;
+ else if (::strcasecmp (arg, "async") == 0 ) flag_bits &= ~GDBR_LOG_ASYNC;
+ else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits &= ~GDBR_LOG_BREAKPOINTS;
+ else if (::strncasecmp (arg, "comm", 4) == 0 ) flag_bits &= ~GDBR_LOG_COMM;
+ else if (::strcasecmp (arg, "default") == 0 ) flag_bits &= ~GDBR_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "packets") == 0 ) flag_bits &= ~GDBR_LOG_PACKETS;
+ else if (::strcasecmp (arg, "memory") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "process") == 0 ) flag_bits &= ~GDBR_LOG_PROCESS;
+ else if (::strcasecmp (arg, "step") == 0 ) flag_bits &= ~GDBR_LOG_STEP;
+ else if (::strcasecmp (arg, "thread") == 0 ) flag_bits &= ~GDBR_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits &= ~GDBR_LOG_VERBOSE;
+ else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits &= ~GDBR_LOG_WATCHPOINTS;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ ListLogCategories (feedback_strm);
+ }
+
+ }
+ }
+
+ if (flag_bits == 0)
+ g_log_enabled = false;
+ else
+ log->GetMask().Reset (flag_bits);
+ }
+
+ return;
+}
+
+Log *
+ProcessGDBRemoteLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm)
+{
+ // Try see if there already is a log - that way we can reuse its settings.
+ // We could reuse the log in toto, but we don't know that the stream is the same.
+ uint32_t flag_bits = 0;
+ if (g_log)
+ flag_bits = g_log->GetMask().Get();
+
+ // Now make a new log with this stream if one was provided
+ if (log_stream_sp)
+ {
+ if (g_log)
+ g_log->SetStream(log_stream_sp);
+ else
+ g_log = new Log(log_stream_sp);
+ }
+
+ if (g_log)
+ {
+ bool got_unknown_category = false;
+ for (size_t i=0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+ if (::strcasecmp (arg, "all") == 0 ) flag_bits |= GDBR_LOG_ALL;
+ else if (::strcasecmp (arg, "async") == 0 ) flag_bits |= GDBR_LOG_ASYNC;
+ else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits |= GDBR_LOG_BREAKPOINTS;
+ else if (::strncasecmp (arg, "comm", 4) == 0 ) flag_bits |= GDBR_LOG_COMM;
+ else if (::strcasecmp (arg, "default") == 0 ) flag_bits |= GDBR_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "packets") == 0 ) flag_bits |= GDBR_LOG_PACKETS;
+ else if (::strcasecmp (arg, "memory") == 0 ) flag_bits |= GDBR_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits |= GDBR_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits |= GDBR_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "process") == 0 ) flag_bits |= GDBR_LOG_PROCESS;
+ else if (::strcasecmp (arg, "step") == 0 ) flag_bits |= GDBR_LOG_STEP;
+ else if (::strcasecmp (arg, "thread") == 0 ) flag_bits |= GDBR_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits |= GDBR_LOG_VERBOSE;
+ else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits |= GDBR_LOG_WATCHPOINTS;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ if (got_unknown_category == false)
+ {
+ got_unknown_category = true;
+ ListLogCategories (feedback_strm);
+ }
+ }
+ }
+ if (flag_bits == 0)
+ flag_bits = GDBR_LOG_DEFAULT;
+ g_log->GetMask().Reset(flag_bits);
+ g_log->GetOptions().Reset(log_options);
+ }
+ g_log_enabled = true;
+ return g_log;
+}
+
+void
+ProcessGDBRemoteLog::ListLogCategories (Stream *strm)
+{
+ strm->Printf ("Logging categories for '%s':\n"
+ " all - turn on all available logging categories\n"
+ " async - log asynchronous activity\n"
+ " break - log breakpoints\n"
+ " communication - log communication activity\n"
+ " default - enable the default set of logging categories for liblldb\n"
+ " packets - log gdb remote packets\n"
+ " memory - log memory reads and writes\n"
+ " data-short - log memory bytes for memory reads and writes for short transactions only\n"
+ " data-long - log memory bytes for memory reads and writes for all transactions\n"
+ " process - log process events and activities\n"
+ " thread - log thread events and activities\n"
+ " step - log step related activities\n"
+ " verbose - enable verbose logging\n"
+ " watch - log watchpoint related activities\n", ProcessGDBRemote::GetPluginNameStatic().GetCString());
+}
+
+
+void
+ProcessGDBRemoteLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (mask));
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
new file mode 100644
index 0000000..3cd974d
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
@@ -0,0 +1,66 @@
+//===-- ProcessGDBRemoteLog.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessGDBRemoteLog_h_
+#define liblldb_ProcessGDBRemoteLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Log.h"
+
+#define GDBR_LOG_VERBOSE (1u << 0)
+#define GDBR_LOG_PROCESS (1u << 1)
+#define GDBR_LOG_THREAD (1u << 2)
+#define GDBR_LOG_PACKETS (1u << 3)
+#define GDBR_LOG_MEMORY (1u << 4) // Log memory reads/writes calls
+#define GDBR_LOG_MEMORY_DATA_SHORT (1u << 5) // Log short memory reads/writes bytes
+#define GDBR_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes
+#define GDBR_LOG_BREAKPOINTS (1u << 7)
+#define GDBR_LOG_WATCHPOINTS (1u << 8)
+#define GDBR_LOG_STEP (1u << 9)
+#define GDBR_LOG_COMM (1u << 10)
+#define GDBR_LOG_ASYNC (1u << 11)
+#define GDBR_LOG_ALL (UINT32_MAX)
+#define GDBR_LOG_DEFAULT GDBR_LOG_PACKETS
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class ProcessGDBRemoteLog
+{
+public:
+ static void
+ Initialize();
+
+ static Log *
+ GetLogIfAllCategoriesSet(uint32_t mask = 0);
+
+ static Log *
+ GetLogIfAnyCategoryIsSet (uint32_t mask);
+
+ static void
+ DisableLog (const char **categories, Stream *feedback_strm);
+
+ static Log *
+ EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm);
+
+ static void
+ ListLogCategories (Stream *strm);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // liblldb_ProcessGDBRemoteLog_h_
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
new file mode 100644
index 0000000..d2a6503
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
@@ -0,0 +1,324 @@
+//===-- ThreadGDBRemote.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "ThreadGDBRemote.h"
+
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/SystemRuntime.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Target/Unwind.h"
+
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "Utility/StringExtractorGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+//----------------------------------------------------------------------
+// Thread Registers
+//----------------------------------------------------------------------
+
+ThreadGDBRemote::ThreadGDBRemote (Process &process, lldb::tid_t tid) :
+ Thread(process, tid),
+ m_thread_name (),
+ m_dispatch_queue_name (),
+ m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS),
+ m_queue_kind(eQueueKindUnknown),
+ m_queue_serial(0)
+{
+ ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)",
+ this,
+ process.GetID(),
+ GetID());
+}
+
+ThreadGDBRemote::~ThreadGDBRemote ()
+{
+ ProcessSP process_sp(GetProcess());
+ ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::~ThreadGDBRemote (pid = %i, tid = 0x%4.4x)",
+ this,
+ process_sp ? process_sp->GetID() : LLDB_INVALID_PROCESS_ID,
+ GetID());
+ DestroyThread();
+}
+
+const char *
+ThreadGDBRemote::GetName ()
+{
+ if (m_thread_name.empty())
+ return NULL;
+ return m_thread_name.c_str();
+}
+
+void
+ThreadGDBRemote::ClearQueueInfo ()
+{
+ m_dispatch_queue_name.clear();
+ m_queue_kind = eQueueKindUnknown;
+ m_queue_serial = 0;
+}
+
+void
+ThreadGDBRemote::SetQueueInfo (std::string &&queue_name, QueueKind queue_kind, uint64_t queue_serial)
+{
+ m_dispatch_queue_name = queue_name;
+ m_queue_kind = queue_kind;
+ m_queue_serial = queue_serial;
+}
+
+
+const char *
+ThreadGDBRemote::GetQueueName ()
+{
+ // If our cached queue info is valid, then someone called ThreadGDBRemote::SetQueueInfo(...)
+ // with valid information that was gleaned from the stop reply packet. In this case we trust
+ // that the info is valid in m_dispatch_queue_name without refetching it
+ if (CachedQueueInfoIsValid())
+ {
+ if (m_dispatch_queue_name.empty())
+ return nullptr;
+ else
+ return m_dispatch_queue_name.c_str();
+ }
+ // Always re-fetch the dispatch queue name since it can change
+
+ if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ SystemRuntime *runtime = process_sp->GetSystemRuntime ();
+ if (runtime)
+ m_dispatch_queue_name = runtime->GetQueueNameFromThreadQAddress (m_thread_dispatch_qaddr);
+ else
+ m_dispatch_queue_name.clear();
+
+ if (!m_dispatch_queue_name.empty())
+ return m_dispatch_queue_name.c_str();
+ }
+ }
+ return NULL;
+}
+
+queue_id_t
+ThreadGDBRemote::GetQueueID ()
+{
+ // If our cached queue info is valid, then someone called ThreadGDBRemote::SetQueueInfo(...)
+ // with valid information that was gleaned from the stop reply packet. In this case we trust
+ // that the info is valid in m_dispatch_queue_name without refetching it
+ if (CachedQueueInfoIsValid())
+ return m_queue_serial;
+
+ if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ SystemRuntime *runtime = process_sp->GetSystemRuntime ();
+ if (runtime)
+ {
+ return runtime->GetQueueIDFromThreadQAddress (m_thread_dispatch_qaddr);
+ }
+ }
+ }
+ return LLDB_INVALID_QUEUE_ID;
+}
+
+QueueSP
+ThreadGDBRemote::GetQueue ()
+{
+ queue_id_t queue_id = GetQueueID();
+ QueueSP queue;
+ if (queue_id != LLDB_INVALID_QUEUE_ID)
+ {
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ queue = process_sp->GetQueueList().FindQueueByID (queue_id);
+ }
+ }
+ return queue;
+}
+
+addr_t
+ThreadGDBRemote::GetQueueLibdispatchQueueAddress ()
+{
+ addr_t dispatch_queue_t_addr = LLDB_INVALID_ADDRESS;
+ if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ SystemRuntime *runtime = process_sp->GetSystemRuntime ();
+ if (runtime)
+ {
+ dispatch_queue_t_addr = runtime->GetLibdispatchQueueAddressFromThreadQAddress (m_thread_dispatch_qaddr);
+ }
+ }
+ }
+ return dispatch_queue_t_addr;
+}
+
+StructuredData::ObjectSP
+ThreadGDBRemote::FetchThreadExtendedInfo ()
+{
+ StructuredData::ObjectSP object_sp;
+ const lldb::user_id_t tid = GetProtocolID();
+ Log *log(GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD));
+ if (log)
+ log->Printf ("Fetching extended information for thread %4.4" PRIx64, tid);
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get());
+ object_sp = gdb_process->GetExtendedInfoForThread (tid);
+ }
+ return object_sp;
+}
+
+void
+ThreadGDBRemote::WillResume (StateType resume_state)
+{
+ int signo = GetResumeSignal();
+ const lldb::user_id_t tid = GetProtocolID();
+ Log *log(GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD));
+ if (log)
+ log->Printf ("Resuming thread: %4.4" PRIx64 " with state: %s.", tid, StateAsCString(resume_state));
+
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get());
+ switch (resume_state)
+ {
+ case eStateSuspended:
+ case eStateStopped:
+ // Don't append anything for threads that should stay stopped.
+ break;
+
+ case eStateRunning:
+ if (gdb_process->GetUnixSignals()->SignalIsValid(signo))
+ gdb_process->m_continue_C_tids.push_back(std::make_pair(tid, signo));
+ else
+ gdb_process->m_continue_c_tids.push_back(tid);
+ break;
+
+ case eStateStepping:
+ if (gdb_process->GetUnixSignals()->SignalIsValid(signo))
+ gdb_process->m_continue_S_tids.push_back(std::make_pair(tid, signo));
+ else
+ gdb_process->m_continue_s_tids.push_back(tid);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void
+ThreadGDBRemote::RefreshStateAfterStop()
+{
+ // Invalidate all registers in our register context. We don't set "force" to
+ // true because the stop reply packet might have had some register values
+ // that were expedited and these will already be copied into the register
+ // context by the time this function gets called. The GDBRemoteRegisterContext
+ // class has been made smart enough to detect when it needs to invalidate
+ // which registers are valid by putting hooks in the register read and
+ // register supply functions where they check the process stop ID and do
+ // the right thing.
+ const bool force = false;
+ GetRegisterContext()->InvalidateIfNeeded (force);
+}
+
+bool
+ThreadGDBRemote::ThreadIDIsValid (lldb::tid_t thread)
+{
+ return thread != 0;
+}
+
+void
+ThreadGDBRemote::Dump(Log *log, uint32_t index)
+{
+}
+
+
+bool
+ThreadGDBRemote::ShouldStop (bool &step_more)
+{
+ return true;
+}
+lldb::RegisterContextSP
+ThreadGDBRemote::GetRegisterContext ()
+{
+ if (m_reg_context_sp.get() == NULL)
+ m_reg_context_sp = CreateRegisterContextForFrame (NULL);
+ return m_reg_context_sp;
+}
+
+lldb::RegisterContextSP
+ThreadGDBRemote::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex ();
+
+
+ if (concrete_frame_idx == 0)
+ {
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get());
+ // read_all_registers_at_once will be true if 'p' packet is not supported.
+ bool read_all_registers_at_once = !gdb_process->GetGDBRemote().GetpPacketSupported (GetID());
+ reg_ctx_sp.reset (new GDBRemoteRegisterContext (*this, concrete_frame_idx, gdb_process->m_register_info, read_all_registers_at_once));
+ }
+ }
+ else
+ {
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ reg_ctx_sp = unwinder->CreateRegisterContextForFrame (frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool
+ThreadGDBRemote::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response)
+{
+ GDBRemoteRegisterContext *gdb_reg_ctx = static_cast<GDBRemoteRegisterContext *>(GetRegisterContext ().get());
+ assert (gdb_reg_ctx);
+ return gdb_reg_ctx->PrivateSetRegisterValue (reg, response);
+}
+
+bool
+ThreadGDBRemote::CalculateStopInfo ()
+{
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ return static_cast<ProcessGDBRemote *>(process_sp.get())->CalculateThreadStopInfo(this);
+ return false;
+}
+
+
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
new file mode 100644
index 0000000..175433a
--- /dev/null
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
@@ -0,0 +1,138 @@
+//===-- ThreadGDBRemote.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ThreadGDBRemote_h_
+#define liblldb_ThreadGDBRemote_h_
+
+#include <string>
+
+#include "lldb/Core/StructuredData.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+class StringExtractor;
+
+namespace lldb_private {
+namespace process_gdb_remote {
+
+class ProcessGDBRemote;
+
+class ThreadGDBRemote : public Thread
+{
+public:
+ ThreadGDBRemote (Process &process, lldb::tid_t tid);
+
+ virtual
+ ~ThreadGDBRemote ();
+
+ void
+ WillResume (lldb::StateType resume_state) override;
+
+ void
+ RefreshStateAfterStop() override;
+
+ const char *
+ GetName () override;
+
+ const char *
+ GetQueueName () override;
+
+ lldb::queue_id_t
+ GetQueueID () override;
+
+ lldb::QueueSP
+ GetQueue () override;
+
+ lldb::addr_t
+ GetQueueLibdispatchQueueAddress () override;
+
+ lldb::RegisterContextSP
+ GetRegisterContext () override;
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame (StackFrame *frame) override;
+
+ void
+ Dump (Log *log, uint32_t index);
+
+ static bool
+ ThreadIDIsValid (lldb::tid_t thread);
+
+ bool
+ ShouldStop (bool &step_more);
+
+ const char *
+ GetBasicInfoAsString ();
+
+ void
+ SetName (const char *name) override
+ {
+ if (name && name[0])
+ m_thread_name.assign (name);
+ else
+ m_thread_name.clear();
+ }
+
+ lldb::addr_t
+ GetThreadDispatchQAddr ()
+ {
+ return m_thread_dispatch_qaddr;
+ }
+
+ void
+ SetThreadDispatchQAddr (lldb::addr_t thread_dispatch_qaddr)
+ {
+ m_thread_dispatch_qaddr = thread_dispatch_qaddr;
+ }
+
+ void
+ ClearQueueInfo ();
+
+ void
+ SetQueueInfo (std::string &&queue_name, lldb::QueueKind queue_kind, uint64_t queue_serial);
+
+ StructuredData::ObjectSP
+ FetchThreadExtendedInfo () override;
+
+protected:
+
+ friend class ProcessGDBRemote;
+
+ bool
+ PrivateSetRegisterValue (uint32_t reg,
+ StringExtractor &response);
+
+ bool
+ CachedQueueInfoIsValid() const
+ {
+ return m_queue_kind != lldb::eQueueKindUnknown;
+ }
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ std::string m_thread_name;
+ std::string m_dispatch_queue_name;
+ lldb::addr_t m_thread_dispatch_qaddr;
+ lldb::QueueKind m_queue_kind; // Queue info from stop reply/stop info for thread
+ uint64_t m_queue_serial; // Queue info from stop reply/stop info for thread
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+
+ void
+ SetStopInfoFromPacket (StringExtractor &stop_packet, uint32_t stop_id);
+
+ bool
+ CalculateStopInfo () override;
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // liblldb_ThreadGDBRemote_h_
OpenPOWER on IntegriCloud