]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
signal-util: add signal_code_to_string
authorEmanuele Rocca <emanuele.rocca@arm.com>
Mon, 11 May 2026 13:13:20 +0000 (13:13 +0000)
committerEmanuele Rocca <emanuele.rocca@arm.com>
Tue, 19 May 2026 08:14:36 +0000 (08:14 +0000)
Add signal_code_to_string() in signal-util.c and cover the si_code values
defined in libc's siginfo-consts.h. Fall back to the numeric value when no
symbolic name is known.

Co-developed-by: Codex (GPT-5) <noreply@openai.com>
Signed-off-by: Emanuele Rocca <emanuele.rocca@arm.com>
src/basic/signal-util.c
src/basic/signal-util.h
src/include/override/signal.h
src/test/test-signal-util.c

index ae7bfa6bd338e3c055bf4ecc9e70e95943dff1e4..aceafd35e2e14f133ca3aca51f13bf5e25333066 100644 (file)
@@ -223,6 +223,154 @@ int signal_from_string(const char *s) {
         return -EINVAL;
 }
 
+static const char *const sigill_code_table[] = {
+        [ILL_ILLOPC]   = "ILL_ILLOPC",
+        [ILL_ILLOPN]   = "ILL_ILLOPN",
+        [ILL_ILLADR]   = "ILL_ILLADR",
+        [ILL_ILLTRP]   = "ILL_ILLTRP",
+        [ILL_PRVOPC]   = "ILL_PRVOPC",
+        [ILL_PRVREG]   = "ILL_PRVREG",
+        [ILL_COPROC]   = "ILL_COPROC",
+        [ILL_BADSTK]   = "ILL_BADSTK",
+        [ILL_BADIADDR] = "ILL_BADIADDR",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(sigill_code, int);
+
+static const char *const sigfpe_code_table[] = {
+        [FPE_INTDIV]   = "FPE_INTDIV",
+        [FPE_INTOVF]   = "FPE_INTOVF",
+        [FPE_FLTDIV]   = "FPE_FLTDIV",
+        [FPE_FLTOVF]   = "FPE_FLTOVF",
+        [FPE_FLTUND]   = "FPE_FLTUND",
+        [FPE_FLTRES]   = "FPE_FLTRES",
+        [FPE_FLTINV]   = "FPE_FLTINV",
+        [FPE_FLTSUB]   = "FPE_FLTSUB",
+        [FPE_FLTUNK]   = "FPE_FLTUNK",
+        [FPE_CONDTRAP] = "FPE_CONDTRAP",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(sigfpe_code, int);
+
+static const char *const sigsegv_code_table[] = {
+        [SEGV_MAPERR]  = "SEGV_MAPERR",
+        [SEGV_ACCERR]  = "SEGV_ACCERR",
+        [SEGV_BNDERR]  = "SEGV_BNDERR",
+        [SEGV_PKUERR]  = "SEGV_PKUERR",
+        [SEGV_ACCADI]  = "SEGV_ACCADI",
+        [SEGV_ADIDERR] = "SEGV_ADIDERR",
+        [SEGV_ADIPERR] = "SEGV_ADIPERR",
+        [SEGV_MTEAERR] = "SEGV_MTEAERR",
+        [SEGV_MTESERR] = "SEGV_MTESERR",
+        [SEGV_CPERR]   = "SEGV_CPERR",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(sigsegv_code, int);
+
+static const char *const sigbus_code_table[] = {
+        [BUS_ADRALN]    = "BUS_ADRALN",
+        [BUS_ADRERR]    = "BUS_ADRERR",
+        [BUS_OBJERR]    = "BUS_OBJERR",
+        [BUS_MCEERR_AR] = "BUS_MCEERR_AR",
+        [BUS_MCEERR_AO] = "BUS_MCEERR_AO",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(sigbus_code, int);
+
+static const char *const sigtrap_code_table[] = {
+        [TRAP_BRKPT]  = "TRAP_BRKPT",
+        [TRAP_TRACE]  = "TRAP_TRACE",
+        [TRAP_BRANCH] = "TRAP_BRANCH",
+        [TRAP_HWBKPT] = "TRAP_HWBKPT",
+        [TRAP_UNK]    = "TRAP_UNK",
+        [TRAP_PERF]   = "TRAP_PERF",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(sigtrap_code, int);
+
+static const char *const sigsys_code_table[] = {
+        [SYS_SECCOMP]       = "SYS_SECCOMP",
+        [SYS_USER_DISPATCH] = "SYS_USER_DISPATCH",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(sigsys_code, int);
+
+/* sigchld_code_table is already defined in src/basic/process-util.c with
+ * decoded, lower-case values (CLD_EXITED -> "exited"). For consistency with
+ * all other values decoded here, provide an uppercase variant. */
+static const char *const sigchld_uppercase_code_table[] = {
+        [CLD_EXITED]    = "CLD_EXITED",
+        [CLD_KILLED]    = "CLD_KILLED",
+        [CLD_DUMPED]    = "CLD_DUMPED",
+        [CLD_TRAPPED]   = "CLD_TRAPPED",
+        [CLD_STOPPED]   = "CLD_STOPPED",
+        [CLD_CONTINUED] = "CLD_CONTINUED",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(sigchld_uppercase_code, int);
+
+static const char *const sigpoll_code_table[] = {
+        [POLL_IN]  = "POLL_IN",
+        [POLL_OUT] = "POLL_OUT",
+        [POLL_MSG] = "POLL_MSG",
+        [POLL_ERR] = "POLL_ERR",
+        [POLL_PRI] = "POLL_PRI",
+        [POLL_HUP] = "POLL_HUP",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(sigpoll_code, int);
+
+const char* signal_code_to_string(int signo, int code) {
+        switch (code) {
+        /* SI_KERNEL is 0x80 (128). Defining a table just for SI_KERNEL and
+         * SI_USER would be a waste of .rodata space: special case them instead. */
+        case SI_KERNEL:
+                return "SI_KERNEL";
+        case SI_USER:
+                return "SI_USER";
+        /* The following values are all negatives. SI_ASYNCNL is -60. Similarly
+         * to the special case for SI_KERNEL above, avoid using a table for negative
+         * values as well. */
+        case SI_ASYNCNL:
+                return "SI_ASYNCNL";
+        case SI_DETHREAD:
+                return "SI_DETHREAD";
+        case SI_TKILL:
+                return "SI_TKILL";
+        case SI_SIGIO:
+                return "SI_SIGIO";
+        case SI_ASYNCIO:
+                return "SI_ASYNCIO";
+        case SI_MESGQ:
+                return "SI_MESGQ";
+        case SI_TIMER:
+                return "SI_TIMER";
+        case SI_QUEUE:
+                return "SI_QUEUE";
+        }
+
+        switch (signo) {
+        case SIGILL:
+                return sigill_code_to_string(code);
+        case SIGFPE:
+                return sigfpe_code_to_string(code);
+        case SIGSEGV:
+                return sigsegv_code_to_string(code);
+        case SIGBUS:
+                return sigbus_code_to_string(code);
+        case SIGTRAP:
+                return sigtrap_code_to_string(code);
+        case SIGCHLD:
+                return sigchld_uppercase_code_to_string(code);
+        case SIGPOLL:
+                return sigpoll_code_to_string(code);
+        case SIGSYS:
+                return sigsys_code_to_string(code);
+        default:
+                return NULL;
+        }
+}
+
 void nop_signal_handler(int sig) {
         /* nothing here */
 }
index c022da62950511ec56bc947e8dac235a43a36292..0c6aa6898d373f454c7fa7e6c054841d9f884ef3 100644 (file)
@@ -32,6 +32,7 @@ int sigprocmask_many_internal(int how, sigset_t *ret_old_mask, ...);
 #define sigprocmask_many(...) sigprocmask_many_internal(__VA_ARGS__, -1)
 
 DECLARE_STRING_TABLE_LOOKUP(signal, int);
+const char* signal_code_to_string(int signo, int code) _const_;
 
 void nop_signal_handler(int sig);
 
index 6e596adaccef2a1bd2ac8379a27835062bd5811a..64ddacc4c9dc04df2f796bcb4cb6baae14cf0df2 100644 (file)
@@ -3,5 +3,52 @@
 
 #include_next <signal.h>        /* IWYU pragma: export */
 
+#ifndef ILL_BADIADDR
+#define ILL_BADIADDR 9
+#endif
+
+#ifndef FPE_FLTUNK
+#define FPE_FLTUNK 14
+#endif
+
+#ifndef FPE_CONDTRAP
+#define FPE_CONDTRAP 15
+#endif
+
+#ifndef SEGV_ACCADI
+#define SEGV_ACCADI 5
+#endif
+
+#ifndef SEGV_ADIDERR
+#define SEGV_ADIDERR 6
+#endif
+
+#ifndef SEGV_ADIPERR
+#define SEGV_ADIPERR 7
+#endif
+
+/* Defined since glibc-2.39. */
+#ifndef SEGV_CPERR
+#define SEGV_CPERR 10
+#endif
+
+#ifndef SI_DETHREAD
+#define SI_DETHREAD -7
+#endif
+
+/* Defined since glibc-2.43. */
+#ifndef TRAP_PERF
+#define TRAP_PERF 6
+#endif
+
+/* Defined since glibc-2.33. */
+#ifndef SYS_SECCOMP
+#define SYS_SECCOMP 1
+#endif
+
+#ifndef SYS_USER_DISPATCH
+#define SYS_USER_DISPATCH 2
+#endif
+
 int rt_tgsigqueueinfo_shim(pid_t tgid, pid_t tid, int sig, siginfo_t *info);
 #define rt_tgsigqueueinfo rt_tgsigqueueinfo_shim
index 822556022d9f5374fc6aa975db0826f08a588f83..541ff8c7fcabe1d9cc5bf711d9bde07ec2b0b22b 100644 (file)
@@ -103,6 +103,17 @@ TEST(signal_from_string) {
         test_signal_from_string_number("-2", -ERANGE);
 }
 
+TEST(signal_code_to_string) {
+        assert_se(streq_ptr(signal_code_to_string(SIGSEGV, SEGV_MAPERR), "SEGV_MAPERR"));
+        assert_se(streq_ptr(signal_code_to_string(SIGILL, ILL_ILLOPC), "ILL_ILLOPC"));
+        assert_se(streq_ptr(signal_code_to_string(SIGCHLD, CLD_CONTINUED), "CLD_CONTINUED"));
+        assert_se(streq_ptr(signal_code_to_string(SIGABRT, SI_TKILL), "SI_TKILL"));
+        assert_se(streq_ptr(signal_code_to_string(SIGABRT, SI_USER), "SI_USER"));
+        assert_se(streq_ptr(signal_code_to_string(SIGABRT, SI_KERNEL), "SI_KERNEL"));
+        assert_se(streq_ptr(signal_code_to_string(SIGSYS, SYS_SECCOMP), "SYS_SECCOMP"));
+        assert_se(signal_code_to_string(SIGABRT, 99) == NULL);
+}
+
 TEST(block_signals) {
         assert_se(signal_is_blocked(SIGUSR1) == 0);
         assert_se(signal_is_blocked(SIGALRM) == 0);