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     m_signals.clear();
93     //        SIGNO  NAME          SUPPRESS STOP   NOTIFY DESCRIPTION
94     //        ====== ============  ======== ====== ====== ===================================================
95     AddSignal (1,    "SIGHUP",     false,   true , true , "hangup");
96     AddSignal (2,    "SIGINT",     true ,   true , true , "interrupt");
97     AddSignal (3,    "SIGQUIT",    false,   true , true , "quit");
98     AddSignal (4,    "SIGILL",     false,   true , true , "illegal instruction");
99     AddSignal (5,    "SIGTRAP",    true ,   true , true , "trace trap (not reset when caught)");
100     AddSignal (6,    "SIGABRT",    false,   true , true , "abort()");
101     AddSignal (7,    "SIGEMT",     false,   true , true , "pollable event");
102     AddSignal (8,    "SIGFPE",     false,   true , true , "floating point exception");
103     AddSignal (9,    "SIGKILL",    false,   true , true , "kill");
104     AddSignal (10,   "SIGBUS",     false,   true , true , "bus error");
105     AddSignal (11,   "SIGSEGV",    false,   true , true , "segmentation violation");
106     AddSignal (12,   "SIGSYS",     false,   true , true , "bad argument to system call");
107     AddSignal (13,   "SIGPIPE",    false,   true , true , "write on a pipe with no one to read it");
108     AddSignal (14,   "SIGALRM",    false,   false, false, "alarm clock");
109     AddSignal (15,   "SIGTERM",    false,   true , true , "software termination signal from kill");
110     AddSignal (16,   "SIGURG",     false,   false, false, "urgent condition on IO channel");
111     AddSignal (17,   "SIGSTOP",    true ,   true , true , "sendable stop signal not from tty");
112     AddSignal (18,   "SIGTSTP",    false,   true , true , "stop signal from tty");
113     AddSignal (19,   "SIGCONT",    false,   true , true , "continue a stopped process");
114     AddSignal (20,   "SIGCHLD",    false,   false, false, "to parent on child stop or exit");
115     AddSignal (21,   "SIGTTIN",    false,   true , true , "to readers process group upon background tty read");
116     AddSignal (22,   "SIGTTOU",    false,   true , true , "to readers process group upon background tty write");
117     AddSignal (23,   "SIGIO",      false,   false, false, "input/output possible signal");
118     AddSignal (24,   "SIGXCPU",    false,   true , true , "exceeded CPU time limit");
119     AddSignal (25,   "SIGXFSZ",    false,   true , true , "exceeded file size limit");
120     AddSignal (26,   "SIGVTALRM",  false,   false, false, "virtual time alarm");
121     AddSignal (27,   "SIGPROF",    false,   false, false, "profiling time alarm");
122     AddSignal (28,   "SIGWINCH",   false,   false, false, "window size changes");
123     AddSignal (29,   "SIGINFO",    false,   true , true , "information request");
124     AddSignal (30,   "SIGUSR1",    false,   true , true , "user defined signal 1");
125     AddSignal (31,   "SIGUSR2",    false,   true , true , "user defined signal 2");
126 }
127 
128 void
129 UnixSignals::AddSignal(int signo,
130                        const char *name,
131                        bool default_suppress,
132                        bool default_stop,
133                        bool default_notify,
134                        const char *description,
135                        const char *alias)
136 {
137     Signal new_signal (name, default_suppress, default_stop, default_notify, description, alias);
138     m_signals.insert (std::make_pair(signo, new_signal));
139 }
140 
141 void
142 UnixSignals::RemoveSignal (int signo)
143 {
144     collection::iterator pos = m_signals.find (signo);
145     if (pos != m_signals.end())
146         m_signals.erase (pos);
147 }
148 
149 const char *
150 UnixSignals::GetSignalAsCString (int signo) const
151 {
152     collection::const_iterator pos = m_signals.find (signo);
153     if (pos == m_signals.end())
154         return nullptr;
155     else
156         return pos->second.m_name.GetCString ();
157 }
158 
159 bool
160 UnixSignals::SignalIsValid (int32_t signo) const
161 {
162     return m_signals.find (signo) != m_signals.end();
163 }
164 
165 ConstString
166 UnixSignals::GetShortName(ConstString name) const
167 {
168     if (name)
169     {
170       const char* signame = name.AsCString();
171       return ConstString(signame + 3); // Remove "SIG" from name
172     }
173     return name;
174 }
175 
176 int32_t
177 UnixSignals::GetSignalNumberFromName (const char *name) const
178 {
179     ConstString const_name (name);
180 
181     collection::const_iterator pos, end = m_signals.end ();
182     for (pos = m_signals.begin (); pos != end; pos++)
183     {
184         if ((const_name == pos->second.m_name) || (const_name == pos->second.m_alias) ||
185             (const_name == GetShortName(pos->second.m_name)) || (const_name == GetShortName(pos->second.m_alias)))
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(int32_t signo,
223                            bool &should_suppress,
224                            bool &should_stop,
225                            bool &should_notify) const
226 {
227     collection::const_iterator pos = m_signals.find (signo);
228     if (pos == m_signals.end())
229         return nullptr;
230     else
231     {
232         const Signal &signal = pos->second;
233         should_suppress = signal.m_suppress;
234         should_stop     = signal.m_stop;
235         should_notify   = signal.m_notify;
236         return signal.m_name.AsCString("");
237     }
238 }
239 
240 bool
241 UnixSignals::GetShouldSuppress (int signo) const
242 {
243     collection::const_iterator pos = m_signals.find (signo);
244     if (pos != m_signals.end())
245         return pos->second.m_suppress;
246     return false;
247 }
248 
249 bool
250 UnixSignals::SetShouldSuppress (int signo, bool value)
251 {
252     collection::iterator pos = m_signals.find (signo);
253     if (pos != m_signals.end())
254     {
255         pos->second.m_suppress = value;
256         return true;
257     }
258     return false;
259 }
260 
261 bool
262 UnixSignals::SetShouldSuppress (const char *signal_name, bool value)
263 {
264     const int32_t signo = GetSignalNumberFromName (signal_name);
265     if (signo != LLDB_INVALID_SIGNAL_NUMBER)
266         return SetShouldSuppress (signo, value);
267     return false;
268 }
269 
270 bool
271 UnixSignals::GetShouldStop (int signo) const
272 {
273     collection::const_iterator pos = m_signals.find (signo);
274     if (pos != m_signals.end())
275         return pos->second.m_stop;
276     return false;
277 }
278 
279 bool
280 UnixSignals::SetShouldStop (int signo, bool value)
281 {
282     collection::iterator pos = m_signals.find (signo);
283     if (pos != m_signals.end())
284     {
285         pos->second.m_stop = value;
286         return true;
287     }
288     return false;
289 }
290 
291 bool
292 UnixSignals::SetShouldStop (const char *signal_name, bool value)
293 {
294     const int32_t signo = GetSignalNumberFromName (signal_name);
295     if (signo != LLDB_INVALID_SIGNAL_NUMBER)
296         return SetShouldStop (signo, value);
297     return false;
298 }
299 
300 bool
301 UnixSignals::GetShouldNotify (int signo) const
302 {
303     collection::const_iterator pos = m_signals.find (signo);
304     if (pos != m_signals.end())
305         return pos->second.m_notify;
306     return false;
307 }
308 
309 bool
310 UnixSignals::SetShouldNotify (int signo, bool value)
311 {
312     collection::iterator pos = m_signals.find (signo);
313     if (pos != m_signals.end())
314     {
315         pos->second.m_notify = value;
316         return true;
317     }
318     return false;
319 }
320 
321 bool
322 UnixSignals::SetShouldNotify (const char *signal_name, bool value)
323 {
324     const int32_t signo = GetSignalNumberFromName (signal_name);
325     if (signo != LLDB_INVALID_SIGNAL_NUMBER)
326         return SetShouldNotify (signo, value);
327     return false;
328 }
329 
330 int32_t
331 UnixSignals::GetNumSignals() const
332 {
333     return m_signals.size();
334 }
335 
336 int32_t
337 UnixSignals::GetSignalAtIndex(int32_t index) const
338 {
339     if (index < 0 || m_signals.size() <= static_cast<size_t>(index))
340         return LLDB_INVALID_SIGNAL_NUMBER;
341     auto it = m_signals.begin();
342     std::advance(it, index);
343     return it->first;
344 }
345