From 577f2f975d09f10bade176cbdbb49ed414630489 Mon Sep 17 00:00:00 2001 From: Emanuele Rocca Date: Wed, 6 May 2026 15:43:58 +0000 Subject: [PATCH 1/3] include: add coredump_code to struct pidfd_info Linux v7.1 adds coredump_code to struct pidfd_info and defines a few new constants. Reflect the changes in include/override/sys/pidfd.h too. Stop including the libc version of sys/pidfd.h to be able to override the definition of pidfd_info. Signed-off-by: Emanuele Rocca --- src/include/override/sys/pidfd.h | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/include/override/sys/pidfd.h b/src/include/override/sys/pidfd.h index 0e9b2f3998..28fb75698e 100644 --- a/src/include/override/sys/pidfd.h +++ b/src/include/override/sys/pidfd.h @@ -1,15 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include - -/* since glibc-2.36. Only descend into the next on glibc — musl ships no such header, - * and musl-gcc's -idirafter /usr/include would otherwise pull in glibc's copy (which depends on - * __THROW and other glibc-isms) from the fallback path. */ -#if defined(__GLIBC__) && __has_include_next() -#include_next /* IWYU pragma: export */ -#endif - #include #include #include @@ -49,8 +40,14 @@ int pidfd_send_signal_shim(int fd, int sig, siginfo_t *info, unsigned flags); #define PIDFD_INFO_CGROUPID (1UL << 2) /* Always returned if available, even if not requested */ #define PIDFD_INFO_EXIT (1UL << 3) /* Only returned if requested. */ #define PIDFD_INFO_COREDUMP (1UL << 4) /* Only returned if requested. */ +#define PIDFD_INFO_SUPPORTED_MASK (1UL << 5) /* Want/got supported mask flags */ +#define PIDFD_INFO_COREDUMP_SIGNAL (1UL << 6) /* Always returned if PIDFD_INFO_COREDUMP is requested. */ +#define PIDFD_INFO_COREDUMP_CODE (1UL << 7) /* Always returned if PIDFD_INFO_COREDUMP is requested. */ #define PIDFD_INFO_SIZE_VER0 64 /* sizeof first published struct */ +#define PIDFD_INFO_SIZE_VER1 72 /* sizeof second published struct */ +#define PIDFD_INFO_SIZE_VER2 80 /* sizeof third published struct */ +#define PIDFD_INFO_SIZE_VER3 88 /* sizeof fourth published struct */ /* * Values for @coredump_mask in pidfd_info. @@ -105,8 +102,13 @@ struct pidfd_info { __u32 fsuid; __u32 fsgid; __s32 exit_code; /* since kernel v6.15 (7477d7dce48a996ae4e4f0b5f7bd82de7ec9131b) */ - __u32 coredump_mask; /* since kernel v6.16 (1d8db6fd698de1f73b1a7d72aea578fdd18d9a87) */ - __u32 __spare1; + struct { /* coredump info */ + __u32 coredump_mask; /* since kernel v6.16 (1d8db6fd698de1f73b1a7d72aea578fdd18d9a87) */ + __u32 coredump_signal; /* since kernel v6.19 (036375522be8425874e9e0f907c7127e315c7a52) */ + __u32 coredump_code; /* since kernel v7.1 (701f7f4fbabbf4989ba6fbf033b160dd943221d5) */ + __u32 coredump_pad; /* since kernel v7.1 (701f7f4fbabbf4989ba6fbf033b160dd943221d5) */ + }; + __u64 supported_mask; /* Mask flags that this kernel supports */ }; #define PIDFD_GET_INFO _IOWR(PIDFS_IOCTL_MAGIC, 11, struct pidfd_info) From c8c1bcf1941047d1fe43d9827ad4826b4620297a Mon Sep 17 00:00:00 2001 From: Emanuele Rocca Date: Mon, 11 May 2026 13:13:20 +0000 Subject: [PATCH 2/3] signal-util: add signal_code_to_string 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) Signed-off-by: Emanuele Rocca --- src/basic/signal-util.c | 148 ++++++++++++++++++++++++++++++++++ src/basic/signal-util.h | 1 + src/include/override/signal.h | 47 +++++++++++ src/test/test-signal-util.c | 11 +++ 4 files changed, 207 insertions(+) diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c index ae7bfa6bd3..aceafd35e2 100644 --- a/src/basic/signal-util.c +++ b/src/basic/signal-util.c @@ -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 */ } diff --git a/src/basic/signal-util.h b/src/basic/signal-util.h index c022da6295..0c6aa6898d 100644 --- a/src/basic/signal-util.h +++ b/src/basic/signal-util.h @@ -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); diff --git a/src/include/override/signal.h b/src/include/override/signal.h index 6e596adacc..64ddacc4c9 100644 --- a/src/include/override/signal.h +++ b/src/include/override/signal.h @@ -3,5 +3,52 @@ #include_next /* 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 diff --git a/src/test/test-signal-util.c b/src/test/test-signal-util.c index 822556022d..541ff8c7fc 100644 --- a/src/test/test-signal-util.c +++ b/src/test/test-signal-util.c @@ -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); From ed143d8623086ebc835679c7f29ae3ff7a69cde3 Mon Sep 17 00:00:00 2001 From: Emanuele Rocca Date: Wed, 6 May 2026 15:46:21 +0000 Subject: [PATCH 3/3] coredump: add COREDUMP_CODE field for signal reason Introduce COREDUMP_CODE as a new captured field alongside the existing COREDUMP_SIGNAL. While COREDUMP_SIGNAL identifies the signal number that terminated the process, COREDUMP_CODE provides the reason the signal was sent. For example, a process terminated by SIGSEGV due to invalid permissions would produce COREDUMP_SIGNAL=11 and COREDUMP_CODE=2 (SEGV_ACCERR). The kernel exposes coredump_code via pidfd starting with v7.1: https://git.kernel.org/torvalds/c/701f7f4fbabbf4989ba6fbf033b160dd943221d5 System administrators can find both the signal and code in coredumpctl info: $ coredumpctl info | grep Signal: Signal: 11 (SEGV) si_code: SEGV_MAPERR Signed-off-by: Emanuele Rocca --- man/systemd-coredump.xml | 14 ++++++ src/coredump/coredump-context.c | 47 +++++++++++++++++++++ src/coredump/coredump-context.h | 3 ++ src/coredump/coredumpctl.c | 29 +++++++++++-- test/units/TEST-87-AUX-UTILS-VM.coredump.sh | 6 +++ 5 files changed, 95 insertions(+), 4 deletions(-) diff --git a/man/systemd-coredump.xml b/man/systemd-coredump.xml index d499600dc1..c27981bd89 100644 --- a/man/systemd-coredump.xml +++ b/man/systemd-coredump.xml @@ -201,6 +201,7 @@ COREDUMP_UID=1000 COREDUMP_GID=1000 COREDUMP_SIGNAL_NAME=SIGSEGV COREDUMP_SIGNAL=11 +COREDUMP_CODE=2 COREDUMP_TIMESTAMP=1614342930000000 COREDUMP_COMM=Web Content COREDUMP_EXE=/usr/lib64/firefox/firefox @@ -327,6 +328,19 @@ COREDUMP_FILENAME=/var/lib/systemd/coredump/core.Web….552351.….zst + + COREDUMP_CODE= + + The reason why the signal was sent as a numerical value. The code is defined as + field si_code in the siginfo_t structure and + documented in sigaction2. + + + + + + COREDUMP_CWD= COREDUMP_ROOT= diff --git a/src/coredump/coredump-context.c b/src/coredump/coredump-context.c index 6cacae4eff..24d273499a 100644 --- a/src/coredump/coredump-context.c +++ b/src/coredump/coredump-context.c @@ -14,6 +14,7 @@ #include "memstream-util.h" #include "namespace-util.h" #include "parse-util.h" +#include "pidfd-util.h" #include "process-util.h" #include "signal-util.h" #include "special.h" @@ -38,6 +39,7 @@ static const char * const metadata_field_table[_META_MAX] = { [META_UNIT] = "COREDUMP_UNIT=", [META_PROC_AUXV] = "COREDUMP_PROC_AUXV=", [META_THREAD_NAME] = "COREDUMP_THREAD_NAME=", + [META_CODE] = "COREDUMP_CODE=", }; DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(metadata_field, MetadataField); @@ -176,6 +178,34 @@ static int get_process_container_parent_cmdline(PidRef *pid, char** ret_cmdline) return 1; } +/* The kernel passes si_signo through core_pattern (%s). Starting with v7.1, + * si_code is reported as well via pidfd. */ +static int coredump_context_read_pidfd_info(CoredumpContext *context) { + struct pidfd_info info = { + .mask = PIDFD_INFO_COREDUMP, + }; + int r; + + assert(context); + assert(pidref_is_set(&context->pidref)); + + if (!context->got_pidfd || context->pidref.fd < 0) + return 0; + + r = pidfd_get_info(context->pidref.fd, &info); + if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) + return log_debug_errno(r, "PIDFD_INFO_COREDUMP not supported, ignoring: %m"); + if (r < 0) + return log_debug_errno(r, "Failed to get pidfd coredump info, ignoring: %m"); + + if (FLAGS_SET(info.mask, PIDFD_INFO_COREDUMP_CODE)) { + context->code = (int) info.coredump_code; + context->got_code = true; + } + + return 0; +} + int coredump_context_build_iovw(CoredumpContext *context) { char *t; int r; @@ -213,6 +243,10 @@ int coredump_context_build_iovw(CoredumpContext *context) { return log_error_errno(r, "Failed to add COREDUMP_SIGNAL= field: %m"); (void) iovw_put_string_field(&context->iovw, "COREDUMP_SIGNAL_NAME=SIG", signal_to_string(context->signo)); + + /* Emit si_code if we learned it from pidfd_info */ + if (context->got_code) + (void) iovw_put_string_fieldf(&context->iovw, "COREDUMP_CODE=", "%i", context->code); } r = iovw_put_string_fieldf(&context->iovw, "COREDUMP_TIMESTAMP=", USEC_FMT, context->timestamp); @@ -367,6 +401,8 @@ static int coredump_context_parse_from_procfs(CoredumpContext *context) { if (r < 0) log_warning_errno(r, "Failed to get auxv, ignoring: %m"); + (void) coredump_context_read_pidfd_info(context); + r = pidref_verify(&context->pidref); if (r < 0) return log_error_errno(r, "PIDFD validation failed: %m"); @@ -499,6 +535,17 @@ static int context_parse_one(CoredumpContext *context, MetadataField meta, bool case META_THREAD_NAME: return free_and_strdup_warn(&context->thread_name, s); + case META_CODE: + /* We must accept both positive and negative values. The former + * are reserved for kernel-generated signals, the latter for signals requested + * from userspace. See /usr/include/bits/siginfo-consts.h. */ + r = safe_atoi(s, &context->code); + if (r < 0) + log_warning_errno(r, "Failed to parse code \"%s\", ignoring: %m", s); + else + context->got_code = true; + return 0; + case META_PROC_AUXV: { char *t = memdup_suffix0(s, size); if (!t) diff --git a/src/coredump/coredump-context.h b/src/coredump/coredump-context.h index 7fedfde2ad..a2ce16b853 100644 --- a/src/coredump/coredump-context.h +++ b/src/coredump/coredump-context.h @@ -42,6 +42,7 @@ typedef enum MetadataField { META_UNIT, META_PROC_AUXV, META_THREAD_NAME, + META_CODE, /* code of signal causing dump (eg: 2 for SEGV_ACCERR). Since v7.1. */ _META_MAX, _META_INVALID = -EINVAL, } MetadataField; @@ -51,6 +52,7 @@ struct CoredumpContext { uid_t uid; /* META_ARGV_UID */ gid_t gid; /* META_ARGV_GID */ int signo; /* META_ARGV_SIGNAL */ + int code; /* META_CODE */ usec_t timestamp; /* META_ARGV_TIMESTAMP */ uint64_t rlimit; /* META_ARGV_RLIMIT */ char *hostname; /* META_ARGV_HOSTNAME */ @@ -63,6 +65,7 @@ struct CoredumpContext { size_t auxv_size; /* META_PROC_AUXV */ char *thread_name; /* META_THREAD_NAME */ bool got_pidfd; /* META_ARGV_PIDFD */ + bool got_code; /* META_CODE */ bool same_pidns; bool forwarded; int input_fd; diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index 3b31471ab4..9b26e23d62 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -585,6 +585,7 @@ typedef enum CoredumpField { COREDUMP_FIELD_UID, COREDUMP_FIELD_GID, COREDUMP_FIELD_SGNL, + COREDUMP_FIELD_CODE, COREDUMP_FIELD_EXE, COREDUMP_FIELD_COMM, COREDUMP_FIELD_CMDLINE, @@ -615,6 +616,7 @@ static const char* const coredump_field_table[_COREDUMP_FIELD_MAX] = { [COREDUMP_FIELD_UID] = "COREDUMP_UID", [COREDUMP_FIELD_GID] = "COREDUMP_GID", [COREDUMP_FIELD_SGNL] = "COREDUMP_SIGNAL", + [COREDUMP_FIELD_CODE] = "COREDUMP_CODE", [COREDUMP_FIELD_EXE] = "COREDUMP_EXE", [COREDUMP_FIELD_COMM] = "COREDUMP_COMM", [COREDUMP_FIELD_CMDLINE] = "COREDUMP_CMDLINE", @@ -770,9 +772,23 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) { int sig; const char *name = f.normal_coredump ? "Signal" : "Reason"; - if (f.normal_coredump && safe_atoi(f.fields[COREDUMP_FIELD_SGNL], &sig) >= 0) - fprintf(file, " %s: %s (%s)\n", name, f.fields[COREDUMP_FIELD_SGNL], signal_to_string(sig)); - else + if (f.normal_coredump && safe_atoi(f.fields[COREDUMP_FIELD_SGNL], &sig) >= 0) { + fprintf(file, " %s: %s (%s)", name, f.fields[COREDUMP_FIELD_SGNL], signal_to_string(sig)); + + if (f.fields[COREDUMP_FIELD_CODE]) { + int n; + const char *s; + + if (safe_atoi(f.fields[COREDUMP_FIELD_CODE], &n) >= 0) + s = signal_code_to_string(sig, n); + else + s = NULL; + + fprintf(file, " si_code: %s", s ?: f.fields[COREDUMP_FIELD_CODE]); + } + + fputc('\n', file); + } else fprintf(file, " %s: %s\n", name, f.fields[COREDUMP_FIELD_SGNL]); } @@ -893,7 +909,8 @@ static int print_info_json(FILE *file, sd_journal *j) { pid_t pid_as_int = 0, tid_as_int = 0; uid_t uid_as_int = UID_INVALID, owner_uid_as_int = UID_INVALID; gid_t gid_as_int = GID_INVALID; - int sig_as_int = 0; + int sig_as_int = 0, code_as_int = 0; + bool code_is_valid = false; usec_t ts = USEC_INFINITY; int r; @@ -916,6 +933,8 @@ static int print_info_json(FILE *file, sd_journal *j) { (void) parse_uid(f.fields[COREDUMP_FIELD_OWNER_UID], &owner_uid_as_int); if (f.normal_coredump && f.fields[COREDUMP_FIELD_SGNL]) (void) safe_atoi(f.fields[COREDUMP_FIELD_SGNL], &sig_as_int); + if (f.normal_coredump && f.fields[COREDUMP_FIELD_CODE]) + code_is_valid = safe_atoi(f.fields[COREDUMP_FIELD_CODE], &code_as_int) >= 0; if (f.fields[COREDUMP_FIELD_TIMESTAMP]) (void) safe_atou64(f.fields[COREDUMP_FIELD_TIMESTAMP], &ts); @@ -932,6 +951,8 @@ static int print_info_json(FILE *file, sd_journal *j) { SD_JSON_BUILD_PAIR_CONDITION(f.normal_coredump && sig_as_int > 0, "Signal", SD_JSON_BUILD_INTEGER(sig_as_int)), SD_JSON_BUILD_PAIR_CONDITION(f.normal_coredump && sig_as_int > 0 && !!signal_to_string(sig_as_int), "SignalName", SD_JSON_BUILD_STRING(signal_to_string(sig_as_int))), SD_JSON_BUILD_PAIR_CONDITION(f.normal_coredump && sig_as_int <= 0 && !!f.fields[COREDUMP_FIELD_SGNL], "Signal", SD_JSON_BUILD_STRING(f.fields[COREDUMP_FIELD_SGNL])), + SD_JSON_BUILD_PAIR_CONDITION(f.normal_coredump && code_is_valid, "SignalCode", SD_JSON_BUILD_INTEGER(code_as_int)), + SD_JSON_BUILD_PAIR_CONDITION(f.normal_coredump && !code_is_valid && !!f.fields[COREDUMP_FIELD_CODE], "SignalCode", SD_JSON_BUILD_STRING(f.fields[COREDUMP_FIELD_CODE])), SD_JSON_BUILD_PAIR_CONDITION(!f.normal_coredump && !!f.fields[COREDUMP_FIELD_SGNL], "Reason", SD_JSON_BUILD_STRING(f.fields[COREDUMP_FIELD_SGNL])), SD_JSON_BUILD_PAIR_CONDITION(ts != USEC_INFINITY, "Timestamp", SD_JSON_BUILD_UNSIGNED(ts)), SD_JSON_BUILD_PAIR_CONDITION(ts == USEC_INFINITY && !!f.fields[COREDUMP_FIELD_TIMESTAMP], "Timestamp", SD_JSON_BUILD_STRING(f.fields[COREDUMP_FIELD_TIMESTAMP])), diff --git a/test/units/TEST-87-AUX-UTILS-VM.coredump.sh b/test/units/TEST-87-AUX-UTILS-VM.coredump.sh index 30252132ff..675d37184b 100755 --- a/test/units/TEST-87-AUX-UTILS-VM.coredump.sh +++ b/test/units/TEST-87-AUX-UTILS-VM.coredump.sh @@ -166,6 +166,12 @@ coredumpctl info "$CORE_TEST_BIN" | grep "TID:" >/dev/null # Check the field is queryable in the journal coredumpctl -F COREDUMP_TID +# If COREDUMP_CODE= is present, check that the expected code is SI_USER (0). +if coredumpctl -F COREDUMP_CODE | grep "^0$" >/dev/null; then + coredumpctl info "$CORE_TEST_BIN" | grep --fixed-strings "Signal: 5 (TRAP) si_code: SI_USER" >/dev/null + coredumpctl info --json=short "$CORE_TEST_BIN" | jq -se 'any(.[]; .SignalCode == 0)' +fi + coredumpctl debug --debugger=/bin/true "$CORE_TEST_BIN" SYSTEMD_DEBUGGER=/bin/true coredumpctl debug "$CORE_TEST_BIN" coredumpctl debug --debugger=/bin/true --debugger-arguments="-this --does --not 'do anything' -a -t --all" "${CORE_TEST_BIN##*/}"