LLDB mainline
UnixSignals.cpp
Go to the documentation of this file.
1//===-- UnixSignals.cpp ---------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
13#include "lldb/Host/HostInfo.h"
15#include <optional>
16#include <sstream>
17
18using namespace lldb_private;
19using namespace llvm;
20
21UnixSignals::Signal::Signal(const char *name, bool default_suppress,
22 bool default_stop, bool default_notify,
23 const char *description, const char *alias)
24 : m_name(name), m_alias(alias), m_description(),
25 m_suppress(default_suppress), m_stop(default_stop),
26 m_notify(default_notify),
27 m_default_suppress(default_suppress), m_default_stop(default_stop),
28 m_default_notify(default_notify) {
29 if (description)
30 m_description.assign(description);
31}
32
33lldb::UnixSignalsSP UnixSignals::Create(const ArchSpec &arch) {
34 const auto &triple = arch.GetTriple();
35 switch (triple.getOS()) {
36 case llvm::Triple::Linux:
37 return std::make_shared<LinuxSignals>();
38 case llvm::Triple::FreeBSD:
39 case llvm::Triple::OpenBSD:
40 return std::make_shared<FreeBSDSignals>();
41 case llvm::Triple::NetBSD:
42 return std::make_shared<NetBSDSignals>();
43 default:
44 return std::make_shared<UnixSignals>();
45 }
46}
47
48lldb::UnixSignalsSP UnixSignals::CreateForHost() {
49 static lldb::UnixSignalsSP s_unix_signals_sp =
50 Create(HostInfo::GetArchitecture());
51 return s_unix_signals_sp;
52}
53
54// UnixSignals constructor
56
58
60
62 // This builds one standard set of Unix Signals. If yours aren't quite in
63 // this order, you can either subclass this class, and use Add & Remove to
64 // change them or you can subclass and build them afresh in your constructor.
65 //
66 // Note: the signals below are the Darwin signals. Do not change these!
67
68 m_signals.clear();
69
70 // clang-format off
71 // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION
72 // ====== ============== ======== ====== ====== ===================================================
73 AddSignal(1, "SIGHUP", false, true, true, "hangup");
74 AddSignal(2, "SIGINT", true, true, true, "interrupt");
75 AddSignal(3, "SIGQUIT", false, true, true, "quit");
76 AddSignal(4, "SIGILL", false, true, true, "illegal instruction");
77 AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)");
78 AddSignal(6, "SIGABRT", false, true, true, "abort()");
79 AddSignal(7, "SIGEMT", false, true, true, "pollable event");
80 AddSignal(8, "SIGFPE", false, true, true, "floating point exception");
81 AddSignal(9, "SIGKILL", false, true, true, "kill");
82 AddSignal(10, "SIGBUS", false, true, true, "bus error");
83 AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation");
84 AddSignal(12, "SIGSYS", false, true, true, "bad argument to system call");
85 AddSignal(13, "SIGPIPE", false, false, false, "write on a pipe with no one to read it");
86 AddSignal(14, "SIGALRM", false, false, false, "alarm clock");
87 AddSignal(15, "SIGTERM", false, true, true, "software termination signal from kill");
88 AddSignal(16, "SIGURG", false, false, false, "urgent condition on IO channel");
89 AddSignal(17, "SIGSTOP", true, true, true, "sendable stop signal not from tty");
90 AddSignal(18, "SIGTSTP", false, true, true, "stop signal from tty");
91 AddSignal(19, "SIGCONT", false, false, true, "continue a stopped process");
92 AddSignal(20, "SIGCHLD", false, false, false, "to parent on child stop or exit");
93 AddSignal(21, "SIGTTIN", false, true, true, "to readers process group upon background tty read");
94 AddSignal(22, "SIGTTOU", false, true, true, "to readers process group upon background tty write");
95 AddSignal(23, "SIGIO", false, false, false, "input/output possible signal");
96 AddSignal(24, "SIGXCPU", false, true, true, "exceeded CPU time limit");
97 AddSignal(25, "SIGXFSZ", false, true, true, "exceeded file size limit");
98 AddSignal(26, "SIGVTALRM", false, false, false, "virtual time alarm");
99 AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm");
100 AddSignal(28, "SIGWINCH", false, false, false, "window size changes");
101 AddSignal(29, "SIGINFO", false, true, true, "information request");
102 AddSignal(30, "SIGUSR1", false, true, true, "user defined signal 1");
103 AddSignal(31, "SIGUSR2", false, true, true, "user defined signal 2");
104 // clang-format on
105}
106
107void UnixSignals::AddSignal(int signo, const char *name, bool default_suppress,
108 bool default_stop, bool default_notify,
109 const char *description, const char *alias) {
110 Signal new_signal(name, default_suppress, default_stop, default_notify,
111 description, alias);
112 m_signals.insert(std::make_pair(signo, new_signal));
113 ++m_version;
114}
115
116void UnixSignals::AddSignalCode(int signo, int code,
117 const llvm::StringLiteral description,
118 SignalCodePrintOption print_option) {
119 collection::iterator signal = m_signals.find(signo);
120 assert(signal != m_signals.end() &&
121 "Tried to add code to signal that does not exist.");
122 signal->second.m_codes.insert(
123 std::pair{code, SignalCode{description, print_option}});
124 ++m_version;
125}
126
128 collection::iterator pos = m_signals.find(signo);
129 if (pos != m_signals.end())
130 m_signals.erase(pos);
131 ++m_version;
132}
133
134const char *UnixSignals::GetSignalAsCString(int signo) const {
135 collection::const_iterator pos = m_signals.find(signo);
136 if (pos == m_signals.end())
137 return nullptr;
138 else
139 return pos->second.m_name.GetCString();
140}
141
142std::string
143UnixSignals::GetSignalDescription(int32_t signo, std::optional<int32_t> code,
144 std::optional<lldb::addr_t> addr,
145 std::optional<lldb::addr_t> lower,
146 std::optional<lldb::addr_t> upper) const {
147 std::string str;
148
149 collection::const_iterator pos = m_signals.find(signo);
150 if (pos != m_signals.end()) {
151 str = pos->second.m_name.GetCString();
152
153 if (code) {
154 std::map<int32_t, SignalCode>::const_iterator cpos =
155 pos->second.m_codes.find(*code);
156 if (cpos != pos->second.m_codes.end()) {
157 const SignalCode &sc = cpos->second;
158 str += ": ";
160 str += sc.m_description.str();
161
162 std::stringstream strm;
163 switch (sc.m_print_option) {
165 break;
167 if (addr)
168 strm << " (fault address: 0x" << std::hex << *addr << ")";
169 break;
171 if (lower && upper && addr) {
172 if ((unsigned long)(*addr) < *lower)
173 strm << "lower bound violation ";
174 else
175 strm << "upper bound violation ";
176
177 strm << "(fault address: 0x" << std::hex << *addr;
178 strm << ", lower bound: 0x" << std::hex << *lower;
179 strm << ", upper bound: 0x" << std::hex << *upper;
180 strm << ")";
181 } else
182 strm << sc.m_description.str();
183
184 break;
185 }
186 str += strm.str();
187 }
188 }
189 }
190
191 return str;
192}
193
194bool UnixSignals::SignalIsValid(int32_t signo) const {
195 return m_signals.find(signo) != m_signals.end();
196}
197
199 if (name)
200 return ConstString(name.GetStringRef().substr(3)); // Remove "SIG" from name
201 return name;
202}
203
204int32_t UnixSignals::GetSignalNumberFromName(const char *name) const {
205 ConstString const_name(name);
206
207 collection::const_iterator pos, end = m_signals.end();
208 for (pos = m_signals.begin(); pos != end; pos++) {
209 if ((const_name == pos->second.m_name) ||
210 (const_name == pos->second.m_alias) ||
211 (const_name == GetShortName(pos->second.m_name)) ||
212 (const_name == GetShortName(pos->second.m_alias)))
213 return pos->first;
214 }
215
216 int32_t signo;
217 if (llvm::to_integer(name, signo))
218 return signo;
220}
221
223 if (m_signals.empty())
225
226 return (*m_signals.begin()).first;
227}
228
229int32_t UnixSignals::GetNextSignalNumber(int32_t current_signal) const {
230 collection::const_iterator pos = m_signals.find(current_signal);
231 collection::const_iterator end = m_signals.end();
232 if (pos == end)
234 else {
235 pos++;
236 if (pos == end)
238 else
239 return pos->first;
240 }
241}
242
243const char *UnixSignals::GetSignalInfo(int32_t signo, bool &should_suppress,
244 bool &should_stop,
245 bool &should_notify) const {
246 collection::const_iterator pos = m_signals.find(signo);
247 if (pos == m_signals.end())
248 return nullptr;
249 else {
250 const Signal &signal = pos->second;
251 should_suppress = signal.m_suppress;
252 should_stop = signal.m_stop;
253 should_notify = signal.m_notify;
254 return signal.m_name.AsCString("");
255 }
256}
257
258bool UnixSignals::GetShouldSuppress(int signo) const {
259 collection::const_iterator pos = m_signals.find(signo);
260 if (pos != m_signals.end())
261 return pos->second.m_suppress;
262 return false;
263}
264
265bool UnixSignals::SetShouldSuppress(int signo, bool value) {
266 collection::iterator pos = m_signals.find(signo);
267 if (pos != m_signals.end()) {
268 pos->second.m_suppress = value;
269 ++m_version;
270 return true;
271 }
272 return false;
273}
274
275bool UnixSignals::SetShouldSuppress(const char *signal_name, bool value) {
276 const int32_t signo = GetSignalNumberFromName(signal_name);
277 if (signo != LLDB_INVALID_SIGNAL_NUMBER)
278 return SetShouldSuppress(signo, value);
279 return false;
280}
281
282bool UnixSignals::GetShouldStop(int signo) const {
283 collection::const_iterator pos = m_signals.find(signo);
284 if (pos != m_signals.end())
285 return pos->second.m_stop;
286 return false;
287}
288
289bool UnixSignals::SetShouldStop(int signo, bool value) {
290 collection::iterator pos = m_signals.find(signo);
291 if (pos != m_signals.end()) {
292 pos->second.m_stop = value;
293 ++m_version;
294 return true;
295 }
296 return false;
297}
298
299bool UnixSignals::SetShouldStop(const char *signal_name, bool value) {
300 const int32_t signo = GetSignalNumberFromName(signal_name);
301 if (signo != LLDB_INVALID_SIGNAL_NUMBER)
302 return SetShouldStop(signo, value);
303 return false;
304}
305
306bool UnixSignals::GetShouldNotify(int signo) const {
307 collection::const_iterator pos = m_signals.find(signo);
308 if (pos != m_signals.end())
309 return pos->second.m_notify;
310 return false;
311}
312
313bool UnixSignals::SetShouldNotify(int signo, bool value) {
314 collection::iterator pos = m_signals.find(signo);
315 if (pos != m_signals.end()) {
316 pos->second.m_notify = value;
317 ++m_version;
318 return true;
319 }
320 return false;
321}
322
323bool UnixSignals::SetShouldNotify(const char *signal_name, bool value) {
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
330int32_t UnixSignals::GetNumSignals() const { return m_signals.size(); }
331
332int32_t UnixSignals::GetSignalAtIndex(int32_t index) const {
333 if (index < 0 || m_signals.size() <= static_cast<size_t>(index))
335 auto it = m_signals.begin();
336 std::advance(it, index);
337 return it->first;
338}
339
340uint64_t UnixSignals::GetVersion() const { return m_version; }
341
342std::vector<int32_t>
343UnixSignals::GetFilteredSignals(std::optional<bool> should_suppress,
344 std::optional<bool> should_stop,
345 std::optional<bool> should_notify) {
346 std::vector<int32_t> result;
347 for (int32_t signo = GetFirstSignalNumber();
349 signo = GetNextSignalNumber(signo)) {
350
351 bool signal_suppress = false;
352 bool signal_stop = false;
353 bool signal_notify = false;
354 GetSignalInfo(signo, signal_suppress, signal_stop, signal_notify);
355
356 // If any of filtering conditions are not met, we move on to the next
357 // signal.
358 if (should_suppress && signal_suppress != *should_suppress)
359 continue;
360
361 if (should_stop && signal_stop != *should_stop)
362 continue;
363
364 if (should_notify && signal_notify != *should_notify)
365 continue;
366
367 result.push_back(signo);
368 }
369
370 return result;
371}
372
374 collection::iterator pos = m_signals.find(signo);
375 if (pos != m_signals.end())
376 pos->second.m_hit_count += 1;
377}
378
380 json::Array json_signals;
381 for (const auto &pair: m_signals) {
382 if (pair.second.m_hit_count > 0)
383 json_signals.emplace_back(json::Object{
384 { pair.second.m_name.GetCString(), pair.second.m_hit_count }
385 });
386 }
387 return std::move(json_signals);
388}
389
390void UnixSignals::Signal::Reset(bool reset_stop, bool reset_notify,
391 bool reset_suppress) {
392 if (reset_stop)
394 if (reset_notify)
396 if (reset_suppress)
398}
399
400bool UnixSignals::ResetSignal(int32_t signo, bool reset_stop,
401 bool reset_notify, bool reset_suppress) {
402 auto elem = m_signals.find(signo);
403 if (elem == m_signals.end())
404 return false;
405 (*elem).second.Reset(reset_stop, reset_notify, reset_suppress);
406 return true;
407}
408
An architecture specification class.
Definition: ArchSpec.h:31
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:450
A uniqued constant string class.
Definition: ConstString.h:40
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
Definition: ConstString.h:198
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
Definition: ConstString.h:207
void AddSignalCode(int signo, int code, const llvm::StringLiteral description, SignalCodePrintOption print_option=SignalCodePrintOption::None)
int32_t GetSignalNumberFromName(const char *name) const
static lldb::UnixSignalsSP CreateForHost()
Definition: UnixSignals.cpp:48
const char * GetSignalInfo(int32_t signo, bool &should_suppress, bool &should_stop, bool &should_notify) const
ConstString GetShortName(ConstString name) const
int32_t GetSignalAtIndex(int32_t index) const
bool GetShouldNotify(int32_t signo) const
std::vector< int32_t > GetFilteredSignals(std::optional< bool > should_suppress, std::optional< bool > should_stop, std::optional< bool > should_notify)
void IncrementSignalHitCount(int signo)
Track how many times signals are hit as stop reasons.
bool SetShouldStop(int32_t signo, bool value)
void RemoveSignal(int signo)
bool SetShouldSuppress(int32_t signo, bool value)
int32_t GetFirstSignalNumber() const
static lldb::UnixSignalsSP Create(const ArchSpec &arch)
Definition: UnixSignals.cpp:33
int32_t GetNumSignals() const
bool ResetSignal(int32_t signo, bool reset_stop=true, bool reset_notify=true, bool reset_suppress=true)
bool SignalIsValid(int32_t signo) const
llvm::json::Value GetHitCountStatistics() const
Get the hit count statistics for signals.
void AddSignal(int signo, const char *name, bool default_suppress, bool default_stop, bool default_notify, const char *description, const char *alias=nullptr)
int32_t GetNextSignalNumber(int32_t current_signal) const
bool SetShouldNotify(int32_t signo, bool value)
const char * GetSignalAsCString(int32_t signo) const
bool GetShouldSuppress(int32_t signo) const
bool GetShouldStop(int32_t signo) const
std::string GetSignalDescription(int32_t signo, std::optional< int32_t > code=std::nullopt, std::optional< lldb::addr_t > addr=std::nullopt, std::optional< lldb::addr_t > lower=std::nullopt, std::optional< lldb::addr_t > upper=std::nullopt) const
uint64_t GetVersion() const
#define LLDB_INVALID_SIGNAL_NUMBER
Definition: lldb-defines.h:84
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Definition: Debugger.h:52
const SignalCodePrintOption m_print_option
Definition: UnixSignals.h:131
const llvm::StringLiteral m_description
Definition: UnixSignals.h:130
Signal(const char *name, bool default_suppress, bool default_stop, bool default_notify, const char *description, const char *alias)
Definition: UnixSignals.cpp:21
void Reset(bool reset_stop, bool reset_notify, bool reset_suppress)