xref: /openbsd-src/gnu/llvm/lldb/source/Target/UnixSignals.cpp (revision 101d251d5caf88a9341f3045ab62e122abae1b90)
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