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