1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "analyze.h"
4 #include "analyze-inspect-elf.h"
5 #include "elf-util.h"
6 #include "errno-util.h"
7 #include "fd-util.h"
8 #include "format-table.h"
9 #include "format-util.h"
10 #include "json.h"
11 #include "path-util.h"
12 #include "strv.h"
13
analyze_elf(char ** filenames,JsonFormatFlags json_flags)14 static int analyze_elf(char **filenames, JsonFormatFlags json_flags) {
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 }
129
verb_elf_inspection(int argc,char * argv[],void * userdata)130 int verb_elf_inspection(int argc, char *argv[], void *userdata) {
131 pager_open(arg_pager_flags);
132
133 return analyze_elf(strv_skip(argv, 1), arg_json_format_flags);
134 }
135