mgorny created this revision. mgorny added reviewers: krytarowski, emaste, labath, jasonmolenda, JDevlieghere. mgorny requested review of this revision.
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. https://reviews.llvm.org/D108018 Files: 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
Index: lldb/test/API/tools/lldb-server/main.cpp =================================================================== --- lldb/test/API/tools/lldb-server/main.cpp +++ lldb/test/API/tools/lldb-server/main.cpp @@ -326,6 +326,10 @@ 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]); Index: lldb/test/API/tools/lldb-server/TestLldbGdbServer.py =================================================================== --- lldb/test/API/tools/lldb-server/TestLldbGdbServer.py +++ lldb/test/API/tools/lldb-server/TestLldbGdbServer.py @@ -1307,3 +1307,56 @@ "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") Index: lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py =================================================================== --- lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py +++ lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py @@ -187,6 +187,10 @@ 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) @@ -303,6 +307,12 @@ 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 Index: lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py =================================================================== --- lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py +++ lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py @@ -258,3 +258,96 @@ 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", + ]) Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -876,7 +876,6 @@ 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) { @@ -898,33 +897,43 @@ } 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; } } }
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits