[Lldb-commits] [lldb] r278915 - Move packet construction from GDBRemoteRegisterContext go the communication class

Pavel Labath via lldb-commits lldb-commits at lists.llvm.org
Wed Aug 17 01:53:32 PDT 2016


Author: labath
Date: Wed Aug 17 03:53:31 2016
New Revision: 278915

URL: http://llvm.org/viewvc/llvm-project?rev=278915&view=rev
Log:
Move packet construction from GDBRemoteRegisterContext go the communication class

Summary:
When saving/restoring registers the GDBRemoteRegisterContext class was manually constructing
the register save/restore packets. This creates appropriate helper functions in
GDBRemoteCommunicationClient, and switches the class to use those. It also removes what a
duplicate packet send in some of those functions, a thing that I can only attribute to a bad
merge artefact.

I also add a test framework for testing gdb-remote client functionality and add tests for the new
functions I introduced. I'd like to be able to test the register context changes in isolation as
well, but currently there doesn't seem to be a way to reasonably construct a standalone register
context object, so we'll have to rely on the end-to-end tests to verify that.

Reviewers: clayborg

Subscribers: lldb-commits

Differential Revision: https://reviews.llvm.org/D23553

Added:
    lldb/trunk/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
    lldb/trunk/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp
    lldb/trunk/unittests/Process/gdb-remote/GDBRemoteTestUtils.h
Modified:
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
    lldb/trunk/unittests/Process/gdb-remote/CMakeLists.txt
    lldb/trunk/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp?rev=278915&r1=278914&r2=278915&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp Wed Aug 17 03:53:31 2016
@@ -3526,6 +3526,57 @@ GDBRemoteCommunicationClient::ReadAllReg
     }
     return false;
 }
+
+bool
+GDBRemoteCommunicationClient::WriteRegister(lldb::tid_t tid, uint32_t reg_num, llvm::StringRef data)
+{
+    Lock lock(*this, false);
+    if (!lock)
+    {
+        if (Log *log = ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | GDBR_LOG_PACKETS))
+            log->Printf("GDBRemoteCommunicationClient::%s: Didn't get sequence mutex for P packet.", __FUNCTION__);
+        return false;
+    }
+
+    const bool thread_suffix_supported = GetThreadSuffixSupported();
+    if (!thread_suffix_supported && !SetCurrentThread(tid))
+        return false;
+
+    StreamString packet;
+    packet.Printf("P%x=", reg_num);
+    packet.PutBytesAsRawHex8(data.data(), data.size(), endian::InlHostByteOrder(), endian::InlHostByteOrder());
+    if (thread_suffix_supported)
+        packet.Printf(";thread:%4.4" PRIx64 ";", tid);
+    StringExtractorGDBRemote response;
+    return SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success &&
+           response.IsOKResponse();
+}
+
+bool
+GDBRemoteCommunicationClient::WriteAllRegisters(lldb::tid_t tid, llvm::StringRef data)
+{
+    Lock lock(*this, false);
+    if (!lock)
+    {
+        if (Log *log = ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | GDBR_LOG_PACKETS))
+            log->Printf("GDBRemoteCommunicationClient::%s: Didn't get sequence mutex for G packet.", __FUNCTION__);
+        return false;
+    }
+
+    const bool thread_suffix_supported = GetThreadSuffixSupported();
+    if (!thread_suffix_supported && !SetCurrentThread(tid))
+        return false;
+
+    StreamString packet;
+    packet.PutChar('G');
+    packet.Write(data.data(), data.size());
+    if (thread_suffix_supported)
+        packet.Printf(";thread:%4.4" PRIx64 ";", tid);
+    StringExtractorGDBRemote response;
+    return SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success &&
+           response.IsOKResponse();
+}
+
 bool
 GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save_id)
 {

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h?rev=278915&r1=278914&r2=278915&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h Wed Aug 17 03:53:31 2016
@@ -497,8 +497,15 @@ public:
                       StringExtractorGDBRemote &response);
 
     bool
-    SaveRegisterState (lldb::tid_t tid, uint32_t &save_id);
-    
+    WriteRegister(lldb::tid_t tid, uint32_t reg_num, // eRegisterKindProcessPlugin register number
+                  llvm::StringRef data);
+
+    bool
+    WriteAllRegisters(lldb::tid_t tid, llvm::StringRef data);
+
+    bool
+    SaveRegisterState(lldb::tid_t tid, uint32_t &save_id);
+
     bool
     RestoreRegisterState (lldb::tid_t tid, uint32_t save_id);
 

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp?rev=278915&r1=278914&r2=278915&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp Wed Aug 17 03:53:31 2016
@@ -576,70 +576,40 @@ GDBRemoteRegisterContext::ReadAllRegiste
     if (lock)
     {
         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()))
+
+        if (use_g_packet && gdb_comm.ReadAllRegisters(m_thread.GetProtocolID(), response))
         {
-            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 (response.IsErrorResponse())
+                return false;
 
-            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;
+            std::string &response_str = response.GetStringRef();
+            if (!isxdigit(response_str[0]))
+                return false;
 
-                // data_sp will take ownership of this DataBufferHeap pointer soon.
-                DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0));
+            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;
 
-                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 will take ownership of this DataBufferHeap pointer soon.
+            DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0));
 
-                data_sp = reg_ctx;
-                return true;
+            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
@@ -684,236 +654,154 @@ GDBRemoteRegisterContext::WriteAllRegist
     GDBRemoteClientBase::Lock lock(gdb_comm, false);
     if (lock)
     {
-        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 G response packet.
+        llvm::StringRef data(reinterpret_cast<const char *>(data_sp->GetBytes()), data_sp->GetByteSize());
+        if (use_g_packet)
         {
-            // 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)
+            if (gdb_comm.WriteAllRegisters(m_thread.GetProtocolID(), data))
+                return true;
+
+            uint32_t num_restored = 0;
+            // We need to manually go through all of the registers and
+            // restore them manually
+
+            response.GetStringRef() = data;
+            DataBufferHeap buffer(data.size() / 2, 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)
             {
-                // 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_info->kinds[eRegisterKindProcessPlugin]);
-                                packet.PutBytesAsRawHex8 (restore_src,
-                                                          reg_byte_size,
-                                                          endian::InlHostByteOrder(),
-                                                          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_info->kinds[eRegisterKindProcessPlugin]);
-                                    packet.PutBytesAsRawHex8 (restore_src,
-                                                              reg_byte_size,
-                                                              endian::InlHostByteOrder(),
-                                                              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;
-                    }
-                }
+                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
             {
-                // 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.
+                // 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;
+            }
 
-                bool arm64_debugserver = false;
-                if (m_thread.GetProcess().get())
+            // 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)
                 {
-                    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;
-                    }
+                    register_offset = reg_info->byte_offset;
                 }
-                uint32_t num_restored = 0;
-                const RegisterInfo *reg_info;
-                for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++)
+                else
+                {
+                    register_offset = running_byte_offset;
+                }
+
+                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)
+                {
+                    SetRegisterIsValid(reg, false);
+                    if (gdb_comm.WriteRegister(m_thread.GetProtocolID(), reg_info->kinds[eRegisterKindProcessPlugin],
+                                               llvm::StringRef(restore_src, reg_byte_size)))
+                        ++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;
+                }
+
+                SetRegisterIsValid(reg_info, false);
+                if (gdb_comm.WriteRegister(
+                        m_thread.GetProtocolID(), reg_info->kinds[eRegisterKindProcessPlugin],
+                        llvm::StringRef(reinterpret_cast<const char *>(data_sp->GetBytes() + reg_info->byte_offset),
+                                        reg_info->byte_size)))
                 {
-                    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[eRegisterKindProcessPlugin]);
-                    packet.PutBytesAsRawHex8 (data_sp->GetBytes() + reg_info->byte_offset, reg_info->byte_size, endian::InlHostByteOrder(), 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;
-                    }
+                    ++num_restored;
                 }
-                return num_restored > 0;
             }
+            return num_restored > 0;
         }
     }
     else

Modified: lldb/trunk/unittests/Process/gdb-remote/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/gdb-remote/CMakeLists.txt?rev=278915&r1=278914&r2=278915&view=diff
==============================================================================
--- lldb/trunk/unittests/Process/gdb-remote/CMakeLists.txt (original)
+++ lldb/trunk/unittests/Process/gdb-remote/CMakeLists.txt Wed Aug 17 03:53:31 2016
@@ -1,3 +1,5 @@
 add_lldb_unittest(ProcessGdbRemoteTests
   GDBRemoteClientBaseTest.cpp
+  GDBRemoteCommunicationClientTest.cpp
+  GDBRemoteTestUtils.cpp
   )

Modified: lldb/trunk/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp?rev=278915&r1=278914&r2=278915&view=diff
==============================================================================
--- lldb/trunk/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp (original)
+++ lldb/trunk/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp Wed Aug 17 03:53:31 2016
@@ -14,15 +14,13 @@
 #endif
 #include <future>
 
+#include "GDBRemoteTestUtils.h"
 #include "gtest/gtest.h"
 
 #include "Plugins/Process/Utility/LinuxSignals.h"
 #include "Plugins/Process/gdb-remote/GDBRemoteClientBase.h"
 #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"
 
-#include "lldb/Host/common/TCPSocket.h"
-#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
-
 #include "llvm/ADT/STLExtras.h"
 
 using namespace lldb_private::process_gdb_remote;
@@ -56,25 +54,6 @@ struct MockDelegate : public GDBRemoteCl
     }
 };
 
-struct MockServer : public GDBRemoteCommunicationServer
-{
-    MockServer() : GDBRemoteCommunicationServer("mock-server", "mock-server.listener") { m_send_acks = false; }
-
-    PacketResult
-    SendPacket(llvm::StringRef payload)
-    {
-        return GDBRemoteCommunicationServer::SendPacketNoLock(payload.data(), payload.size());
-    }
-
-    PacketResult
-    GetPacket(StringExtractorGDBRemote &response)
-    {
-        const unsigned timeout_usec = 1000000; // 1s
-        const bool sync_on_timeout = false;
-        return WaitForPacketWithTimeoutMicroSecondsNoLock(response, timeout_usec, sync_on_timeout);
-    }
-};
-
 struct TestClient : public GDBRemoteClientBase
 {
     TestClient() : GDBRemoteClientBase("test.client", "test.client.listener") { m_send_acks = false; }
@@ -106,53 +85,14 @@ struct ContinueFixture
 
 ContinueFixture::ContinueFixture() : listener_sp(Listener::MakeListener("listener"))
 {
-    bool child_processes_inherit = false;
-    Error error;
-    TCPSocket listen_socket(child_processes_inherit, error);
-    EXPECT_FALSE(error.Fail());
-    error = listen_socket.Listen("127.0.0.1:0", 5);
-    EXPECT_FALSE(error.Fail());
-
-    Socket *accept_socket;
-    std::future<Error> accept_error = std::async(std::launch::async, [&] {
-        return listen_socket.Accept("127.0.0.1:0", child_processes_inherit, accept_socket);
-    });
-
-    char connect_remote_address[64];
-    snprintf(connect_remote_address, sizeof(connect_remote_address), "connect://localhost:%u",
-             listen_socket.GetLocalPortNumber());
-
-    std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
-    EXPECT_EQ(conn_ap->Connect(connect_remote_address, nullptr), lldb::eConnectionStatusSuccess);
-
-    client.SetConnection(conn_ap.release());
-    EXPECT_TRUE(accept_error.get().Success());
-    server.SetConnection(new ConnectionFileDescriptor(accept_socket));
-
+    Connect(client, server);
     listener_sp->StartListeningForEvents(&client, TestClient::eBroadcastBitRunPacketSent);
 }
 
 } // end anonymous namespace
 
-class GDBRemoteClientBaseTest : public testing::Test
+class GDBRemoteClientBaseTest : public GDBRemoteTest
 {
-public:
-    static void
-    SetUpTestCase()
-    {
-#if defined(_MSC_VER)
-        WSADATA data;
-        ::WSAStartup(MAKEWORD(2, 2), &data);
-#endif
-    }
-
-    static void
-    TearDownTestCase()
-    {
-#if defined(_MSC_VER)
-        ::WSACleanup();
-#endif
-    }
 };
 
 TEST_F(GDBRemoteClientBaseTest, SendContinueAndWait)

Added: lldb/trunk/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp?rev=278915&view=auto
==============================================================================
--- lldb/trunk/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp (added)
+++ lldb/trunk/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp Wed Aug 17 03:53:31 2016
@@ -0,0 +1,111 @@
+//===-- GDBRemoteCommunicationClientTest.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(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
+// Workaround for MSVC standard library bug, which fails to include <thread> when
+// exceptions are disabled.
+#include <eh.h>
+#endif
+#include <future>
+
+#include "GDBRemoteTestUtils.h"
+#include "gtest/gtest.h"
+
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h"
+
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private;
+using namespace lldb;
+
+namespace
+{
+
+typedef GDBRemoteCommunication::PacketResult PacketResult;
+
+struct TestClient : public GDBRemoteCommunicationClient
+{
+    TestClient() { m_send_acks = false; }
+};
+
+void
+Handle_QThreadSuffixSupported(MockServer &server, bool supported)
+{
+    StringExtractorGDBRemote request;
+    ASSERT_EQ(PacketResult::Success, server.GetPacket(request));
+    ASSERT_EQ("QThreadSuffixSupported", request.GetStringRef());
+    if (supported)
+        ASSERT_EQ(PacketResult::Success, server.SendOKResponse());
+    else
+        ASSERT_EQ(PacketResult::Success, server.SendUnimplementedResponse(nullptr));
+}
+
+void
+HandlePacket(MockServer &server, llvm::StringRef expected, llvm::StringRef response)
+{
+    StringExtractorGDBRemote request;
+    ASSERT_EQ(PacketResult::Success, server.GetPacket(request));
+    ASSERT_EQ(expected, request.GetStringRef());
+    ASSERT_EQ(PacketResult::Success, server.SendPacket(response));
+}
+
+} // end anonymous namespace
+
+class GDBRemoteCommunicationClientTest : public GDBRemoteTest
+{
+};
+
+TEST_F(GDBRemoteCommunicationClientTest, WriteRegister)
+{
+    TestClient client;
+    MockServer server;
+    Connect(client, server);
+    if (HasFailure())
+        return;
+
+    const lldb::tid_t tid = 0x47;
+    const uint32_t reg_num = 4;
+    std::future<bool> write_result =
+        std::async(std::launch::async, [&client] { return client.WriteRegister(tid, reg_num, "ABCD"); });
+
+    Handle_QThreadSuffixSupported(server, true);
+
+    HandlePacket(server, "P4=41424344;thread:0047;", "OK");
+    ASSERT_TRUE(write_result.get());
+
+    write_result = std::async(std::launch::async,
+                              [&client] { return client.WriteAllRegisters(tid, "404142434445464748494a4b4c4d4e4f"); });
+
+    HandlePacket(server, "G404142434445464748494a4b4c4d4e4f;thread:0047;", "OK");
+    ASSERT_TRUE(write_result.get());
+}
+
+TEST_F(GDBRemoteCommunicationClientTest, WriteRegisterNoSuffix)
+{
+    TestClient client;
+    MockServer server;
+    Connect(client, server);
+    if (HasFailure())
+        return;
+
+    const lldb::tid_t tid = 0x47;
+    const uint32_t reg_num = 4;
+    std::future<bool> write_result =
+        std::async(std::launch::async, [&client] { return client.WriteRegister(tid, reg_num, "ABCD"); });
+
+    Handle_QThreadSuffixSupported(server, false);
+    HandlePacket(server, "Hg47", "OK");
+    HandlePacket(server, "P4=41424344", "OK");
+    ASSERT_TRUE(write_result.get());
+
+    write_result = std::async(std::launch::async,
+                              [&client] { return client.WriteAllRegisters(tid, "404142434445464748494a4b4c4d4e4f"); });
+
+    HandlePacket(server, "G404142434445464748494a4b4c4d4e4f", "OK");
+    ASSERT_TRUE(write_result.get());
+}

Added: lldb/trunk/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp?rev=278915&view=auto
==============================================================================
--- lldb/trunk/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp (added)
+++ lldb/trunk/unittests/Process/gdb-remote/GDBRemoteTestUtils.cpp Wed Aug 17 03:53:31 2016
@@ -0,0 +1,74 @@
+//===-- GDBRemoteTestUtils.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(_MSC_VER) && (_HAS_EXCEPTIONS == 0)
+// Workaround for MSVC standard library bug, which fails to include <thread> when
+// exceptions are disabled.
+#include <eh.h>
+#endif
+
+#include "GDBRemoteTestUtils.h"
+#include "gtest/gtest.h"
+
+#include "lldb/Host/common/TCPSocket.h"
+#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
+
+#include <future>
+
+namespace lldb_private
+{
+namespace process_gdb_remote
+{
+
+void
+GDBRemoteTest::SetUpTestCase()
+{
+#if defined(_MSC_VER)
+    WSADATA data;
+    ::WSAStartup(MAKEWORD(2, 2), &data);
+#endif
+}
+
+void
+GDBRemoteTest::TearDownTestCase()
+{
+#if defined(_MSC_VER)
+    ::WSACleanup();
+#endif
+}
+
+void
+Connect(GDBRemoteCommunication &client, GDBRemoteCommunication &server)
+{
+    bool child_processes_inherit = false;
+    Error error;
+    TCPSocket listen_socket(child_processes_inherit, error);
+    ASSERT_FALSE(error.Fail());
+    error = listen_socket.Listen("127.0.0.1:0", 5);
+    ASSERT_FALSE(error.Fail());
+
+    Socket *accept_socket;
+    std::future<Error> accept_error = std::async(std::launch::async, [&] {
+        return listen_socket.Accept("127.0.0.1:0", child_processes_inherit, accept_socket);
+    });
+
+    char connect_remote_address[64];
+    snprintf(connect_remote_address, sizeof(connect_remote_address), "connect://localhost:%u",
+             listen_socket.GetLocalPortNumber());
+
+    std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+    ASSERT_EQ(conn_ap->Connect(connect_remote_address, nullptr), lldb::eConnectionStatusSuccess);
+
+    client.SetConnection(conn_ap.release());
+    ASSERT_TRUE(accept_error.get().Success());
+    server.SetConnection(new ConnectionFileDescriptor(accept_socket));
+}
+
+} // namespace process_gdb_remote
+} // namespace lldb_private

Added: lldb/trunk/unittests/Process/gdb-remote/GDBRemoteTestUtils.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Process/gdb-remote/GDBRemoteTestUtils.h?rev=278915&view=auto
==============================================================================
--- lldb/trunk/unittests/Process/gdb-remote/GDBRemoteTestUtils.h (added)
+++ lldb/trunk/unittests/Process/gdb-remote/GDBRemoteTestUtils.h Wed Aug 17 03:53:31 2016
@@ -0,0 +1,57 @@
+//===-- GDBRemoteTestUtils.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_unittests_Process_gdb_remote_GDBRemoteTestUtils_h
+#define lldb_unittests_Process_gdb_remote_GDBRemoteTestUtils_h
+
+#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"
+
+namespace lldb_private
+{
+namespace process_gdb_remote
+{
+
+class GDBRemoteTest : public testing::Test
+{
+public:
+    static void
+    SetUpTestCase();
+
+    static void
+    TearDownTestCase();
+};
+
+void
+Connect(GDBRemoteCommunication &client, GDBRemoteCommunication &server);
+
+struct MockServer : public GDBRemoteCommunicationServer
+{
+    MockServer() : GDBRemoteCommunicationServer("mock-server", "mock-server.listener") { m_send_acks = false; }
+
+    PacketResult
+    SendPacket(llvm::StringRef payload)
+    {
+        return GDBRemoteCommunicationServer::SendPacketNoLock(payload.data(), payload.size());
+    }
+
+    PacketResult
+    GetPacket(StringExtractorGDBRemote &response)
+    {
+        const unsigned timeout_usec = 1000000; // 1s
+        const bool sync_on_timeout = false;
+        return WaitForPacketWithTimeoutMicroSecondsNoLock(response, timeout_usec, sync_on_timeout);
+    }
+
+    using GDBRemoteCommunicationServer::SendOKResponse;
+    using GDBRemoteCommunicationServer::SendUnimplementedResponse;
+};
+
+} // namespace process_gdb_remote
+} // namespace lldb_private
+
+#endif // lldb_unittests_Process_gdb_remote_GDBRemoteTestUtils_h




More information about the lldb-commits mailing list