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     bool default_suppress,
29     bool default_stop,
30     bool default_notify,
31     const char *description,
32     const char *alias
33 ) :
34     m_name (name),
35     m_alias (alias),
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          SUPPRESS STOP   NOTIFY DESCRIPTION
101     //        ====== ============  ======== ====== ====== ===================================================
102     AddSignal (1,    "SIGHUP",     false,   true , true , "hangup");
103     AddSignal (2,    "SIGINT",     true ,   true , true , "interrupt");
104     AddSignal (3,    "SIGQUIT",    false,   true , true , "quit");
105     AddSignal (4,    "SIGILL",     false,   true , true , "illegal instruction");
106     AddSignal (5,    "SIGTRAP",    true ,   true , true , "trace trap (not reset when caught)");
107     AddSignal (6,    "SIGABRT",    false,   true , true , "abort()");
108     AddSignal (7,    "SIGEMT",     false,   true , true , "pollable event");
109     AddSignal (8,    "SIGFPE",     false,   true , true , "floating point exception");
110     AddSignal (9,    "SIGKILL",    false,   true , true , "kill");
111     AddSignal (10,   "SIGBUS",     false,   true , true , "bus error");
112     AddSignal (11,   "SIGSEGV",    false,   true , true , "segmentation violation");
113     AddSignal (12,   "SIGSYS",     false,   true , true , "bad argument to system call");
114     AddSignal (13,   "SIGPIPE",    false,   true , true , "write on a pipe with no one to read it");
115     AddSignal (14,   "SIGALRM",    false,   false, false, "alarm clock");
116     AddSignal (15,   "SIGTERM",    false,   true , true , "software termination signal from kill");
117     AddSignal (16,   "SIGURG",     false,   false, false, "urgent condition on IO channel");
118     AddSignal (17,   "SIGSTOP",    true ,   true , true , "sendable stop signal not from tty");
119     AddSignal (18,   "SIGTSTP",    false,   true , true , "stop signal from tty");
120     AddSignal (19,   "SIGCONT",    false,   true , true , "continue a stopped process");
121     AddSignal (20,   "SIGCHLD",    false,   false, false, "to parent on child stop or exit");
122     AddSignal (21,   "SIGTTIN",    false,   true , true , "to readers process group upon background tty read");
123     AddSignal (22,   "SIGTTOU",    false,   true , true , "to readers process group upon background tty write");
124     AddSignal (23,   "SIGIO",      false,   false, false, "input/output possible signal");
125     AddSignal (24,   "SIGXCPU",    false,   true , true , "exceeded CPU time limit");
126     AddSignal (25,   "SIGXFSZ",    false,   true , true , "exceeded file size limit");
127     AddSignal (26,   "SIGVTALRM",  false,   false, false, "virtual time alarm");
128     AddSignal (27,   "SIGPROF",    false,   false, false, "profiling time alarm");
129     AddSignal (28,   "SIGWINCH",   false,   false, false, "window size changes");
130     AddSignal (29,   "SIGINFO",    false,   true , true , "information request");
131     AddSignal (30,   "SIGUSR1",    false,   true , true , "user defined signal 1");
132     AddSignal (31,   "SIGUSR2",    false,   true , true , "user defined signal 2");
133 }
134 
135 void
136 UnixSignals::AddSignal
137 (
138     int signo,
139     const char *name,
140     bool default_suppress,
141     bool default_stop,
142     bool default_notify,
143     const char *description,
144     const char *alias
145 )
146 {
147     Signal new_signal (name, default_suppress, default_stop, default_notify, description, alias);
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 ConstString
177 UnixSignals::GetShortName(ConstString name) const
178 {
179     if (name)
180     {
181       char* signame = (char*)(name.AsCString());
182       return ConstString(signame + 3); // Remove "SIG" from name
183     }
184     return name;
185 }
186 
187 int32_t
188 UnixSignals::GetSignalNumberFromName (const char *name) const
189 {
190     ConstString const_name (name);
191 
192     collection::const_iterator pos, end = m_signals.end ();
193     for (pos = m_signals.begin (); pos != end; pos++)
194     {
195         if ((const_name == pos->second.m_name) || (const_name == pos->second.m_alias) ||
196             (const_name == GetShortName(pos->second.m_name)) || (const_name == GetShortName(pos->second.m_alias)))
197             return pos->first;
198     }
199 
200     const int32_t signo = StringConvert::ToSInt32(name, LLDB_INVALID_SIGNAL_NUMBER, 0);
201     if (signo != LLDB_INVALID_SIGNAL_NUMBER)
202         return signo;
203     return LLDB_INVALID_SIGNAL_NUMBER;
204 }
205 
206 int32_t
207 UnixSignals::GetFirstSignalNumber () const
208 {
209     if (m_signals.empty())
210         return LLDB_INVALID_SIGNAL_NUMBER;
211 
212     return (*m_signals.begin ()).first;
213 }
214 
215 int32_t
216 UnixSignals::GetNextSignalNumber (int32_t current_signal) const
217 {
218     collection::const_iterator pos = m_signals.find (current_signal);
219     collection::const_iterator end = m_signals.end();
220     if (pos == end)
221         return LLDB_INVALID_SIGNAL_NUMBER;
222     else
223     {
224         pos++;
225         if (pos == end)
226             return LLDB_INVALID_SIGNAL_NUMBER;
227         else
228             return pos->first;
229     }
230 }
231 
232 const char *
233 UnixSignals::GetSignalInfo
234 (
235     int32_t signo,
236     bool &should_suppress,
237     bool &should_stop,
238     bool &should_notify
239 ) const
240 {
241     collection::const_iterator pos = m_signals.find (signo);
242     if (pos == m_signals.end())
243         return NULL;
244     else
245     {
246         const Signal &signal = pos->second;
247         should_suppress = signal.m_suppress;
248         should_stop     = signal.m_stop;
249         should_notify   = signal.m_notify;
250         return signal.m_name.AsCString("");
251     }
252 }
253 
254 bool
255 UnixSignals::GetShouldSuppress (int signo) const
256 {
257     collection::const_iterator pos = m_signals.find (signo);
258     if (pos != m_signals.end())
259         return pos->second.m_suppress;
260     return false;
261 }
262 
263 bool
264 UnixSignals::SetShouldSuppress (int signo, bool value)
265 {
266     collection::iterator pos = m_signals.find (signo);
267     if (pos != m_signals.end())
268     {
269         pos->second.m_suppress = value;
270         return true;
271     }
272     return false;
273 }
274 
275 bool
276 UnixSignals::SetShouldSuppress (const char *signal_name, bool value)
277 {
278     const int32_t signo = GetSignalNumberFromName (signal_name);
279     if (signo != LLDB_INVALID_SIGNAL_NUMBER)
280         return SetShouldSuppress (signo, value);
281     return false;
282 }
283 
284 bool
285 UnixSignals::GetShouldStop (int signo) const
286 {
287     collection::const_iterator pos = m_signals.find (signo);
288     if (pos != m_signals.end())
289         return pos->second.m_stop;
290     return false;
291 }
292 
293 bool
294 UnixSignals::SetShouldStop (int signo, bool value)
295 {
296     collection::iterator pos = m_signals.find (signo);
297     if (pos != m_signals.end())
298     {
299         pos->second.m_stop = value;
300         return true;
301     }
302     return false;
303 }
304 
305 bool
306 UnixSignals::SetShouldStop (const char *signal_name, bool value)
307 {
308     const int32_t signo = GetSignalNumberFromName (signal_name);
309     if (signo != LLDB_INVALID_SIGNAL_NUMBER)
310         return SetShouldStop (signo, value);
311     return false;
312 }
313 
314 bool
315 UnixSignals::GetShouldNotify (int signo) const
316 {
317     collection::const_iterator pos = m_signals.find (signo);
318     if (pos != m_signals.end())
319         return pos->second.m_notify;
320     return false;
321 }
322 
323 bool
324 UnixSignals::SetShouldNotify (int signo, bool value)
325 {
326     collection::iterator pos = m_signals.find (signo);
327     if (pos != m_signals.end())
328     {
329         pos->second.m_notify = value;
330         return true;
331     }
332     return false;
333 }
334 
335 bool
336 UnixSignals::SetShouldNotify (const char *signal_name, bool value)
337 {
338     const int32_t signo = GetSignalNumberFromName (signal_name);
339     if (signo != LLDB_INVALID_SIGNAL_NUMBER)
340         return SetShouldNotify (signo, value);
341     return false;
342 }
343 
344 int32_t
345 UnixSignals::GetNumSignals() const
346 {
347     return m_signals.size();
348 }
349 
350 int32_t
351 UnixSignals::GetSignalAtIndex(int32_t index) const
352 {
353     if (index < 0 || m_signals.size() <= static_cast<size_t>(index))
354         return LLDB_INVALID_SIGNAL_NUMBER;
355     auto it = m_signals.begin();
356     std::advance(it, index);
357     return it->first;
358 }
359