1254721Semaste//===-- UnixSignals.cpp -----------------------------------------*- C++ -*-===//
2254721Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6254721Semaste//
7254721Semaste//===----------------------------------------------------------------------===//
8254721Semaste
9309124Sdim#include "lldb/Target/UnixSignals.h"
10288943Sdim#include "Plugins/Process/Utility/FreeBSDSignals.h"
11288943Sdim#include "Plugins/Process/Utility/LinuxSignals.h"
12288943Sdim#include "Plugins/Process/Utility/MipsLinuxSignals.h"
13296417Sdim#include "Plugins/Process/Utility/NetBSDSignals.h"
14353358Sdim#include "lldb/Host/HostInfo.h"
15314564Sdim#include "lldb/Host/StringConvert.h"
16327952Sdim#include "lldb/Utility/ArchSpec.h"
17288943Sdim
18254721Semasteusing namespace lldb_private;
19254721Semaste
20314564SdimUnixSignals::Signal::Signal(const char *name, bool default_suppress,
21314564Sdim                            bool default_stop, bool default_notify,
22314564Sdim                            const char *description, const char *alias)
23314564Sdim    : m_name(name), m_alias(alias), m_description(),
24314564Sdim      m_suppress(default_suppress), m_stop(default_stop),
25314564Sdim      m_notify(default_notify) {
26314564Sdim  if (description)
27314564Sdim    m_description.assign(description);
28254721Semaste}
29254721Semaste
30314564Sdimlldb::UnixSignalsSP UnixSignals::Create(const ArchSpec &arch) {
31314564Sdim  const auto &triple = arch.GetTriple();
32314564Sdim  switch (triple.getOS()) {
33314564Sdim  case llvm::Triple::Linux: {
34314564Sdim    switch (triple.getArch()) {
35314564Sdim    case llvm::Triple::mips:
36314564Sdim    case llvm::Triple::mipsel:
37314564Sdim    case llvm::Triple::mips64:
38314564Sdim    case llvm::Triple::mips64el:
39314564Sdim      return std::make_shared<MipsLinuxSignals>();
40314564Sdim    default:
41314564Sdim      return std::make_shared<LinuxSignals>();
42288943Sdim    }
43314564Sdim  }
44314564Sdim  case llvm::Triple::FreeBSD:
45314564Sdim  case llvm::Triple::OpenBSD:
46314564Sdim    return std::make_shared<FreeBSDSignals>();
47314564Sdim  case llvm::Triple::NetBSD:
48314564Sdim    return std::make_shared<NetBSDSignals>();
49314564Sdim  default:
50314564Sdim    return std::make_shared<UnixSignals>();
51314564Sdim  }
52288943Sdim}
53288943Sdim
54353358Sdimlldb::UnixSignalsSP UnixSignals::CreateForHost() {
55353358Sdim  static lldb::UnixSignalsSP s_unix_signals_sp =
56353358Sdim      Create(HostInfo::GetArchitecture());
57353358Sdim  return s_unix_signals_sp;
58353358Sdim}
59353358Sdim
60254721Semaste// UnixSignals constructor
61314564SdimUnixSignals::UnixSignals() { Reset(); }
62254721Semaste
63314564SdimUnixSignals::UnixSignals(const UnixSignals &rhs) : m_signals(rhs.m_signals) {}
64288943Sdim
65309124SdimUnixSignals::~UnixSignals() = default;
66254721Semaste
67314564Sdimvoid UnixSignals::Reset() {
68314564Sdim  // This builds one standard set of Unix Signals.  If yours aren't quite in
69341825Sdim  // this order, you can either subclass this class, and use Add & Remove to
70341825Sdim  // change them
71314564Sdim  // or you can subclass and build them afresh in your constructor;
72314564Sdim  //
73314564Sdim  // Note: the signals below are the Darwin signals.  Do not change these!
74314564Sdim  m_signals.clear();
75314564Sdim  //        SIGNO  NAME          SUPPRESS STOP   NOTIFY DESCRIPTION
76314564Sdim  //        ====== ============  ======== ====== ======
77314564Sdim  //        ===================================================
78314564Sdim  AddSignal(1, "SIGHUP", false, true, true, "hangup");
79314564Sdim  AddSignal(2, "SIGINT", true, true, true, "interrupt");
80314564Sdim  AddSignal(3, "SIGQUIT", false, true, true, "quit");
81314564Sdim  AddSignal(4, "SIGILL", false, true, true, "illegal instruction");
82314564Sdim  AddSignal(5, "SIGTRAP", true, true, true,
83314564Sdim            "trace trap (not reset when caught)");
84314564Sdim  AddSignal(6, "SIGABRT", false, true, true, "abort()");
85314564Sdim  AddSignal(7, "SIGEMT", false, true, true, "pollable event");
86314564Sdim  AddSignal(8, "SIGFPE", false, true, true, "floating point exception");
87314564Sdim  AddSignal(9, "SIGKILL", false, true, true, "kill");
88314564Sdim  AddSignal(10, "SIGBUS", false, true, true, "bus error");
89314564Sdim  AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation");
90314564Sdim  AddSignal(12, "SIGSYS", false, true, true, "bad argument to system call");
91344779Sdim  AddSignal(13, "SIGPIPE", false, false, false,
92314564Sdim            "write on a pipe with no one to read it");
93314564Sdim  AddSignal(14, "SIGALRM", false, false, false, "alarm clock");
94314564Sdim  AddSignal(15, "SIGTERM", false, true, true,
95314564Sdim            "software termination signal from kill");
96314564Sdim  AddSignal(16, "SIGURG", false, false, false,
97314564Sdim            "urgent condition on IO channel");
98314564Sdim  AddSignal(17, "SIGSTOP", true, true, true,
99314564Sdim            "sendable stop signal not from tty");
100314564Sdim  AddSignal(18, "SIGTSTP", false, true, true, "stop signal from tty");
101314564Sdim  AddSignal(19, "SIGCONT", false, true, true, "continue a stopped process");
102314564Sdim  AddSignal(20, "SIGCHLD", false, false, false,
103314564Sdim            "to parent on child stop or exit");
104314564Sdim  AddSignal(21, "SIGTTIN", false, true, true,
105314564Sdim            "to readers process group upon background tty read");
106314564Sdim  AddSignal(22, "SIGTTOU", false, true, true,
107314564Sdim            "to readers process group upon background tty write");
108314564Sdim  AddSignal(23, "SIGIO", false, false, false, "input/output possible signal");
109314564Sdim  AddSignal(24, "SIGXCPU", false, true, true, "exceeded CPU time limit");
110314564Sdim  AddSignal(25, "SIGXFSZ", false, true, true, "exceeded file size limit");
111314564Sdim  AddSignal(26, "SIGVTALRM", false, false, false, "virtual time alarm");
112314564Sdim  AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm");
113314564Sdim  AddSignal(28, "SIGWINCH", false, false, false, "window size changes");
114314564Sdim  AddSignal(29, "SIGINFO", false, true, true, "information request");
115314564Sdim  AddSignal(30, "SIGUSR1", false, true, true, "user defined signal 1");
116314564Sdim  AddSignal(31, "SIGUSR2", false, true, true, "user defined signal 2");
117254721Semaste}
118254721Semaste
119314564Sdimvoid UnixSignals::AddSignal(int signo, const char *name, bool default_suppress,
120314564Sdim                            bool default_stop, bool default_notify,
121314564Sdim                            const char *description, const char *alias) {
122314564Sdim  Signal new_signal(name, default_suppress, default_stop, default_notify,
123314564Sdim                    description, alias);
124314564Sdim  m_signals.insert(std::make_pair(signo, new_signal));
125321369Sdim  ++m_version;
126254721Semaste}
127254721Semaste
128314564Sdimvoid UnixSignals::RemoveSignal(int signo) {
129314564Sdim  collection::iterator pos = m_signals.find(signo);
130314564Sdim  if (pos != m_signals.end())
131314564Sdim    m_signals.erase(pos);
132321369Sdim  ++m_version;
133254721Semaste}
134254721Semaste
135314564Sdimconst char *UnixSignals::GetSignalAsCString(int signo) const {
136314564Sdim  collection::const_iterator pos = m_signals.find(signo);
137314564Sdim  if (pos == m_signals.end())
138314564Sdim    return nullptr;
139314564Sdim  else
140314564Sdim    return pos->second.m_name.GetCString();
141254721Semaste}
142254721Semaste
143314564Sdimbool UnixSignals::SignalIsValid(int32_t signo) const {
144314564Sdim  return m_signals.find(signo) != m_signals.end();
145254721Semaste}
146254721Semaste
147314564SdimConstString UnixSignals::GetShortName(ConstString name) const {
148314564Sdim  if (name) {
149314564Sdim    const char *signame = name.AsCString();
150314564Sdim    return ConstString(signame + 3); // Remove "SIG" from name
151314564Sdim  }
152314564Sdim  return name;
153296417Sdim}
154254721Semaste
155314564Sdimint32_t UnixSignals::GetSignalNumberFromName(const char *name) const {
156314564Sdim  ConstString const_name(name);
157254721Semaste
158314564Sdim  collection::const_iterator pos, end = m_signals.end();
159314564Sdim  for (pos = m_signals.begin(); pos != end; pos++) {
160314564Sdim    if ((const_name == pos->second.m_name) ||
161314564Sdim        (const_name == pos->second.m_alias) ||
162314564Sdim        (const_name == GetShortName(pos->second.m_name)) ||
163314564Sdim        (const_name == GetShortName(pos->second.m_alias)))
164314564Sdim      return pos->first;
165314564Sdim  }
166314564Sdim
167314564Sdim  const int32_t signo =
168314564Sdim      StringConvert::ToSInt32(name, LLDB_INVALID_SIGNAL_NUMBER, 0);
169314564Sdim  if (signo != LLDB_INVALID_SIGNAL_NUMBER)
170314564Sdim    return signo;
171314564Sdim  return LLDB_INVALID_SIGNAL_NUMBER;
172254721Semaste}
173254721Semaste
174314564Sdimint32_t UnixSignals::GetFirstSignalNumber() const {
175314564Sdim  if (m_signals.empty())
176314564Sdim    return LLDB_INVALID_SIGNAL_NUMBER;
177254721Semaste
178314564Sdim  return (*m_signals.begin()).first;
179254721Semaste}
180254721Semaste
181314564Sdimint32_t UnixSignals::GetNextSignalNumber(int32_t current_signal) const {
182314564Sdim  collection::const_iterator pos = m_signals.find(current_signal);
183314564Sdim  collection::const_iterator end = m_signals.end();
184314564Sdim  if (pos == end)
185314564Sdim    return LLDB_INVALID_SIGNAL_NUMBER;
186314564Sdim  else {
187314564Sdim    pos++;
188254721Semaste    if (pos == end)
189314564Sdim      return LLDB_INVALID_SIGNAL_NUMBER;
190254721Semaste    else
191314564Sdim      return pos->first;
192314564Sdim  }
193254721Semaste}
194254721Semaste
195314564Sdimconst char *UnixSignals::GetSignalInfo(int32_t signo, bool &should_suppress,
196314564Sdim                                       bool &should_stop,
197314564Sdim                                       bool &should_notify) const {
198314564Sdim  collection::const_iterator pos = m_signals.find(signo);
199314564Sdim  if (pos == m_signals.end())
200314564Sdim    return nullptr;
201314564Sdim  else {
202314564Sdim    const Signal &signal = pos->second;
203314564Sdim    should_suppress = signal.m_suppress;
204314564Sdim    should_stop = signal.m_stop;
205314564Sdim    should_notify = signal.m_notify;
206314564Sdim    return signal.m_name.AsCString("");
207314564Sdim  }
208254721Semaste}
209254721Semaste
210314564Sdimbool UnixSignals::GetShouldSuppress(int signo) const {
211314564Sdim  collection::const_iterator pos = m_signals.find(signo);
212314564Sdim  if (pos != m_signals.end())
213314564Sdim    return pos->second.m_suppress;
214314564Sdim  return false;
215254721Semaste}
216254721Semaste
217314564Sdimbool UnixSignals::SetShouldSuppress(int signo, bool value) {
218314564Sdim  collection::iterator pos = m_signals.find(signo);
219314564Sdim  if (pos != m_signals.end()) {
220314564Sdim    pos->second.m_suppress = value;
221321369Sdim    ++m_version;
222314564Sdim    return true;
223314564Sdim  }
224314564Sdim  return false;
225254721Semaste}
226254721Semaste
227314564Sdimbool UnixSignals::SetShouldSuppress(const char *signal_name, bool value) {
228314564Sdim  const int32_t signo = GetSignalNumberFromName(signal_name);
229314564Sdim  if (signo != LLDB_INVALID_SIGNAL_NUMBER)
230314564Sdim    return SetShouldSuppress(signo, value);
231314564Sdim  return false;
232254721Semaste}
233254721Semaste
234314564Sdimbool UnixSignals::GetShouldStop(int signo) const {
235314564Sdim  collection::const_iterator pos = m_signals.find(signo);
236314564Sdim  if (pos != m_signals.end())
237314564Sdim    return pos->second.m_stop;
238314564Sdim  return false;
239254721Semaste}
240254721Semaste
241314564Sdimbool UnixSignals::SetShouldStop(int signo, bool value) {
242314564Sdim  collection::iterator pos = m_signals.find(signo);
243314564Sdim  if (pos != m_signals.end()) {
244314564Sdim    pos->second.m_stop = value;
245321369Sdim    ++m_version;
246314564Sdim    return true;
247314564Sdim  }
248314564Sdim  return false;
249254721Semaste}
250254721Semaste
251314564Sdimbool UnixSignals::SetShouldStop(const char *signal_name, bool value) {
252314564Sdim  const int32_t signo = GetSignalNumberFromName(signal_name);
253314564Sdim  if (signo != LLDB_INVALID_SIGNAL_NUMBER)
254314564Sdim    return SetShouldStop(signo, value);
255314564Sdim  return false;
256254721Semaste}
257254721Semaste
258314564Sdimbool UnixSignals::GetShouldNotify(int signo) const {
259314564Sdim  collection::const_iterator pos = m_signals.find(signo);
260314564Sdim  if (pos != m_signals.end())
261314564Sdim    return pos->second.m_notify;
262314564Sdim  return false;
263254721Semaste}
264254721Semaste
265314564Sdimbool UnixSignals::SetShouldNotify(int signo, bool value) {
266314564Sdim  collection::iterator pos = m_signals.find(signo);
267314564Sdim  if (pos != m_signals.end()) {
268314564Sdim    pos->second.m_notify = value;
269321369Sdim    ++m_version;
270314564Sdim    return true;
271314564Sdim  }
272314564Sdim  return false;
273254721Semaste}
274254721Semaste
275314564Sdimbool UnixSignals::SetShouldNotify(const char *signal_name, bool value) {
276314564Sdim  const int32_t signo = GetSignalNumberFromName(signal_name);
277314564Sdim  if (signo != LLDB_INVALID_SIGNAL_NUMBER)
278314564Sdim    return SetShouldNotify(signo, value);
279314564Sdim  return false;
280254721Semaste}
281288943Sdim
282314564Sdimint32_t UnixSignals::GetNumSignals() const { return m_signals.size(); }
283288943Sdim
284314564Sdimint32_t UnixSignals::GetSignalAtIndex(int32_t index) const {
285314564Sdim  if (index < 0 || m_signals.size() <= static_cast<size_t>(index))
286314564Sdim    return LLDB_INVALID_SIGNAL_NUMBER;
287314564Sdim  auto it = m_signals.begin();
288314564Sdim  std::advance(it, index);
289314564Sdim  return it->first;
290288943Sdim}
291321369Sdim
292321369Sdimuint64_t UnixSignals::GetVersion() const { return m_version; }
293321369Sdim
294321369Sdimstd::vector<int32_t>
295321369SdimUnixSignals::GetFilteredSignals(llvm::Optional<bool> should_suppress,
296321369Sdim                                llvm::Optional<bool> should_stop,
297321369Sdim                                llvm::Optional<bool> should_notify) {
298321369Sdim  std::vector<int32_t> result;
299321369Sdim  for (int32_t signo = GetFirstSignalNumber();
300321369Sdim       signo != LLDB_INVALID_SIGNAL_NUMBER;
301321369Sdim       signo = GetNextSignalNumber(signo)) {
302321369Sdim
303321369Sdim    bool signal_suppress = false;
304321369Sdim    bool signal_stop = false;
305321369Sdim    bool signal_notify = false;
306321369Sdim    GetSignalInfo(signo, signal_suppress, signal_stop, signal_notify);
307321369Sdim
308341825Sdim    // If any of filtering conditions are not met, we move on to the next
309341825Sdim    // signal.
310321369Sdim    if (should_suppress.hasValue() &&
311321369Sdim        signal_suppress != should_suppress.getValue())
312321369Sdim      continue;
313321369Sdim
314321369Sdim    if (should_stop.hasValue() && signal_stop != should_stop.getValue())
315321369Sdim      continue;
316321369Sdim
317321369Sdim    if (should_notify.hasValue() && signal_notify != should_notify.getValue())
318321369Sdim      continue;
319321369Sdim
320321369Sdim    result.push_back(signo);
321321369Sdim  }
322321369Sdim
323321369Sdim  return result;
324321369Sdim}
325