#include "fileio.h"
#include "format-util.h"
#include "io-util.h"
+#include "json-util.h"
#include "log.h"
#include "memstream-util.h"
#include "path-util.h"
unsigned n_thread;
unsigned n_frame;
sd_json_variant **package_metadata;
+ sd_json_variant **dlopen_metadata;
Set **modules;
} StackContext;
fputs("\n", c->m.f);
}
-static int parse_package_metadata(const char *name, sd_json_variant *id_json, Elf *elf, bool *ret_interpreter_found, StackContext *c) {
- bool interpreter_found = false;
+static int parse_metadata(const char *name, sd_json_variant *id_json, Elf *elf, bool *ret_interpreter_found, StackContext *c) {
+ bool package_metadata_found = false, interpreter_found = false;
size_t n_program_headers;
int r;
/* Package metadata might have different owners, but the
* magic ID is always the same. */
- if (note_header.n_type != ELF_PACKAGE_METADATA_ID)
+ if (!IN_SET(note_header.n_type, ELF_PACKAGE_METADATA_ID, ELF_NOTE_DLOPEN_TYPE))
continue;
_cleanup_free_ char *payload_0suffixed = NULL;
return log_error_errno(r, "json_parse on \"%s\" failed: %m", strnull(esc));
}
- /* 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 = sd_json_variant_merge_object(&v, id_json);
+ if (note_header.n_type == ELF_PACKAGE_METADATA_ID) {
+ /* 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 = sd_json_variant_merge_object(&v, id_json);
+ if (r < 0)
+ return log_error_errno(r, "sd_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. */
+ r = sd_json_buildo(&w, SD_JSON_BUILD_PAIR(name, SD_JSON_BUILD_VARIANT(v)));
if (r < 0)
- return log_error_errno(r, "sd_json_variant_merge of package meta with buildId failed: %m");
- }
+ return log_error_errno(r, "Failed to build JSON object: %m");
- /* Pretty-print to the buffer, so that the metadata goes as plaintext in the
- * journal. */
- report_module_metadata(c, name, v);
+ r = sd_json_variant_merge_object(c->package_metadata, w);
+ if (r < 0)
+ return log_error_errno(r, "sd_json_variant_merge of package meta with buildId failed: %m");
- /* 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. */
- r = sd_json_buildo(&w, SD_JSON_BUILD_PAIR(name, SD_JSON_BUILD_VARIANT(v)));
- if (r < 0)
- return log_error_errno(r, "Failed to build JSON object: %m");
+ package_metadata_found = true;
+ } else if (c->dlopen_metadata) {
+ sd_json_variant *z;
- r = sd_json_variant_merge_object(c->package_metadata, w);
- if (r < 0)
- return log_error_errno(r, "sd_json_variant_merge of package meta with buildId failed: %m");
+ JSON_VARIANT_ARRAY_FOREACH(z, v) {
+ r = sd_json_variant_append_array(c->dlopen_metadata, z);
+ if (r < 0)
+ return log_error_errno(r, "Failed to append entry to dlopen metadata: %m");
+ }
+ }
/* Finally stash the name, so we avoid double visits. */
r = set_put_strdup(c->modules, name);
if (r < 0)
return log_error_errno(r, "set_put_strdup failed: %m");
- if (ret_interpreter_found)
- *ret_interpreter_found = interpreter_found;
+ if (!c->dlopen_metadata) {
+ if (ret_interpreter_found)
+ *ret_interpreter_found = interpreter_found;
- return 1;
+ return 1;
+ }
}
}
if (ret_interpreter_found)
*ret_interpreter_found = interpreter_found;
- /* Didn't find package metadata for this module - that's ok, just go to the next. */
- return 0;
+ return c->dlopen_metadata ? 0 : package_metadata_found;
}
/* Get the build-id out of an ELF object or a dwarf core module. */
* to the ELF object first. We might be lucky and just get it from elfutils. */
elf = sym_dwfl_module_getelf(mod, &bias);
if (elf) {
- r = parse_package_metadata(name, id_json, elf, NULL, c);
+ r = parse_metadata(name, id_json, elf, NULL, c);
if (r < 0)
return DWARF_CB_ABORT;
if (r > 0)
_cleanup_(elf_endp) Elf *memelf = sym_elf_memory(data->d_buf, data->d_size);
if (!memelf)
continue;
- r = parse_package_metadata(name, id_json, memelf, NULL, c);
+
+ r = parse_metadata(name, id_json, memelf, NULL, c);
if (r < 0)
return DWARF_CB_ABORT;
if (r > 0)
return DWARF_CB_OK;
}
-static int parse_core(int fd, const char *root, char **ret, sd_json_variant **ret_package_metadata) {
+static int parse_core(
+ int fd,
+ const char *root,
+ char **ret,
+ sd_json_variant **ret_package_metadata,
+ sd_json_variant **ret_dlopen_metadata) {
const Dwfl_Callbacks callbacks = {
.find_elf = sym_dwfl_build_id_find_elf,
.find_debuginfo = sym_dwfl_standard_find_debuginfo,
};
- _cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL;
+ _cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL, *dlopen_metadata = NULL;
_cleanup_set_free_ Set *modules = NULL;
_cleanup_(stack_context_done) StackContext c = {
.package_metadata = &package_metadata,
+ .dlopen_metadata = ret_dlopen_metadata ? &dlopen_metadata : NULL,
.modules = &modules,
};
int r;
if (ret_package_metadata)
*ret_package_metadata = TAKE_PTR(package_metadata);
+ if (ret_dlopen_metadata)
+ *ret_dlopen_metadata = TAKE_PTR(dlopen_metadata);
return 0;
}
-static int parse_elf(int fd, const char *executable, const char *root, char **ret, sd_json_variant **ret_package_metadata) {
- _cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL, *elf_metadata = NULL;
+static int parse_elf(
+ int fd,
+ const char *executable,
+ const char *root,
+ char **ret,
+ sd_json_variant **ret_package_metadata,
+ sd_json_variant **ret_dlopen_metadata) {
+ _cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL, *dlopen_metadata = NULL, *elf_metadata = NULL;
_cleanup_set_free_ Set *modules = NULL;
_cleanup_(stack_context_done) StackContext c = {
.package_metadata = &package_metadata,
+ .dlopen_metadata = ret_dlopen_metadata ? &dlopen_metadata : NULL,
.modules = &modules,
};
const char *elf_type;
if (elf_header.e_type == ET_CORE) {
_cleanup_free_ char *out = NULL;
- r = parse_core(fd, root, ret ? &out : NULL, &package_metadata);
+ r = parse_core(fd, root, ret ? &out : NULL, &package_metadata, &dlopen_metadata);
if (r < 0)
return log_warning_errno(r, "Failed to inspect core file: %m");
if (r < 0)
return log_warning_errno(r, "Failed to parse build-id of ELF file: %m");
- r = parse_package_metadata(e, id_json, c.elf, &interpreter_found, &c);
+ r = parse_metadata(e, id_json, c.elf, &interpreter_found, &c);
if (r < 0)
return log_warning_errno(r, "Failed to parse package metadata of ELF file: %m");
if (ret_package_metadata)
*ret_package_metadata = TAKE_PTR(elf_metadata);
+ if (ret_dlopen_metadata)
+ *ret_dlopen_metadata = TAKE_PTR(dlopen_metadata);
return 0;
}
#endif
-int parse_elf_object(int fd, const char *executable, const char *root, bool fork_disable_dump, char **ret, sd_json_variant **ret_package_metadata) {
+int parse_elf_object(
+ int fd,
+ const char *executable,
+ const char *root,
+ bool fork_disable_dump,
+ char **ret,
+ sd_json_variant **ret_package_metadata,
+ sd_json_variant **ret_dlopen_metadata) {
#if HAVE_ELFUTILS
_cleanup_close_pair_ int error_pipe[2] = EBADF_PAIR,
return_pipe[2] = EBADF_PAIR,
- json_pipe[2] = EBADF_PAIR;
- _cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL;
+ package_metadata_pipe[2] = EBADF_PAIR,
+ dlopen_metadata_pipe[2] = EBADF_PAIR;
+ _cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL, *dlopen_metadata = NULL;
_cleanup_free_ char *buf = NULL;
int r;
}
if (ret_package_metadata) {
- r = RET_NERRNO(pipe2(json_pipe, O_CLOEXEC|O_NONBLOCK));
+ r = RET_NERRNO(pipe2(package_metadata_pipe, O_CLOEXEC|O_NONBLOCK));
+ if (r < 0)
+ return r;
+ }
+
+ if (ret_dlopen_metadata) {
+ r = RET_NERRNO(pipe2(dlopen_metadata_pipe, O_CLOEXEC|O_NONBLOCK));
if (r < 0)
return r;
}
* the file descriptor and writing into these four pipes. */
r = safe_fork_full("(sd-parse-elf)",
NULL,
- (int[]){ fd, error_pipe[1], return_pipe[1], json_pipe[1] },
- 4,
+ (int[]){ fd, error_pipe[1], return_pipe[1], package_metadata_pipe[1], dlopen_metadata_pipe[1] },
+ 5,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_NEW_USERNS|FORK_WAIT|FORK_REOPEN_LOG,
NULL);
if (r < 0) {
report_errno_and_exit(error_pipe[1], r);
}
- r = parse_elf(fd, executable, root, ret ? &buf : NULL, ret_package_metadata ? &package_metadata : NULL);
+ r = parse_elf(
+ fd,
+ executable,
+ root,
+ ret ? &buf : NULL,
+ ret_package_metadata ? &package_metadata : NULL,
+ ret_dlopen_metadata ? &dlopen_metadata : NULL);
if (r < 0)
report_errno_and_exit(error_pipe[1], r);
/* Bump the space for the returned string. We don't know how much space we'll need in
* advance, so we'll just try to write as much as possible and maybe fail later. */
- (void) fcntl(json_pipe[1], F_SETPIPE_SZ, COREDUMP_PIPE_MAX);
+ (void) fcntl(package_metadata_pipe[1], F_SETPIPE_SZ, COREDUMP_PIPE_MAX);
- json_out = take_fdopen(&json_pipe[1], "w");
+ json_out = take_fdopen(&package_metadata_pipe[1], "w");
if (!json_out)
report_errno_and_exit(error_pipe[1], -errno);
log_warning_errno(r, "Failed to write JSON package metadata, ignoring: %m");
}
+ if (dlopen_metadata) {
+ _cleanup_fclose_ FILE *json_out = NULL;
+
+ /* Bump the space for the returned string. We don't know how much space we'll need in
+ * advance, so we'll just try to write as much as possible and maybe fail later. */
+ (void) fcntl(dlopen_metadata_pipe[1], F_SETPIPE_SZ, COREDUMP_PIPE_MAX);
+
+ json_out = take_fdopen(&dlopen_metadata_pipe[1], "w");
+ if (!json_out)
+ report_errno_and_exit(error_pipe[1], -errno);
+
+ r = sd_json_variant_dump(dlopen_metadata, SD_JSON_FORMAT_FLUSH, json_out, NULL);
+ if (r < 0)
+ log_warning_errno(r, "Failed to write JSON package metadata, ignoring: %m");
+ }
+
_exit(EXIT_SUCCESS);
}
error_pipe[1] = safe_close(error_pipe[1]);
return_pipe[1] = safe_close(return_pipe[1]);
- json_pipe[1] = safe_close(json_pipe[1]);
+ package_metadata_pipe[1] = safe_close(package_metadata_pipe[1]);
+ dlopen_metadata_pipe[1] = safe_close(dlopen_metadata_pipe[1]);
if (ret) {
_cleanup_fclose_ FILE *in = NULL;
if (ret_package_metadata) {
_cleanup_fclose_ FILE *json_in = NULL;
- json_in = take_fdopen(&json_pipe[0], "r");
+ json_in = take_fdopen(&package_metadata_pipe[0], "r");
if (!json_in)
return -errno;
r = sd_json_parse_file(json_in, NULL, 0, &package_metadata, NULL, NULL);
if (r < 0 && r != -ENODATA) /* ENODATA: json was empty, so we got nothing, but that's ok */
- log_warning_errno(r, "Failed to read or parse json metadata, ignoring: %m");
+ log_warning_errno(r, "Failed to read or parse package metadata, ignoring: %m");
+ }
+
+ if (ret_dlopen_metadata) {
+ _cleanup_fclose_ FILE *json_in = NULL;
+
+ json_in = take_fdopen(&dlopen_metadata_pipe[0], "r");
+ if (!json_in)
+ return -errno;
+
+ r = sd_json_parse_file(json_in, NULL, 0, &dlopen_metadata, NULL, NULL);
+ if (r < 0 && r != -ENODATA) /* ENODATA: json was empty, so we got nothing, but that's ok */
+ log_warning_errno(r, "Failed to read or parse dlopen metadata, ignoring: %m");
}
if (ret)
*ret = TAKE_PTR(buf);
if (ret_package_metadata)
*ret_package_metadata = TAKE_PTR(package_metadata);
+ if (ret_dlopen_metadata)
+ *ret_dlopen_metadata = TAKE_PTR(dlopen_metadata);
return 0;
#else