1dda28197Spatrick //===-- UnixSignals.cpp ---------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Target/UnixSignals.h"
10061da546Spatrick #include "Plugins/Process/Utility/FreeBSDSignals.h"
11061da546Spatrick #include "Plugins/Process/Utility/LinuxSignals.h"
12061da546Spatrick #include "Plugins/Process/Utility/MipsLinuxSignals.h"
13061da546Spatrick #include "Plugins/Process/Utility/NetBSDSignals.h"
14adae0cfdSpatrick #include "Plugins/Process/Utility/OpenBSDSignals.h"
15061da546Spatrick #include "lldb/Host/HostInfo.h"
16061da546Spatrick #include "lldb/Utility/ArchSpec.h"
17*101d251dSrobert #include <optional>
18061da546Spatrick
19061da546Spatrick using namespace lldb_private;
20*101d251dSrobert using namespace llvm;
21061da546Spatrick
Signal(const char * name,bool default_suppress,bool default_stop,bool default_notify,const char * description,const char * alias)22061da546Spatrick UnixSignals::Signal::Signal(const char *name, bool default_suppress,
23061da546Spatrick bool default_stop, bool default_notify,
24061da546Spatrick const char *description, const char *alias)
25061da546Spatrick : m_name(name), m_alias(alias), m_description(),
26061da546Spatrick m_suppress(default_suppress), m_stop(default_stop),
27*101d251dSrobert m_notify(default_notify),
28*101d251dSrobert m_default_suppress(default_suppress), m_default_stop(default_stop),
29*101d251dSrobert m_default_notify(default_notify) {
30061da546Spatrick if (description)
31061da546Spatrick m_description.assign(description);
32061da546Spatrick }
33061da546Spatrick
Create(const ArchSpec & arch)34061da546Spatrick lldb::UnixSignalsSP UnixSignals::Create(const ArchSpec &arch) {
35061da546Spatrick const auto &triple = arch.GetTriple();
36061da546Spatrick switch (triple.getOS()) {
37061da546Spatrick case llvm::Triple::Linux: {
38061da546Spatrick switch (triple.getArch()) {
39061da546Spatrick case llvm::Triple::mips:
40061da546Spatrick case llvm::Triple::mipsel:
41061da546Spatrick case llvm::Triple::mips64:
42061da546Spatrick case llvm::Triple::mips64el:
43061da546Spatrick return std::make_shared<MipsLinuxSignals>();
44061da546Spatrick default:
45061da546Spatrick return std::make_shared<LinuxSignals>();
46061da546Spatrick }
47061da546Spatrick }
48061da546Spatrick case llvm::Triple::FreeBSD:
49dda28197Spatrick return std::make_shared<FreeBSDSignals>();
50adae0cfdSpatrick case llvm::Triple::OpenBSD:
51adae0cfdSpatrick return std::make_shared<OpenBSDSignals>();
52061da546Spatrick case llvm::Triple::NetBSD:
53061da546Spatrick return std::make_shared<NetBSDSignals>();
54061da546Spatrick default:
55061da546Spatrick return std::make_shared<UnixSignals>();
56061da546Spatrick }
57061da546Spatrick }
58061da546Spatrick
CreateForHost()59061da546Spatrick lldb::UnixSignalsSP UnixSignals::CreateForHost() {
60061da546Spatrick static lldb::UnixSignalsSP s_unix_signals_sp =
61061da546Spatrick Create(HostInfo::GetArchitecture());
62061da546Spatrick return s_unix_signals_sp;
63061da546Spatrick }
64061da546Spatrick
65061da546Spatrick // UnixSignals constructor
UnixSignals()66061da546Spatrick UnixSignals::UnixSignals() { Reset(); }
67061da546Spatrick
UnixSignals(const UnixSignals & rhs)68061da546Spatrick UnixSignals::UnixSignals(const UnixSignals &rhs) : m_signals(rhs.m_signals) {}
69061da546Spatrick
70061da546Spatrick UnixSignals::~UnixSignals() = default;
71061da546Spatrick
Reset()72061da546Spatrick void UnixSignals::Reset() {
73061da546Spatrick // This builds one standard set of Unix Signals. If yours aren't quite in
74061da546Spatrick // this order, you can either subclass this class, and use Add & Remove to
75a0747c9fSpatrick // change them or you can subclass and build them afresh in your constructor.
76061da546Spatrick //
77061da546Spatrick // Note: the signals below are the Darwin signals. Do not change these!
78a0747c9fSpatrick
79061da546Spatrick m_signals.clear();
80a0747c9fSpatrick
81a0747c9fSpatrick // clang-format off
82061da546Spatrick // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION
83a0747c9fSpatrick // ====== ============== ======== ====== ====== ===================================================
84061da546Spatrick AddSignal(1, "SIGHUP", false, true, true, "hangup");
85061da546Spatrick AddSignal(2, "SIGINT", true, true, true, "interrupt");
86061da546Spatrick AddSignal(3, "SIGQUIT", false, true, true, "quit");
87061da546Spatrick AddSignal(4, "SIGILL", false, true, true, "illegal instruction");
88a0747c9fSpatrick AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)");
89061da546Spatrick AddSignal(6, "SIGABRT", false, true, true, "abort()");
90061da546Spatrick AddSignal(7, "SIGEMT", false, true, true, "pollable event");
91061da546Spatrick AddSignal(8, "SIGFPE", false, true, true, "floating point exception");
92061da546Spatrick AddSignal(9, "SIGKILL", false, true, true, "kill");
93061da546Spatrick AddSignal(10, "SIGBUS", false, true, true, "bus error");
94061da546Spatrick AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation");
95061da546Spatrick AddSignal(12, "SIGSYS", false, true, true, "bad argument to system call");
96a0747c9fSpatrick AddSignal(13, "SIGPIPE", false, false, false, "write on a pipe with no one to read it");
97061da546Spatrick AddSignal(14, "SIGALRM", false, false, false, "alarm clock");
98a0747c9fSpatrick AddSignal(15, "SIGTERM", false, true, true, "software termination signal from kill");
99a0747c9fSpatrick AddSignal(16, "SIGURG", false, false, false, "urgent condition on IO channel");
100a0747c9fSpatrick AddSignal(17, "SIGSTOP", true, true, true, "sendable stop signal not from tty");
101061da546Spatrick AddSignal(18, "SIGTSTP", false, true, true, "stop signal from tty");
102a0747c9fSpatrick AddSignal(19, "SIGCONT", false, false, true, "continue a stopped process");
103a0747c9fSpatrick AddSignal(20, "SIGCHLD", false, false, false, "to parent on child stop or exit");
104a0747c9fSpatrick AddSignal(21, "SIGTTIN", false, true, true, "to readers process group upon background tty read");
105a0747c9fSpatrick AddSignal(22, "SIGTTOU", false, true, true, "to readers process group upon background tty write");
106061da546Spatrick AddSignal(23, "SIGIO", false, false, false, "input/output possible signal");
107061da546Spatrick AddSignal(24, "SIGXCPU", false, true, true, "exceeded CPU time limit");
108061da546Spatrick AddSignal(25, "SIGXFSZ", false, true, true, "exceeded file size limit");
109061da546Spatrick AddSignal(26, "SIGVTALRM", false, false, false, "virtual time alarm");
110061da546Spatrick AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm");
111061da546Spatrick AddSignal(28, "SIGWINCH", false, false, false, "window size changes");
112061da546Spatrick AddSignal(29, "SIGINFO", false, true, true, "information request");
113061da546Spatrick AddSignal(30, "SIGUSR1", false, true, true, "user defined signal 1");
114061da546Spatrick AddSignal(31, "SIGUSR2", false, true, true, "user defined signal 2");
115a0747c9fSpatrick // clang-format on
116061da546Spatrick }
117061da546Spatrick
AddSignal(int signo,const char * name,bool default_suppress,bool default_stop,bool default_notify,const char * description,const char * alias)118061da546Spatrick void UnixSignals::AddSignal(int signo, const char *name, bool default_suppress,
119061da546Spatrick bool default_stop, bool default_notify,
120061da546Spatrick const char *description, const char *alias) {
121061da546Spatrick Signal new_signal(name, default_suppress, default_stop, default_notify,
122061da546Spatrick description, alias);
123061da546Spatrick m_signals.insert(std::make_pair(signo, new_signal));
124061da546Spatrick ++m_version;
125061da546Spatrick }
126061da546Spatrick
RemoveSignal(int signo)127061da546Spatrick void UnixSignals::RemoveSignal(int signo) {
128061da546Spatrick collection::iterator pos = m_signals.find(signo);
129061da546Spatrick if (pos != m_signals.end())
130061da546Spatrick m_signals.erase(pos);
131061da546Spatrick ++m_version;
132061da546Spatrick }
133061da546Spatrick
GetSignalAsCString(int signo) const134061da546Spatrick const char *UnixSignals::GetSignalAsCString(int signo) const {
135061da546Spatrick collection::const_iterator pos = m_signals.find(signo);
136061da546Spatrick if (pos == m_signals.end())
137061da546Spatrick return nullptr;
138061da546Spatrick else
139061da546Spatrick return pos->second.m_name.GetCString();
140061da546Spatrick }
141061da546Spatrick
SignalIsValid(int32_t signo) const142061da546Spatrick bool UnixSignals::SignalIsValid(int32_t signo) const {
143061da546Spatrick return m_signals.find(signo) != m_signals.end();
144061da546Spatrick }
145061da546Spatrick
GetShortName(ConstString name) const146061da546Spatrick ConstString UnixSignals::GetShortName(ConstString name) const {
147dda28197Spatrick if (name)
148dda28197Spatrick return ConstString(name.GetStringRef().substr(3)); // Remove "SIG" from name
149061da546Spatrick return name;
150061da546Spatrick }
151061da546Spatrick
GetSignalNumberFromName(const char * name) const152061da546Spatrick int32_t UnixSignals::GetSignalNumberFromName(const char *name) const {
153061da546Spatrick ConstString const_name(name);
154061da546Spatrick
155061da546Spatrick collection::const_iterator pos, end = m_signals.end();
156061da546Spatrick for (pos = m_signals.begin(); pos != end; pos++) {
157061da546Spatrick if ((const_name == pos->second.m_name) ||
158061da546Spatrick (const_name == pos->second.m_alias) ||
159061da546Spatrick (const_name == GetShortName(pos->second.m_name)) ||
160061da546Spatrick (const_name == GetShortName(pos->second.m_alias)))
161061da546Spatrick return pos->first;
162061da546Spatrick }
163061da546Spatrick
164*101d251dSrobert int32_t signo;
165*101d251dSrobert if (llvm::to_integer(name, signo))
166061da546Spatrick return signo;
167061da546Spatrick return LLDB_INVALID_SIGNAL_NUMBER;
168061da546Spatrick }
169061da546Spatrick
GetFirstSignalNumber() const170061da546Spatrick int32_t UnixSignals::GetFirstSignalNumber() const {
171061da546Spatrick if (m_signals.empty())
172061da546Spatrick return LLDB_INVALID_SIGNAL_NUMBER;
173061da546Spatrick
174061da546Spatrick return (*m_signals.begin()).first;
175061da546Spatrick }
176061da546Spatrick
GetNextSignalNumber(int32_t current_signal) const177061da546Spatrick int32_t UnixSignals::GetNextSignalNumber(int32_t current_signal) const {
178061da546Spatrick collection::const_iterator pos = m_signals.find(current_signal);
179061da546Spatrick collection::const_iterator end = m_signals.end();
180061da546Spatrick if (pos == end)
181061da546Spatrick return LLDB_INVALID_SIGNAL_NUMBER;
182061da546Spatrick else {
183061da546Spatrick pos++;
184061da546Spatrick if (pos == end)
185061da546Spatrick return LLDB_INVALID_SIGNAL_NUMBER;
186061da546Spatrick else
187061da546Spatrick return pos->first;
188061da546Spatrick }
189061da546Spatrick }
190061da546Spatrick
GetSignalInfo(int32_t signo,bool & should_suppress,bool & should_stop,bool & should_notify) const191061da546Spatrick const char *UnixSignals::GetSignalInfo(int32_t signo, bool &should_suppress,
192061da546Spatrick bool &should_stop,
193061da546Spatrick bool &should_notify) const {
194061da546Spatrick collection::const_iterator pos = m_signals.find(signo);
195061da546Spatrick if (pos == m_signals.end())
196061da546Spatrick return nullptr;
197061da546Spatrick else {
198061da546Spatrick const Signal &signal = pos->second;
199061da546Spatrick should_suppress = signal.m_suppress;
200061da546Spatrick should_stop = signal.m_stop;
201061da546Spatrick should_notify = signal.m_notify;
202061da546Spatrick return signal.m_name.AsCString("");
203061da546Spatrick }
204061da546Spatrick }
205061da546Spatrick
GetShouldSuppress(int signo) const206061da546Spatrick bool UnixSignals::GetShouldSuppress(int signo) const {
207061da546Spatrick collection::const_iterator pos = m_signals.find(signo);
208061da546Spatrick if (pos != m_signals.end())
209061da546Spatrick return pos->second.m_suppress;
210061da546Spatrick return false;
211061da546Spatrick }
212061da546Spatrick
SetShouldSuppress(int signo,bool value)213061da546Spatrick bool UnixSignals::SetShouldSuppress(int signo, bool value) {
214061da546Spatrick collection::iterator pos = m_signals.find(signo);
215061da546Spatrick if (pos != m_signals.end()) {
216061da546Spatrick pos->second.m_suppress = value;
217061da546Spatrick ++m_version;
218061da546Spatrick return true;
219061da546Spatrick }
220061da546Spatrick return false;
221061da546Spatrick }
222061da546Spatrick
SetShouldSuppress(const char * signal_name,bool value)223061da546Spatrick bool UnixSignals::SetShouldSuppress(const char *signal_name, bool value) {
224061da546Spatrick const int32_t signo = GetSignalNumberFromName(signal_name);
225061da546Spatrick if (signo != LLDB_INVALID_SIGNAL_NUMBER)
226061da546Spatrick return SetShouldSuppress(signo, value);
227061da546Spatrick return false;
228061da546Spatrick }
229061da546Spatrick
GetShouldStop(int signo) const230061da546Spatrick bool UnixSignals::GetShouldStop(int signo) const {
231061da546Spatrick collection::const_iterator pos = m_signals.find(signo);
232061da546Spatrick if (pos != m_signals.end())
233061da546Spatrick return pos->second.m_stop;
234061da546Spatrick return false;
235061da546Spatrick }
236061da546Spatrick
SetShouldStop(int signo,bool value)237061da546Spatrick bool UnixSignals::SetShouldStop(int signo, bool value) {
238061da546Spatrick collection::iterator pos = m_signals.find(signo);
239061da546Spatrick if (pos != m_signals.end()) {
240061da546Spatrick pos->second.m_stop = value;
241061da546Spatrick ++m_version;
242061da546Spatrick return true;
243061da546Spatrick }
244061da546Spatrick return false;
245061da546Spatrick }
246061da546Spatrick
SetShouldStop(const char * signal_name,bool value)247061da546Spatrick bool UnixSignals::SetShouldStop(const char *signal_name, bool value) {
248061da546Spatrick const int32_t signo = GetSignalNumberFromName(signal_name);
249061da546Spatrick if (signo != LLDB_INVALID_SIGNAL_NUMBER)
250061da546Spatrick return SetShouldStop(signo, value);
251061da546Spatrick return false;
252061da546Spatrick }
253061da546Spatrick
GetShouldNotify(int signo) const254061da546Spatrick bool UnixSignals::GetShouldNotify(int signo) const {
255061da546Spatrick collection::const_iterator pos = m_signals.find(signo);
256061da546Spatrick if (pos != m_signals.end())
257061da546Spatrick return pos->second.m_notify;
258061da546Spatrick return false;
259061da546Spatrick }
260061da546Spatrick
SetShouldNotify(int signo,bool value)261061da546Spatrick bool UnixSignals::SetShouldNotify(int signo, bool value) {
262061da546Spatrick collection::iterator pos = m_signals.find(signo);
263061da546Spatrick if (pos != m_signals.end()) {
264061da546Spatrick pos->second.m_notify = value;
265061da546Spatrick ++m_version;
266061da546Spatrick return true;
267061da546Spatrick }
268061da546Spatrick return false;
269061da546Spatrick }
270061da546Spatrick
SetShouldNotify(const char * signal_name,bool value)271061da546Spatrick bool UnixSignals::SetShouldNotify(const char *signal_name, bool value) {
272061da546Spatrick const int32_t signo = GetSignalNumberFromName(signal_name);
273061da546Spatrick if (signo != LLDB_INVALID_SIGNAL_NUMBER)
274061da546Spatrick return SetShouldNotify(signo, value);
275061da546Spatrick return false;
276061da546Spatrick }
277061da546Spatrick
GetNumSignals() const278061da546Spatrick int32_t UnixSignals::GetNumSignals() const { return m_signals.size(); }
279061da546Spatrick
GetSignalAtIndex(int32_t index) const280061da546Spatrick int32_t UnixSignals::GetSignalAtIndex(int32_t index) const {
281061da546Spatrick if (index < 0 || m_signals.size() <= static_cast<size_t>(index))
282061da546Spatrick return LLDB_INVALID_SIGNAL_NUMBER;
283061da546Spatrick auto it = m_signals.begin();
284061da546Spatrick std::advance(it, index);
285061da546Spatrick return it->first;
286061da546Spatrick }
287061da546Spatrick
GetVersion() const288061da546Spatrick uint64_t UnixSignals::GetVersion() const { return m_version; }
289061da546Spatrick
290061da546Spatrick std::vector<int32_t>
GetFilteredSignals(std::optional<bool> should_suppress,std::optional<bool> should_stop,std::optional<bool> should_notify)291*101d251dSrobert UnixSignals::GetFilteredSignals(std::optional<bool> should_suppress,
292*101d251dSrobert std::optional<bool> should_stop,
293*101d251dSrobert std::optional<bool> should_notify) {
294061da546Spatrick std::vector<int32_t> result;
295061da546Spatrick for (int32_t signo = GetFirstSignalNumber();
296061da546Spatrick signo != LLDB_INVALID_SIGNAL_NUMBER;
297061da546Spatrick signo = GetNextSignalNumber(signo)) {
298061da546Spatrick
299061da546Spatrick bool signal_suppress = false;
300061da546Spatrick bool signal_stop = false;
301061da546Spatrick bool signal_notify = false;
302061da546Spatrick GetSignalInfo(signo, signal_suppress, signal_stop, signal_notify);
303061da546Spatrick
304061da546Spatrick // If any of filtering conditions are not met, we move on to the next
305061da546Spatrick // signal.
306*101d251dSrobert if (should_suppress && signal_suppress != *should_suppress)
307061da546Spatrick continue;
308061da546Spatrick
309*101d251dSrobert if (should_stop && signal_stop != *should_stop)
310061da546Spatrick continue;
311061da546Spatrick
312*101d251dSrobert if (should_notify && signal_notify != *should_notify)
313061da546Spatrick continue;
314061da546Spatrick
315061da546Spatrick result.push_back(signo);
316061da546Spatrick }
317061da546Spatrick
318061da546Spatrick return result;
319061da546Spatrick }
320*101d251dSrobert
IncrementSignalHitCount(int signo)321*101d251dSrobert void UnixSignals::IncrementSignalHitCount(int signo) {
322*101d251dSrobert collection::iterator pos = m_signals.find(signo);
323*101d251dSrobert if (pos != m_signals.end())
324*101d251dSrobert pos->second.m_hit_count += 1;
325*101d251dSrobert }
326*101d251dSrobert
GetHitCountStatistics() const327*101d251dSrobert json::Value UnixSignals::GetHitCountStatistics() const {
328*101d251dSrobert json::Array json_signals;
329*101d251dSrobert for (const auto &pair: m_signals) {
330*101d251dSrobert if (pair.second.m_hit_count > 0)
331*101d251dSrobert json_signals.emplace_back(json::Object{
332*101d251dSrobert { pair.second.m_name.GetCString(), pair.second.m_hit_count }
333*101d251dSrobert });
334*101d251dSrobert }
335*101d251dSrobert return std::move(json_signals);
336*101d251dSrobert }
337*101d251dSrobert
Reset(bool reset_stop,bool reset_notify,bool reset_suppress)338*101d251dSrobert void UnixSignals::Signal::Reset(bool reset_stop, bool reset_notify,
339*101d251dSrobert bool reset_suppress) {
340*101d251dSrobert if (reset_stop)
341*101d251dSrobert m_stop = m_default_stop;
342*101d251dSrobert if (reset_notify)
343*101d251dSrobert m_notify = m_default_notify;
344*101d251dSrobert if (reset_suppress)
345*101d251dSrobert m_suppress = m_default_suppress;
346*101d251dSrobert }
347*101d251dSrobert
ResetSignal(int32_t signo,bool reset_stop,bool reset_notify,bool reset_suppress)348*101d251dSrobert bool UnixSignals::ResetSignal(int32_t signo, bool reset_stop,
349*101d251dSrobert bool reset_notify, bool reset_suppress) {
350*101d251dSrobert auto elem = m_signals.find(signo);
351*101d251dSrobert if (elem == m_signals.end())
352*101d251dSrobert return false;
353*101d251dSrobert (*elem).second.Reset(reset_stop, reset_notify, reset_suppress);
354*101d251dSrobert return true;
355*101d251dSrobert }
356*101d251dSrobert
357