Author: Michał Górny
Date: 2021-09-10T14:08:36+02:00
New Revision: 3fade9542200c96021522f91ba5afdbff02729e1

URL: 
https://github.com/llvm/llvm-project/commit/3fade9542200c96021522f91ba5afdbff02729e1
DIFF: 
https://github.com/llvm/llvm-project/commit/3fade9542200c96021522f91ba5afdbff02729e1.diff

LOG: [lldb] [gdb-remote] Support QEnvironment fallback to hex-encoded

Fall back to QEnvironmentHexEncoded if QEnvironment is not supported.
The latter packet is an LLDB extension, while the former is universally
supported.

Add tests for both QEnvironment and QEnvironmentHexEncoded packets,
including both use due to characters that need escaping and fallback
when QEnvironment is not supported.

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

Added: 
    

Modified: 
    lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
    lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py
    lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py
    lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
    lldb/test/API/tools/lldb-server/main.cpp

Removed: 
    


################################################################################
diff  --git 
a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp 
b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 3696c7096e30..ae5ef51c5b38 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -903,7 +903,6 @@ int GDBRemoteCommunicationClient::SendEnvironment(const 
Environment &env) {
 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;
          ++p) {
@@ -925,33 +924,43 @@ int GDBRemoteCommunicationClient::SendEnvironmentPacket(
     }
 
     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.GetString(), response) ==
-            PacketResult::Success) {
-          if (response.IsOKResponse())
-            return 0;
-          uint8_t error = response.GetError();
-          if (error)
-            return error;
-          if (response.IsUnsupportedResponse())
-            m_supports_QEnvironmentHexEncoded = false;
-        }
+    // Prefer sending unencoded, if possible and the server supports it.
+    if (!send_hex_encoding && m_supports_QEnvironment) {
+      StreamString packet;
+      packet.Printf("QEnvironment:%s", name_equal_value);
+      if (SendPacketAndWaitForResponse(packet.GetString(), response) !=
+          PacketResult::Success)
+        return -1;
+
+      if (response.IsOKResponse())
+        return 0;
+      if (response.IsUnsupportedResponse())
+        m_supports_QEnvironment = false;
+      else {
+        uint8_t error = response.GetError();
+        if (error)
+          return error;
+        return -1;
       }
+    }
 
-    } else if (m_supports_QEnvironment) {
-      packet.Printf("QEnvironment:%s", name_equal_value);
-      if (SendPacketAndWaitForResponse(packet.GetString(), response) ==
-          PacketResult::Success) {
-        if (response.IsOKResponse())
-          return 0;
+    if (m_supports_QEnvironmentHexEncoded) {
+      StreamString packet;
+      packet.PutCString("QEnvironmentHexEncoded:");
+      packet.PutBytesAsRawHex8(name_equal_value, strlen(name_equal_value));
+      if (SendPacketAndWaitForResponse(packet.GetString(), response) !=
+          PacketResult::Success)
+        return -1;
+
+      if (response.IsOKResponse())
+        return 0;
+      if (response.IsUnsupportedResponse())
+        m_supports_QEnvironmentHexEncoded = false;
+      else {
         uint8_t error = response.GetError();
         if (error)
           return error;
-        if (response.IsUnsupportedResponse())
-          m_supports_QEnvironment = false;
+        return -1;
       }
     }
   }

diff  --git 
a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py 
b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py
index f5b59c689020..049ea6f42057 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py
@@ -258,3 +258,96 @@ def A(self, packet):
         self.assertPacketLogContains([
           "vRun;%s;61726731;61726732;61726733" % (exe_hex,)
         ])
+
+    def test_launch_QEnvironment(self):
+        class MyResponder(MockGDBServerResponder):
+            def qC(self):
+                return "E42"
+
+            def qfThreadInfo(self):
+               return "E42"
+
+            def vRun(self, packet):
+                self.started = True
+                return "E28"
+
+        self.server.responder = MyResponder()
+
+        target = self.createTarget("a.yaml")
+        process = self.connect(target)
+        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process,
+                                      [lldb.eStateConnected])
+
+        target.Launch(lldb.SBListener(),
+                      [],  # argv
+                      ["PLAIN=foo",
+                       "NEEDSENC=frob$",
+                       "NEEDSENC2=fr*ob",
+                       "NEEDSENC3=fro}b",
+                       "NEEDSENC4=f#rob",
+                       "EQUALS=foo=bar",
+                       ],  # envp
+                      None,  # stdin_path
+                      None,  # stdout_path
+                      None,  # stderr_path
+                      None,  # working_directory
+                      0,  # launch_flags
+                      True,  # stop_at_entry
+                      lldb.SBError())  # error
+
+        self.assertPacketLogContains([
+          "QEnvironment:PLAIN=foo",
+          "QEnvironmentHexEncoded:4e45454453454e433d66726f6224",
+          "QEnvironmentHexEncoded:4e45454453454e43323d66722a6f62",
+          "QEnvironmentHexEncoded:4e45454453454e43333d66726f7d62",
+          "QEnvironmentHexEncoded:4e45454453454e43343d6623726f62",
+          "QEnvironment:EQUALS=foo=bar",
+        ])
+
+    def test_launch_QEnvironmentHexEncoded_only(self):
+        class MyResponder(MockGDBServerResponder):
+            def qC(self):
+                return "E42"
+
+            def qfThreadInfo(self):
+               return "E42"
+
+            def vRun(self, packet):
+                self.started = True
+                return "E28"
+
+            def QEnvironment(self, packet):
+                return ""
+
+        self.server.responder = MyResponder()
+
+        target = self.createTarget("a.yaml")
+        process = self.connect(target)
+        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process,
+                                      [lldb.eStateConnected])
+
+        target.Launch(lldb.SBListener(),
+                      [],  # argv
+                      ["PLAIN=foo",
+                       "NEEDSENC=frob$",
+                       "NEEDSENC2=fr*ob",
+                       "NEEDSENC3=fro}b",
+                       "NEEDSENC4=f#rob",
+                       "EQUALS=foo=bar",
+                       ],  # envp
+                      None,  # stdin_path
+                      None,  # stdout_path
+                      None,  # stderr_path
+                      None,  # working_directory
+                      0,  # launch_flags
+                      True,  # stop_at_entry
+                      lldb.SBError())  # error
+
+        self.assertPacketLogContains([
+          "QEnvironmentHexEncoded:504c41494e3d666f6f",
+          "QEnvironmentHexEncoded:4e45454453454e433d66726f6224",
+          "QEnvironmentHexEncoded:4e45454453454e43323d66722a6f62",
+          "QEnvironmentHexEncoded:4e45454453454e43333d66726f7d62",
+          "QEnvironmentHexEncoded:4e45454453454e43343d6623726f62",
+          "QEnvironmentHexEncoded:455155414c533d666f6f3d626172",
+        ])

diff  --git a/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py 
b/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py
index bfdefc8c3785..60dcf1111cc4 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py
+++ b/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py
@@ -194,6 +194,10 @@ def respond(self, packet):
             return self.vRun(packet)
         if packet.startswith("qLaunchSuccess"):
             return self.qLaunchSuccess()
+        if packet.startswith("QEnvironment:"):
+            return self.QEnvironment(packet)
+        if packet.startswith("QEnvironmentHexEncoded:"):
+            return self.QEnvironmentHexEncoded(packet)
 
         return self.other(packet)
 
@@ -313,6 +317,12 @@ def vRun(self, packet):
     def qLaunchSuccess(self):
         return ""
 
+    def QEnvironment(self, packet):
+        return "OK"
+
+    def QEnvironmentHexEncoded(self, packet):
+        return "OK"
+
     """
     Raised when we receive a packet for which there is no default action.
     Override the responder class to implement behavior suitable for the test at

diff  --git a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py 
b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
index 6f68a8b038ee..aac73dd53998 100644
--- a/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
+++ b/lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
@@ -1307,3 +1307,56 @@ def test_launch_via_vRun_no_args(self):
              "send packet: $W00#00"],
             True)
         self.expect_gdbremote_sequence()
+
+    def test_QEnvironment(self):
+        self.build()
+        exe_path = self.getBuildArtifact("a.out")
+        env = {"FOO": "test", "BAR": "a=z"}
+        args = [exe_path, "print-env:FOO", "print-env:BAR"]
+        hex_args = [binascii.b2a_hex(x.encode()).decode() for x in args]
+
+        server = self.connect_to_debug_monitor()
+        self.assertIsNotNone(server)
+        self.do_handshake()
+
+        for key, value in env.items():
+            self.test_sequence.add_log_lines(
+                ["read packet: $QEnvironment:%s=%s#00" % (key, value),
+                 "send packet: $OK#00"],
+                True)
+        self.test_sequence.add_log_lines(
+            ["read packet: $vRun;%s#00" % (";".join(hex_args),),
+             {"direction": "send",
+              "regex": r"^\$T([0-9a-fA-F]+)"},
+             "read packet: $c#00",
+             "send packet: $W00#00"],
+            True)
+        context = self.expect_gdbremote_sequence()
+        self.assertEqual(context["O_content"], b"test\r\na=z\r\n")
+
+    def test_QEnvironmentHexEncoded(self):
+        self.build()
+        exe_path = self.getBuildArtifact("a.out")
+        env = {"FOO": "test", "BAR": "a=z", "BAZ": "a*}#z"}
+        args = [exe_path, "print-env:FOO", "print-env:BAR", "print-env:BAZ"]
+        hex_args = [binascii.b2a_hex(x.encode()).decode() for x in args]
+
+        server = self.connect_to_debug_monitor()
+        self.assertIsNotNone(server)
+        self.do_handshake()
+
+        for key, value in env.items():
+            hex_enc = binascii.b2a_hex(("%s=%s" % (key, 
value)).encode()).decode()
+            self.test_sequence.add_log_lines(
+                ["read packet: $QEnvironmentHexEncoded:%s#00" % (hex_enc,),
+                 "send packet: $OK#00"],
+                True)
+        self.test_sequence.add_log_lines(
+            ["read packet: $vRun;%s#00" % (";".join(hex_args),),
+             {"direction": "send",
+              "regex": r"^\$T([0-9a-fA-F]+)"},
+             "read packet: $c#00",
+             "send packet: $W00#00"],
+            True)
+        context = self.expect_gdbremote_sequence()
+        self.assertEqual(context["O_content"], b"test\r\na=z\r\na*}#z\r\n")

diff  --git a/lldb/test/API/tools/lldb-server/main.cpp 
b/lldb/test/API/tools/lldb-server/main.cpp
index c02c991300fc..f872eabcac98 100644
--- a/lldb/test/API/tools/lldb-server/main.cpp
+++ b/lldb/test/API/tools/lldb-server/main.cpp
@@ -326,6 +326,10 @@ int main(int argc, char **argv) {
       g_threads_do_segfault = true;
     } else if (consume_front(arg, "print-pid")) {
       print_pid();
+    } else if (consume_front(arg, "print-env:")) {
+      // Print the value of specified envvar to stdout.
+      const char *value = getenv(arg.c_str());
+      printf("%s\n", value ? value : "__unset__");
     } else {
       // Treat the argument as text for stdout.
       printf("%s\n", argv[i]);


        
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to