Add Linux support for reading/writing extended register sets.

Patch by Ashok Thirumurthi.

llvm-svn: 177568
diff --git a/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp b/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp
index 6528b7e..cc41234 100644
--- a/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp
+++ b/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp
@@ -39,6 +39,14 @@
 
 #define DEBUG_PTRACE_MAXBYTES 20
 
+// Support ptrace extensions even when compiled without required kernel support
+#ifndef PTRACE_GETREGSET
+  #define PTRACE_GETREGSET 0x4204
+#endif
+#ifndef PTRACE_SETREGSET
+  #define PTRACE_SETREGSET 0x4205
+#endif
+
 using namespace lldb_private;
 
 // FIXME: this code is host-dependent with respect to types and
@@ -63,7 +71,7 @@
     }
 }
 
-static void PtraceDisplayBytes(__ptrace_request &req, void *data, size_t data_size)
+static void PtraceDisplayBytes(int &req, void *data, size_t data_size)
 {
     StreamString buf;
     LogSP verbose_log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (
@@ -109,6 +117,13 @@
                 verbose_log->Printf("PTRACE_SETSIGINFO %s", buf.GetData());
                 break;
             }
+        case PTRACE_SETREGSET:
+            {
+                // Extract iov_base from data, which is a pointer to the struct IOVEC
+                DisplayBytes(buf, *(void **)data, data_size);
+                verbose_log->Printf("PTRACE_SETREGSET %s", buf.GetData());
+                break;
+            }
         default:
             {
             }
@@ -119,7 +134,7 @@
 // Wrapper for ptrace to catch errors and log calls.
 // Note that ptrace sets errno on error because -1 is a valid result for PTRACE_PEEK*
 extern long
-PtraceWrapper(__ptrace_request req, pid_t pid, void *addr, void *data, size_t data_size,
+PtraceWrapper(int req, lldb::pid_t pid, void *addr, void *data, size_t data_size,
               const char* reqName, const char* file, int line)
 {
     long int result;
@@ -127,13 +142,16 @@
     LogSP log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PTRACE));
 
     if (log)
-        log->Printf("ptrace(%s, %u, %p, %p, %zu) called from file %s line %d",
+        log->Printf("ptrace(%s, %lu, %p, %p, %zu) called from file %s line %d",
                     reqName, pid, addr, data, data_size, file, line);
 
     PtraceDisplayBytes(req, data, data_size);
 
     errno = 0;
-    result = ptrace(req, pid, addr, data);
+    if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET)
+        result = ptrace(static_cast<__ptrace_request>(req), pid, *(unsigned int *)addr, data);
+    else
+        result = ptrace(static_cast<__ptrace_request>(req), pid, addr, data);
 
     PtraceDisplayBytes(req, data, data_size);
 
@@ -157,10 +175,14 @@
 // Wrapper for ptrace when logging is not required.
 // Sets errno to 0 prior to calling ptrace.
 extern long
-PtraceWrapper(__ptrace_request req, pid_t pid, void *addr, void *data, size_t data_size)
+PtraceWrapper(int req, pid_t pid, void *addr, void *data, size_t data_size)
 {
+    long result = 0;
     errno = 0;
-    long result = ptrace(req, pid, addr, data);
+    if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET)
+        result = ptrace(static_cast<__ptrace_request>(req), pid, *(unsigned int *)addr, data);
+    else
+        result = ptrace(static_cast<__ptrace_request>(req), pid, addr, data);
     return result;
 }
 
@@ -556,6 +578,35 @@
 }
 
 //------------------------------------------------------------------------------
+/// @class ReadRegisterSetOperation
+/// @brief Implements ProcessMonitor::ReadRegisterSet.
+class ReadRegisterSetOperation : public Operation
+{
+public:
+    ReadRegisterSetOperation(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset, bool &result)
+        : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_regset(regset), m_result(result)
+        { }
+
+    void Execute(ProcessMonitor *monitor);
+
+private:
+    lldb::tid_t m_tid;
+    void *m_buf;
+    size_t m_buf_size;
+    const unsigned int m_regset;
+    bool &m_result;
+};
+
+void
+ReadRegisterSetOperation::Execute(ProcessMonitor *monitor)
+{
+    if (PTRACE(PTRACE_GETREGSET, m_tid, (void *)&m_regset, m_buf, m_buf_size) < 0)
+        m_result = false;
+    else
+        m_result = true;
+}
+
+//------------------------------------------------------------------------------
 /// @class WriteGPROperation
 /// @brief Implements ProcessMonitor::WriteGPR.
 class WriteGPROperation : public Operation
@@ -612,6 +663,35 @@
 }
 
 //------------------------------------------------------------------------------
+/// @class WriteRegisterSetOperation
+/// @brief Implements ProcessMonitor::WriteRegisterSet.
+class WriteRegisterSetOperation : public Operation
+{
+public:
+    WriteRegisterSetOperation(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset, bool &result)
+        : m_tid(tid), m_buf(buf), m_buf_size(buf_size), m_regset(regset), m_result(result)
+        { }
+
+    void Execute(ProcessMonitor *monitor);
+
+private:
+    lldb::tid_t m_tid;
+    void *m_buf;
+    size_t m_buf_size;
+    const unsigned int m_regset;
+    bool &m_result;
+};
+
+void
+WriteRegisterSetOperation::Execute(ProcessMonitor *monitor)
+{
+    if (PTRACE(PTRACE_SETREGSET, m_tid, (void *)&m_regset, m_buf, m_buf_size) < 0)
+        m_result = false;
+    else
+        m_result = true;
+}
+
+//------------------------------------------------------------------------------
 /// @class ResumeOperation
 /// @brief Implements ProcessMonitor::Resume.
 class ResumeOperation : public Operation
@@ -1664,6 +1744,15 @@
 }
 
 bool
+ProcessMonitor::ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+    bool result;
+    ReadRegisterSetOperation op(tid, buf, buf_size, regset, result);
+    DoOperation(&op);
+    return result;
+}
+
+bool
 ProcessMonitor::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size)
 {
     bool result;
@@ -1682,6 +1771,15 @@
 }
 
 bool
+ProcessMonitor::WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+    bool result;
+    WriteRegisterSetOperation op(tid, buf, buf_size, regset, result);
+    DoOperation(&op);
+    return result;
+}
+
+bool
 ProcessMonitor::Resume(lldb::tid_t tid, uint32_t signo)
 {
     bool result;