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