1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include <elfutils/libdwelf.h>
7 #include <elfutils/libdwfl.h>
10 #include <sys/resource.h>
11 #include <sys/types.h>
14 #include "alloc-util.h"
15 #include "dlfcn-util.h"
17 #include "errno-util.h"
20 #include "format-util.h"
21 #include "hexdecoct.h"
24 #include "process-util.h"
25 #include "rlimit-util.h"
26 #include "string-util.h"
30 #define THREADS_MAX 64
31 #define ELF_PACKAGE_METADATA_ID 0xcafe1a7e
33 static void *dw_dl
= NULL
;
34 static void *elf_dl
= NULL
;
37 Dwarf_Attribute
*(*sym_dwarf_attr_integrate
)(Dwarf_Die
*, unsigned int, Dwarf_Attribute
*);
38 const char *(*sym_dwarf_diename
)(Dwarf_Die
*);
39 const char *(*sym_dwarf_formstring
)(Dwarf_Attribute
*);
40 int (*sym_dwarf_getscopes
)(Dwarf_Die
*, Dwarf_Addr
, Dwarf_Die
**);
41 int (*sym_dwarf_getscopes_die
)(Dwarf_Die
*, Dwarf_Die
**);
42 Elf
*(*sym_dwelf_elf_begin
)(int);
43 #if HAVE_DWELF_ELF_E_MACHINE_STRING
44 const char *(*sym_dwelf_elf_e_machine_string
)(int);
46 ssize_t (*sym_dwelf_elf_gnu_build_id
)(Elf
*, const void **);
47 int (*sym_dwarf_tag
)(Dwarf_Die
*);
48 Dwfl_Module
*(*sym_dwfl_addrmodule
)(Dwfl
*, Dwarf_Addr
);
49 Dwfl
*(*sym_dwfl_begin
)(const Dwfl_Callbacks
*);
50 int (*sym_dwfl_build_id_find_elf
)(Dwfl_Module
*, void **, const char *, Dwarf_Addr
, char **, Elf
**);
51 int (*sym_dwfl_core_file_attach
)(Dwfl
*, Elf
*);
52 int (*sym_dwfl_core_file_report
)(Dwfl
*, Elf
*, const char *);
53 void (*sym_dwfl_end
)(Dwfl
*);
54 const char *(*sym_dwfl_errmsg
)(int);
55 int (*sym_dwfl_errno
)(void);
56 bool (*sym_dwfl_frame_pc
)(Dwfl_Frame
*, Dwarf_Addr
*, bool *);
57 ptrdiff_t (*sym_dwfl_getmodules
)(Dwfl
*, int (*)(Dwfl_Module
*, void **, const char *, Dwarf_Addr
, void *), void *, ptrdiff_t);
58 int (*sym_dwfl_getthreads
)(Dwfl
*, int (*)(Dwfl_Thread
*, void *), void *);
59 Dwarf_Die
*(*sym_dwfl_module_addrdie
)(Dwfl_Module
*, Dwarf_Addr
, Dwarf_Addr
*);
60 const char *(*sym_dwfl_module_addrname
)(Dwfl_Module
*, GElf_Addr
);
61 int (*sym_dwfl_module_build_id
)(Dwfl_Module
*, const unsigned char **, GElf_Addr
*);
62 Elf
*(*sym_dwfl_module_getelf
)(Dwfl_Module
*, GElf_Addr
*);
63 const char *(*sym_dwfl_module_info
)(Dwfl_Module
*, void ***, Dwarf_Addr
*, Dwarf_Addr
*, Dwarf_Addr
*, Dwarf_Addr
*, const char **, const char **);
64 int (*sym_dwfl_offline_section_address
)(Dwfl_Module
*, void **, const char *, Dwarf_Addr
, const char *, GElf_Word
, const GElf_Shdr
*, Dwarf_Addr
*);
65 int (*sym_dwfl_report_end
)(Dwfl
*, int (*)(Dwfl_Module
*, void *, const char *, Dwarf_Addr
, void *), void *);
66 int (*sym_dwfl_standard_find_debuginfo
)(Dwfl_Module
*, void **, const char *, Dwarf_Addr
, const char *, const char *, GElf_Word
, char **);
67 int (*sym_dwfl_thread_getframes
)(Dwfl_Thread
*, int (*)(Dwfl_Frame
*, void *), void *);
68 pid_t (*sym_dwfl_thread_tid
)(Dwfl_Thread
*);
71 Elf
*(*sym_elf_begin
)(int, Elf_Cmd
, Elf
*);
72 int (*sym_elf_end
)(Elf
*);
73 Elf_Data
*(*sym_elf_getdata_rawchunk
)(Elf
*, int64_t, size_t, Elf_Type
);
74 GElf_Ehdr
*(*sym_gelf_getehdr
)(Elf
*, GElf_Ehdr
*);
75 int (*sym_elf_getphdrnum
)(Elf
*, size_t *);
76 const char *(*sym_elf_errmsg
)(int);
77 int (*sym_elf_errno
)(void);
78 Elf
*(*sym_elf_memory
)(char *, size_t);
79 unsigned int (*sym_elf_version
)(unsigned int);
80 GElf_Phdr
*(*sym_gelf_getphdr
)(Elf
*, int, GElf_Phdr
*);
81 size_t (*sym_gelf_getnote
)(Elf_Data
*, size_t, GElf_Nhdr
*, size_t *, size_t *);
86 r
= dlopen_many_sym_or_warn(
87 &dw_dl
, "libdw.so.1", LOG_DEBUG
,
88 DLSYM_ARG(dwarf_getscopes
),
89 DLSYM_ARG(dwarf_getscopes_die
),
91 DLSYM_ARG(dwarf_attr_integrate
),
92 DLSYM_ARG(dwarf_formstring
),
93 DLSYM_ARG(dwarf_diename
),
94 DLSYM_ARG(dwelf_elf_gnu_build_id
),
95 DLSYM_ARG(dwelf_elf_begin
),
96 #if HAVE_DWELF_ELF_E_MACHINE_STRING
97 DLSYM_ARG(dwelf_elf_e_machine_string
),
99 DLSYM_ARG(dwfl_addrmodule
),
100 DLSYM_ARG(dwfl_frame_pc
),
101 DLSYM_ARG(dwfl_module_addrdie
),
102 DLSYM_ARG(dwfl_module_addrname
),
103 DLSYM_ARG(dwfl_module_info
),
104 DLSYM_ARG(dwfl_module_build_id
),
105 DLSYM_ARG(dwfl_module_getelf
),
106 DLSYM_ARG(dwfl_begin
),
107 DLSYM_ARG(dwfl_core_file_report
),
108 DLSYM_ARG(dwfl_report_end
),
109 DLSYM_ARG(dwfl_getmodules
),
110 DLSYM_ARG(dwfl_core_file_attach
),
112 DLSYM_ARG(dwfl_errmsg
),
113 DLSYM_ARG(dwfl_errno
),
114 DLSYM_ARG(dwfl_build_id_find_elf
),
115 DLSYM_ARG(dwfl_standard_find_debuginfo
),
116 DLSYM_ARG(dwfl_thread_tid
),
117 DLSYM_ARG(dwfl_thread_getframes
),
118 DLSYM_ARG(dwfl_getthreads
),
119 DLSYM_ARG(dwfl_offline_section_address
));
126 int dlopen_elf(void) {
129 r
= dlopen_many_sym_or_warn(
130 &elf_dl
, "libelf.so.1", LOG_DEBUG
,
131 DLSYM_ARG(elf_begin
),
133 DLSYM_ARG(elf_getphdrnum
),
134 DLSYM_ARG(elf_getdata_rawchunk
),
135 DLSYM_ARG(elf_errmsg
),
136 DLSYM_ARG(elf_errno
),
137 DLSYM_ARG(elf_memory
),
138 DLSYM_ARG(elf_version
),
139 DLSYM_ARG(gelf_getehdr
),
140 DLSYM_ARG(gelf_getphdr
),
141 DLSYM_ARG(gelf_getnote
));
148 typedef struct StackContext
{
154 JsonVariant
**package_metadata
;
158 static StackContext
* stack_context_destroy(StackContext
*c
) {
162 c
->f
= safe_fclose(c
->f
);
165 sym_dwfl_end(c
->dwfl
);
177 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(Elf
*, sym_elf_end
, NULL
);
179 static int frame_callback(Dwfl_Frame
*frame
, void *userdata
) {
180 StackContext
*c
= ASSERT_PTR(userdata
);
181 Dwarf_Addr pc
, pc_adjusted
;
182 const char *fname
= NULL
, *symbol
= NULL
;
185 uint64_t module_offset
= 0;
189 if (c
->n_frame
>= FRAMES_MAX
)
190 return DWARF_CB_ABORT
;
192 if (!sym_dwfl_frame_pc(frame
, &pc
, &is_activation
))
193 return DWARF_CB_ABORT
;
195 pc_adjusted
= pc
- (is_activation
? 0 : 1);
197 module
= sym_dwfl_addrmodule(c
->dwfl
, pc_adjusted
);
199 Dwarf_Addr start
, bias
= 0;
202 cudie
= sym_dwfl_module_addrdie(module
, pc_adjusted
, &bias
);
204 _cleanup_free_ Dwarf_Die
*scopes
= NULL
;
207 n
= sym_dwarf_getscopes(cudie
, pc_adjusted
- bias
, &scopes
);
209 for (Dwarf_Die
*s
= scopes
; s
&& s
< scopes
+ n
; s
++) {
210 Dwarf_Attribute
*a
, space
;
212 if (!IN_SET(sym_dwarf_tag(s
), DW_TAG_subprogram
, DW_TAG_inlined_subroutine
, DW_TAG_entry_point
))
215 a
= sym_dwarf_attr_integrate(s
, DW_AT_MIPS_linkage_name
, &space
);
217 a
= sym_dwarf_attr_integrate(s
, DW_AT_linkage_name
, &space
);
219 symbol
= sym_dwarf_formstring(a
);
221 symbol
= sym_dwarf_diename(s
);
229 symbol
= sym_dwfl_module_addrname(module
, pc_adjusted
);
231 fname
= sym_dwfl_module_info(module
, NULL
, &start
, NULL
, NULL
, NULL
, NULL
, NULL
);
232 module_offset
= pc
- start
;
236 fprintf(c
->f
, "#%-2u 0x%016" PRIx64
" %s (%s + 0x%" PRIx64
")\n", c
->n_frame
, (uint64_t) pc
, strna(symbol
), strna(fname
), module_offset
);
242 static int thread_callback(Dwfl_Thread
*thread
, void *userdata
) {
243 StackContext
*c
= ASSERT_PTR(userdata
);
248 if (c
->n_thread
>= THREADS_MAX
)
249 return DWARF_CB_ABORT
;
251 if (c
->n_thread
!= 0 && c
->f
)
257 tid
= sym_dwfl_thread_tid(thread
);
258 fprintf(c
->f
, "Stack trace of thread " PID_FMT
":\n", tid
);
261 if (sym_dwfl_thread_getframes(thread
, frame_callback
, c
) < 0)
262 return DWARF_CB_ABORT
;
269 static int parse_package_metadata(const char *name
, JsonVariant
*id_json
, Elf
*elf
, bool *ret_interpreter_found
, StackContext
*c
) {
270 bool interpreter_found
= false;
271 size_t n_program_headers
;
278 /* When iterating over PT_LOAD we will visit modules more than once */
279 if (set_contains(*c
->modules
, name
))
282 r
= sym_elf_getphdrnum(elf
, &n_program_headers
);
283 if (r
< 0) /* Not the handle we are looking for - that's ok, skip it */
286 /* Iterate over all program headers in that ELF object. These will have been copied by
287 * the kernel verbatim when the core file is generated. */
288 for (size_t i
= 0; i
< n_program_headers
; ++i
) {
289 GElf_Phdr mem
, *program_header
;
290 GElf_Nhdr note_header
;
293 /* Package metadata is in PT_NOTE headers. */
294 program_header
= sym_gelf_getphdr(elf
, i
, &mem
);
295 if (!program_header
|| (program_header
->p_type
!= PT_NOTE
&& program_header
->p_type
!= PT_INTERP
))
298 if (program_header
->p_type
== PT_INTERP
) {
299 interpreter_found
= true;
303 /* Fortunately there is an iterator we can use to walk over the
304 * elements of a PT_NOTE program header. We are interested in the
306 data
= sym_elf_getdata_rawchunk(elf
,
307 program_header
->p_offset
,
308 program_header
->p_filesz
,
313 for (size_t note_offset
= 0, name_offset
, desc_offset
;
314 note_offset
< data
->d_size
&&
315 (note_offset
= sym_gelf_getnote(data
, note_offset
, ¬e_header
, &name_offset
, &desc_offset
)) > 0;) {
317 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
, *w
= NULL
;
318 const char *note_name
= (const char *)data
->d_buf
+ name_offset
;
319 const char *payload
= (const char *)data
->d_buf
+ desc_offset
;
321 if (note_header
.n_namesz
== 0 || note_header
.n_descsz
== 0)
324 /* Package metadata might have different owners, but the
325 * magic ID is always the same. */
326 if (note_header
.n_type
!= ELF_PACKAGE_METADATA_ID
)
329 r
= json_parse(payload
, 0, &v
, NULL
, NULL
);
331 return log_error_errno(r
, "json_parse on %s failed: %m", payload
);
333 /* First pretty-print to the buffer, so that the metadata goes as
334 * plaintext in the journal. */
336 fprintf(c
->f
, "Metadata for module %s owned by %s found: ",
338 json_variant_dump(v
, JSON_FORMAT_NEWLINE
|JSON_FORMAT_PRETTY
, c
->f
, NULL
);
342 /* Secondly, if we have a build-id, merge it in the same JSON object
343 * so that it appears all nicely together in the logs/metadata. */
345 r
= json_variant_merge(&v
, id_json
);
347 return log_error_errno(r
, "json_variant_merge of package meta with buildid failed: %m");
350 /* Then we build a new object using the module name as the key, and merge it
351 * with the previous parses, so that in the end it all fits together in a single
353 r
= json_build(&w
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR(name
, JSON_BUILD_VARIANT(v
))));
355 return log_error_errno(r
, "Failed to build JSON object: %m");
357 r
= json_variant_merge(c
->package_metadata
, w
);
359 return log_error_errno(r
, "json_variant_merge of package meta with buildid failed: %m");
361 /* Finally stash the name, so we avoid double visits. */
362 r
= set_put_strdup(c
->modules
, name
);
364 return log_error_errno(r
, "set_put_strdup failed: %m");
366 if (ret_interpreter_found
)
367 *ret_interpreter_found
= interpreter_found
;
373 if (ret_interpreter_found
)
374 *ret_interpreter_found
= interpreter_found
;
376 /* Didn't find package metadata for this module - that's ok, just go to the next. */
380 /* Get the build-id out of an ELF object or a dwarf core module. */
381 static int parse_buildid(Dwfl_Module
*mod
, Elf
*elf
, const char *name
, StackContext
*c
, JsonVariant
**ret_id_json
) {
382 _cleanup_(json_variant_unrefp
) JsonVariant
*id_json
= NULL
;
383 const unsigned char *id
;
393 id_len
= sym_dwfl_module_build_id(mod
, &id
, &id_vaddr
);
395 id_len
= sym_dwelf_elf_gnu_build_id(elf
, (const void **)&id
);
397 /* If we don't find a build-id, note it in the journal message, and try
398 * anyway to find the package metadata. It's unlikely to have the latter
399 * without the former, but there's no hard rule. */
401 fprintf(c
->f
, "Module %s without build-id.\n", name
);
403 /* We will later parse package metadata json and pass it to our caller. Prepare the
404 * build-id in json format too, so that it can be appended and parsed cleanly. It
405 * will then be added as metadata to the journal message with the stack trace. */
406 r
= json_build(&id_json
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("buildId", JSON_BUILD_HEX(id
, id_len
))));
408 return log_error_errno(r
, "json_build on build-id failed: %m");
411 JsonVariant
*build_id
= json_variant_by_key(id_json
, "buildId");
413 fprintf(c
->f
, "Module %s with build-id %s\n", name
, json_variant_string(build_id
));
418 *ret_id_json
= TAKE_PTR(id_json
);
423 static int module_callback(Dwfl_Module
*mod
, void **userdata
, const char *name
, Dwarf_Addr start
, void *arg
) {
424 _cleanup_(json_variant_unrefp
) JsonVariant
*id_json
= NULL
;
425 StackContext
*c
= ASSERT_PTR(arg
);
426 size_t n_program_headers
;
434 name
= "(unnamed)"; /* For logging purposes */
436 /* We are iterating on each "module", which is what dwfl calls ELF objects contained in the
437 * core file, and extracting the build-id first and then the package metadata.
438 * We proceed in a best-effort fashion - not all ELF objects might contain both or either.
439 * The build-id is easy, as libdwfl parses it during the sym_dwfl_core_file_report() call and
440 * stores it separately in an internal library struct. */
441 r
= parse_buildid(mod
, NULL
, name
, c
, &id_json
);
443 return DWARF_CB_ABORT
;
445 /* The .note.package metadata is more difficult. From the module, we need to get a reference
446 * to the ELF object first. We might be lucky and just get it from elfutils. */
447 elf
= sym_dwfl_module_getelf(mod
, &bias
);
449 r
= parse_package_metadata(name
, id_json
, elf
, NULL
, c
);
451 return DWARF_CB_ABORT
;
457 /* We did not get the ELF object, or it's just a reference to the core. That is likely
458 * because we didn't get direct access to the executable, and the version of elfutils does
459 * not yet support parsing it out of the core file directly.
460 * So fallback to manual extraction - get the PT_LOAD section from the core,
461 * and if it's the right one we can interpret it as an Elf object, and parse
462 * its notes manually. */
464 r
= sym_elf_getphdrnum(elf
, &n_program_headers
);
466 log_warning("Could not parse number of program headers from core file: %s",
467 sym_elf_errmsg(-1)); /* -1 retrieves the most recent error */
471 for (size_t i
= 0; i
< n_program_headers
; ++i
) {
472 GElf_Phdr mem
, *program_header
;
475 /* The core file stores the ELF files in the PT_LOAD segment. */
476 program_header
= sym_gelf_getphdr(elf
, i
, &mem
);
477 if (!program_header
|| program_header
->p_type
!= PT_LOAD
)
480 /* Now get a usable Elf reference, and parse the notes from it. */
481 data
= sym_elf_getdata_rawchunk(elf
,
482 program_header
->p_offset
,
483 program_header
->p_filesz
,
488 _cleanup_(sym_elf_endp
) Elf
*memelf
= sym_elf_memory(data
->d_buf
, data
->d_size
);
491 r
= parse_package_metadata(name
, id_json
, memelf
, NULL
, c
);
493 return DWARF_CB_ABORT
;
501 static int parse_core(int fd
, const char *executable
, char **ret
, JsonVariant
**ret_package_metadata
) {
503 const Dwfl_Callbacks callbacks
= {
504 .find_elf
= sym_dwfl_build_id_find_elf
,
505 .section_address
= sym_dwfl_offline_section_address
,
506 .find_debuginfo
= sym_dwfl_standard_find_debuginfo
,
509 _cleanup_(json_variant_unrefp
) JsonVariant
*package_metadata
= NULL
;
510 _cleanup_(set_freep
) Set
*modules
= NULL
;
511 _cleanup_free_
char *buf
= NULL
; /* buf should be freed last, c.f closed first (via stack_context_destroy) */
512 _cleanup_(stack_context_destroy
) StackContext c
= {
513 .package_metadata
= &package_metadata
,
521 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1)
522 return log_warning_errno(errno
, "Failed to seek to beginning of the core file: %m");
525 c
.f
= open_memstream_unlocked(&buf
, &sz
);
530 sym_elf_version(EV_CURRENT
);
532 c
.elf
= sym_elf_begin(fd
, ELF_C_READ_MMAP
, NULL
);
534 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse core file, elf_begin() failed: %s", sym_elf_errmsg(sym_elf_errno()));
536 c
.dwfl
= sym_dwfl_begin(&callbacks
);
538 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse core file, dwfl_begin() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
540 if (sym_dwfl_core_file_report(c
.dwfl
, c
.elf
, executable
) < 0)
541 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse core file, dwfl_core_file_report() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
543 if (sym_dwfl_report_end(c
.dwfl
, NULL
, NULL
) != 0)
544 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse core file, dwfl_report_end() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
546 if (sym_dwfl_getmodules(c
.dwfl
, &module_callback
, &c
, 0) < 0)
547 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse core file, dwfl_getmodules() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
549 if (sym_dwfl_core_file_attach(c
.dwfl
, c
.elf
) < 0)
550 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse core file, dwfl_core_file_attach() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
552 if (sym_dwfl_getthreads(c
.dwfl
, thread_callback
, &c
) < 0)
553 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse core file, dwfl_getthreads() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
556 r
= fflush_and_check(c
.f
);
558 return log_warning_errno(r
, "Could not parse core file, flushing file buffer failed: %m");
560 c
.f
= safe_fclose(c
.f
);
561 *ret
= TAKE_PTR(buf
);
563 if (ret_package_metadata
)
564 *ret_package_metadata
= TAKE_PTR(package_metadata
);
569 static int parse_elf(int fd
, const char *executable
, char **ret
, JsonVariant
**ret_package_metadata
) {
570 _cleanup_(json_variant_unrefp
) JsonVariant
*package_metadata
= NULL
, *elf_metadata
= NULL
;
571 _cleanup_(set_freep
) Set
*modules
= NULL
;
572 _cleanup_free_
char *buf
= NULL
; /* buf should be freed last, c.f closed first (via stack_context_destroy) */
573 _cleanup_(stack_context_destroy
) StackContext c
= {
574 .package_metadata
= &package_metadata
,
577 const char *elf_type
;
578 GElf_Ehdr elf_header
;
584 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1)
585 return log_warning_errno(errno
, "Failed to seek to beginning of the ELF file: %m");
588 c
.f
= open_memstream_unlocked(&buf
, &sz
);
593 sym_elf_version(EV_CURRENT
);
595 c
.elf
= sym_elf_begin(fd
, ELF_C_READ_MMAP
, NULL
);
597 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse ELF file, elf_begin() failed: %s", sym_elf_errmsg(sym_elf_errno()));
599 if (!sym_gelf_getehdr(c
.elf
, &elf_header
))
600 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse ELF file, gelf_getehdr() failed: %s", sym_elf_errmsg(sym_elf_errno()));
602 if (elf_header
.e_type
== ET_CORE
) {
603 _cleanup_free_
char *out
= NULL
;
605 r
= parse_core(fd
, executable
, ret
? &out
: NULL
, &package_metadata
);
607 return log_warning_errno(r
, "Failed to inspect core file: %m");
610 fprintf(c
.f
, "%s", out
);
612 elf_type
= "coredump";
614 _cleanup_(json_variant_unrefp
) JsonVariant
*id_json
= NULL
;
615 const char *e
= executable
?: "(unnamed)";
616 bool interpreter_found
= false;
618 r
= parse_buildid(NULL
, c
.elf
, e
, &c
, &id_json
);
620 return log_warning_errno(r
, "Failed to parse build-id of ELF file: %m");
622 r
= parse_package_metadata(e
, id_json
, c
.elf
, &interpreter_found
, &c
);
624 return log_warning_errno(r
, "Failed to parse package metadata of ELF file: %m");
626 /* If we found a build-id and nothing else, return at least that. */
627 if (!package_metadata
&& id_json
) {
628 r
= json_build(&package_metadata
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR(e
, JSON_BUILD_VARIANT(id_json
))));
630 return log_warning_errno(r
, "Failed to build JSON object: %m");
633 if (interpreter_found
)
634 elf_type
= "executable";
636 elf_type
= "library";
639 /* Note that e_type is always DYN for both executables and libraries, so we can't tell them apart from the header,
640 * but we will search for the PT_INTERP section when parsing the metadata. */
641 r
= json_build(&elf_metadata
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("elfType", JSON_BUILD_STRING(elf_type
))));
643 return log_warning_errno(r
, "Failed to build JSON object: %m");
645 #if HAVE_DWELF_ELF_E_MACHINE_STRING
646 const char *elf_architecture
= sym_dwelf_elf_e_machine_string(elf_header
.e_machine
);
647 if (elf_architecture
) {
648 _cleanup_(json_variant_unrefp
) JsonVariant
*json_architecture
= NULL
;
650 r
= json_build(&json_architecture
,
651 JSON_BUILD_OBJECT(JSON_BUILD_PAIR("elfArchitecture", JSON_BUILD_STRING(elf_architecture
))));
653 return log_warning_errno(r
, "Failed to build JSON object: %m");
655 r
= json_variant_merge(&elf_metadata
, json_architecture
);
657 return log_warning_errno(r
, "Failed to merge JSON objects: %m");
660 fprintf(c
.f
, "ELF object binary architecture: %s\n", elf_architecture
);
664 /* We always at least have the ELF type, so merge that (and possibly the arch). */
665 r
= json_variant_merge(&elf_metadata
, package_metadata
);
667 return log_warning_errno(r
, "Failed to merge JSON objects: %m");
670 r
= fflush_and_check(c
.f
);
672 return log_warning_errno(r
, "Could not parse ELF file, flushing file buffer failed: %m");
674 c
.f
= safe_fclose(c
.f
);
675 *ret
= TAKE_PTR(buf
);
677 if (ret_package_metadata
)
678 *ret_package_metadata
= TAKE_PTR(elf_metadata
);
683 int parse_elf_object(int fd
, const char *executable
, bool fork_disable_dump
, char **ret
, JsonVariant
**ret_package_metadata
) {
684 _cleanup_close_pair_
int error_pipe
[2] = { -1, -1 }, return_pipe
[2] = { -1, -1 }, json_pipe
[2] = { -1, -1 };
685 _cleanup_(json_variant_unrefp
) JsonVariant
*package_metadata
= NULL
;
686 _cleanup_free_
char *buf
= NULL
;
699 r
= RET_NERRNO(pipe2(error_pipe
, O_CLOEXEC
|O_NONBLOCK
));
704 r
= RET_NERRNO(pipe2(return_pipe
, O_CLOEXEC
));
709 if (ret_package_metadata
) {
710 r
= RET_NERRNO(pipe2(json_pipe
, O_CLOEXEC
));
715 /* Parsing possibly malformed data is crash-happy, so fork. In case we crash,
716 * the core file will not be lost, and the messages will still be attached to
717 * the journal. Reading the elf object might be slow, but it still has an upper
718 * bound since the core files have an upper size limit. It's also not doing any
719 * system call or interacting with the system in any way, besides reading from
720 * the file descriptor and writing into these four pipes. */
721 r
= safe_fork_full("(sd-parse-elf)",
722 (int[]){ fd
, error_pipe
[1], return_pipe
[1], json_pipe
[1] },
724 FORK_RESET_SIGNALS
|FORK_CLOSE_ALL_FDS
|FORK_NEW_MOUNTNS
|FORK_MOUNTNS_SLAVE
|FORK_NEW_USERNS
|FORK_WAIT
|FORK_REOPEN_LOG
,
727 if (r
== -EPROTO
) { /* We should have the errno from the child, but don't clobber original error */
730 k
= read(error_pipe
[0], &e
, sizeof(e
));
731 if (k
< 0 && errno
!= EAGAIN
) /* Pipe is non-blocking, EAGAIN means there's nothing */
734 return e
; /* propagate error sent to us from child */
742 /* We want to avoid loops, given this can be called from systemd-coredump */
743 if (fork_disable_dump
) {
744 r
= RET_NERRNO(prctl(PR_SET_DUMPABLE
, 0));
749 r
= parse_elf(fd
, executable
, ret
? &buf
: NULL
, ret_package_metadata
? &package_metadata
: NULL
);
754 r
= loop_write(return_pipe
[1], buf
, strlen(buf
), false);
758 return_pipe
[1] = safe_close(return_pipe
[1]);
761 if (package_metadata
) {
762 _cleanup_fclose_
FILE *json_out
= NULL
;
764 json_out
= take_fdopen(&json_pipe
[1], "w");
770 json_variant_dump(package_metadata
, JSON_FORMAT_FLUSH
, json_out
, NULL
);
776 (void) write(error_pipe
[1], &r
, sizeof(r
));
780 error_pipe
[1] = safe_close(error_pipe
[1]);
781 return_pipe
[1] = safe_close(return_pipe
[1]);
782 json_pipe
[1] = safe_close(json_pipe
[1]);
785 _cleanup_fclose_
FILE *in
= NULL
;
787 in
= take_fdopen(&return_pipe
[0], "r");
791 r
= read_full_stream(in
, &buf
, NULL
);
796 if (ret_package_metadata
) {
797 _cleanup_fclose_
FILE *json_in
= NULL
;
799 json_in
= take_fdopen(&json_pipe
[0], "r");
803 r
= json_parse_file(json_in
, NULL
, 0, &package_metadata
, NULL
, NULL
);
804 if (r
< 0 && r
!= -EINVAL
) /* EINVAL: json was empty, so we got nothing, but that's ok */
809 *ret
= TAKE_PTR(buf
);
810 if (ret_package_metadata
)
811 *ret_package_metadata
= TAKE_PTR(package_metadata
);