mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-03-08 20:58:20 +03:00
Merge pull request #24739 from keszybz/coredump-formatting
Improve formatting of package metadata in coredumps
This commit is contained in:
commit
e69e3830c3
3
TODO
3
TODO
@ -2002,8 +2002,7 @@ Features:
|
||||
* coredump:
|
||||
- save coredump in Windows/Mozilla minidump format
|
||||
- when truncating coredumps, also log the full size that the process had, and make a metadata field so we can report truncated coredumps
|
||||
- when using package notes, compact output to one-line-per-module:
|
||||
libfoo.so, build-id DEADF12340, foo-libs-33.4-1.fc12
|
||||
- add examples for other distros in ELF_PACKAGE_METADATA
|
||||
|
||||
* support crash reporting operation modes (https://live.gnome.org/GnomeOS/Design/Whiteboards/ProblemReporting)
|
||||
|
||||
|
@ -266,6 +266,60 @@ static int thread_callback(Dwfl_Thread *thread, void *userdata) {
|
||||
return DWARF_CB_OK;
|
||||
}
|
||||
|
||||
static char* build_package_reference(
|
||||
const char *type,
|
||||
const char *name,
|
||||
const char *version,
|
||||
const char *arch) {
|
||||
|
||||
/* Construct an identifier for a specific version of the package. The syntax is most suitable for
|
||||
* rpm: the resulting string can be used directly in queries and rpm/dnf/yum commands. For dpkg and
|
||||
* other systems, it might not be usable directly, but users should still be able to figure out the
|
||||
* meaning.
|
||||
*/
|
||||
|
||||
return strjoin(type ?: "package",
|
||||
" ",
|
||||
name,
|
||||
|
||||
version ? "-" : "",
|
||||
strempty(version),
|
||||
|
||||
/* arch is meaningful even without version, so always print it */
|
||||
arch ? "." : "",
|
||||
strempty(arch));
|
||||
}
|
||||
|
||||
static void report_module_metadata(StackContext *c, const char *name, JsonVariant *metadata) {
|
||||
assert(c);
|
||||
assert(name);
|
||||
assert(metadata);
|
||||
|
||||
if (!c->f)
|
||||
return;
|
||||
|
||||
const char
|
||||
*build_id = json_variant_string(json_variant_by_key(metadata, "buildId")),
|
||||
*type = json_variant_string(json_variant_by_key(metadata, "type")),
|
||||
*package = json_variant_string(json_variant_by_key(metadata, "name")),
|
||||
*version = json_variant_string(json_variant_by_key(metadata, "version")),
|
||||
*arch = json_variant_string(json_variant_by_key(metadata, "architecture"));
|
||||
|
||||
fprintf(c->f, "Module %s", name);
|
||||
|
||||
if (package) {
|
||||
/* Version/architecture is only meaningful with a package name.
|
||||
* Skip the detailed fields if package is unknown. */
|
||||
_cleanup_free_ char *id = build_package_reference(type, package, version, arch);
|
||||
fprintf(c->f, " from %s", strnull(id));
|
||||
}
|
||||
|
||||
if (build_id && !(package && version))
|
||||
fprintf(c->f, ", build-id=%s", build_id);
|
||||
|
||||
fputs("\n", c->f);
|
||||
}
|
||||
|
||||
static int parse_package_metadata(const char *name, JsonVariant *id_json, Elf *elf, bool *ret_interpreter_found, StackContext *c) {
|
||||
bool interpreter_found = false;
|
||||
size_t n_program_headers;
|
||||
@ -315,7 +369,6 @@ static int parse_package_metadata(const char *name, JsonVariant *id_json, Elf *e
|
||||
(note_offset = sym_gelf_getnote(data, note_offset, ¬e_header, &name_offset, &desc_offset)) > 0;) {
|
||||
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL;
|
||||
const char *note_name = (const char *)data->d_buf + name_offset;
|
||||
const char *payload = (const char *)data->d_buf + desc_offset;
|
||||
|
||||
if (note_header.n_namesz == 0 || note_header.n_descsz == 0)
|
||||
@ -326,27 +379,35 @@ static int parse_package_metadata(const char *name, JsonVariant *id_json, Elf *e
|
||||
if (note_header.n_type != ELF_PACKAGE_METADATA_ID)
|
||||
continue;
|
||||
|
||||
_cleanup_free_ char *payload_0suffixed = NULL;
|
||||
assert(note_offset > desc_offset);
|
||||
size_t payload_len = note_offset - desc_offset;
|
||||
|
||||
/* If we are lucky and the payload is NUL-padded, we don't need to copy the string.
|
||||
* But if happens to go all the way until the end of the buffer, make a copy. */
|
||||
if (payload[payload_len-1] != '\0') {
|
||||
payload_0suffixed = memdup_suffix0(payload, payload_len);
|
||||
if (!payload_0suffixed)
|
||||
return log_oom();
|
||||
payload = payload_0suffixed;
|
||||
}
|
||||
|
||||
r = json_parse(payload, 0, &v, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "json_parse on %s failed: %m", payload);
|
||||
|
||||
/* First pretty-print to the buffer, so that the metadata goes as
|
||||
* plaintext in the journal. */
|
||||
if (c->f) {
|
||||
fprintf(c->f, "Metadata for module %s owned by %s found: ",
|
||||
name, note_name);
|
||||
json_variant_dump(v, JSON_FORMAT_NEWLINE|JSON_FORMAT_PRETTY, c->f, NULL);
|
||||
fputc('\n', c->f);
|
||||
}
|
||||
|
||||
/* Secondly, if we have a build-id, merge it in the same JSON object
|
||||
* so that it appears all nicely together in the logs/metadata. */
|
||||
/* If we have a build-id, merge it in the same JSON object so that it appears all
|
||||
* nicely together in the logs/metadata. */
|
||||
if (id_json) {
|
||||
r = json_variant_merge(&v, id_json);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "json_variant_merge of package meta with buildid failed: %m");
|
||||
return log_error_errno(r, "json_variant_merge of package meta with buildId failed: %m");
|
||||
}
|
||||
|
||||
/* Pretty-print to the buffer, so that the metadata goes as plaintext in the
|
||||
* journal. */
|
||||
report_module_metadata(c, name, v);
|
||||
|
||||
/* Then we build a new object using the module name as the key, and merge it
|
||||
* with the previous parses, so that in the end it all fits together in a single
|
||||
* JSON blob. */
|
||||
@ -356,7 +417,7 @@ static int parse_package_metadata(const char *name, JsonVariant *id_json, Elf *e
|
||||
|
||||
r = json_variant_merge(c->package_metadata, w);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "json_variant_merge of package meta with buildid failed: %m");
|
||||
return log_error_errno(r, "json_variant_merge of package meta with buildId failed: %m");
|
||||
|
||||
/* Finally stash the name, so we avoid double visits. */
|
||||
r = set_put_strdup(c->modules, name);
|
||||
@ -405,13 +466,7 @@ static int parse_buildid(Dwfl_Module *mod, Elf *elf, const char *name, StackCont
|
||||
* will then be added as metadata to the journal message with the stack trace. */
|
||||
r = json_build(&id_json, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("buildId", JSON_BUILD_HEX(id, id_len))));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "json_build on build-id failed: %m");
|
||||
|
||||
if (c->f) {
|
||||
JsonVariant *build_id = json_variant_by_key(id_json, "buildId");
|
||||
assert(build_id);
|
||||
fprintf(c->f, "Module %s with build-id %s\n", name, json_variant_string(build_id));
|
||||
}
|
||||
return log_error_errno(r, "json_build on buildId failed: %m");
|
||||
}
|
||||
|
||||
if (ret_id_json)
|
||||
@ -465,6 +520,8 @@ static int module_callback(Dwfl_Module *mod, void **userdata, const char *name,
|
||||
if (r < 0) {
|
||||
log_warning("Could not parse number of program headers from core file: %s",
|
||||
sym_elf_errmsg(-1)); /* -1 retrieves the most recent error */
|
||||
report_module_metadata(c, name, id_json);
|
||||
|
||||
return DWARF_CB_OK;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user