1 //===-- UnixSignals.cpp -----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 
11 // C Includes
12 // C++ Includes
13 // Other libraries and framework includes
14 // Project includes
15 #include "lldb/Target/UnixSignals.h"
16 #include "lldb/Core/ArchSpec.h"
17 #include "lldb/Host/StringConvert.h"
18 #include "Plugins/Process/Utility/FreeBSDSignals.h"
19 #include "Plugins/Process/Utility/LinuxSignals.h"
20 #include "Plugins/Process/Utility/MipsLinuxSignals.h"
21 #include "Plugins/Process/Utility/NetBSDSignals.h"
22 
23 using namespace lldb_private;
24 
25 UnixSignals::Signal::Signal(const char *name,
26                             bool default_suppress,
27                             bool default_stop,
28                             bool default_notify,
29                             const char *description,
30                             const char *alias) :
31     m_name (name),
32     m_alias (alias),
33     m_description (),
34     m_suppress (default_suppress),
35     m_stop (default_stop),
36     m_notify (default_notify)
37 {
38     if (description)
39         m_description.assign (description);
40 }
41 
42 lldb::UnixSignalsSP
43 UnixSignals::Create(const ArchSpec &arch)
44 {
45     const auto &triple = arch.GetTriple();
46     switch (triple.getOS())
47     {
48         case llvm::Triple::Linux:
49         {
50             switch (triple.getArch())
51             {
52                 case llvm::Triple::mips:
53                 case llvm::Triple::mipsel:
54                 case llvm::Triple::mips64:
55                 case llvm::Triple::mips64el:
56                     return std::make_shared<MipsLinuxSignals>();
57                 default:
58                     return std::make_shared<LinuxSignals>();
59             }
60         }
61         case llvm::Triple::FreeBSD:
62         case llvm::Triple::OpenBSD:
63             return std::make_shared<FreeBSDSignals>();
64         case llvm::Triple::NetBSD:
65             return std::make_shared<NetBSDSignals>();
66         default:
67             return std::make_shared<UnixSignals>();
68     }
69 }
70 
71 //----------------------------------------------------------------------
72 // UnixSignals constructor
73 //----------------------------------------------------------------------
74 UnixSignals::UnixSignals ()
75 {
76     Reset ();
77 }
78 
79 UnixSignals::UnixSignals(const UnixSignals &rhs)
80     : m_signals(rhs.m_signals)
81 {
82 }
83 
84 UnixSignals::~UnixSignals() = default;
85 
86 void
87 UnixSignals::Reset ()
88 {
89     // This builds one standard set of Unix Signals.  If yours aren't quite in this
90     // order, you can either subclass this class, and use Add & Remove to change them
91     // or you can subclass and build them afresh in your constructor;
92     //
93     // Note: the signals below are the Darwin signals.  Do not change these!
94     m_signals.clear();
95     //        SIGNO  NAME          SUPPRESS STOP   NOTIFY DESCRIPTION
96     //        ====== ============  ======== ====== ====== ===================================================
97     AddSignal (1,    "SIGHUP",     false,   true , true , "hangup");
98     AddSignal (2,    "SIGINT",     true ,   true , true , "interrupt");
99     AddSignal (3,    "SIGQUIT",    false,   true , true , "quit");
100     AddSignal (4,    "SIGILL",     false,   true , true , "illegal instruction");
101     AddSignal (5,    "SIGTRAP",    true ,   true , true , "trace trap (not reset when caught)");
102     AddSignal (6,    "SIGABRT",    false,   true , true , "abort()");
103     AddSignal (7,    "SIGEMT",     false,   true , true , "pollable event");
104     AddSignal (8,    "SIGFPE",     false,   true , true , "floating point exception");
105     AddSignal (9,    "SIGKILL",    false,   true , true , "kill");
106     AddSignal (10,   "SIGBUS",     false,   true , true , "bus error");
107     AddSignal (11,   "SIGSEGV",    false,   true , true , "segmentation violation");
108     AddSignal (12,   "SIGSYS",     false,   true , true , "bad argument to system call");
109     AddSignal (13,   "SIGPIPE",    false,   true , true , "write on a pipe with no one to read it");
110     AddSignal (14,   "SIGALRM",    false,   false, false, "alarm clock");
111     AddSignal (15,   "SIGTERM",    false,   true , true , "software termination signal from kill");
112     AddSignal (16,   "SIGURG",     false,   false, false, "urgent condition on IO channel");
113     AddSignal (17,   "SIGSTOP",    true ,   true , true , "sendable stop signal not from tty");
114     AddSignal (18,   "SIGTSTP",    false,   true , true , "stop signal from tty");
115     AddSignal (19,   "SIGCONT",    false,   true , true , "continue a stopped process");
116     AddSignal (20,   "SIGCHLD",    false,   false, false, "to parent on child stop or exit");
117     AddSignal (21,   "SIGTTIN",    false,   true , true , "to readers process group upon background tty read");
118     AddSignal (22,   "SIGTTOU",    false,   true , true , "to readers process group upon background tty write");
119     AddSignal (23,   "SIGIO",      false,   false, false, "input/output possible signal");
120     AddSignal (24,   "SIGXCPU",    false,   true , true , "exceeded CPU time limit");
121     AddSignal (25,   "SIGXFSZ",    false,   true , true , "exceeded file size limit");
122     AddSignal (26,   "SIGVTALRM",  false,   false, false, "virtual time alarm");
123     AddSignal (27,   "SIGPROF",    false,   false, false, "profiling time alarm");
124     AddSignal (28,   "SIGWINCH",   false,   false, false, "window size changes");
125     AddSignal (29,   "SIGINFO",    false,   true , true , "information request");
126     AddSignal (30,   "SIGUSR1",    false,   true , true , "user defined signal 1");
127     AddSignal (31,   "SIGUSR2",    false,   true , true , "user defined signal 2");
128 }
129 
130 void
131 UnixSignals::AddSignal(int signo,
132                        const char *name,
133                        bool default_suppress,
134                        bool default_stop,
135                        bool default_notify,
136                        const char *description,
137                        const char *alias)
138 {
139     Signal new_signal (name, default_suppress, default_stop, default_notify, description, alias);
140     m_signals.insert (std::make_pair(signo, new_signal));
141 }
142 
143 void
144 UnixSignals::RemoveSignal (int signo)
145 {
146     collection::iterator pos = m_signals.find (signo);
147     if (pos != m_signals.end())
148         m_signals.erase (pos);
149 }
150 
151 const char *
152 UnixSignals::GetSignalAsCString (int signo) const
153 {
154     collection::const_iterator pos = m_signals.find (signo);
155     if (pos == m_signals.end())
156         return nullptr;
157     else
158         return pos->second.m_name.GetCString ();
159 }
160 
161 bool
162 UnixSignals::SignalIsValid (int32_t signo) const
163 {
164     return m_signals.find (signo) != m_signals.end();
165 }
166 
167 ConstString
168 UnixSignals::GetShortName(ConstString name) const
169 {
170     if (name)
171     {
172       const char* signame = name.AsCString();
173       return ConstString(signame + 3); // Remove "SIG" from name
174     }
175     return name;
176 }
177 
178 int32_t
179 UnixSignals::GetSignalNumberFromName (const char *name) const
180 {
181     ConstString const_name (name);
182 
183     collection::const_iterator pos, end = m_signals.end ();
184     for (pos = m_signals.begin (); pos != end; pos++)
185     {
186         if ((const_name == pos->second.m_name) || (const_name == pos->second.m_alias) ||
187             (const_name == GetShortName(pos->second.m_name)) || (const_name == GetShortName(pos->second.m_alias)))
188             return pos->first;
189     }
190 
191     const int32_t signo = StringConvert::ToSInt32(name, LLDB_INVALID_SIGNAL_NUMBER, 0);
192     if (signo != LLDB_INVALID_SIGNAL_NUMBER)
193         return signo;
194     return LLDB_INVALID_SIGNAL_NUMBER;
195 }
196 
197 int32_t
198 UnixSignals::GetFirstSignalNumber () const
199 {
200     if (m_signals.empty())
201         return LLDB_INVALID_SIGNAL_NUMBER;
202 
203     return (*m_signals.begin ()).first;
204 }
205 
206 int32_t
207 UnixSignals::GetNextSignalNumber (int32_t current_signal) const
208 {
209     collection::const_iterator pos = m_signals.find (current_signal);
210     collection::const_iterator end = m_signals.end();
211     if (pos == end)
212         return LLDB_INVALID_SIGNAL_NUMBER;
213     else
214     {
215         pos++;
216         if (pos == end)
217             return LLDB_INVALID_SIGNAL_NUMBER;
218         else
219             return pos->first;
220     }
221 }
222 
223 const char *
224 UnixSignals::GetSignalInfo(int32_t signo,
225                            bool &should_suppress,
226                            bool &should_stop,
227                            bool &should_notify) const
228 {
229     collection::const_iterator pos = m_signals.find (signo);
230     if (pos == m_signals.end())
231         return nullptr;
232     else
233     {
234         const Signal &signal = pos->second;
235         should_suppress = signal.m_suppress;
236         should_stop     = signal.m_stop;
237         should_notify   = signal.m_notify;
238         return signal.m_name.AsCString("");
239     }
240 }
241 
242 bool
243 UnixSignals::GetShouldSuppress (int signo) const
244 {
245     collection::const_iterator pos = m_signals.find (signo);
246     if (pos != m_signals.end())
247         return pos->second.m_suppress;
248     return false;
249 }
250 
251 bool
252 UnixSignals::SetShouldSuppress (int signo, bool value)
253 {
254     collection::iterator pos = m_signals.find (signo);
255     if (pos != m_signals.end())
256     {
257         pos->second.m_suppress = value;
258         return true;
259     }
260     return false;
261 }
262 
263 bool
264 UnixSignals::SetShouldSuppress (const char *signal_name, bool value)
265 {
266     const int32_t signo = GetSignalNumberFromName (signal_name);
267     if (signo != LLDB_INVALID_SIGNAL_NUMBER)
268         return SetShouldSuppress (signo, value);
269     return false;
270 }
271 
272 bool
273 UnixSignals::GetShouldStop (int signo) const
274 {
275     collection::const_iterator pos = m_signals.find (signo);
276     if (pos != m_signals.end())
277         return pos->second.m_stop;
278     return false;
279 }
280 
281 bool
282 UnixSignals::SetShouldStop (int signo, bool value)
283 {
284     collection::iterator pos = m_signals.find (signo);
285     if (pos != m_signals.end())
286     {
287         pos->second.m_stop = value;
288         return true;
289     }
290     return false;
291 }
292 
293 bool
294 UnixSignals::SetShouldStop (const char *signal_name, bool value)
295 {
296     const int32_t signo = GetSignalNumberFromName (signal_name);
297     if (signo != LLDB_INVALID_SIGNAL_NUMBER)
298         return SetShouldStop (signo, value);
299     return false;
300 }
301 
302 bool
303 UnixSignals::GetShouldNotify (int signo) const
304 {
305     collection::const_iterator pos = m_signals.find (signo);
306     if (pos != m_signals.end())
307         return pos->second.m_notify;
308     return false;
309 }
310 
311 bool
312 UnixSignals::SetShouldNotify (int signo, bool value)
313 {
314     collection::iterator pos = m_signals.find (signo);
315     if (pos != m_signals.end())
316     {
317         pos->second.m_notify = value;
318         return true;
319     }
320     return false;
321 }
322 
323 bool
324 UnixSignals::SetShouldNotify (const char *signal_name, bool value)
325 {
326     const int32_t signo = GetSignalNumberFromName (signal_name);
327     if (signo != LLDB_INVALID_SIGNAL_NUMBER)
328         return SetShouldNotify (signo, value);
329     return false;
330 }
331 
332 int32_t
333 UnixSignals::GetNumSignals() const
334 {
335     return m_signals.size();
336 }
337 
338 int32_t
339 UnixSignals::GetSignalAtIndex(int32_t index) const
340 {
341     if (index < 0 || m_signals.size() <= static_cast<size_t>(index))
342         return LLDB_INVALID_SIGNAL_NUMBER;
343     auto it = m_signals.begin();
344     std::advance(it, index);
345     return it->first;
346 }
347