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
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>COREDUMP_CODE=</varname></term>
+
+ <listitem><para>The reason why the signal was sent as a numerical value. The code is defined as
+ field <varname>si_code</varname> in the <varname>siginfo_t</varname> structure and
+ documented in <citerefentry
+ project='man-pages'><refentrytitle>sigaction</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
+ </para>
+
+ <xi:include href="version-info.xml" xpointer="v261"/>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>COREDUMP_CWD=</varname></term>
<term><varname>COREDUMP_ROOT=</varname></term>
#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"
[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);
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;
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);
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");
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)
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;
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 */
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;
COREDUMP_FIELD_UID,
COREDUMP_FIELD_GID,
COREDUMP_FIELD_SGNL,
+ COREDUMP_FIELD_CODE,
COREDUMP_FIELD_EXE,
COREDUMP_FIELD_COMM,
COREDUMP_FIELD_CMDLINE,
[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",
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]);
}
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;
(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);
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])),
# 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##*/}"