omjavaid created this revision.
omjavaid added a reviewer: labath.
omjavaid requested review of this revision.

GDB remote protocol does not specify length of g packet for register read. It 
depends on remote to include all or exclude certain registers from g packet. In 
case a register or set of registers is not included as part of g packet then we 
should fall back to p packet for reading all registers excluded from g packet 
by remote. This patch adds support for above feature and adds a test-case for 
the same.


https://reviews.llvm.org/D97498

Files:
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
  lldb/test/API/functionalities/gdb_remote_client/TestPartialGPacket.py

Index: lldb/test/API/functionalities/gdb_remote_client/TestPartialGPacket.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/gdb_remote_client/TestPartialGPacket.py
@@ -0,0 +1,106 @@
+from __future__ import print_function
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+from gdbclientutils import *
+
+
+class TestPartialGPacket(GDBRemoteTestBase):
+
+    @skipIfXmlSupportMissing
+    @skipIfRemote
+    def test(self):
+        """
+        Test GDB remote fallback to 'p' packet when 'g' packet does not include all registers.
+        """
+        class MyResponder(MockGDBServerResponder):
+
+            def qXferRead(self, obj, annex, offset, length):
+                if annex == "target.xml":
+                    return """<?xml version="1.0"?>
+                        <!DOCTYPE feature SYSTEM "gdb-target.dtd">
+                        <target>
+                        <architecture>arm</architecture>
+                        <feature name="org.gnu.gdb.arm.m-profile">
+                        <reg name="r0" bitsize="32" type="uint32" group="general"/>
+                        <reg name="r1" bitsize="32" type="uint32" group="general"/>
+                        <reg name="r2" bitsize="32" type="uint32" group="general"/>
+                        <reg name="r3" bitsize="32" type="uint32" group="general"/>
+                        <reg name="r4" bitsize="32" type="uint32" group="general"/>
+                        <reg name="r5" bitsize="32" type="uint32" group="general"/>
+                        <reg name="r6" bitsize="32" type="uint32" group="general"/>
+                        <reg name="r7" bitsize="32" type="uint32" group="general"/>
+                        <reg name="r8" bitsize="32" type="uint32" group="general"/>
+                        <reg name="r9" bitsize="32" type="uint32" group="general"/>
+                        <reg name="r10" bitsize="32" type="uint32" group="general"/>
+                        <reg name="r11" bitsize="32" type="uint32" group="general"/>
+                        <reg name="r12" bitsize="32" type="uint32" group="general"/>
+                        <reg name="sp" bitsize="32" type="data_ptr" group="general"/>
+                        <reg name="lr" bitsize="32" type="uint32" group="general"/>
+                        <reg name="pc" bitsize="32" type="code_ptr" group="general"/>
+                        <reg name="xpsr" bitsize="32" regnum="25" type="uint32" group="general"/>
+                        <reg name="MSP" bitsize="32" regnum="26" type="uint32" group="general"/>
+                        <reg name="PSP" bitsize="32" regnum="27" type="uint32" group="general"/>
+                        <reg name="PRIMASK" bitsize="32" regnum="28" type="uint32" group="general"/>
+                        <reg name="BASEPRI" bitsize="32" regnum="29" type="uint32" group="general"/>
+                        <reg name="FAULTMASK" bitsize="32" regnum="30" type="uint32" group="general"/>
+                        <reg name="CONTROL" bitsize="32" regnum="31" type="uint32" group="general"/>
+                        </feature>
+                        </target>""", False
+                else:
+                    return None, False
+
+            def readRegister(self, regnum):
+                if regnum == 31:
+                    return "cdcc8c3f00000000"
+                return "E01"
+
+            def readRegisters(self):
+                return "20000000f8360020001000002fcb0008f8360020a0360020200c0020000000000000000000000000000000000000000000000000b87f0120b7d100082ed2000800000001"
+
+            def haltReason(self):
+                return "S05"
+
+            def qfThreadInfo(self):
+                return "mdead"
+
+            def qC(self):
+                return ""
+
+            def qSupported(self, client_supported):
+                return "PacketSize=4000;qXfer:memory-map:read-;QStartNoAckMode+;qXfer:threads:read+;hwbreak+;qXfer:features:read+"
+
+            def QThreadSuffixSupported(self):
+                return "OK"
+
+            def QListThreadsInStopReply(self):
+                return "OK"
+
+        self.server.responder = MyResponder()
+        if self.TraceOn():
+            self.runCmd("log enable gdb-remote packets")
+            self.addTearDownHook(
+                lambda: self.runCmd("log disable gdb-remote packets"))
+
+        self.dbg.SetDefaultArchitecture("armv7em")
+        target = self.dbg.CreateTargetWithFileAndArch(None, None)
+
+        process = self.connect(target)
+
+        if self.TraceOn():
+            interp = self.dbg.GetCommandInterpreter()
+            result = lldb.SBCommandReturnObject()
+            interp.HandleCommand("target list", result)
+            print(result.GetOutput())
+
+        r0_valobj = process.GetThreadAtIndex(
+            0).GetFrameAtIndex(0).FindRegister("r0")
+        self.assertEqual(r0_valobj.GetValueAsUnsigned(), 0x20)
+
+        pc_valobj = process.GetThreadAtIndex(
+            0).GetFrameAtIndex(0).FindRegister("pc")
+        self.assertEqual(pc_valobj.GetValueAsUnsigned(), 0x0800d22e)
+
+        pc_valobj = process.GetThreadAtIndex(
+            0).GetFrameAtIndex(0).FindRegister("CONTROL")
+        self.assertEqual(pc_valobj.GetValueAsUnsigned(), 0x3f8ccccd)
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -118,6 +118,7 @@
   DataExtractor m_reg_data;
   bool m_read_all_at_once;
   bool m_write_all_at_once;
+  bool m_gpacket_cached;
 
 private:
   // Helper function for ReadRegisterBytes().
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -36,7 +36,7 @@
     : RegisterContext(thread, concrete_frame_idx),
       m_reg_info_sp(std::move(reg_info_sp)), m_reg_valid(), m_reg_data(),
       m_read_all_at_once(read_all_at_once),
-      m_write_all_at_once(write_all_at_once) {
+      m_write_all_at_once(write_all_at_once), m_gpacket_cached(false) {
   // 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.
@@ -57,6 +57,7 @@
 }
 
 void GDBRemoteRegisterContext::SetAllRegisterValid(bool b) {
+  m_gpacket_cached = b;
   std::vector<bool>::iterator pos, end = m_reg_valid.end();
   for (pos = m_reg_valid.begin(); pos != end; ++pos)
     *pos = b;
@@ -200,7 +201,7 @@
   const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
 
   if (!GetRegisterIsValid(reg)) {
-    if (m_read_all_at_once) {
+    if (m_read_all_at_once && !m_gpacket_cached) {
       if (DataBufferSP buffer_sp =
               gdb_comm.ReadAllRegisters(m_thread.GetProtocolID())) {
         memcpy(const_cast<uint8_t *>(m_reg_data.GetDataStart()),
@@ -221,7 +222,10 @@
               m_reg_valid[i] = false;
             }
           }
-          return true;
+
+          m_gpacket_cached = true;
+          if (GetRegisterIsValid(reg))
+            return true;
         } else {
           Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_THREAD |
                                                                 GDBR_LOG_PACKETS));
@@ -233,9 +237,9 @@
               " bytes "
               "but only got %" PRId64 " bytes.",
               m_reg_data.GetByteSize(), buffer_sp->GetByteSize());
+          return false;
         }
       }
-      return false;
     }
     if (reg_info->value_regs) {
       // Process this composite register request by delegating to the
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
  • [Lldb-commits] [PAT... Muhammad Omair Javaid via Phabricator via lldb-commits

Reply via email to