mirror of
https://github.com/systemd/systemd.git
synced 2025-01-11 09:18:07 +03:00
coredump: parse and append package metadata to journal message
Append 'package' and 'packageVersion' to the journal as discrete fields COREDUMP_PKGMETA_PACKAGE and COREDUMP_PKGMETA_PACKAGEVERSION respectively, and the full json blurb as COREDUMP_PKGMETA_JSON.
This commit is contained in:
parent
95f7180773
commit
c546154a44
@ -352,6 +352,20 @@ flags: ...
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>COREDUMP_PKGMETA_PACKAGE=</varname></term>
|
||||
<term><varname>COREDUMP_PKGMETA_PACKAGEVERSION=</varname></term>
|
||||
<term><varname>COREDUMP_PKGMETA_JSON=</varname></term>
|
||||
|
||||
<listitem><para>If the executable contained .package metadata ELF notes, they will be
|
||||
parsed and attached. The <varname>package</varname> and <varname>packageVersion</varname>
|
||||
of the 'main' ELF module (ie: the excutable) will be appended individually. The
|
||||
JSON-formatted content of all modules will be appended as a single JSON object, each with
|
||||
the module name as the key. For more information about this metadata format and content, see
|
||||
<ulink url="https://systemd.io/COREDUMP_PACKAGE_METADATA/">the coredump metadata spec</ulink>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>MESSAGE=</varname></term>
|
||||
|
||||
|
@ -703,14 +703,16 @@ static int submit_coredump(
|
||||
struct iovec_wrapper *iovw,
|
||||
int input_fd) {
|
||||
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *json_metadata = NULL;
|
||||
_cleanup_close_ int coredump_fd = -1, coredump_node_fd = -1;
|
||||
_cleanup_free_ char *filename = NULL, *coredump_data = NULL;
|
||||
_cleanup_free_ char *stacktrace = NULL;
|
||||
char *core_message;
|
||||
const char *module_name;
|
||||
uint64_t coredump_size = UINT64_MAX;
|
||||
bool truncated = false;
|
||||
JsonVariant *module_json;
|
||||
int r;
|
||||
|
||||
assert(context);
|
||||
assert(iovw);
|
||||
assert(input_fd >= 0);
|
||||
@ -757,7 +759,7 @@ static int submit_coredump(
|
||||
"than %"PRIu64" (the configured maximum)",
|
||||
coredump_size, arg_process_size_max);
|
||||
} else
|
||||
coredump_parse_core(coredump_fd, context->meta[META_EXE], &stacktrace);
|
||||
coredump_parse_core(coredump_fd, context->meta[META_EXE], &stacktrace, &json_metadata);
|
||||
#endif
|
||||
|
||||
log:
|
||||
@ -781,6 +783,67 @@ log:
|
||||
if (truncated)
|
||||
(void) iovw_put_string_field(iovw, "COREDUMP_TRUNCATED=", "1");
|
||||
|
||||
/* If we managed to parse any ELF metadata (build-id, ELF package meta),
|
||||
* attach it as journal metadata. */
|
||||
if (json_metadata) {
|
||||
_cleanup_free_ char *formatted_json = NULL;
|
||||
|
||||
r = json_variant_format(json_metadata, 0, &formatted_json);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to format JSON package metadata: %m");
|
||||
|
||||
(void) iovw_put_string_field(iovw, "COREDUMP_PKGMETA_JSON=", formatted_json);
|
||||
}
|
||||
|
||||
JSON_VARIANT_OBJECT_FOREACH(module_name, module_json, json_metadata) {
|
||||
_cleanup_free_ char *module_basename = NULL, *exe_basename = NULL;
|
||||
const char *key;
|
||||
JsonVariant *w;
|
||||
|
||||
/* The module name, most likely parsed from the ELF core file,
|
||||
* sometimes contains the full path and sometimes does not. */
|
||||
r = path_extract_filename(module_name, &module_basename);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse module basename: %m");
|
||||
r = path_extract_filename(context->meta[META_EXE], &exe_basename);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse executable basename: %m");
|
||||
|
||||
/* We only add structured fields for the 'main' ELF module */
|
||||
if (!streq(module_basename, exe_basename))
|
||||
continue;
|
||||
|
||||
/* Cannot nest two JSON_VARIANT_OBJECT_FOREACH as they define the same
|
||||
* iterator variable '_state' */
|
||||
for (struct json_variant_foreach_state _state2 = { (module_json), 0 }; \
|
||||
json_variant_is_object(_state2.variant) && \
|
||||
_state2.idx < json_variant_elements(_state2.variant) && \
|
||||
({ key = json_variant_string(json_variant_by_index(_state2.variant, _state2.idx)); \
|
||||
w = json_variant_by_index(_state2.variant, _state2.idx + 1); \
|
||||
true; }); \
|
||||
_state2.idx += 2) {
|
||||
_cleanup_free_ char *metadata_id = NULL, *key_upper = NULL;
|
||||
|
||||
if (!json_variant_is_string(w))
|
||||
continue;
|
||||
|
||||
if (!STR_IN_SET(key, "package", "packageVersion"))
|
||||
continue;
|
||||
|
||||
/* Journal metadata field names need to be upper case */
|
||||
key_upper = strdup(key);
|
||||
if (!key_upper)
|
||||
return log_oom();
|
||||
key_upper = ascii_strupper(key_upper);
|
||||
|
||||
metadata_id = strjoin("COREDUMP_PKGMETA_", key_upper, "=");
|
||||
if (!metadata_id)
|
||||
return log_oom();
|
||||
|
||||
(void) iovw_put_string_field(iovw, metadata_id, json_variant_string(w));
|
||||
}
|
||||
}
|
||||
|
||||
/* Optionally store the entire coredump in the journal */
|
||||
if (arg_storage == COREDUMP_STORAGE_JOURNAL) {
|
||||
if (coredump_size <= arg_journal_size_max) {
|
||||
|
@ -324,7 +324,7 @@ static int module_callback(Dwfl_Module *mod, void **userdata, const char *name,
|
||||
return DWARF_CB_OK;
|
||||
}
|
||||
|
||||
static int parse_core(int fd, const char *executable, char **ret) {
|
||||
static int parse_core(int fd, const char *executable, char **ret, JsonVariant **ret_package_metadata) {
|
||||
|
||||
static const Dwfl_Callbacks callbacks = {
|
||||
.find_elf = dwfl_build_id_find_elf,
|
||||
@ -394,6 +394,8 @@ static int parse_core(int fd, const char *executable, char **ret) {
|
||||
c.f = safe_fclose(c.f);
|
||||
|
||||
*ret = TAKE_PTR(buf);
|
||||
if (ret_package_metadata)
|
||||
*ret_package_metadata = TAKE_PTR(package_metadata);
|
||||
|
||||
r = 0;
|
||||
|
||||
@ -411,10 +413,10 @@ finish:
|
||||
return r;
|
||||
}
|
||||
|
||||
void coredump_parse_core(int fd, const char *executable, char **ret) {
|
||||
void coredump_parse_core(int fd, const char *executable, char **ret, JsonVariant **ret_package_metadata) {
|
||||
int r;
|
||||
|
||||
r = parse_core(fd, executable, ret);
|
||||
r = parse_core(fd, executable, ret, ret_package_metadata);
|
||||
if (r == -EINVAL)
|
||||
log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
|
||||
else if (r < 0)
|
||||
|
@ -3,4 +3,4 @@
|
||||
|
||||
#include "json.h"
|
||||
|
||||
void coredump_parse_core(int fd, const char *executable, char **ret);
|
||||
void coredump_parse_core(int fd, const char *executable, char **ret, JsonVariant **ret_package_metadata);
|
||||
|
Loading…
Reference in New Issue
Block a user