| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "signal-code.h" |
| 4 | #include "libnetdata/libnetdata.h" |
| 5 | |
| 6 | #define SIG_NOT_FOUND 0xFFFFFFF |
| 7 | |
| 8 | // -------------------------------------------------------------------------------------------------------------------- |
| 9 | |
| 10 | typedef int SIGNAL_NUM; |
| 11 | |
| 12 | ENUM_STR_MAP_DEFINE(SIGNAL_NUM) = { |
| 13 | { SIGHUP, "SIGHUP" }, // 1 Hangup. |
| 14 | { SIGINT, "SIGINT" }, // 2 Interactive attention signal. |
| 15 | { SIGQUIT, "SIGQUIT" }, // 3 Quit. |
| 16 | { SIGILL, "SIGILL" }, // 4 Illegal instruction. |
| 17 | { SIGTRAP, "SIGTRAP" }, // 5 Trace/breakpoint trap. |
| 18 | { SIGABRT, "SIGABRT" }, // 6 Abnormal termination. |
| 19 | { SIGBUS, "SIGBUS" }, // 7 Bus error. |
| 20 | { SIGFPE, "SIGFPE" }, // 8 Erroneous arithmetic operation. |
| 21 | { SIGKILL, "SIGKILL" }, // 9 Killed. |
| 22 | { SIGUSR1, "SIGUSR1" }, // 10 User-defined signal 1. |
| 23 | { SIGSEGV, "SIGSEGV" }, // 11 Invalid access to storage. |
| 24 | { SIGUSR2, "SIGUSR2" }, // 12 User-defined signal 2. |
| 25 | { SIGPIPE, "SIGPIPE" }, // 13 Broken pipe. |
| 26 | { SIGALRM, "SIGALRM" }, // 14 Alarm clock. |
| 27 | { SIGTERM, "SIGTERM" }, // 15 Termination request. |
| 28 | #ifdef SIGSTKFLT |
| 29 | { SIGSTKFLT, "SIGSTKFLT" }, // 16 Stack fault (obsolete). |
| 30 | #endif |
| 31 | { SIGCHLD, "SIGCHLD" }, // 17 Child terminated or stopped. |
| 32 | { SIGCONT, "SIGCONT" }, // 18 Continue. |
| 33 | { SIGSTOP, "SIGSTOP" }, // 19 Stop, unblockable. |
| 34 | { SIGTSTP, "SIGTSTP" }, // 20 Keyboard stop. |
| 35 | { SIGTTIN, "SIGTTIN" }, // 21 Background read from control terminal. |
| 36 | { SIGTTOU, "SIGTTOU" }, // 22 Background write to control terminal. |
| 37 | { SIGURG, "SIGURG" }, // 23 Urgent data is available at a socket. |
| 38 | { SIGXCPU, "SIGXCPU" }, // 24 CPU time limit exceeded. |
| 39 | { SIGXFSZ, "SIGXFSZ" }, // 25 File size limit exceeded. |
| 40 | { SIGVTALRM, "SIGVTALRM" }, // 26 Virtual timer expired. |
| 41 | { SIGPROF, "SIGPROF" }, // 27 Profiling timer expired. |
| 42 | { SIGWINCH, "SIGWINCH" }, // 28 Window size change (4.3 BSD, Sun). |
| 43 | #ifdef SIGPOLL |
| 44 | { SIGPOLL, "SIGPOLL" }, // 29 Pollable event occurred (System V). |
| 45 | #endif |
| 46 | #ifdef SIGPWR |
| 47 | { SIGPWR, "SIGPWR" }, // 30 Power failure imminent. |
| 48 | #endif |
| 49 | { SIGSYS, "SIGSYS" }, // 31 Bad system call. |
| 50 | |
| 51 | // Terminator |
| 52 | { 0, NULL }, |
| 53 | }; |
| 54 | |
| 55 | // IMPORTANT: These function return invalid values when the signal is not found - always use a function wrapper |
| 56 | ENUM_STR_DEFINE_FUNCTIONS(SIGNAL_NUM, SIG_NOT_FOUND, NULL); |
| 57 | |
| 58 | // -------------------------------------------------------------------------------------------------------------------- |
| 59 | |
| 60 | typedef int SI_CODE; |
| 61 | |
| 62 | ENUM_STR_MAP_DEFINE(SI_CODE) = { |
| 63 | #ifdef SI_ASYNCNL |
| 64 | { SI_ASYNCNL, "SI_ASYNCNL" }, |
| 65 | #endif |
| 66 | #ifdef SI_DETHREAD |
| 67 | { SI_DETHREAD, "SI_DETHREAD" }, |
| 68 | #endif |
| 69 | #ifdef SI_TKILL |
| 70 | { SI_TKILL, "SI_TKILL" }, |
| 71 | #endif |
| 72 | #ifdef SI_SIGIO |
| 73 | { SI_SIGIO, "SI_SIGIO" }, |
| 74 | #endif |
| 75 | { SI_ASYNCIO, "SI_ASYNCIO" }, |
| 76 | { SI_MESGQ, "SI_MESGQ" }, |
| 77 | { SI_TIMER, "SI_TIMER" }, |
| 78 | { SI_QUEUE, "SI_QUEUE" }, |
| 79 | { SI_USER, "SI_USER" }, |
| 80 | #ifdef SI_KERNEL |
| 81 | { SI_KERNEL, "SI_KERNEL" }, |
| 82 | #endif |
| 83 | |
| 84 | // Terminator |
| 85 | {0, NULL}, |
| 86 | }; |
| 87 | |
| 88 | // IMPORTANT: These function return invalid values when the signal is not found - always use a function wrapper |
| 89 | ENUM_STR_DEFINE_FUNCTIONS(SI_CODE, SIG_NOT_FOUND, NULL); |
| 90 | |
| 91 | // -------------------------------------------------------------------------------------------------------------------- |
| 92 | |
| 93 | // Helper macro to create a SIGNAL_CODE value |
| 94 | #define SIGNAL_CODE_CREATE(signo, si_code) (((uint64_t)(signo) << 32) | (uint32_t)(si_code)) |
| 95 | |
| 96 | // Define mapping from SIGNAL_CODE to string representation |
| 97 | ENUM_STR_MAP_DEFINE(SIGNAL_CODE) = { |
| 98 | // SIGILL codes |
| 99 | { SIGNAL_CODE_CREATE(SIGILL, ILL_ILLOPC), "ILL_ILLOPC" }, // Illegal opcode |
| 100 | { SIGNAL_CODE_CREATE(SIGILL, ILL_ILLOPN), "ILL_ILLOPN" }, // Illegal operand |
| 101 | { SIGNAL_CODE_CREATE(SIGILL, ILL_ILLADR), "ILL_ILLADR" }, // Illegal addressing mode |
| 102 | { SIGNAL_CODE_CREATE(SIGILL, ILL_ILLTRP), "ILL_ILLTRP" }, // Illegal trap |
| 103 | { SIGNAL_CODE_CREATE(SIGILL, ILL_PRVOPC), "ILL_PRVOPC" }, // Privileged opcode |
| 104 | { SIGNAL_CODE_CREATE(SIGILL, ILL_PRVREG), "ILL_PRVREG" }, // Privileged register |
| 105 | { SIGNAL_CODE_CREATE(SIGILL, ILL_COPROC), "ILL_COPROC" }, // Coprocessor error |
| 106 | { SIGNAL_CODE_CREATE(SIGILL, ILL_BADSTK), "ILL_BADSTK" }, // Internal stack error |
| 107 | #ifdef ILL_BADIADDR |
| 108 | { SIGNAL_CODE_CREATE(SIGILL, ILL_BADIADDR), "ILL_BADIADDR" }, // Unimplemented instruction address |
| 109 | #endif |
| 110 | |
| 111 | // SIGFPE codes |
| 112 | { SIGNAL_CODE_CREATE(SIGFPE, FPE_INTDIV), "FPE_INTDIV" }, // Integer divide by zero |
| 113 | { SIGNAL_CODE_CREATE(SIGFPE, FPE_INTOVF), "FPE_INTOVF" }, // Integer overflow |
| 114 | { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTDIV), "FPE_FLTDIV" }, // Floating point divide by zero |
| 115 | { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTOVF), "FPE_FLTOVF" }, // Floating point overflow |
| 116 | { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTUND), "FPE_FLTUND" }, // Floating point underflow |
| 117 | { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTRES), "FPE_FLTRES" }, // Floating point inexact result |
| 118 | { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTINV), "FPE_FLTINV" }, // Floating point invalid operation |
| 119 | { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTSUB), "FPE_FLTSUB" }, // Subscript out of range |
| 120 | #ifdef FPE_FLTUNK |
| 121 | { SIGNAL_CODE_CREATE(SIGFPE, FPE_FLTUNK), "FPE_FLTUNK" }, // Undiagnosed floating-point exception |
| 122 | #endif |
| 123 | #ifdef FPE_CONDTRAP |
| 124 | { SIGNAL_CODE_CREATE(SIGFPE, FPE_CONDTRAP), "FPE_CONDTRAP" }, // Trap on condition |
| 125 | #endif |
| 126 | |
| 127 | // SIGSEGV codes |
| 128 | { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_MAPERR), "SEGV_MAPERR" }, // Address not mapped to object |
| 129 | { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_ACCERR), "SEGV_ACCERR" }, // Invalid permissions for mapped object |
| 130 | #ifdef SEGV_BNDERR |
| 131 | { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_BNDERR), "SEGV_BNDERR" }, // Bounds checking failure |
| 132 | #endif |
| 133 | #ifdef SEGV_PKUERR |
| 134 | { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_PKUERR), "SEGV_PKUERR" }, // Protection key checking failure |
| 135 | #endif |
| 136 | #ifdef SEGV_ACCADI |
| 137 | { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_ACCADI), "SEGV_ACCADI" }, // ADI not enabled for mapped object |
| 138 | #endif |
| 139 | #ifdef SEGV_ADIDERR |
| 140 | { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_ADIDERR), "SEGV_ADIDERR" }, // Disrupting MCD error |
| 141 | #endif |
| 142 | #ifdef SEGV_ADIPERR |
| 143 | { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_ADIPERR), "SEGV_ADIPERR" }, // Precise MCD exception |
| 144 | #endif |
| 145 | #ifdef SEGV_MTEAERR |
| 146 | { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_MTEAERR), "SEGV_MTEAERR" }, // Asynchronous ARM MTE error |
| 147 | #endif |
| 148 | #ifdef SEGV_MTESERR |
| 149 | { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_MTESERR), "SEGV_MTESERR" }, // Synchronous ARM MTE exception |
| 150 | #endif |
| 151 | #ifdef SEGV_CPERR |
| 152 | { SIGNAL_CODE_CREATE(SIGSEGV, SEGV_CPERR), "SEGV_CPERR" }, // Control protection fault |
| 153 | #endif |
| 154 | |
| 155 | // SIGBUS codes |
| 156 | { SIGNAL_CODE_CREATE(SIGBUS, BUS_ADRALN), "BUS_ADRALN" }, // Invalid address alignment |
| 157 | { SIGNAL_CODE_CREATE(SIGBUS, BUS_ADRERR), "BUS_ADRERR" }, // Non-existent physical address |
| 158 | { SIGNAL_CODE_CREATE(SIGBUS, BUS_OBJERR), "BUS_OBJERR" }, // Object specific hardware error |
| 159 | #ifdef BUS_MCEERR_AR |
| 160 | { SIGNAL_CODE_CREATE(SIGBUS, BUS_MCEERR_AR), "BUS_MCEERR_AR" }, // Hardware memory error: action required |
| 161 | #endif |
| 162 | #ifdef BUS_MCEERR_AO |
| 163 | { SIGNAL_CODE_CREATE(SIGBUS, BUS_MCEERR_AO), "BUS_MCEERR_AO" }, // Hardware memory error: action optional |
| 164 | #endif |
| 165 | |
| 166 | // SIGTRAP codes |
| 167 | #ifdef TRAP_BRKPT |
| 168 | { SIGNAL_CODE_CREATE(SIGTRAP, TRAP_BRKPT), "TRAP_BRKPT" }, // Process breakpoint |
| 169 | #endif |
| 170 | #ifdef TRAP_TRACE |
| 171 | { SIGNAL_CODE_CREATE(SIGTRAP, TRAP_TRACE), "TRAP_TRACE" }, // Process trace trap |
| 172 | #endif |
| 173 | #ifdef TRAP_BRANCH |
| 174 | { SIGNAL_CODE_CREATE(SIGTRAP, TRAP_BRANCH), "TRAP_BRANCH" }, // Process taken branch trap |
| 175 | #endif |
| 176 | #ifdef TRAP_HWBKPT |
| 177 | { SIGNAL_CODE_CREATE(SIGTRAP, TRAP_HWBKPT), "TRAP_HWBKPT" }, // Hardware breakpoint/watchpoint |
| 178 | #endif |
| 179 | #ifdef TRAP_UNK |
| 180 | { SIGNAL_CODE_CREATE(SIGTRAP, TRAP_UNK), "TRAP_UNK" }, // Undiagnosed trap |
| 181 | #endif |
| 182 | |
| 183 | // Terminator |
| 184 | { 0, NULL }, |
| 185 | }; |
| 186 | |
| 187 | // IMPORTANT: These function return invalid values when the signal is not found - always use a function wrapper |
| 188 | ENUM_STR_DEFINE_FUNCTIONS(SIGNAL_CODE, SIG_NOT_FOUND, NULL); |
| 189 | |
| 190 | // -------------------------------------------------------------------------------------------------------------------- |
| 191 | |
| 192 | void SIGNAL_CODE_2str_h(SIGNAL_CODE code, char *buf, size_t size) { |
| 193 | if(!buf || !size) return; |
| 194 | if(size < 3 || code == 0) { |
| 195 | buf[0] = '\0'; |
| 196 | return; |
| 197 | } |
| 198 | |
| 199 | char b1[UINT64_MAX_LENGTH]; |
| 200 | char b2[UINT64_MAX_LENGTH]; |
| 201 | |
| 202 | int signo = SIGNAL_CODE_GET_SIGNO(code); |
| 203 | int si_code = SIGNAL_CODE_GET_SI_CODE(code); |
| 204 | |
| 205 | // find the string for the signal |
| 206 | const char *signo_str = SIGNAL_NUM_2str(signo); |
| 207 | if(!signo_str || !*signo_str) { |
| 208 | print_int64(b1, signo); |
| 209 | signo_str = b1; |
| 210 | } |
| 211 | |
| 212 | // find the string for the si_code |
| 213 | const char *si_code_str = SIGNAL_CODE_2str(code); |
| 214 | if(!si_code_str || !*si_code_str) { |
| 215 | si_code_str = SI_CODE_2str(si_code); |
| 216 | if(!si_code_str || !*si_code_str) { |
| 217 | print_int64(b2, si_code); |
| 218 | si_code_str = b2; |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | // now we have to concatenate the two strings |
| 223 | // with a slash in between |
| 224 | |
| 225 | strncpyz(buf, signo_str, size - 1); |
| 226 | size_t len = strlen(buf); |
| 227 | |
| 228 | if(size - 1 > len) |
| 229 | buf[len++] = '/'; |
| 230 | |
| 231 | if(size -1 > len) |
| 232 | strncpyz(&buf[len], si_code_str, size - 1 - len); |
| 233 | |
| 234 | buf[size - 1] = '\0'; |
| 235 | } |
| 236 | |
| 237 | SIGNAL_CODE SIGNAL_CODE_2id_h(const char *str) { |
| 238 | if(!str || !*str) return 0; |
| 239 | |
| 240 | CLEAN_CHAR_P *buf = strdupz(str); |
| 241 | |
| 242 | char *si_code_str = strchr(buf, '/'); |
| 243 | if(si_code_str) { |
| 244 | *si_code_str = '\0'; |
| 245 | si_code_str++; |
| 246 | } |
| 247 | |
| 248 | int signo = SIGNAL_NUM_2id(buf); |
| 249 | if(signo == SIG_NOT_FOUND) |
| 250 | signo = str2i(buf); |
| 251 | |
| 252 | SIGNAL_CODE code = si_code_str ? SIGNAL_CODE_2id(si_code_str) : SIG_NOT_FOUND; |
| 253 | if(code != SIG_NOT_FOUND) |
| 254 | // this has both signo and si_code in it |
| 255 | return code; |
| 256 | |
| 257 | int si_code = si_code_str ? SI_CODE_2id(si_code_str) : SIG_NOT_FOUND; |
| 258 | if(si_code == SIG_NOT_FOUND) |
| 259 | si_code = si_code_str ? str2i(si_code_str) : 0; |
| 260 | |
| 261 | return SIGNAL_CODE_CREATE(signo, si_code); |
| 262 | } |
| 263 | |
| 264 | // Function to create a SIGNAL_CODE from signal number and signal code |
| 265 | SIGNAL_CODE signal_code(int signo, int si_code) { |
| 266 | return SIGNAL_CODE_CREATE(signo, si_code); |
| 267 | } |