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