eugene updated this revision to Diff 90563.
eugene added a comment.
Herald added a subscriber: mgorny.
Moved signal filtering to UnixSignals and added unit tests for UnixSignals
class.
https://reviews.llvm.org/D30520
Files:
include/lldb/Target/Process.h
include/lldb/Target/UnixSignals.h
source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
source/Target/Process.cpp
source/Target/UnixSignals.cpp
unittests/CMakeLists.txt
unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
unittests/Signals/CMakeLists.txt
unittests/Signals/UnixSignalsTest.cpp
Index: unittests/Signals/UnixSignalsTest.cpp
===================================================================
--- /dev/null
+++ unittests/Signals/UnixSignalsTest.cpp
@@ -0,0 +1,140 @@
+//===-- UnixSignalsTest.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <string>
+
+#include "gtest/gtest.h"
+
+#include "lldb/Target/UnixSignals.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using llvm::None;
+
+class TestSignals : public UnixSignals {
+public:
+ TestSignals() {
+ m_signals.clear();
+ AddSignal(2, "SIG2", false, true, true, "DESC2");
+ AddSignal(4, "SIG4", true, false, true, "DESC4");
+ AddSignal(8, "SIG8", true, true, true, "DESC8");
+ AddSignal(16, "SIG16", true, false, false, "DESC16");
+ }
+};
+
+void AssertEqArrays(llvm::ArrayRef<int32_t> expected,
+ llvm::ArrayRef<int32_t> observed, const char *file,
+ int line) {
+ std::string location = llvm::formatv("{0}:{1}", file, line);
+ ASSERT_EQ(expected.size(), observed.size()) << location;
+
+ for (size_t i = 0; i < observed.size(); ++i) {
+ ASSERT_EQ(expected[i], observed[i])
+ << "array index: " << i << "location:" << location;
+ }
+}
+
+#define ASSERT_EQ_ARRAYS(expected, observed) \
+ AssertEqArrays((expected), (observed), __FILE__, __LINE__);
+
+TEST(UnixSignalsTest, Iteration) {
+ TestSignals signals;
+
+ EXPECT_EQ(signals.GetNumSignals(), 4);
+ EXPECT_EQ(signals.GetFirstSignalNumber(), 2);
+ EXPECT_EQ(signals.GetNextSignalNumber(2), 4);
+ EXPECT_EQ(signals.GetNextSignalNumber(4), 8);
+ EXPECT_EQ(signals.GetNextSignalNumber(8), 16);
+ EXPECT_EQ(signals.GetNextSignalNumber(16), LLDB_INVALID_SIGNAL_NUMBER);
+}
+
+TEST(UnixSignalsTest, GetInfo) {
+ TestSignals signals;
+
+ bool should_suppress = false, should_stop = false, should_notify = false;
+ int32_t signo = 4;
+ std::string name =
+ signals.GetSignalInfo(signo, should_suppress, should_stop, should_notify);
+ EXPECT_EQ(name, "SIG4");
+ EXPECT_EQ(should_suppress, true);
+ EXPECT_EQ(should_stop, false);
+ EXPECT_EQ(should_notify, true);
+
+ EXPECT_EQ(signals.GetShouldSuppress(signo), true);
+ EXPECT_EQ(signals.GetShouldStop(signo), false);
+ EXPECT_EQ(signals.GetShouldNotify(signo), true);
+ EXPECT_EQ(signals.GetSignalAsCString(signo), name);
+}
+
+TEST(UnixSignalsTest, VersionChange) {
+ TestSignals signals;
+
+ int32_t signo = 8;
+ uint64_t ver = signals.GetVersion();
+ EXPECT_GT(ver, 0ull);
+ EXPECT_EQ(signals.GetShouldSuppress(signo), true);
+ EXPECT_EQ(signals.GetShouldStop(signo), true);
+ EXPECT_EQ(signals.GetShouldNotify(signo), true);
+
+ EXPECT_EQ(ver, signals.GetVersion());
+
+ signals.SetShouldSuppress(signo, false);
+ EXPECT_LT(ver, signals.GetVersion());
+ ver = signals.GetVersion();
+
+ signals.SetShouldStop(signo, true);
+ EXPECT_LT(ver, signals.GetVersion());
+ ver = signals.GetVersion();
+
+ signals.SetShouldNotify(signo, false);
+ EXPECT_LT(ver, signals.GetVersion());
+ ver = signals.GetVersion();
+
+ EXPECT_EQ(signals.GetShouldSuppress(signo), false);
+ EXPECT_EQ(signals.GetShouldStop(signo), true);
+ EXPECT_EQ(signals.GetShouldNotify(signo), false);
+
+ EXPECT_EQ(ver, signals.GetVersion());
+}
+
+TEST(UnixSignalsTest, GetFilteredSignals) {
+ TestSignals signals;
+
+ auto all_signals = signals.GetFilteredSignals(None, None, None);
+ std::vector<int32_t> expected = {2, 4, 8, 16};
+ ASSERT_EQ_ARRAYS(expected, all_signals);
+
+ auto supressed = signals.GetFilteredSignals(true, None, None);
+ expected = {4, 8, 16};
+ ASSERT_EQ_ARRAYS(expected, supressed);
+
+ auto not_supressed = signals.GetFilteredSignals(false, None, None);
+ expected = {2};
+ ASSERT_EQ_ARRAYS(expected, not_supressed);
+
+ auto stopped = signals.GetFilteredSignals(None, true, None);
+ expected = {2, 8};
+ ASSERT_EQ_ARRAYS(expected, stopped);
+
+ auto not_stopped = signals.GetFilteredSignals(None, false, None);
+ expected = {4, 16};
+ ASSERT_EQ_ARRAYS(expected, not_stopped);
+
+ auto notified = signals.GetFilteredSignals(None, None, true);
+ expected = {2, 4, 8};
+ ASSERT_EQ_ARRAYS(expected, notified);
+
+ auto not_notified = signals.GetFilteredSignals(None, None, false);
+ expected = {16};
+ ASSERT_EQ_ARRAYS(expected, not_notified);
+
+ auto signal4 = signals.GetFilteredSignals(true, false, true);
+ expected = {4};
+ ASSERT_EQ_ARRAYS(expected, signal4);
+}
Index: unittests/Signals/CMakeLists.txt
===================================================================
--- /dev/null
+++ unittests/Signals/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_lldb_unittest(SignalsTest
+ UnixSignalsTest.cpp
+
+ LINK_LIBS
+ lldbTarget
+ )
Index: unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
===================================================================
--- unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
+++ unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
@@ -314,3 +314,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<Error> result = std::async(std::launch::async, [&] {
+ return client.SendSignalsToIgnore({2, 3, 5, 7, 0xB, 0xD, 0x11});
+ });
+
+ HandlePacket(server, "QPassSignals:02;03;05;07;0b;0d;11", "OK");
+ EXPECT_TRUE(result.get().Success());
+
+ result = std::async(std::launch::async, [&] {
+ return client.SendSignalsToIgnore(std::vector<int32_t>());
+ });
+
+ HandlePacket(server, "QPassSignals:", "OK");
+ EXPECT_TRUE(result.get().Success());
+}
Index: unittests/CMakeLists.txt
===================================================================
--- unittests/CMakeLists.txt
+++ unittests/CMakeLists.txt
@@ -63,6 +63,7 @@
add_subdirectory(Platform)
add_subdirectory(Process)
add_subdirectory(ScriptInterpreter)
+add_subdirectory(Signals)
add_subdirectory(Symbol)
add_subdirectory(SymbolFile)
add_subdirectory(Target)
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,37 @@
std::advance(it, index);
return it->first;
}
+
+uint64_t UnixSignals::GetVersion() const { return m_version; }
+
+std::vector<int32_t>
+UnixSignals::GetFilteredSignals(llvm::Optional<bool> should_suppress,
+ llvm::Optional<bool> should_stop,
+ llvm::Optional<bool> should_notify) {
+ std::vector<int32_t> result;
+ for (int32_t signo = GetFirstSignalNumber();
+ signo != LLDB_INVALID_SIGNAL_NUMBER;
+ signo = GetNextSignalNumber(signo)) {
+
+ bool signal_suppress = false;
+ bool signal_stop = false;
+ bool signal_notify = false;
+ GetSignalInfo(signo, signal_suppress, signal_stop, signal_notify);
+
+ // If any of filtering conditions are not met,
+ // we move on to the next signal.
+ if (should_suppress.hasValue() &&
+ signal_suppress != should_suppress.getValue())
+ continue;
+
+ if (should_stop.hasValue() && signal_stop != should_stop.getValue())
+ continue;
+
+ if (should_notify.hasValue() && signal_notify != should_notify.getValue())
+ continue;
+
+ result.push_back(signo);
+ }
+
+ return result;
+}
Index: source/Target/Process.cpp
===================================================================
--- source/Target/Process.cpp
+++ source/Target/Process.cpp
@@ -1621,6 +1621,13 @@
return PrivateResume();
}
+Error Process::WillResume() {
+ UpdateAutomaticSignalFiltering();
+ return Error();
+}
+
+void Process::DidLaunch() { UpdateAutomaticSignalFiltering(); }
+
Error Process::ResumeSynchronous(Stream *stream) {
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE |
LIBLLDB_LOG_PROCESS));
@@ -6217,3 +6224,9 @@
find_it->second->HandleArrivalOfStructuredData(*this, type_name, object_sp);
return true;
}
+
+Error Process::UpdateAutomaticSignalFiltering() {
+ // Default implementation does nothign.
+ // No automatic signal filtering to speak of.
+ return Error();
+}
Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
===================================================================
--- source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -397,12 +397,15 @@
lldb::addr_t base_addr,
bool value_is_offset);
+ Error UpdateAutomaticSignalFiltering() override;
+
private:
//------------------------------------------------------------------
// For ProcessGDBRemote only
//------------------------------------------------------------------
std::string m_partial_profile_data;
std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map;
+ uint64_t m_last_signals_version = 0;
static bool NewThreadNotifyBreakpointHit(void *baton,
StoppointCallbackContext *context,
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;
@@ -1165,6 +1166,7 @@
}
void ProcessGDBRemote::DidLaunch() {
+ Process::DidLaunch();
ArchSpec process_arch;
DidLaunchOrAttach(process_arch);
}
@@ -1248,6 +1250,7 @@
}
Error ProcessGDBRemote::WillResume() {
+ Process::WillResume();
m_continue_c_tids.clear();
m_continue_C_tids.clear();
m_continue_s_tids.clear();
@@ -3739,6 +3742,43 @@
return false;
}
+Error ProcessGDBRemote::UpdateAutomaticSignalFiltering() {
+ 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();
+ }
+
+ auto signals_to_ignore =
+ m_unix_signals_sp->GetFilteredSignals(false, false, false);
+ Error error = m_gdb_comm.SendSignalsToIgnore(signals_to_ignore);
+
+ LLDB_LOG(log,
+ "Signals' version changed. old version={0}, new version={1}, "
+ "signals ignored={2}, update result={3}",
+ m_last_signals_version, new_signals_version,
+ signals_to_ignore.size(), error);
+
+ if (error.Success())
+ m_last_signals_version = new_signals_version;
+
+ return error;
+}
+
bool ProcessGDBRemote::StartNoticingNewThreads() {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
if (m_thread_create_bp_sp) {
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<int32_t> 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
@@ -87,6 +87,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 +151,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 +427,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 +
@@ -3569,6 +3582,26 @@
: nullptr;
}
+Error GDBRemoteCommunicationClient::SendSignalsToIgnore(
+ llvm::ArrayRef<int32_t> signals) {
+ // Format packet:
+ // QPassSignals:<hex_sig1>;<hex_sig2>...;<hex_sigN>
+ auto range = llvm::make_range(signals.begin(), signals.end());
+ std::string packet = formatv("QPassSignals:{0:$[;]@(x-2)}", range).str();
+
+ StringExtractorGDBRemote response;
+ auto send_status = SendPacketAndWaitForResponse(packet, 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: include/lldb/Target/UnixSignals.h
===================================================================
--- include/lldb/Target/UnixSignals.h
+++ include/lldb/Target/UnixSignals.h
@@ -14,11 +14,13 @@
// C++ Includes
#include <map>
#include <string>
+#include <vector>
// Other libraries and framework includes
// Project includes
#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-private.h"
+#include "llvm/ADT/Optional.h"
namespace lldb_private {
@@ -88,6 +90,19 @@
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;
+
+ // Returns a vector of signals that meet criteria provided in arguments.
+ // Each should_[suppress|stop|notify] flag can be
+ // None - no filtering by this flag
+ // true - only signals that have it set to true are returned
+ // false - only signals that have it set to true are returned
+ std::vector<int32_t> GetFilteredSignals(llvm::Optional<bool> should_suppress,
+ llvm::Optional<bool> should_stop,
+ llvm::Optional<bool> should_notify);
+
protected:
//------------------------------------------------------------------
// Classes that inherit from UnixSignals can see and modify these
@@ -111,6 +126,12 @@
collection m_signals;
+ // This version gets incremented every time something is changing in
+ // this class, including when we call AddSignal from the constructor.
+ // So after the object is constructed m_version is going to be > 0
+ // if it has at least one signal registered in it.
+ uint64_t m_version = 0;
+
// GDBRemote signals need to be copyable.
UnixSignals(const UnixSignals &rhs);
Index: include/lldb/Target/Process.h
===================================================================
--- include/lldb/Target/Process.h
+++ include/lldb/Target/Process.h
@@ -1236,7 +1236,7 @@
/// Allow Process plug-ins to execute some code after launching
/// a process.
//------------------------------------------------------------------
- virtual void DidLaunch() {}
+ virtual void DidLaunch();
//------------------------------------------------------------------
/// Called before resuming to a process.
@@ -1247,7 +1247,7 @@
/// @return
/// Returns an error object.
//------------------------------------------------------------------
- virtual Error WillResume() { return Error(); }
+ virtual Error WillResume();
//------------------------------------------------------------------
/// Resumes all of a process's threads as configured using the
@@ -2607,7 +2607,7 @@
bool RunPreResumeActions();
void ClearPreResumeActions();
-
+
void ClearPreResumeAction(PreResumeActionCallback callback, void *baton);
ProcessRunLock &GetRunLock();
@@ -3145,6 +3145,8 @@
Error StopForDestroyOrDetach(lldb::EventSP &exit_event_sp);
+ virtual Error UpdateAutomaticSignalFiltering();
+
bool StateChangedIsExternallyHijacked();
void LoadOperatingSystemPlugin(bool flush);
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits