summaryrefslogtreecommitdiffstats
path: root/src/analyze/analyze-inspect-elf.c
blob: 1ae73041630fed6cb2755eae6ec8287f3fe634f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/* SPDX-License-Identifier: LGPL-2.1-or-later */

#include "sd-json.h"

#include "analyze.h"
#include "analyze-inspect-elf.h"
#include "elf-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "format-table.h"
#include "format-util.h"
#include "json-util.h"
#include "path-util.h"
#include "strv.h"

static int analyze_elf(char **filenames, sd_json_format_flags_t json_flags) {
        int r;

        STRV_FOREACH(filename, filenames) {
                _cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL;
                _cleanup_(table_unrefp) Table *t = NULL;
                _cleanup_free_ char *abspath = NULL, *path = NULL, *stacktrace = NULL;
                _cleanup_close_ int fd = -EBADF;
                bool coredump = false;

                r = path_make_absolute_cwd(*filename, &abspath);
                if (r < 0)
                        return log_error_errno(r, "Could not make an absolute path out of \"%s\": %m", *filename);

                path = path_join(empty_to_root(arg_root), abspath);
                if (!path)
                        return log_oom();

                path_simplify(path);

                fd = RET_NERRNO(open(path, O_RDONLY|O_CLOEXEC));
                if (fd < 0)
                        return log_error_errno(fd, "Could not open \"%s\": %m", path);

                r = parse_elf_object(fd, abspath, arg_root, /* fork_disable_dump= */false, &stacktrace, &package_metadata);
                if (r < 0)
                        return log_error_errno(r, "Parsing \"%s\" as ELF object failed: %m", abspath);

                t = table_new_vertical();
                if (!t)
                        return log_oom();

                r = table_add_many(
                                t,
                                TABLE_FIELD, "path",
                                TABLE_STRING, abspath);
                if (r < 0)
                        return table_log_add_error(r);

                if (package_metadata) {
                        sd_json_variant *module_json;
                        const char *module_name;

                        JSON_VARIANT_OBJECT_FOREACH(module_name, module_json, package_metadata) {
                                const char *field_name;
                                sd_json_variant *field;

                                /* The ELF type and architecture are added as top-level objects,
                                 * since they are only parsed for the file itself, but the packaging
                                 * metadata is parsed recursively in core files, so there might be
                                 * multiple modules. */
                                if (STR_IN_SET(module_name, "elfType", "elfArchitecture")) {
                                        if (streq(module_name, "elfType") && streq("coredump", sd_json_variant_string(module_json)))
                                                coredump = true;

                                        r = table_add_many(
                                                        t,
                                                        TABLE_FIELD, module_name,
                                                        TABLE_STRING, sd_json_variant_string(module_json));
                                        if (r < 0)
                                                return table_log_add_error(r);

                                        continue;
                                }

                                /* path/elfType/elfArchitecture come first just once per file,
                                 * then we might have multiple modules, so add a separator between
                                 * them to make the output more readable. */
                                r = table_add_many(t, TABLE_EMPTY, TABLE_EMPTY);
                                if (r < 0)
                                        return table_log_add_error(r);

                                /* In case of core files the module name will be the executable,
                                 * but for binaries/libraries it's just the path, so don't print it
                                 * twice. */
                                if (!streq(abspath, module_name)) {
                                        r = table_add_many(
                                                        t,
                                                        TABLE_FIELD, "module name",
                                                        TABLE_STRING, module_name);
                                        if (r < 0)
                                                return table_log_add_error(r);
                                }

                                JSON_VARIANT_OBJECT_FOREACH(field_name, field, module_json)
                                        if (sd_json_variant_is_string(field)) {
                                                r = table_add_many(
                                                                t,
                                                                TABLE_FIELD, field_name,
                                                                TABLE_STRING, sd_json_variant_string(field));
                                                if (r < 0)
                                                        return table_log_add_error(r);
                                        }
                        }
                }

                if (coredump) {
                        r = table_add_many(t,
                                        TABLE_EMPTY, TABLE_EMPTY,
                                        TABLE_FIELD, "stacktrace",
                                        TABLE_STRING, stacktrace);
                        if (r < 0)
                                return table_log_add_error(r);
                }

                if (json_flags & SD_JSON_FORMAT_OFF) {
                        r = table_print(t, NULL);
                        if (r < 0)
                                return table_log_print_error(r);
                } else
                        sd_json_variant_dump(package_metadata, json_flags, stdout, NULL);
        }

        return 0;
}

int verb_elf_inspection(int argc, char *argv[], void *userdata) {
        pager_open(arg_pager_flags);

        return analyze_elf(strv_skip(argv, 1), arg_json_format_flags);
}