|
| 1 | +/* SPDX-License-Identifier: LGPL-2.1-or-later */ |
| 2 | + |
| 3 | +#include "analyze-elf.h" |
| 4 | +#include "elf-util.h" |
| 5 | +#include "errno-util.h" |
| 6 | +#include "fd-util.h" |
| 7 | +#include "format-table.h" |
| 8 | +#include "format-util.h" |
| 9 | +#include "json.h" |
| 10 | +#include "path-util.h" |
| 11 | +#include "strv.h" |
| 12 | + |
| 13 | +int analyze_elf(char **filenames, JsonFormatFlags json_flags) { |
| 14 | + char **filename; |
| 15 | + int r; |
| 16 | + |
| 17 | + STRV_FOREACH(filename, filenames) { |
| 18 | + _cleanup_(json_variant_unrefp) JsonVariant *package_metadata = NULL; |
| 19 | + _cleanup_(table_unrefp) Table *t = NULL; |
| 20 | + _cleanup_free_ char *abspath = NULL; |
| 21 | + _cleanup_close_ int fd = -1; |
| 22 | + |
| 23 | + r = path_make_absolute_cwd(*filename, &abspath); |
| 24 | + if (r < 0) |
| 25 | + return log_error_errno(r, "Could not make an absolute path out of \"%s\": %m", *filename); |
| 26 | + |
| 27 | + path_simplify(abspath); |
| 28 | + |
| 29 | + fd = RET_NERRNO(open(abspath, O_RDONLY|O_CLOEXEC)); |
| 30 | + if (fd < 0) |
| 31 | + return log_error_errno(fd, "Could not open \"%s\": %m", abspath); |
| 32 | + |
| 33 | + r = parse_elf_object(fd, abspath, /* fork_disable_dump= */false, NULL, &package_metadata); |
| 34 | + if (r < 0) |
| 35 | + return log_error_errno(r, "Parsing \"%s\" as ELF object failed: %m", abspath); |
| 36 | + |
| 37 | + t = table_new("", ""); |
| 38 | + if (!t) |
| 39 | + return log_oom(); |
| 40 | + |
| 41 | + r = table_set_align_percent(t, TABLE_HEADER_CELL(0), 100); |
| 42 | + if (r < 0) |
| 43 | + return table_log_add_error(r); |
| 44 | + |
| 45 | + r = table_add_many( |
| 46 | + t, |
| 47 | + TABLE_STRING, "path:", |
| 48 | + TABLE_STRING, abspath); |
| 49 | + if (r < 0) |
| 50 | + return table_log_add_error(r); |
| 51 | + |
| 52 | + if (package_metadata) { |
| 53 | + JsonVariant *module_json; |
| 54 | + const char *module_name; |
| 55 | + |
| 56 | + JSON_VARIANT_OBJECT_FOREACH(module_name, module_json, package_metadata) { |
| 57 | + const char *field_name; |
| 58 | + JsonVariant *field; |
| 59 | + |
| 60 | + /* The ELF type and architecture are added as top-level objects, |
| 61 | + * since they are only parsed for the file itself, but the packaging |
| 62 | + * metadata is parsed recursively in core files, so there might be |
| 63 | + * multiple modules. */ |
| 64 | + if (STR_IN_SET(module_name, "elfType", "elfArchitecture")) { |
| 65 | + _cleanup_free_ char *suffixed = NULL; |
| 66 | + |
| 67 | + suffixed = strjoin(module_name, ":"); |
| 68 | + if (!suffixed) |
| 69 | + return log_oom(); |
| 70 | + |
| 71 | + r = table_add_many( |
| 72 | + t, |
| 73 | + TABLE_STRING, suffixed, |
| 74 | + TABLE_STRING, json_variant_string(module_json)); |
| 75 | + if (r < 0) |
| 76 | + return table_log_add_error(r); |
| 77 | + |
| 78 | + continue; |
| 79 | + } |
| 80 | + |
| 81 | + /* path/elfType/elfArchitecture come first just once per file, |
| 82 | + * then we might have multiple modules, so add a separator between |
| 83 | + * them to make the output more readable. */ |
| 84 | + r = table_add_many(t, TABLE_EMPTY, TABLE_EMPTY); |
| 85 | + if (r < 0) |
| 86 | + return table_log_add_error(r); |
| 87 | + |
| 88 | + /* In case of core files the module name will be the executable, |
| 89 | + * but for binaries/libraries it's just the path, so don't print it |
| 90 | + * twice. */ |
| 91 | + if (!streq(abspath, module_name)) { |
| 92 | + r = table_add_many( |
| 93 | + t, |
| 94 | + TABLE_STRING, "module name:", |
| 95 | + TABLE_STRING, module_name); |
| 96 | + if (r < 0) |
| 97 | + return table_log_add_error(r); |
| 98 | + } |
| 99 | + |
| 100 | + JSON_VARIANT_OBJECT_FOREACH(field_name, field, module_json) |
| 101 | + if (json_variant_is_string(field)) { |
| 102 | + _cleanup_free_ char *suffixed = NULL; |
| 103 | + |
| 104 | + suffixed = strjoin(field_name, ":"); |
| 105 | + if (!suffixed) |
| 106 | + return log_oom(); |
| 107 | + |
| 108 | + r = table_add_many( |
| 109 | + t, |
| 110 | + TABLE_STRING, suffixed, |
| 111 | + TABLE_STRING, json_variant_string(field)); |
| 112 | + if (r < 0) |
| 113 | + return table_log_add_error(r); |
| 114 | + } |
| 115 | + } |
| 116 | + } |
| 117 | + if (json_flags & JSON_FORMAT_OFF) { |
| 118 | + (void) table_set_header(t, true); |
| 119 | + |
| 120 | + r = table_print(t, NULL); |
| 121 | + if (r < 0) |
| 122 | + return table_log_print_error(r); |
| 123 | + } else |
| 124 | + json_variant_dump(package_metadata, json_flags, stdout, NULL); |
| 125 | + } |
| 126 | + |
| 127 | + return 0; |
| 128 | +} |
0 commit comments