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"
21 #include "format-util.h"
22 #include "hexdecoct.h"
25 #include "process-util.h"
26 #include "rlimit-util.h"
27 #include "string-util.h"
30 #define THREADS_MAX 64
31 #define ELF_PACKAGE_METADATA_ID 0xcafe1a7e
33 /* The amount of data we're willing to write to each of the output pipes. */
34 #define COREDUMP_PIPE_MAX (1024*1024U)
36 static void *dw_dl
= NULL
;
37 static void *elf_dl
= NULL
;
40 Dwarf_Attribute
*(*sym_dwarf_attr_integrate
)(Dwarf_Die
*, unsigned int, Dwarf_Attribute
*);
41 const char *(*sym_dwarf_diename
)(Dwarf_Die
*);
42 const char *(*sym_dwarf_formstring
)(Dwarf_Attribute
*);
43 int (*sym_dwarf_getscopes
)(Dwarf_Die
*, Dwarf_Addr
, Dwarf_Die
**);
44 int (*sym_dwarf_getscopes_die
)(Dwarf_Die
*, Dwarf_Die
**);
45 Elf
*(*sym_dwelf_elf_begin
)(int);
46 #if HAVE_DWELF_ELF_E_MACHINE_STRING
47 const char *(*sym_dwelf_elf_e_machine_string
)(int);
49 ssize_t (*sym_dwelf_elf_gnu_build_id
)(Elf
*, const void **);
50 int (*sym_dwarf_tag
)(Dwarf_Die
*);
51 Dwfl_Module
*(*sym_dwfl_addrmodule
)(Dwfl
*, Dwarf_Addr
);
52 Dwfl
*(*sym_dwfl_begin
)(const Dwfl_Callbacks
*);
53 int (*sym_dwfl_build_id_find_elf
)(Dwfl_Module
*, void **, const char *, Dwarf_Addr
, char **, Elf
**);
54 int (*sym_dwfl_core_file_attach
)(Dwfl
*, Elf
*);
55 int (*sym_dwfl_core_file_report
)(Dwfl
*, Elf
*, const char *);
56 void (*sym_dwfl_end
)(Dwfl
*);
57 const char *(*sym_dwfl_errmsg
)(int);
58 int (*sym_dwfl_errno
)(void);
59 bool (*sym_dwfl_frame_pc
)(Dwfl_Frame
*, Dwarf_Addr
*, bool *);
60 ptrdiff_t (*sym_dwfl_getmodules
)(Dwfl
*, int (*)(Dwfl_Module
*, void **, const char *, Dwarf_Addr
, void *), void *, ptrdiff_t);
61 int (*sym_dwfl_getthreads
)(Dwfl
*, int (*)(Dwfl_Thread
*, void *), void *);
62 Dwarf_Die
*(*sym_dwfl_module_addrdie
)(Dwfl_Module
*, Dwarf_Addr
, Dwarf_Addr
*);
63 const char *(*sym_dwfl_module_addrname
)(Dwfl_Module
*, GElf_Addr
);
64 int (*sym_dwfl_module_build_id
)(Dwfl_Module
*, const unsigned char **, GElf_Addr
*);
65 Elf
*(*sym_dwfl_module_getelf
)(Dwfl_Module
*, GElf_Addr
*);
66 const char *(*sym_dwfl_module_info
)(Dwfl_Module
*, void ***, Dwarf_Addr
*, Dwarf_Addr
*, Dwarf_Addr
*, Dwarf_Addr
*, const char **, const char **);
67 int (*sym_dwfl_offline_section_address
)(Dwfl_Module
*, void **, const char *, Dwarf_Addr
, const char *, GElf_Word
, const GElf_Shdr
*, Dwarf_Addr
*);
68 int (*sym_dwfl_report_end
)(Dwfl
*, int (*)(Dwfl_Module
*, void *, const char *, Dwarf_Addr
, void *), void *);
69 int (*sym_dwfl_standard_find_debuginfo
)(Dwfl_Module
*, void **, const char *, Dwarf_Addr
, const char *, const char *, GElf_Word
, char **);
70 int (*sym_dwfl_thread_getframes
)(Dwfl_Thread
*, int (*)(Dwfl_Frame
*, void *), void *);
71 pid_t (*sym_dwfl_thread_tid
)(Dwfl_Thread
*);
74 Elf
*(*sym_elf_begin
)(int, Elf_Cmd
, Elf
*);
75 int (*sym_elf_end
)(Elf
*);
76 Elf_Data
*(*sym_elf_getdata_rawchunk
)(Elf
*, int64_t, size_t, Elf_Type
);
77 GElf_Ehdr
*(*sym_gelf_getehdr
)(Elf
*, GElf_Ehdr
*);
78 int (*sym_elf_getphdrnum
)(Elf
*, size_t *);
79 const char *(*sym_elf_errmsg
)(int);
80 int (*sym_elf_errno
)(void);
81 Elf
*(*sym_elf_memory
)(char *, size_t);
82 unsigned int (*sym_elf_version
)(unsigned int);
83 GElf_Phdr
*(*sym_gelf_getphdr
)(Elf
*, int, GElf_Phdr
*);
84 size_t (*sym_gelf_getnote
)(Elf_Data
*, size_t, GElf_Nhdr
*, size_t *, size_t *);
89 r
= dlopen_many_sym_or_warn(
90 &dw_dl
, "libdw.so.1", LOG_DEBUG
,
91 DLSYM_ARG(dwarf_getscopes
),
92 DLSYM_ARG(dwarf_getscopes_die
),
94 DLSYM_ARG(dwarf_attr_integrate
),
95 DLSYM_ARG(dwarf_formstring
),
96 DLSYM_ARG(dwarf_diename
),
97 DLSYM_ARG(dwelf_elf_gnu_build_id
),
98 DLSYM_ARG(dwelf_elf_begin
),
99 #if HAVE_DWELF_ELF_E_MACHINE_STRING
100 DLSYM_ARG(dwelf_elf_e_machine_string
),
102 DLSYM_ARG(dwfl_addrmodule
),
103 DLSYM_ARG(dwfl_frame_pc
),
104 DLSYM_ARG(dwfl_module_addrdie
),
105 DLSYM_ARG(dwfl_module_addrname
),
106 DLSYM_ARG(dwfl_module_info
),
107 DLSYM_ARG(dwfl_module_build_id
),
108 DLSYM_ARG(dwfl_module_getelf
),
109 DLSYM_ARG(dwfl_begin
),
110 DLSYM_ARG(dwfl_core_file_report
),
111 DLSYM_ARG(dwfl_report_end
),
112 DLSYM_ARG(dwfl_getmodules
),
113 DLSYM_ARG(dwfl_core_file_attach
),
115 DLSYM_ARG(dwfl_errmsg
),
116 DLSYM_ARG(dwfl_errno
),
117 DLSYM_ARG(dwfl_build_id_find_elf
),
118 DLSYM_ARG(dwfl_standard_find_debuginfo
),
119 DLSYM_ARG(dwfl_thread_tid
),
120 DLSYM_ARG(dwfl_thread_getframes
),
121 DLSYM_ARG(dwfl_getthreads
),
122 DLSYM_ARG(dwfl_offline_section_address
));
129 int dlopen_elf(void) {
132 r
= dlopen_many_sym_or_warn(
133 &elf_dl
, "libelf.so.1", LOG_DEBUG
,
134 DLSYM_ARG(elf_begin
),
136 DLSYM_ARG(elf_getphdrnum
),
137 DLSYM_ARG(elf_getdata_rawchunk
),
138 DLSYM_ARG(elf_errmsg
),
139 DLSYM_ARG(elf_errno
),
140 DLSYM_ARG(elf_memory
),
141 DLSYM_ARG(elf_version
),
142 DLSYM_ARG(gelf_getehdr
),
143 DLSYM_ARG(gelf_getphdr
),
144 DLSYM_ARG(gelf_getnote
));
151 typedef struct StackContext
{
157 JsonVariant
**package_metadata
;
161 static StackContext
* stack_context_destroy(StackContext
*c
) {
165 c
->f
= safe_fclose(c
->f
);
168 sym_dwfl_end(c
->dwfl
);
180 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(Elf
*, sym_elf_end
, NULL
);
182 static int frame_callback(Dwfl_Frame
*frame
, void *userdata
) {
183 StackContext
*c
= ASSERT_PTR(userdata
);
184 Dwarf_Addr pc
, pc_adjusted
;
185 const char *fname
= NULL
, *symbol
= NULL
;
188 uint64_t module_offset
= 0;
192 if (c
->n_frame
>= FRAMES_MAX
)
193 return DWARF_CB_ABORT
;
195 if (!sym_dwfl_frame_pc(frame
, &pc
, &is_activation
))
196 return DWARF_CB_ABORT
;
198 pc_adjusted
= pc
- (is_activation
? 0 : 1);
200 module
= sym_dwfl_addrmodule(c
->dwfl
, pc_adjusted
);
202 Dwarf_Addr start
, bias
= 0;
205 cudie
= sym_dwfl_module_addrdie(module
, pc_adjusted
, &bias
);
207 _cleanup_free_ Dwarf_Die
*scopes
= NULL
;
210 n
= sym_dwarf_getscopes(cudie
, pc_adjusted
- bias
, &scopes
);
212 for (Dwarf_Die
*s
= scopes
; s
&& s
< scopes
+ n
; s
++) {
213 Dwarf_Attribute
*a
, space
;
215 if (!IN_SET(sym_dwarf_tag(s
), DW_TAG_subprogram
, DW_TAG_inlined_subroutine
, DW_TAG_entry_point
))
218 a
= sym_dwarf_attr_integrate(s
, DW_AT_MIPS_linkage_name
, &space
);
220 a
= sym_dwarf_attr_integrate(s
, DW_AT_linkage_name
, &space
);
222 symbol
= sym_dwarf_formstring(a
);
224 symbol
= sym_dwarf_diename(s
);
232 symbol
= sym_dwfl_module_addrname(module
, pc_adjusted
);
234 fname
= sym_dwfl_module_info(module
, NULL
, &start
, NULL
, NULL
, NULL
, NULL
, NULL
);
235 module_offset
= pc
- start
;
239 fprintf(c
->f
, "#%-2u 0x%016" PRIx64
" %s (%s + 0x%" PRIx64
")\n", c
->n_frame
, (uint64_t) pc
, strna(symbol
), strna(fname
), module_offset
);
245 static int thread_callback(Dwfl_Thread
*thread
, void *userdata
) {
246 StackContext
*c
= ASSERT_PTR(userdata
);
251 if (c
->n_thread
>= THREADS_MAX
)
252 return DWARF_CB_ABORT
;
254 if (c
->n_thread
!= 0 && c
->f
)
260 tid
= sym_dwfl_thread_tid(thread
);
261 fprintf(c
->f
, "Stack trace of thread " PID_FMT
":\n", tid
);
264 if (sym_dwfl_thread_getframes(thread
, frame_callback
, c
) < 0)
265 return DWARF_CB_ABORT
;
272 static char* build_package_reference(
278 /* Construct an identifier for a specific version of the package. The syntax is most suitable for
279 * rpm: the resulting string can be used directly in queries and rpm/dnf/yum commands. For dpkg and
280 * other systems, it might not be usable directly, but users should still be able to figure out the
284 return strjoin(type
?: "package",
291 /* arch is meaningful even without version, so always print it */
296 static void report_module_metadata(StackContext
*c
, const char *name
, JsonVariant
*metadata
) {
303 fprintf(c
->f
, "Module %s", name
);
307 *build_id
= json_variant_string(json_variant_by_key(metadata
, "buildId")),
308 *type
= json_variant_string(json_variant_by_key(metadata
, "type")),
309 *package
= json_variant_string(json_variant_by_key(metadata
, "name")),
310 *version
= json_variant_string(json_variant_by_key(metadata
, "version")),
311 *arch
= json_variant_string(json_variant_by_key(metadata
, "architecture"));
314 /* Version/architecture is only meaningful with a package name.
315 * Skip the detailed fields if package is unknown. */
316 _cleanup_free_
char *id
= build_package_reference(type
, package
, version
, arch
);
317 fprintf(c
->f
, " from %s", strnull(id
));
320 if (build_id
&& !(package
&& version
))
321 fprintf(c
->f
, ", build-id=%s", build_id
);
327 static int parse_package_metadata(const char *name
, JsonVariant
*id_json
, Elf
*elf
, bool *ret_interpreter_found
, StackContext
*c
) {
328 bool interpreter_found
= false;
329 size_t n_program_headers
;
336 /* When iterating over PT_LOAD we will visit modules more than once */
337 if (set_contains(*c
->modules
, name
))
340 r
= sym_elf_getphdrnum(elf
, &n_program_headers
);
341 if (r
< 0) /* Not the handle we are looking for - that's ok, skip it */
344 /* Iterate over all program headers in that ELF object. These will have been copied by
345 * the kernel verbatim when the core file is generated. */
346 for (size_t i
= 0; i
< n_program_headers
; ++i
) {
347 GElf_Phdr mem
, *program_header
;
348 GElf_Nhdr note_header
;
351 /* Package metadata is in PT_NOTE headers. */
352 program_header
= sym_gelf_getphdr(elf
, i
, &mem
);
353 if (!program_header
|| (program_header
->p_type
!= PT_NOTE
&& program_header
->p_type
!= PT_INTERP
))
356 if (program_header
->p_type
== PT_INTERP
) {
357 interpreter_found
= true;
361 /* Fortunately there is an iterator we can use to walk over the
362 * elements of a PT_NOTE program header. We are interested in the
364 data
= sym_elf_getdata_rawchunk(elf
,
365 program_header
->p_offset
,
366 program_header
->p_filesz
,
371 for (size_t note_offset
= 0, name_offset
, desc_offset
;
372 note_offset
< data
->d_size
&&
373 (note_offset
= sym_gelf_getnote(data
, note_offset
, ¬e_header
, &name_offset
, &desc_offset
)) > 0;) {
375 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
, *w
= NULL
;
376 const char *payload
= (const char *)data
->d_buf
+ desc_offset
;
378 if (note_header
.n_namesz
== 0 || note_header
.n_descsz
== 0)
381 /* Package metadata might have different owners, but the
382 * magic ID is always the same. */
383 if (note_header
.n_type
!= ELF_PACKAGE_METADATA_ID
)
386 _cleanup_free_
char *payload_0suffixed
= NULL
;
387 assert(note_offset
> desc_offset
);
388 size_t payload_len
= note_offset
- desc_offset
;
390 /* If we are lucky and the payload is NUL-padded, we don't need to copy the string.
391 * But if happens to go all the way until the end of the buffer, make a copy. */
392 if (payload
[payload_len
-1] != '\0') {
393 payload_0suffixed
= memdup_suffix0(payload
, payload_len
);
394 if (!payload_0suffixed
)
396 payload
= payload_0suffixed
;
399 r
= json_parse(payload
, 0, &v
, NULL
, NULL
);
401 _cleanup_free_
char *esc
= cescape(payload
);
402 return log_error_errno(r
, "json_parse on \"%s\" failed: %m", strnull(esc
));
405 /* If we have a build-id, merge it in the same JSON object so that it appears all
406 * nicely together in the logs/metadata. */
408 r
= json_variant_merge(&v
, id_json
);
410 return log_error_errno(r
, "json_variant_merge of package meta with buildId failed: %m");
413 /* Pretty-print to the buffer, so that the metadata goes as plaintext in the
415 report_module_metadata(c
, name
, v
);
417 /* Then we build a new object using the module name as the key, and merge it
418 * with the previous parses, so that in the end it all fits together in a single
420 r
= json_build(&w
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR(name
, JSON_BUILD_VARIANT(v
))));
422 return log_error_errno(r
, "Failed to build JSON object: %m");
424 r
= json_variant_merge(c
->package_metadata
, w
);
426 return log_error_errno(r
, "json_variant_merge of package meta with buildId failed: %m");
428 /* Finally stash the name, so we avoid double visits. */
429 r
= set_put_strdup(c
->modules
, name
);
431 return log_error_errno(r
, "set_put_strdup failed: %m");
433 if (ret_interpreter_found
)
434 *ret_interpreter_found
= interpreter_found
;
440 if (ret_interpreter_found
)
441 *ret_interpreter_found
= interpreter_found
;
443 /* Didn't find package metadata for this module - that's ok, just go to the next. */
447 /* Get the build-id out of an ELF object or a dwarf core module. */
448 static int parse_buildid(Dwfl_Module
*mod
, Elf
*elf
, const char *name
, StackContext
*c
, JsonVariant
**ret_id_json
) {
449 _cleanup_(json_variant_unrefp
) JsonVariant
*id_json
= NULL
;
450 const unsigned char *id
;
460 id_len
= sym_dwfl_module_build_id(mod
, &id
, &id_vaddr
);
462 id_len
= sym_dwelf_elf_gnu_build_id(elf
, (const void **)&id
);
464 /* If we don't find a build-id, note it in the journal message, and try
465 * anyway to find the package metadata. It's unlikely to have the latter
466 * without the former, but there's no hard rule. */
468 fprintf(c
->f
, "Module %s without build-id.\n", name
);
470 /* We will later parse package metadata json and pass it to our caller. Prepare the
471 * build-id in json format too, so that it can be appended and parsed cleanly. It
472 * will then be added as metadata to the journal message with the stack trace. */
473 r
= json_build(&id_json
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("buildId", JSON_BUILD_HEX(id
, id_len
))));
475 return log_error_errno(r
, "json_build on buildId failed: %m");
479 *ret_id_json
= TAKE_PTR(id_json
);
484 static int module_callback(Dwfl_Module
*mod
, void **userdata
, const char *name
, Dwarf_Addr start
, void *arg
) {
485 _cleanup_(json_variant_unrefp
) JsonVariant
*id_json
= NULL
;
486 StackContext
*c
= ASSERT_PTR(arg
);
487 size_t n_program_headers
;
495 name
= "(unnamed)"; /* For logging purposes */
497 /* We are iterating on each "module", which is what dwfl calls ELF objects contained in the
498 * core file, and extracting the build-id first and then the package metadata.
499 * We proceed in a best-effort fashion - not all ELF objects might contain both or either.
500 * The build-id is easy, as libdwfl parses it during the sym_dwfl_core_file_report() call and
501 * stores it separately in an internal library struct. */
502 r
= parse_buildid(mod
, NULL
, name
, c
, &id_json
);
504 return DWARF_CB_ABORT
;
506 /* The .note.package metadata is more difficult. From the module, we need to get a reference
507 * to the ELF object first. We might be lucky and just get it from elfutils. */
508 elf
= sym_dwfl_module_getelf(mod
, &bias
);
510 r
= parse_package_metadata(name
, id_json
, elf
, NULL
, c
);
512 return DWARF_CB_ABORT
;
518 /* We did not get the ELF object, or it's just a reference to the core. That is likely
519 * because we didn't get direct access to the executable, and the version of elfutils does
520 * not yet support parsing it out of the core file directly.
521 * So fallback to manual extraction - get the PT_LOAD section from the core,
522 * and if it's the right one we can interpret it as an Elf object, and parse
523 * its notes manually. */
525 r
= sym_elf_getphdrnum(elf
, &n_program_headers
);
527 log_warning("Could not parse number of program headers from core file: %s",
528 sym_elf_errmsg(-1)); /* -1 retrieves the most recent error */
529 report_module_metadata(c
, name
, id_json
);
534 for (size_t i
= 0; i
< n_program_headers
; ++i
) {
535 GElf_Phdr mem
, *program_header
;
538 /* The core file stores the ELF files in the PT_LOAD segment. */
539 program_header
= sym_gelf_getphdr(elf
, i
, &mem
);
540 if (!program_header
|| program_header
->p_type
!= PT_LOAD
)
543 /* Now get a usable Elf reference, and parse the notes from it. */
544 data
= sym_elf_getdata_rawchunk(elf
,
545 program_header
->p_offset
,
546 program_header
->p_filesz
,
551 _cleanup_(sym_elf_endp
) Elf
*memelf
= sym_elf_memory(data
->d_buf
, data
->d_size
);
554 r
= parse_package_metadata(name
, id_json
, memelf
, NULL
, c
);
556 return DWARF_CB_ABORT
;
564 static int parse_core(int fd
, const char *executable
, char **ret
, JsonVariant
**ret_package_metadata
) {
566 const Dwfl_Callbacks callbacks
= {
567 .find_elf
= sym_dwfl_build_id_find_elf
,
568 .section_address
= sym_dwfl_offline_section_address
,
569 .find_debuginfo
= sym_dwfl_standard_find_debuginfo
,
572 _cleanup_(json_variant_unrefp
) JsonVariant
*package_metadata
= NULL
;
573 _cleanup_(set_freep
) Set
*modules
= NULL
;
574 _cleanup_free_
char *buf
= NULL
; /* buf should be freed last, c.f closed first (via stack_context_destroy) */
575 _cleanup_(stack_context_destroy
) StackContext c
= {
576 .package_metadata
= &package_metadata
,
584 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1)
585 return log_warning_errno(errno
, "Failed to seek to beginning of the core 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 core file, elf_begin() failed: %s", sym_elf_errmsg(sym_elf_errno()));
599 c
.dwfl
= sym_dwfl_begin(&callbacks
);
601 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse core file, dwfl_begin() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
603 if (sym_dwfl_core_file_report(c
.dwfl
, c
.elf
, executable
) < 0)
604 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse core file, dwfl_core_file_report() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
606 if (sym_dwfl_report_end(c
.dwfl
, NULL
, NULL
) != 0)
607 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse core file, dwfl_report_end() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
609 if (sym_dwfl_getmodules(c
.dwfl
, &module_callback
, &c
, 0) < 0)
610 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse core file, dwfl_getmodules() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
612 if (sym_dwfl_core_file_attach(c
.dwfl
, c
.elf
) < 0)
613 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse core file, dwfl_core_file_attach() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
615 if (sym_dwfl_getthreads(c
.dwfl
, thread_callback
, &c
) < 0)
616 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse core file, dwfl_getthreads() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
619 r
= fflush_and_check(c
.f
);
621 return log_warning_errno(r
, "Could not parse core file, flushing file buffer failed: %m");
623 c
.f
= safe_fclose(c
.f
);
624 *ret
= TAKE_PTR(buf
);
626 if (ret_package_metadata
)
627 *ret_package_metadata
= TAKE_PTR(package_metadata
);
632 static int parse_elf(int fd
, const char *executable
, char **ret
, JsonVariant
**ret_package_metadata
) {
633 _cleanup_(json_variant_unrefp
) JsonVariant
*package_metadata
= NULL
, *elf_metadata
= NULL
;
634 _cleanup_(set_freep
) Set
*modules
= NULL
;
635 _cleanup_free_
char *buf
= NULL
; /* buf should be freed last, c.f closed first (via stack_context_destroy) */
636 _cleanup_(stack_context_destroy
) StackContext c
= {
637 .package_metadata
= &package_metadata
,
640 const char *elf_type
;
641 GElf_Ehdr elf_header
;
647 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1)
648 return log_warning_errno(errno
, "Failed to seek to beginning of the ELF file: %m");
651 c
.f
= open_memstream_unlocked(&buf
, &sz
);
656 sym_elf_version(EV_CURRENT
);
658 c
.elf
= sym_elf_begin(fd
, ELF_C_READ_MMAP
, NULL
);
660 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse ELF file, elf_begin() failed: %s", sym_elf_errmsg(sym_elf_errno()));
662 if (!sym_gelf_getehdr(c
.elf
, &elf_header
))
663 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Could not parse ELF file, gelf_getehdr() failed: %s", sym_elf_errmsg(sym_elf_errno()));
665 if (elf_header
.e_type
== ET_CORE
) {
666 _cleanup_free_
char *out
= NULL
;
668 r
= parse_core(fd
, executable
, ret
? &out
: NULL
, &package_metadata
);
670 return log_warning_errno(r
, "Failed to inspect core file: %m");
673 fprintf(c
.f
, "%s", out
);
675 elf_type
= "coredump";
677 _cleanup_(json_variant_unrefp
) JsonVariant
*id_json
= NULL
;
678 const char *e
= executable
?: "(unnamed)";
679 bool interpreter_found
= false;
681 r
= parse_buildid(NULL
, c
.elf
, e
, &c
, &id_json
);
683 return log_warning_errno(r
, "Failed to parse build-id of ELF file: %m");
685 r
= parse_package_metadata(e
, id_json
, c
.elf
, &interpreter_found
, &c
);
687 return log_warning_errno(r
, "Failed to parse package metadata of ELF file: %m");
689 /* If we found a build-id and nothing else, return at least that. */
690 if (!package_metadata
&& id_json
) {
691 r
= json_build(&package_metadata
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR(e
, JSON_BUILD_VARIANT(id_json
))));
693 return log_warning_errno(r
, "Failed to build JSON object: %m");
696 if (interpreter_found
)
697 elf_type
= "executable";
699 elf_type
= "library";
702 /* Note that e_type is always DYN for both executables and libraries, so we can't tell them apart from the header,
703 * but we will search for the PT_INTERP section when parsing the metadata. */
704 r
= json_build(&elf_metadata
, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("elfType", JSON_BUILD_STRING(elf_type
))));
706 return log_warning_errno(r
, "Failed to build JSON object: %m");
708 #if HAVE_DWELF_ELF_E_MACHINE_STRING
709 const char *elf_architecture
= sym_dwelf_elf_e_machine_string(elf_header
.e_machine
);
710 if (elf_architecture
) {
711 _cleanup_(json_variant_unrefp
) JsonVariant
*json_architecture
= NULL
;
713 r
= json_build(&json_architecture
,
714 JSON_BUILD_OBJECT(JSON_BUILD_PAIR("elfArchitecture", JSON_BUILD_STRING(elf_architecture
))));
716 return log_warning_errno(r
, "Failed to build JSON object: %m");
718 r
= json_variant_merge(&elf_metadata
, json_architecture
);
720 return log_warning_errno(r
, "Failed to merge JSON objects: %m");
723 fprintf(c
.f
, "ELF object binary architecture: %s\n", elf_architecture
);
727 /* We always at least have the ELF type, so merge that (and possibly the arch). */
728 r
= json_variant_merge(&elf_metadata
, package_metadata
);
730 return log_warning_errno(r
, "Failed to merge JSON objects: %m");
733 r
= fflush_and_check(c
.f
);
735 return log_warning_errno(r
, "Could not parse ELF file, flushing file buffer failed: %m");
737 c
.f
= safe_fclose(c
.f
);
738 *ret
= TAKE_PTR(buf
);
740 if (ret_package_metadata
)
741 *ret_package_metadata
= TAKE_PTR(elf_metadata
);
746 int parse_elf_object(int fd
, const char *executable
, bool fork_disable_dump
, char **ret
, JsonVariant
**ret_package_metadata
) {
747 _cleanup_close_pair_
int error_pipe
[2] = { -EBADF
, -EBADF
},
748 return_pipe
[2] = { -EBADF
, -EBADF
},
749 json_pipe
[2] = { -EBADF
, -EBADF
};
750 _cleanup_(json_variant_unrefp
) JsonVariant
*package_metadata
= NULL
;
751 _cleanup_free_
char *buf
= NULL
;
764 r
= RET_NERRNO(pipe2(error_pipe
, O_CLOEXEC
|O_NONBLOCK
));
769 r
= RET_NERRNO(pipe2(return_pipe
, O_CLOEXEC
|O_NONBLOCK
));
774 if (ret_package_metadata
) {
775 r
= RET_NERRNO(pipe2(json_pipe
, O_CLOEXEC
|O_NONBLOCK
));
780 /* Parsing possibly malformed data is crash-happy, so fork. In case we crash,
781 * the core file will not be lost, and the messages will still be attached to
782 * the journal. Reading the elf object might be slow, but it still has an upper
783 * bound since the core files have an upper size limit. It's also not doing any
784 * system call or interacting with the system in any way, besides reading from
785 * the file descriptor and writing into these four pipes. */
786 r
= safe_fork_full("(sd-parse-elf)",
787 (int[]){ fd
, error_pipe
[1], return_pipe
[1], json_pipe
[1] },
789 FORK_RESET_SIGNALS
|FORK_CLOSE_ALL_FDS
|FORK_NEW_MOUNTNS
|FORK_MOUNTNS_SLAVE
|FORK_NEW_USERNS
|FORK_WAIT
|FORK_REOPEN_LOG
,
792 if (r
== -EPROTO
) { /* We should have the errno from the child, but don't clobber original error */
795 k
= read(error_pipe
[0], &e
, sizeof(e
));
796 if (k
< 0 && errno
!= EAGAIN
) /* Pipe is non-blocking, EAGAIN means there's nothing */
799 return e
; /* propagate error sent to us from child */
807 /* We want to avoid loops, given this can be called from systemd-coredump */
808 if (fork_disable_dump
) {
809 r
= RET_NERRNO(prctl(PR_SET_DUMPABLE
, 0));
814 r
= parse_elf(fd
, executable
, ret
? &buf
: NULL
, ret_package_metadata
? &package_metadata
: NULL
);
819 size_t len
= strlen(buf
);
821 if (len
> COREDUMP_PIPE_MAX
) {
822 /* This is iffy. A backtrace can be a few hundred kilobytes, but too much is
823 * too much. Let's log a warning and ignore the rest. */
824 log_warning("Generated backtrace is %zu bytes (more than the limit of %u bytes), backtrace will be truncated.",
825 len
, COREDUMP_PIPE_MAX
);
826 len
= COREDUMP_PIPE_MAX
;
829 /* Bump the space for the returned string.
830 * Failure is ignored, because partial output is still useful. */
831 (void) fcntl(return_pipe
[1], F_SETPIPE_SZ
, len
);
833 r
= loop_write(return_pipe
[1], buf
, len
, false);
835 log_warning("Write failed, backtrace will be truncated.");
839 return_pipe
[1] = safe_close(return_pipe
[1]);
842 if (package_metadata
) {
843 _cleanup_fclose_
FILE *json_out
= NULL
;
845 /* Bump the space for the returned string. We don't know how much space we'll need in
846 * advance, so we'll just try to write as much as possible and maybe fail later. */
847 (void) fcntl(json_pipe
[1], F_SETPIPE_SZ
, COREDUMP_PIPE_MAX
);
849 json_out
= take_fdopen(&json_pipe
[1], "w");
855 r
= json_variant_dump(package_metadata
, JSON_FORMAT_FLUSH
, json_out
, NULL
);
857 log_warning_errno(r
, "Failed to write JSON package metadata, ignoring: %m");
863 (void) write(error_pipe
[1], &r
, sizeof(r
));
867 error_pipe
[1] = safe_close(error_pipe
[1]);
868 return_pipe
[1] = safe_close(return_pipe
[1]);
869 json_pipe
[1] = safe_close(json_pipe
[1]);
872 _cleanup_fclose_
FILE *in
= NULL
;
874 in
= take_fdopen(&return_pipe
[0], "r");
878 r
= read_full_stream(in
, &buf
, NULL
);
883 if (ret_package_metadata
) {
884 _cleanup_fclose_
FILE *json_in
= NULL
;
886 json_in
= take_fdopen(&json_pipe
[0], "r");
890 r
= json_parse_file(json_in
, NULL
, 0, &package_metadata
, NULL
, NULL
);
891 if (r
< 0 && r
!= -ENODATA
) /* ENODATA: json was empty, so we got nothing, but that's ok */
892 log_warning_errno(r
, "Failed to read or parse json metadata, ignoring: %m");
896 *ret
= TAKE_PTR(buf
);
897 if (ret_package_metadata
)
898 *ret_package_metadata
= TAKE_PTR(package_metadata
);