Index: include/lldb/Target/UnixSignals.h =================================================================== --- include/lldb/Target/UnixSignals.h +++ include/lldb/Target/UnixSignals.h @@ -88,6 +88,10 @@ void RemoveSignal(int signo); + // Returns a current version of the data stored in this class. + // Version gets incremented each time Set... method is called. + uint64_t GetVersion() const; + protected: //------------------------------------------------------------------ // Classes that inherit from UnixSignals can see and modify these @@ -110,6 +114,7 @@ typedef std::map collection; collection m_signals; + uint64_t m_version = 0; // GDBRemote signals need to be copyable. UnixSignals(const UnixSignals &rhs); Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -347,6 +347,8 @@ bool GetEchoSupported(); + bool GetQPassSignalsSupported(); + bool GetAugmentedLibrariesSVR4ReadSupported(); bool GetQXferFeaturesReadSupported(); @@ -450,6 +452,9 @@ void ServeSymbolLookups(lldb_private::Process *process); + // Sends QPassSignals packet to the server with given signals to ignore. + Error SendSignalsToIgnore(llvm::ArrayRef signals); + //------------------------------------------------------------------ /// Return the feature set supported by the gdb-remote server. /// @@ -527,6 +532,7 @@ LazyBool m_supports_jThreadExtendedInfo; LazyBool m_supports_jLoadedDynamicLibrariesInfos; LazyBool m_supports_jGetSharedCacheInfo; + LazyBool m_supports_QPassSignals; bool m_supports_qProcessInfoPID : 1, m_supports_qfProcessInfo : 1, m_supports_qUserName : 1, m_supports_qGroupName : 1, Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -40,6 +40,7 @@ #include "Utility/StringExtractorGDBRemote.h" #include "lldb/Host/Config.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #if defined(HAVE_LIBCOMPRESSION) @@ -87,6 +88,7 @@ m_supports_jThreadExtendedInfo(eLazyBoolCalculate), m_supports_jLoadedDynamicLibrariesInfos(eLazyBoolCalculate), m_supports_jGetSharedCacheInfo(eLazyBoolCalculate), + m_supports_QPassSignals(eLazyBoolCalculate), m_supports_qProcessInfoPID(true), m_supports_qfProcessInfo(true), m_supports_qUserName(true), m_supports_qGroupName(true), m_supports_qThreadStopInfo(true), m_supports_z0(true), @@ -150,6 +152,13 @@ return m_supports_qEcho == eLazyBoolYes; } +bool GDBRemoteCommunicationClient::GetQPassSignalsSupported() { + if (m_supports_QPassSignals == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_QPassSignals == eLazyBoolYes; +} + bool GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported() { if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate) { GetRemoteQSupported(); @@ -419,6 +428,11 @@ else m_supports_qEcho = eLazyBoolNo; + if (::strstr(response_cstr, "QPassSignals+")) + m_supports_QPassSignals = eLazyBoolYes; + else + m_supports_QPassSignals = eLazyBoolNo; + const char *packet_size_str = ::strstr(response_cstr, "PacketSize="); if (packet_size_str) { StringExtractorGDBRemote packet_response(packet_size_str + @@ -589,9 +603,9 @@ if (m_supports_jLoadedDynamicLibrariesInfos == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolNo; - if (SendPacketAndWaitForResponse("jGetLoadedDynamicLibrariesInfos:", - response, - false) == PacketResult::Success) { + if (SendPacketAndWaitForResponse( + "jGetLoadedDynamicLibrariesInfos:", response, false) == + PacketResult::Success) { if (response.IsOKResponse()) { m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolYes; } @@ -1276,9 +1290,10 @@ if (log) log->Printf("GDBRemoteCommunicationClient::%s parsed host " "architecture as %s, triple as %s from triple text %s", - __FUNCTION__, m_host_arch.GetArchitectureName() - ? m_host_arch.GetArchitectureName() - : "", + __FUNCTION__, + m_host_arch.GetArchitectureName() + ? m_host_arch.GetArchitectureName() + : "", m_host_arch.GetTriple().getTriple().c_str(), triple.c_str()); } @@ -2417,7 +2432,7 @@ * The reply from '?' packet could be as simple as 'S05'. There is no packet * which can * give us pid and/or tid. Assume pid=tid=1 in such cases. - */ + */ if (response.IsUnsupportedResponse() && IsConnected()) { m_curr_tid = 1; return true; @@ -2453,7 +2468,7 @@ * The reply from '?' packet could be as simple as 'S05'. There is no packet * which can * give us pid and/or tid. Assume pid=tid=1 in such cases. - */ + */ if (response.IsUnsupportedResponse() && IsConnected()) { m_curr_tid_run = 1; return true; @@ -2591,7 +2606,7 @@ * be as simple as 'S05'. There is no packet which can give us pid and/or * tid. * Assume pid=tid=1 in such cases. - */ + */ if (response.IsUnsupportedResponse() && thread_ids.size() == 0 && IsConnected()) { thread_ids.push_back(1); @@ -3569,6 +3584,33 @@ : nullptr; } +Error GDBRemoteCommunicationClient::SendSignalsToIgnore( + llvm::ArrayRef signals) { + // Format package: + // QPassSignals:;...; + StreamString packet; + packet.PutCString("QPassSignals:"); + for (size_t i = 0; i < signals.size(); ++i) { + if (i != 0) + packet.PutCString(";"); + + packet << llvm::utohexstr(static_cast(signals[i])); + } + + StringExtractorGDBRemote response; + auto send_status = + SendPacketAndWaitForResponse(packet.GetString(), response, false); + + if (send_status != GDBRemoteCommunication::PacketResult::Success) + return Error("Sending QPassSignals packet failed"); + + if (response.IsOKResponse()) { + return Error(); + } else { + return Error("Unknown error happened during sending QPassSignals packet."); + } +} + Error GDBRemoteCommunicationClient::ConfigureRemoteStructuredData( const ConstString &type_name, const StructuredData::ObjectSP &config_sp) { Error error; Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.h =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -403,12 +403,15 @@ //------------------------------------------------------------------ std::string m_partial_profile_data; std::map m_thread_id_to_used_usec_map; + uint64_t m_last_signals_version = 0; static bool NewThreadNotifyBreakpointHit(void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + Error SendSignalsToIgnoreIfNeeded(); + //------------------------------------------------------------------ // ContinueDelegate interface //------------------------------------------------------------------ Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -79,9 +79,10 @@ #include "Utility/StringExtractorGDBRemote.h" #include "lldb/Host/Host.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Threading.h" +#include "llvm/Support/raw_ostream.h" #define DEBUGSERVER_BASENAME "debugserver" using namespace lldb; @@ -949,6 +950,7 @@ lldb_utility::PseudoTerminal::invalid_fd) SetSTDIOFileDescriptor(pty.ReleaseMasterFileDescriptor()); } + SendSignalsToIgnoreIfNeeded(); } } else { if (log) @@ -1064,9 +1066,10 @@ if (log) log->Printf("ProcessGDBRemote::%s gdb-remote had process architecture, " "using %s %s", - __FUNCTION__, process_arch.GetArchitectureName() - ? process_arch.GetArchitectureName() - : "", + __FUNCTION__, + process_arch.GetArchitectureName() + ? process_arch.GetArchitectureName() + : "", process_arch.GetTriple().getTriple().c_str() ? process_arch.GetTriple().getTriple().c_str() : ""); @@ -1075,9 +1078,10 @@ if (log) log->Printf("ProcessGDBRemote::%s gdb-remote did not have process " "architecture, using gdb-remote host architecture %s %s", - __FUNCTION__, process_arch.GetArchitectureName() - ? process_arch.GetArchitectureName() - : "", + __FUNCTION__, + process_arch.GetArchitectureName() + ? process_arch.GetArchitectureName() + : "", process_arch.GetTriple().getTriple().c_str() ? process_arch.GetTriple().getTriple().c_str() : ""); @@ -1089,9 +1093,10 @@ if (log) log->Printf( "ProcessGDBRemote::%s analyzing target arch, currently %s %s", - __FUNCTION__, target_arch.GetArchitectureName() - ? target_arch.GetArchitectureName() - : "", + __FUNCTION__, + target_arch.GetArchitectureName() + ? target_arch.GetArchitectureName() + : "", target_arch.GetTriple().getTriple().c_str() ? target_arch.GetTriple().getTriple().c_str() : ""); @@ -1112,9 +1117,10 @@ if (log) log->Printf("ProcessGDBRemote::%s remote process is ARM/Apple, " "setting target arch to %s %s", - __FUNCTION__, process_arch.GetArchitectureName() - ? process_arch.GetArchitectureName() - : "", + __FUNCTION__, + process_arch.GetArchitectureName() + ? process_arch.GetArchitectureName() + : "", process_arch.GetTriple().getTriple().c_str() ? process_arch.GetTriple().getTriple().c_str() : ""); @@ -1142,9 +1148,10 @@ if (log) log->Printf("ProcessGDBRemote::%s final target arch after " "adjustments for remote architecture: %s %s", - __FUNCTION__, target_arch.GetArchitectureName() - ? target_arch.GetArchitectureName() - : "", + __FUNCTION__, + target_arch.GetArchitectureName() + ? target_arch.GetArchitectureName() + : "", target_arch.GetTriple().getTriple().c_str() ? target_arch.GetTriple().getTriple().c_str() : ""); @@ -1265,6 +1272,7 @@ ListenerSP listener_sp( Listener::MakeListener("gdb-remote.resume-packet-sent")); + SendSignalsToIgnoreIfNeeded(); if (listener_sp->StartListeningForEvents( &m_gdb_comm, GDBRemoteCommunication::eBroadcastBitRunPacketSent)) { listener_sp->StartListeningForEvents( @@ -3739,6 +3747,55 @@ return false; } +Error ProcessGDBRemote::SendSignalsToIgnoreIfNeeded() { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + LLDB_LOG(log, "Check if need to update ignored signals"); + + // QPassSignals package is not supported by the server, + // there is way we can ignore any signals on server side. + if (!m_gdb_comm.GetQPassSignalsSupported()) + return Error(); + + // No signals, nothing to send. + if (m_unix_signals_sp == nullptr) + return Error(); + + // Signals' version hasn't changed, no need to send anything. + uint64_t new_signals_version = m_unix_signals_sp->GetVersion(); + if (new_signals_version == m_last_signals_version) { + LLDB_LOG(log, "Signals' version hasn't changed. version={0}", + m_last_signals_version); + return Error(); + } + + llvm::SmallVector signals_to_ignore; + int32_t signo = m_unix_signals_sp->GetFirstSignalNumber(); + while (signo != LLDB_INVALID_SIGNAL_NUMBER) { + bool should_ignore = !m_unix_signals_sp->GetShouldStop(signo) && + !m_unix_signals_sp->GetShouldNotify(signo) && + !m_unix_signals_sp->GetShouldSuppress(signo); + + if (should_ignore) + signals_to_ignore.push_back(signo); + signo = m_unix_signals_sp->GetNextSignalNumber(signo); + } + + LLDB_LOG(log, + "Signals' version changed. old version={0}, new version={1}, " + "signals ignored={2}", + m_last_signals_version, new_signals_version, + signals_to_ignore.size()); + + Error error = m_gdb_comm.SendSignalsToIgnore(signals_to_ignore); + + if (error.Success()) + m_last_signals_version = new_signals_version; + else { + LLDB_LOG(log, "Error: {0}", error); + } + return error; +} + bool ProcessGDBRemote::StartNoticingNewThreads() { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); if (m_thread_create_bp_sp) { @@ -4112,8 +4169,9 @@ return false; feature_node.ForEachChildElementWithName( - "reg", [&target_info, &dyn_reg_info, &cur_reg_num, ®_offset, - &abi_sp](const XMLNode ®_node) -> bool { + "reg", + [&target_info, &dyn_reg_info, &cur_reg_num, ®_offset, + &abi_sp](const XMLNode ®_node) -> bool { std::string gdb_group; std::string gdb_type; ConstString reg_name; Index: source/Target/UnixSignals.cpp =================================================================== --- source/Target/UnixSignals.cpp +++ source/Target/UnixSignals.cpp @@ -123,12 +123,14 @@ Signal new_signal(name, default_suppress, default_stop, default_notify, description, alias); m_signals.insert(std::make_pair(signo, new_signal)); + ++m_version; } void UnixSignals::RemoveSignal(int signo) { collection::iterator pos = m_signals.find(signo); if (pos != m_signals.end()) m_signals.erase(pos); + ++m_version; } const char *UnixSignals::GetSignalAsCString(int signo) const { @@ -217,6 +219,7 @@ collection::iterator pos = m_signals.find(signo); if (pos != m_signals.end()) { pos->second.m_suppress = value; + ++m_version; return true; } return false; @@ -240,6 +243,7 @@ collection::iterator pos = m_signals.find(signo); if (pos != m_signals.end()) { pos->second.m_stop = value; + ++m_version; return true; } return false; @@ -263,6 +267,7 @@ collection::iterator pos = m_signals.find(signo); if (pos != m_signals.end()) { pos->second.m_notify = value; + ++m_version; return true; } return false; @@ -284,3 +289,7 @@ std::advance(it, index); return it->first; } + +uint64_t UnixSignals::GetVersion() const { + return m_version; +} Index: unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp =================================================================== --- unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp +++ unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp @@ -211,10 +211,11 @@ std::async(std::launch::async, [&] { return client.GetModulesInfo(file_specs, triple); }); HandlePacket( - server, "jModulesInfo:[" - R"({"file":"/foo/bar.so","triple":"i386-pc-linux"},)" - R"({"file":"/foo/baz.so","triple":"i386-pc-linux"},)" - R"({"file":"/foo/baw.so","triple":"i386-pc-linux"}])", + server, + "jModulesInfo:[" + R"({"file":"/foo/bar.so","triple":"i386-pc-linux"},)" + R"({"file":"/foo/baz.so","triple":"i386-pc-linux"},)" + R"({"file":"/foo/baw.so","triple":"i386-pc-linux"}])", R"([{"uuid":"404142434445464748494a4b4c4d4e4f","triple":"i386-pc-linux",)" R"("file_path":"/foo/bar.so","file_offset":0,"file_size":1234}]])"); @@ -314,3 +315,27 @@ << ss.GetString(); ASSERT_EQ(10, num_packets); } + +TEST_F(GDBRemoteCommunicationClientTest, SendSignalsToIgnore) { + TestClient client; + MockServer server; + Connect(client, server); + if (HasFailure()) + return; + + const lldb::tid_t tid = 0x47; + const uint32_t reg_num = 4; + std::future result = std::async(std::launch::async, [&] { + return client.SendSignalsToIgnore({2, 3, 5, 7, 0xB, 0xD, 0x11}); + }); + + HandlePacket(server, "QPassSignals:2;3;5;7;B;D;11", "OK"); + EXPECT_TRUE(result.get().Success()); + + result = std::async(std::launch::async, [&] { + return client.SendSignalsToIgnore(std::vector()); + }); + + HandlePacket(server, "QPassSignals:", "OK"); + EXPECT_TRUE(result.get().Success()); +}