• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 18958539692

30 Oct 2025 09:15PM UTC coverage: 72.046% (-0.2%) from 72.245%
18958539692

push

github

web-flow
importd: port export-tar code to use the one systemd-dissect already uses (#39405)

Split out of #38728.

(Testcase is part of that PR)

92 of 135 new or added lines in 5 files covered. (68.15%)

4530 existing lines in 57 files now uncovered.

304067 of 422048 relevant lines covered (72.05%)

1172093.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.28
/src/shared/elf-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#if HAVE_ELFUTILS
4
#include <dwarf.h>
5
#include <elfutils/libdwelf.h>
6
#include <elfutils/libdwfl.h>
7
#include <libelf.h>
8
#endif
9
#include <unistd.h>
10

11
#include "sd-json.h"
12

13
#include "alloc-util.h"
14
#include "coredump-util.h"
15
#include "dlfcn-util.h"
16
#include "elf-util.h"
17
#include "errno-util.h"
18
#include "escape.h"
19
#include "fd-util.h"
20
#include "fileio.h"
21
#include "format-util.h"
22
#include "io-util.h"
23
#include "json-util.h"
24
#include "log.h"
25
#include "memstream-util.h"
26
#include "path-util.h"
27
#include "process-util.h"
28
#include "set.h"
29
#include "string-util.h"
30

31
#define FRAMES_MAX 64
32
#define THREADS_MAX 64
33
#define ELF_PACKAGE_METADATA_ID 0xcafe1a7e
34

35
/* The amount of data we're willing to write to each of the output pipes. */
36
#define COREDUMP_PIPE_MAX (1024*1024U)
37

38
#if HAVE_ELFUTILS
39

40
static void *dw_dl = NULL;
41
static void *elf_dl = NULL;
42

43
/* libdw symbols */
44
static DLSYM_PROTOTYPE(dwarf_attr_integrate) = NULL;
45
static DLSYM_PROTOTYPE(dwarf_diename) = NULL;
46
static DLSYM_PROTOTYPE(dwarf_formstring) = NULL;
47
static DLSYM_PROTOTYPE(dwarf_getscopes) = NULL;
48
static DLSYM_PROTOTYPE(dwarf_getscopes_die) = NULL;
49
static DLSYM_PROTOTYPE(dwelf_elf_begin) = NULL;
50
#if HAVE_DWELF_ELF_E_MACHINE_STRING
51
static DLSYM_PROTOTYPE(dwelf_elf_e_machine_string) = NULL;
52
#endif
53
static DLSYM_PROTOTYPE(dwelf_elf_gnu_build_id) = NULL;
54
static DLSYM_PROTOTYPE(dwarf_tag) = NULL;
55
static DLSYM_PROTOTYPE(dwfl_addrmodule) = NULL;
56
static DLSYM_PROTOTYPE(dwfl_begin) = NULL;
57
static DLSYM_PROTOTYPE(dwfl_build_id_find_elf) = NULL;
58
static DLSYM_PROTOTYPE(dwfl_core_file_attach) = NULL;
59
static DLSYM_PROTOTYPE(dwfl_core_file_report) = NULL;
60
#if HAVE_DWFL_SET_SYSROOT
61
static DLSYM_PROTOTYPE(dwfl_set_sysroot) = NULL;
62
#endif
63
static DLSYM_PROTOTYPE(dwfl_end) = NULL;
64
static DLSYM_PROTOTYPE(dwfl_errmsg) = NULL;
65
static DLSYM_PROTOTYPE(dwfl_errno) = NULL;
66
static DLSYM_PROTOTYPE(dwfl_frame_pc) = NULL;
67
static DLSYM_PROTOTYPE(dwfl_getmodules) = NULL;
68
static DLSYM_PROTOTYPE(dwfl_getthreads) = NULL;
69
static DLSYM_PROTOTYPE(dwfl_module_addrdie) = NULL;
70
static DLSYM_PROTOTYPE(dwfl_module_addrname) = NULL;
71
static DLSYM_PROTOTYPE(dwfl_module_build_id) = NULL;
72
static DLSYM_PROTOTYPE(dwfl_module_getelf) = NULL;
73
static DLSYM_PROTOTYPE(dwfl_module_info) = NULL;
74
static DLSYM_PROTOTYPE(dwfl_offline_section_address) = NULL;
75
static DLSYM_PROTOTYPE(dwfl_report_end) = NULL;
76
static DLSYM_PROTOTYPE(dwfl_standard_find_debuginfo) = NULL;
77
static DLSYM_PROTOTYPE(dwfl_thread_getframes) = NULL;
78
static DLSYM_PROTOTYPE(dwfl_thread_tid) = NULL;
79

80
/* libelf symbols */
81
static DLSYM_PROTOTYPE(elf_begin) = NULL;
82
static DLSYM_PROTOTYPE(elf_end) = NULL;
83
static DLSYM_PROTOTYPE(elf_getdata_rawchunk) = NULL;
84
static DLSYM_PROTOTYPE(gelf_getehdr) = NULL;
85
static DLSYM_PROTOTYPE(elf_getphdrnum) = NULL;
86
static DLSYM_PROTOTYPE(elf_errmsg) = NULL;
87
static DLSYM_PROTOTYPE(elf_errno) = NULL;
88
static DLSYM_PROTOTYPE(elf_memory) = NULL;
89
static DLSYM_PROTOTYPE(elf_version) = NULL;
90
static DLSYM_PROTOTYPE(gelf_getphdr) = NULL;
91
static DLSYM_PROTOTYPE(gelf_getnote) = NULL;
92

93
#endif
94

95
int dlopen_dw(void) {
29✔
96
#if HAVE_ELFUTILS
97
        int r;
29✔
98

99
        ELF_NOTE_DLOPEN("dw",
29✔
100
                        "Support for backtrace and ELF package metadata decoding from core files",
101
                        ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
102
                        "libdw.so.1");
103

104
        r = dlopen_many_sym_or_warn(
29✔
105
                        &dw_dl, "libdw.so.1", LOG_DEBUG,
106
                        DLSYM_ARG(dwarf_getscopes),
107
                        DLSYM_ARG(dwarf_getscopes_die),
108
                        DLSYM_ARG(dwarf_tag),
109
                        DLSYM_ARG(dwarf_attr_integrate),
110
                        DLSYM_ARG(dwarf_formstring),
111
                        DLSYM_ARG(dwarf_diename),
112
                        DLSYM_ARG(dwelf_elf_gnu_build_id),
113
                        DLSYM_ARG(dwelf_elf_begin),
114
#if HAVE_DWELF_ELF_E_MACHINE_STRING
115
                        DLSYM_ARG(dwelf_elf_e_machine_string),
116
#endif
117
                        DLSYM_ARG(dwfl_addrmodule),
118
                        DLSYM_ARG(dwfl_frame_pc),
119
                        DLSYM_ARG(dwfl_module_addrdie),
120
                        DLSYM_ARG(dwfl_module_addrname),
121
                        DLSYM_ARG(dwfl_module_info),
122
                        DLSYM_ARG(dwfl_module_build_id),
123
                        DLSYM_ARG(dwfl_module_getelf),
124
                        DLSYM_ARG(dwfl_begin),
125
                        DLSYM_ARG(dwfl_core_file_report),
126
#if HAVE_DWFL_SET_SYSROOT
127
                        DLSYM_ARG(dwfl_set_sysroot),
128
#endif
129
                        DLSYM_ARG(dwfl_report_end),
130
                        DLSYM_ARG(dwfl_getmodules),
131
                        DLSYM_ARG(dwfl_core_file_attach),
132
                        DLSYM_ARG(dwfl_end),
133
                        DLSYM_ARG(dwfl_errmsg),
134
                        DLSYM_ARG(dwfl_errno),
135
                        DLSYM_ARG(dwfl_build_id_find_elf),
136
                        DLSYM_ARG(dwfl_standard_find_debuginfo),
137
                        DLSYM_ARG(dwfl_thread_tid),
138
                        DLSYM_ARG(dwfl_thread_getframes),
139
                        DLSYM_ARG(dwfl_getthreads),
140
                        DLSYM_ARG(dwfl_offline_section_address));
141
        if (r <= 0)
29✔
UNCOV
142
                return r;
×
143

144
        return 1;
145
#else
146
        return -EOPNOTSUPP;
147
#endif
148
}
149

150
int dlopen_elf(void) {
29✔
151
#if HAVE_ELFUTILS
152
        int r;
29✔
153

154
        ELF_NOTE_DLOPEN("elf",
29✔
155
                        "Support for backtraces and reading ELF package metadata from core files",
156
                        ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
157
                        "libelf.so.1");
158

159
        r = dlopen_many_sym_or_warn(
29✔
160
                        &elf_dl, "libelf.so.1", LOG_DEBUG,
161
                        DLSYM_ARG(elf_begin),
162
                        DLSYM_ARG(elf_end),
163
                        DLSYM_ARG(elf_getphdrnum),
164
                        DLSYM_ARG(elf_getdata_rawchunk),
165
                        DLSYM_ARG(elf_errmsg),
166
                        DLSYM_ARG(elf_errno),
167
                        DLSYM_ARG(elf_memory),
168
                        DLSYM_ARG(elf_version),
169
                        DLSYM_ARG(gelf_getehdr),
170
                        DLSYM_ARG(gelf_getphdr),
171
                        DLSYM_ARG(gelf_getnote));
172
        if (r <= 0)
29✔
UNCOV
173
                return r;
×
174

175
        return 1;
176
#else
177
        return -EOPNOTSUPP;
178
#endif
179
}
180

181
#if HAVE_ELFUTILS
182

183
typedef struct StackContext {
184
        MemStream m;
185
        Dwfl *dwfl;
186
        Elf *elf;
187
        unsigned n_thread;
188
        unsigned n_frame;
189
        sd_json_variant **package_metadata;
190
        sd_json_variant **dlopen_metadata;
191
        Set **modules;
192
} StackContext;
193

194
static void stack_context_done(StackContext *c) {
24✔
195
        assert(c);
24✔
196

197
        memstream_done(&c->m);
24✔
198

199
        if (c->dwfl) {
24✔
200
                sym_dwfl_end(c->dwfl);
10✔
201
                c->dwfl = NULL;
10✔
202
        }
203

204
        if (c->elf) {
24✔
205
                sym_elf_end(c->elf);
24✔
206
                c->elf = NULL;
24✔
207
        }
208
}
24✔
209

210
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(Elf *, sym_elf_end, elf_endp, NULL);
8✔
211

212
static int frame_callback(Dwfl_Frame *frame, void *userdata) {
110✔
213
        StackContext *c = ASSERT_PTR(userdata);
110✔
214
        Dwarf_Addr pc, pc_adjusted;
110✔
215
        const char *fname = NULL, *symbol = NULL;
110✔
216
        Dwfl_Module *module;
110✔
217
        bool is_activation;
110✔
218
        uint64_t module_offset = 0;
110✔
219

220
        assert(frame);
110✔
221

222
        if (c->n_frame >= FRAMES_MAX)
110✔
223
                return DWARF_CB_ABORT;
110✔
224

225
        if (!sym_dwfl_frame_pc(frame, &pc, &is_activation))
110✔
226
                return DWARF_CB_ABORT;
227

228
        pc_adjusted = pc - (is_activation ? 0 : 1);
110✔
229

230
        module = sym_dwfl_addrmodule(c->dwfl, pc_adjusted);
110✔
231
        if (module) {
110✔
232
                Dwarf_Addr start, bias = 0;
110✔
233
                Dwarf_Die *cudie;
110✔
234

235
                cudie = sym_dwfl_module_addrdie(module, pc_adjusted, &bias);
110✔
236
                if (cudie) {
110✔
237
                        _cleanup_free_ Dwarf_Die *scopes = NULL;
62✔
238
                        int n;
31✔
239

240
                        n = sym_dwarf_getscopes(cudie, pc_adjusted - bias, &scopes);
31✔
241
                        if (n > 0)
31✔
242
                                for (Dwarf_Die *s = scopes; s && s < scopes + n; s++) {
41✔
243
                                        Dwarf_Attribute *a, space;
41✔
244

245
                                        if (!IN_SET(sym_dwarf_tag(s), DW_TAG_subprogram, DW_TAG_inlined_subroutine, DW_TAG_entry_point))
41✔
246
                                                continue;
10✔
247

248
                                        a = sym_dwarf_attr_integrate(s, DW_AT_MIPS_linkage_name, &space);
31✔
249
                                        if (!a)
31✔
250
                                                a = sym_dwarf_attr_integrate(s, DW_AT_linkage_name, &space);
31✔
251
                                        if (a)
31✔
UNCOV
252
                                                symbol = sym_dwarf_formstring(a);
×
253
                                        if (!symbol)
31✔
254
                                                symbol = sym_dwarf_diename(s);
31✔
255

256
                                        if (symbol)
31✔
257
                                                break;
258
                                }
259
                }
260

261
                if (!symbol)
31✔
262
                        symbol = sym_dwfl_module_addrname(module, pc_adjusted);
79✔
263

264
                fname = sym_dwfl_module_info(module, NULL, &start, NULL, NULL, NULL, NULL, NULL);
110✔
265
                module_offset = pc - start;
110✔
266
        }
267

268
        if (c->m.f)
110✔
269
                fprintf(c->m.f, "#%-2u 0x%016" PRIx64 " %s (%s + 0x%" PRIx64 ")\n", c->n_frame, (uint64_t) pc, strna(symbol), strna(fname), module_offset);
167✔
270
        c->n_frame++;
110✔
271

272
        return DWARF_CB_OK;
110✔
273
}
274

275
static int thread_callback(Dwfl_Thread *thread, void *userdata) {
10✔
276
        StackContext *c = ASSERT_PTR(userdata);
10✔
277
        pid_t tid;
10✔
278

279
        assert(thread);
10✔
280

281
        if (c->n_thread >= THREADS_MAX)
10✔
282
                return DWARF_CB_ABORT;
283

284
        if (c->n_thread != 0 && c->m.f)
10✔
UNCOV
285
                fputc('\n', c->m.f);
×
286

287
        c->n_frame = 0;
10✔
288

289
        if (c->m.f) {
10✔
290
                tid = sym_dwfl_thread_tid(thread);
10✔
291
                fprintf(c->m.f, "Stack trace of thread " PID_FMT ":\n", tid);
10✔
292
        }
293

294
        if (sym_dwfl_thread_getframes(thread, frame_callback, c) < 0)
10✔
295
                return DWARF_CB_ABORT;
296

297
        c->n_thread++;
2✔
298

299
        return DWARF_CB_OK;
2✔
300
}
301

UNCOV
302
static char* build_package_reference(
×
303
                const char *type,
304
                const char *name,
305
                const char *version,
306
                const char *arch) {
307

308
        /* Construct an identifier for a specific version of the package. The syntax is most suitable for
309
         * rpm: the resulting string can be used directly in queries and rpm/dnf/yum commands. For dpkg and
310
         * other systems, it might not be usable directly, but users should still be able to figure out the
311
         * meaning.
312
         */
313

UNCOV
314
        return strjoin(type ?: "package",
×
315
                       " ",
316
                       name,
317

318
                       version ? "-" : "",
319
                       strempty(version),
320

321
                       /* arch is meaningful even without version, so always print it */
322
                       arch ? "." : "",
323
                       strempty(arch));
324
}
325

326
static void report_module_metadata(StackContext *c, const char *name, sd_json_variant *metadata) {
×
UNCOV
327
        assert(c);
×
328
        assert(name);
×
329

UNCOV
330
        if (!c->m.f)
×
331
                return;
332

333
        fprintf(c->m.f, "Module %s", name);
×
334

335
        if (metadata) {
×
336
                const char
×
337
                        *build_id = sd_json_variant_string(sd_json_variant_by_key(metadata, "buildId")),
×
338
                        *type = sd_json_variant_string(sd_json_variant_by_key(metadata, "type")),
×
339
                        *package = sd_json_variant_string(sd_json_variant_by_key(metadata, "name")),
×
UNCOV
340
                        *version = sd_json_variant_string(sd_json_variant_by_key(metadata, "version")),
×
341
                        *arch = sd_json_variant_string(sd_json_variant_by_key(metadata, "architecture"));
×
342

UNCOV
343
                if (package) {
×
344
                        /* Version/architecture is only meaningful with a package name.
345
                         * Skip the detailed fields if package is unknown. */
UNCOV
346
                        _cleanup_free_ char *id = build_package_reference(type, package, version, arch);
×
UNCOV
347
                        fprintf(c->m.f, " from %s", strnull(id));
×
348
                }
349

UNCOV
350
                if (build_id && !(package && version))
×
UNCOV
351
                        fprintf(c->m.f, ", build-id=%s", build_id);
×
352
        }
353

UNCOV
354
        fputs("\n", c->m.f);
×
355
}
356

357
static int parse_metadata(const char *name, sd_json_variant *id_json, Elf *elf, bool *ret_interpreter_found, StackContext *c) {
53✔
358
        bool package_metadata_found = false, interpreter_found = false;
53✔
359
        size_t n_program_headers;
53✔
360
        int r;
53✔
361

362
        assert(name);
53✔
363
        assert(elf);
53✔
364
        assert(c);
53✔
365

366
        /* When iterating over PT_LOAD we will visit modules more than once */
367
        if (set_contains(*c->modules, name))
53✔
368
                return 0;
53✔
369

370
        r = sym_elf_getphdrnum(elf, &n_program_headers);
53✔
371
        if (r < 0) /* Not the handle we are looking for - that's ok, skip it */
53✔
372
                return 0;
373

374
        /* Iterate over all program headers in that ELF object. These will have been copied by
375
         * the kernel verbatim when the core file is generated. */
376
        for (size_t i = 0; i < n_program_headers; ++i) {
681✔
377
                GElf_Phdr mem, *program_header;
628✔
378
                GElf_Nhdr note_header;
628✔
379
                Elf_Data *data;
628✔
380

381
                /* Package metadata is in PT_NOTE headers. */
382
                program_header = sym_gelf_getphdr(elf, i, &mem);
628✔
383
                if (!program_header || !IN_SET(program_header->p_type, PT_NOTE, PT_INTERP))
628✔
384
                        continue;
514✔
385

386
                if (program_header->p_type == PT_INTERP) {
144✔
387
                        interpreter_found = true;
22✔
388
                        continue;
22✔
389
                }
390

391
                /* Fortunately there is an iterator we can use to walk over the
392
                 * elements of a PT_NOTE program header. We are interested in the
393
                 * note with type. */
394
                data = sym_elf_getdata_rawchunk(elf,
244✔
395
                                                program_header->p_offset,
122✔
396
                                                program_header->p_filesz,
122✔
397
                                                ELF_T_NHDR);
398
                if (!data)
122✔
399
                        continue;
8✔
400

401
                for (size_t note_offset = 0, name_offset, desc_offset;
402
                     note_offset < data->d_size &&
320✔
403
                     (note_offset = sym_gelf_getnote(data, note_offset, &note_header, &name_offset, &desc_offset)) > 0;) {
206✔
404

405
                        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *w = NULL;
281✔
406
                        const char *payload = (const char *)data->d_buf + desc_offset;
206✔
407

408
                        if (note_header.n_namesz == 0 || note_header.n_descsz == 0)
206✔
UNCOV
409
                                continue;
×
410

411
                        /* Package metadata might have different owners, but the
412
                         * magic ID is always the same. */
413
                        if (!IN_SET(note_header.n_type, ELF_PACKAGE_METADATA_ID, ELF_NOTE_DLOPEN_TYPE))
206✔
414
                                continue;
131✔
415

416
                        _cleanup_free_ char *payload_0suffixed = NULL;
75✔
417
                        assert(note_offset > desc_offset);
75✔
418
                        size_t payload_len = note_offset - desc_offset;
75✔
419

420
                        /* If we are lucky and the payload is NUL-padded, we don't need to copy the string.
421
                         * But if happens to go all the way until the end of the buffer, make a copy. */
422
                        if (payload[payload_len-1] != '\0') {
75✔
423
                                payload_0suffixed = memdup_suffix0(payload, payload_len);
×
UNCOV
424
                                if (!payload_0suffixed)
×
UNCOV
425
                                        return log_oom();
×
426
                                payload = payload_0suffixed;
427
                        }
428

429
                        r = sd_json_parse(payload, 0, &v, NULL, NULL);
75✔
430
                        if (r < 0) {
75✔
UNCOV
431
                                _cleanup_free_ char *esc = cescape(payload);
×
UNCOV
432
                                return log_error_errno(r, "json_parse on \"%s\" failed: %m", strnull(esc));
×
433
                        }
434

435
                        if (note_header.n_type == ELF_PACKAGE_METADATA_ID) {
75✔
436
                                /* If we have a build-id, merge it in the same JSON object so that it appears all
437
                                 * nicely together in the logs/metadata. */
438
                                if (id_json) {
×
UNCOV
439
                                        r = sd_json_variant_merge_object(&v, id_json);
×
UNCOV
440
                                        if (r < 0)
×
UNCOV
441
                                                return log_error_errno(r, "sd_json_variant_merge of package meta with buildId failed: %m");
×
442
                                }
443

444
                                /* Pretty-print to the buffer, so that the metadata goes as plaintext in the
445
                                 * journal. */
UNCOV
446
                                report_module_metadata(c, name, v);
×
447

448
                                /* Then we build a new object using the module name as the key, and merge it
449
                                 * with the previous parses, so that in the end it all fits together in a single
450
                                 * JSON blob. */
UNCOV
451
                                r = sd_json_buildo(&w, SD_JSON_BUILD_PAIR(name, SD_JSON_BUILD_VARIANT(v)));
×
452
                                if (r < 0)
×
453
                                        return log_error_errno(r, "Failed to build JSON object: %m");
×
454

UNCOV
455
                                r = sd_json_variant_merge_object(c->package_metadata, w);
×
UNCOV
456
                                if (r < 0)
×
457
                                        return log_error_errno(r, "sd_json_variant_merge of package meta with buildId failed: %m");
×
458

459
                                package_metadata_found = true;
460
                        } else if (c->dlopen_metadata) {
75✔
461
                                sd_json_variant *z;
75✔
462

463
                                JSON_VARIANT_ARRAY_FOREACH(z, v) {
150✔
464
                                        r = sd_json_variant_append_array(c->dlopen_metadata, z);
75✔
465
                                        if (r < 0)
75✔
UNCOV
466
                                                return log_error_errno(r, "Failed to append entry to dlopen metadata: %m");
×
467
                                }
468
                        }
469

470
                        /* Finally stash the name, so we avoid double visits. */
471
                        r = set_put_strdup(c->modules, name);
75✔
472
                        if (r < 0)
75✔
UNCOV
473
                                return log_error_errno(r, "set_put_strdup failed: %m");
×
474

475
                        if (!c->dlopen_metadata) {
75✔
UNCOV
476
                                if (ret_interpreter_found)
×
UNCOV
477
                                        *ret_interpreter_found = interpreter_found;
×
478

UNCOV
479
                                return 1;
×
480
                        }
481
                }
482
        }
483

484
        if (ret_interpreter_found)
53✔
485
                *ret_interpreter_found = interpreter_found;
4✔
486

487
        return c->dlopen_metadata ? 0 : package_metadata_found;
53✔
488
}
489

490
/* Get the build-id out of an ELF object or a dwarf core module. */
491
static int parse_buildid(Dwfl_Module *mod, Elf *elf, const char *name, StackContext *c, sd_json_variant **ret_id_json) {
53✔
492
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *id_json = NULL;
53✔
493
        const unsigned char *id;
53✔
494
        GElf_Addr id_vaddr;
53✔
495
        ssize_t id_len;
53✔
496
        int r;
53✔
497

498
        assert(mod || elf);
53✔
499
        assert(name);
53✔
500
        assert(c);
53✔
501

502
        if (mod)
53✔
503
                id_len = sym_dwfl_module_build_id(mod, &id, &id_vaddr);
49✔
504
        else
505
                id_len = sym_dwelf_elf_gnu_build_id(elf, (const void **)&id);
4✔
506
        if (id_len <= 0) {
53✔
507
                /* If we don't find a build-id, note it in the journal message, and try
508
                 * anyway to find the package metadata. It's unlikely to have the latter
509
                 * without the former, but there's no hard rule. */
UNCOV
510
                if (c->m.f)
×
UNCOV
511
                        fprintf(c->m.f, "Module %s without build-id.\n", name);
×
512
        } else {
513
                /* We will later parse package metadata json and pass it to our caller. Prepare the
514
                * build-id in json format too, so that it can be appended and parsed cleanly. It
515
                * will then be added as metadata to the journal message with the stack trace. */
516
                r = sd_json_buildo(&id_json, SD_JSON_BUILD_PAIR("buildId", SD_JSON_BUILD_HEX(id, id_len)));
53✔
517
                if (r < 0)
53✔
UNCOV
518
                        return log_error_errno(r, "json_build on buildId failed: %m");
×
519
        }
520

521
        if (ret_id_json)
53✔
522
                *ret_id_json = TAKE_PTR(id_json);
53✔
523

524
        return 0;
525
}
526

527
static int module_callback(Dwfl_Module *mod, void **userdata, const char *name, Dwarf_Addr start, void *arg) {
49✔
528
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *id_json = NULL;
49✔
529
        StackContext *c = ASSERT_PTR(arg);
49✔
530
        size_t n_program_headers;
49✔
531
        GElf_Addr bias;
49✔
532
        int r;
49✔
533
        Elf *elf;
49✔
534

535
        assert(mod);
49✔
536

537
        if (!name)
49✔
UNCOV
538
                name = "(unnamed)"; /* For logging purposes */
×
539

540
        /* We are iterating on each "module", which is what dwfl calls ELF objects contained in the
541
         * core file, and extracting the build-id first and then the package metadata.
542
         * We proceed in a best-effort fashion - not all ELF objects might contain both or either.
543
         * The build-id is easy, as libdwfl parses it during the sym_dwfl_core_file_report() call and
544
         * stores it separately in an internal library struct. */
545
        r = parse_buildid(mod, NULL, name, c, &id_json);
49✔
546
        if (r < 0)
49✔
547
                return DWARF_CB_ABORT;
548

549
        /* The .note.package metadata is more difficult. From the module, we need to get a reference
550
         * to the ELF object first. We might be lucky and just get it from elfutils. */
551
        elf = sym_dwfl_module_getelf(mod, &bias);
49✔
552
        if (elf) {
49✔
553
                r = parse_metadata(name, id_json, elf, NULL, c);
41✔
554
                if (r < 0)
41✔
555
                        return DWARF_CB_ABORT;
556
                if (r > 0)
41✔
557
                        return DWARF_CB_OK;
558
        } else
559
                elf = c->elf;
8✔
560

561
        /* We did not get the ELF object, or it's just a reference to the core. That is likely
562
         * because we didn't get direct access to the executable, and the version of elfutils does
563
         * not yet support parsing it out of the core file directly.
564
         * So fallback to manual extraction - get the PT_LOAD section from the core,
565
         * and if it's the right one we can interpret it as an Elf object, and parse
566
         * its notes manually. */
567

568
        r = sym_elf_getphdrnum(elf, &n_program_headers);
49✔
569
        if (r < 0) {
49✔
UNCOV
570
                log_warning("Could not parse number of program headers from core file: %s",
×
571
                            sym_elf_errmsg(-1)); /* -1 retrieves the most recent error */
UNCOV
572
                report_module_metadata(c, name, id_json);
×
573

574
                return DWARF_CB_OK;
575
        }
576

577
        for (size_t i = 0; i < n_program_headers; ++i) {
799✔
578
                GElf_Phdr mem, *program_header;
750✔
579
                Elf_Data *data;
750✔
580
                GElf_Addr end_of_segment;
750✔
581

582
                /* The core file stores the ELF files in the PT_LOAD segment. */
583
                program_header = sym_gelf_getphdr(elf, i, &mem);
750✔
584
                if (!program_header || program_header->p_type != PT_LOAD)
750✔
585
                        continue;
742✔
586

587
                /* Check that the end of segment is a valid address. */
588
                if (!ADD_SAFE(&end_of_segment, program_header->p_vaddr, program_header->p_memsz)) {
422✔
UNCOV
589
                        log_error("Abort due to corrupted core dump, end of segment address %#zx + %#zx overflows", (size_t)program_header->p_vaddr, (size_t)program_header->p_memsz);
×
UNCOV
590
                        return DWARF_CB_ABORT;
×
591
                }
592

593
                /* This PT_LOAD segment doesn't contain the start address, so it can't be the module we are looking for. */
594
                if (start < program_header->p_vaddr || start >= end_of_segment)
422✔
595
                        continue;
414✔
596

597
                /* Now get a usable Elf reference, and parse the notes from it. */
598
                data = sym_elf_getdata_rawchunk(elf,
16✔
599
                                                program_header->p_offset,
8✔
600
                                                program_header->p_filesz,
8✔
601
                                                ELF_T_NHDR);
602
                if (!data)
8✔
UNCOV
603
                        continue;
×
604

605
                _cleanup_(elf_endp) Elf *memelf = sym_elf_memory(data->d_buf, data->d_size);
16✔
606
                if (!memelf)
8✔
UNCOV
607
                        continue;
×
608

609
                r = parse_metadata(name, id_json, memelf, NULL, c);
8✔
610
                if (r < 0)
8✔
UNCOV
611
                        return DWARF_CB_ABORT;
×
612
                if (r > 0)
8✔
613
                        break;
614
        }
615

616
        return DWARF_CB_OK;
617
}
618

619
static int parse_core(
10✔
620
                int fd,
621
                const char *root,
622
                char **ret,
623
                sd_json_variant **ret_package_metadata,
624
                sd_json_variant **ret_dlopen_metadata) {
625

626
        const Dwfl_Callbacks callbacks = {
10✔
627
                .find_elf = sym_dwfl_build_id_find_elf,
628
                .section_address = sym_dwfl_offline_section_address,
629
                .find_debuginfo = sym_dwfl_standard_find_debuginfo,
630
        };
631

632
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL, *dlopen_metadata = NULL;
10✔
633
        _cleanup_set_free_ Set *modules = NULL;
10✔
634
        _cleanup_(stack_context_done) StackContext c = {
10✔
635
                .package_metadata = &package_metadata,
636
                .dlopen_metadata = ret_dlopen_metadata ? &dlopen_metadata : NULL,
10✔
637
                .modules = &modules,
638
        };
639
        int r;
10✔
640

641
        assert(fd >= 0);
10✔
642

643
        if (lseek(fd, 0, SEEK_SET) < 0)
10✔
UNCOV
644
                return log_warning_errno(errno, "Failed to seek to beginning of the core file: %m");
×
645

646
        if (ret && !memstream_init(&c.m))
10✔
UNCOV
647
                return log_oom();
×
648

649
        sym_elf_version(EV_CURRENT);
10✔
650

651
        c.elf = sym_elf_begin(fd, ELF_C_READ_MMAP, NULL);
10✔
652
        if (!c.elf)
10✔
UNCOV
653
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse core file, elf_begin() failed: %s", sym_elf_errmsg(sym_elf_errno()));
×
654

655
        c.dwfl = sym_dwfl_begin(&callbacks);
10✔
656
        if (!c.dwfl)
10✔
657
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse core file, dwfl_begin() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
×
658

659
        if (empty_or_root(root))
10✔
660
                root = NULL;
661
#if HAVE_DWFL_SET_SYSROOT
UNCOV
662
        if (root && sym_dwfl_set_sysroot(c.dwfl, root) < 0)
×
UNCOV
663
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not set root directory, dwfl_set_sysroot() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
×
664
#else
665
        if (root)
666
                log_warning("Compiled without dwfl_set_sysroot() support, ignoring provided root directory.");
667
#endif
668

669
        if (sym_dwfl_core_file_report(c.dwfl, c.elf, NULL) < 0)
10✔
UNCOV
670
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse core file, dwfl_core_file_report() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
×
671

672
        if (sym_dwfl_report_end(c.dwfl, NULL, NULL) != 0)
10✔
UNCOV
673
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse core file, dwfl_report_end() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
×
674

675
        if (sym_dwfl_getmodules(c.dwfl, &module_callback, &c, 0) < 0)
10✔
UNCOV
676
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse core file, dwfl_getmodules() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
×
677

678
        if (sym_dwfl_core_file_attach(c.dwfl, c.elf) < 0)
10✔
UNCOV
679
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse core file, dwfl_core_file_attach() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
×
680

681
        if (sym_dwfl_getthreads(c.dwfl, thread_callback, &c) < 0)
10✔
UNCOV
682
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse core file, dwfl_getthreads() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
×
683

684
        if (ret) {
10✔
685
                r = memstream_finalize(&c.m, ret, NULL);
10✔
686
                if (r < 0)
10✔
UNCOV
687
                        return log_warning_errno(r, "Could not parse core file, flushing file buffer failed: %m");
×
688
        }
689

690
        if (ret_package_metadata)
10✔
691
                *ret_package_metadata = TAKE_PTR(package_metadata);
10✔
692
        if (ret_dlopen_metadata)
10✔
693
                *ret_dlopen_metadata = TAKE_PTR(dlopen_metadata);
10✔
694

695
        return 0;
696
}
697

698
static int parse_elf(
14✔
699
                int fd,
700
                const char *executable,
701
                const char *root,
702
                char **ret,
703
                sd_json_variant **ret_package_metadata,
704
                sd_json_variant **ret_dlopen_metadata) {
705
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL, *dlopen_metadata = NULL, *elf_metadata = NULL;
19✔
706
        _cleanup_set_free_ Set *modules = NULL;
14✔
707
        _cleanup_(stack_context_done) StackContext c = {
14✔
708
                .package_metadata = &package_metadata,
709
                .dlopen_metadata = ret_dlopen_metadata ? &dlopen_metadata : NULL,
14✔
710
                .modules = &modules,
711
        };
712
        const char *elf_type;
14✔
713
        GElf_Ehdr elf_header;
14✔
714
        int r;
14✔
715

716
        assert(fd >= 0);
14✔
717

718
        if (lseek(fd, 0, SEEK_SET) < 0)
14✔
UNCOV
719
                return log_warning_errno(errno, "Failed to seek to beginning of the ELF file: %m");
×
720

721
        if (ret && !memstream_init(&c.m))
14✔
UNCOV
722
                return log_oom();
×
723

724
        sym_elf_version(EV_CURRENT);
14✔
725

726
        c.elf = sym_elf_begin(fd, ELF_C_READ_MMAP, NULL);
14✔
727
        if (!c.elf)
14✔
UNCOV
728
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse ELF file, elf_begin() failed: %s", sym_elf_errmsg(sym_elf_errno()));
×
729

730
        if (!sym_gelf_getehdr(c.elf, &elf_header))
14✔
UNCOV
731
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse ELF file, gelf_getehdr() failed: %s", sym_elf_errmsg(sym_elf_errno()));
×
732

733
        if (elf_header.e_type == ET_CORE) {
14✔
734
                _cleanup_free_ char *out = NULL;
10✔
735

736
                r = parse_core(fd, root, ret ? &out : NULL, &package_metadata, &dlopen_metadata);
10✔
737
                if (r < 0)
10✔
UNCOV
738
                        return log_warning_errno(r, "Failed to inspect core file: %m");
×
739

740
                if (out)
10✔
741
                        fprintf(c.m.f, "%s", out);
10✔
742

743
                elf_type = "coredump";
10✔
744
        } else {
745
                _cleanup_(sd_json_variant_unrefp) sd_json_variant *id_json = NULL;
4✔
746
                const char *e = executable ?: "(unnamed)";
4✔
747
                bool interpreter_found = false;
4✔
748

749
                r = parse_buildid(NULL, c.elf, e, &c, &id_json);
4✔
750
                if (r < 0)
4✔
UNCOV
751
                        return log_warning_errno(r, "Failed to parse build-id of ELF file: %m");
×
752

753
                r = parse_metadata(e, id_json, c.elf, &interpreter_found, &c);
4✔
754
                if (r < 0)
4✔
UNCOV
755
                        return log_warning_errno(r, "Failed to parse package metadata of ELF file: %m");
×
756

757
                /* If we found a build-id and nothing else, return at least that. */
758
                if (!package_metadata && id_json) {
4✔
759
                        r = sd_json_buildo(&package_metadata, SD_JSON_BUILD_PAIR(e, SD_JSON_BUILD_VARIANT(id_json)));
4✔
760
                        if (r < 0)
4✔
UNCOV
761
                                return log_warning_errno(r, "Failed to build JSON object: %m");
×
762
                }
763

764
                if (interpreter_found)
4✔
765
                        elf_type = "executable";
766
                else
767
                        elf_type = "library";
2✔
768
        }
769

770
        /* Note that e_type is always DYN for both executables and libraries, so we can't tell them apart from the header,
771
         * but we will search for the PT_INTERP section when parsing the metadata. */
772
        r = sd_json_buildo(&elf_metadata, SD_JSON_BUILD_PAIR("elfType", SD_JSON_BUILD_STRING(elf_type)));
14✔
773
        if (r < 0)
14✔
UNCOV
774
                return log_warning_errno(r, "Failed to build JSON object: %m");
×
775

776
#if HAVE_DWELF_ELF_E_MACHINE_STRING
777
        const char *elf_architecture = sym_dwelf_elf_e_machine_string(elf_header.e_machine);
14✔
778
        if (elf_architecture) {
14✔
779
                r = sd_json_variant_merge_objectbo(
14✔
780
                                &elf_metadata,
781
                                SD_JSON_BUILD_PAIR("elfArchitecture", SD_JSON_BUILD_STRING(elf_architecture)));
782
                if (r < 0)
14✔
UNCOV
783
                        return log_warning_errno(r, "Failed to add elfArchitecture field: %m");
×
784

785
                if (ret)
14✔
786
                        fprintf(c.m.f, "ELF object binary architecture: %s\n", elf_architecture);
12✔
787
        }
788
#endif
789

790
        /* We always at least have the ELF type, so merge that (and possibly the arch). */
791
        r = sd_json_variant_merge_object(&elf_metadata, package_metadata);
14✔
792
        if (r < 0)
14✔
UNCOV
793
                return log_warning_errno(r, "Failed to merge JSON objects: %m");
×
794

795
        if (ret) {
14✔
796
                r = memstream_finalize(&c.m, ret, NULL);
12✔
797
                if (r < 0)
12✔
798
                        return log_warning_errno(r, "Could not parse ELF file, flushing file buffer failed: %m");
×
799
        }
800

801
        if (ret_package_metadata)
14✔
802
                *ret_package_metadata = TAKE_PTR(elf_metadata);
12✔
803
        if (ret_dlopen_metadata)
14✔
804
                *ret_dlopen_metadata = TAKE_PTR(dlopen_metadata);
2✔
805

806
        return 0;
807
}
808

809
#endif
810

811
int parse_elf_object(
28✔
812
                int fd,
813
                const char *executable,
814
                const char *root,
815
                bool fork_disable_dump,
816
                char **ret,
817
                sd_json_variant **ret_package_metadata,
818
                sd_json_variant **ret_dlopen_metadata) {
819
#if HAVE_ELFUTILS
820
        _cleanup_close_pair_ int error_pipe[2] = EBADF_PAIR,
14✔
821
                                 return_pipe[2] = EBADF_PAIR,
14✔
822
                                 package_metadata_pipe[2] = EBADF_PAIR,
14✔
823
                                 dlopen_metadata_pipe[2] = EBADF_PAIR;
14✔
824
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL, *dlopen_metadata = NULL;
14✔
825
        _cleanup_free_ char *buf = NULL;
14✔
826
        int r;
28✔
827

828
        assert(fd >= 0);
28✔
829

830
        r = dlopen_dw();
28✔
831
        if (r < 0)
28✔
832
                return r;
833

834
        r = dlopen_elf();
28✔
835
        if (r < 0)
28✔
836
                return r;
837

838
        r = RET_NERRNO(pipe2(error_pipe, O_CLOEXEC|O_NONBLOCK));
28✔
839
        if (r < 0)
×
840
                return r;
841

842
        if (ret) {
28✔
843
                r = RET_NERRNO(pipe2(return_pipe, O_CLOEXEC|O_NONBLOCK));
24✔
844
                if (r < 0)
×
845
                        return r;
846
        }
847

848
        if (ret_package_metadata) {
28✔
849
                r = RET_NERRNO(pipe2(package_metadata_pipe, O_CLOEXEC|O_NONBLOCK));
24✔
UNCOV
850
                if (r < 0)
×
851
                        return r;
852
        }
853

854
        if (ret_dlopen_metadata) {
28✔
855
                r = RET_NERRNO(pipe2(dlopen_metadata_pipe, O_CLOEXEC|O_NONBLOCK));
4✔
UNCOV
856
                if (r < 0)
×
857
                        return r;
858
        }
859

860
        /* Parsing possibly malformed data is crash-happy, so fork. In case we crash,
861
         * the core file will not be lost, and the messages will still be attached to
862
         * the journal. Reading the elf object might be slow, but it still has an upper
863
         * bound since the core files have an upper size limit. It's also not doing any
864
         * system call or interacting with the system in any way, besides reading from
865
         * the file descriptor and writing into these four pipes. */
866
        r = safe_fork_full("(sd-parse-elf)",
56✔
867
                           NULL,
868
                           (int[]){ fd, error_pipe[1], return_pipe[1], package_metadata_pipe[1], dlopen_metadata_pipe[1] },
28✔
869
                           5,
870
                           FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_NEW_USERNS|FORK_WAIT|FORK_REOPEN_LOG,
871
                           NULL);
872
        if (r < 0) {
28✔
UNCOV
873
                if (r == -EPROTO) { /* We should have the errno from the child, but don't clobber original error */
×
UNCOV
874
                        ssize_t k;
×
UNCOV
875
                        int e;
×
876

UNCOV
877
                        k = read(error_pipe[0], &e, sizeof(e));
×
878
                        if (k < 0 && errno != EAGAIN) /* Pipe is non-blocking, EAGAIN means there's nothing */
×
UNCOV
879
                                return -errno;
×
UNCOV
880
                        if (k == sizeof(e))
×
UNCOV
881
                                return e; /* propagate error sent to us from child */
×
UNCOV
882
                        if (k != 0)
×
883
                                return -EIO;
884
                }
885

886
                return r;
×
887
        }
888
        if (r == 0) {
28✔
889
                /* We want to avoid loops, given this can be called from systemd-coredump */
890
                if (fork_disable_dump) {
14✔
UNCOV
891
                        r = set_dumpable(SUID_DUMP_DISABLE);
×
UNCOV
892
                        if (r < 0)
×
UNCOV
893
                                report_errno_and_exit(error_pipe[1], r);
×
894
                }
895

896
                r = parse_elf(
30✔
897
                                fd,
898
                                executable,
899
                                root,
900
                                ret ? &buf : NULL,
901
                                ret_package_metadata ? &package_metadata : NULL,
902
                                ret_dlopen_metadata ? &dlopen_metadata : NULL);
903
                if (r < 0)
14✔
UNCOV
904
                        report_errno_and_exit(error_pipe[1], r);
×
905

906
                if (buf) {
14✔
907
                        size_t len = strlen(buf);
12✔
908

909
                        if (len > COREDUMP_PIPE_MAX) {
12✔
910
                                /* This is iffy. A backtrace can be a few hundred kilobytes, but too much is
911
                                 * too much. Let's log a warning and ignore the rest. */
UNCOV
912
                                log_warning("Generated backtrace is %zu bytes (more than the limit of %u bytes), backtrace will be truncated.",
×
913
                                            len, COREDUMP_PIPE_MAX);
914
                                len = COREDUMP_PIPE_MAX;
915
                        }
916

917
                        /* Bump the space for the returned string.
918
                         * Failure is ignored, because partial output is still useful. */
919
                        (void) fcntl(return_pipe[1], F_SETPIPE_SZ, len);
12✔
920

921
                        r = loop_write(return_pipe[1], buf, len);
12✔
922
                        if (r == -EAGAIN)
12✔
UNCOV
923
                                log_warning("Write failed, backtrace will be truncated.");
×
924
                        else if (r < 0)
12✔
UNCOV
925
                                report_errno_and_exit(error_pipe[1], r);
×
926

927
                        return_pipe[1] = safe_close(return_pipe[1]);
12✔
928
                }
929

930
                if (package_metadata) {
14✔
UNCOV
931
                        _cleanup_fclose_ FILE *json_out = NULL;
×
932

933
                        /* Bump the space for the returned string. We don't know how much space we'll need in
934
                         * advance, so we'll just try to write as much as possible and maybe fail later. */
935
                        (void) fcntl(package_metadata_pipe[1], F_SETPIPE_SZ, COREDUMP_PIPE_MAX);
12✔
936

937
                        json_out = take_fdopen(&package_metadata_pipe[1], "w");
12✔
938
                        if (!json_out)
12✔
UNCOV
939
                                report_errno_and_exit(error_pipe[1], -errno);
×
940

941
                        r = sd_json_variant_dump(package_metadata, SD_JSON_FORMAT_FLUSH, json_out, NULL);
12✔
942
                        if (r < 0)
12✔
943
                                log_warning_errno(r, "Failed to write JSON package metadata, ignoring: %m");
12✔
944
                }
945

946
                if (dlopen_metadata) {
14✔
UNCOV
947
                        _cleanup_fclose_ FILE *json_out = NULL;
×
948

949
                        /* Bump the space for the returned string. We don't know how much space we'll need in
950
                         * advance, so we'll just try to write as much as possible and maybe fail later. */
951
                        (void) fcntl(dlopen_metadata_pipe[1], F_SETPIPE_SZ, COREDUMP_PIPE_MAX);
2✔
952

953
                        json_out = take_fdopen(&dlopen_metadata_pipe[1], "w");
2✔
954
                        if (!json_out)
2✔
UNCOV
955
                                report_errno_and_exit(error_pipe[1], -errno);
×
956

957
                        r = sd_json_variant_dump(dlopen_metadata, SD_JSON_FORMAT_FLUSH, json_out, NULL);
2✔
958
                        if (r < 0)
2✔
959
                                log_warning_errno(r, "Failed to write JSON package metadata, ignoring: %m");
2✔
960
                }
961

962
                _exit(EXIT_SUCCESS);
14✔
963
        }
964

965
        error_pipe[1] = safe_close(error_pipe[1]);
14✔
966
        return_pipe[1] = safe_close(return_pipe[1]);
14✔
967
        package_metadata_pipe[1] = safe_close(package_metadata_pipe[1]);
14✔
968
        dlopen_metadata_pipe[1] = safe_close(dlopen_metadata_pipe[1]);
14✔
969

970
        if (ret) {
14✔
UNCOV
971
                _cleanup_fclose_ FILE *in = NULL;
×
972

973
                in = take_fdopen(&return_pipe[0], "r");
12✔
974
                if (!in)
12✔
UNCOV
975
                        return -errno;
×
976

977
                r = read_full_stream(in, &buf, NULL);
12✔
978
                if (r < 0)
12✔
979
                        return r;
980
        }
981

982
        if (ret_package_metadata) {
14✔
UNCOV
983
                _cleanup_fclose_ FILE *json_in = NULL;
×
984

985
                json_in = take_fdopen(&package_metadata_pipe[0], "r");
12✔
986
                if (!json_in)
12✔
UNCOV
987
                        return -errno;
×
988

989
                r = sd_json_parse_file(json_in, NULL, 0, &package_metadata, NULL, NULL);
12✔
990
                if (r < 0 && r != -ENODATA) /* ENODATA: json was empty, so we got nothing, but that's ok */
12✔
991
                        log_warning_errno(r, "Failed to read or parse package metadata, ignoring: %m");
12✔
992
        }
993

994
        if (ret_dlopen_metadata) {
14✔
995
                _cleanup_fclose_ FILE *json_in = NULL;
14✔
996

997
                json_in = take_fdopen(&dlopen_metadata_pipe[0], "r");
2✔
998
                if (!json_in)
2✔
UNCOV
999
                        return -errno;
×
1000

1001
                r = sd_json_parse_file(json_in, NULL, 0, &dlopen_metadata, NULL, NULL);
2✔
1002
                if (r < 0 && r != -ENODATA) /* ENODATA: json was empty, so we got nothing, but that's ok */
2✔
1003
                        log_warning_errno(r, "Failed to read or parse dlopen metadata, ignoring: %m");
2✔
1004
        }
1005

1006
        if (ret)
14✔
1007
                *ret = TAKE_PTR(buf);
12✔
1008
        if (ret_package_metadata)
14✔
1009
                *ret_package_metadata = TAKE_PTR(package_metadata);
12✔
1010
        if (ret_dlopen_metadata)
14✔
1011
                *ret_dlopen_metadata = TAKE_PTR(dlopen_metadata);
2✔
1012

1013
        return 0;
1014
#else
1015
        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "elfutils disabled, parsing ELF objects not supported");
1016
#endif
1017
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc