1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2014 Lennart Poettering
7 #include <elfutils/libdwfl.h>
10 #include "alloc-util.h"
12 #include "format-util.h"
14 #include "stacktrace.h"
15 #include "string-util.h"
19 #define THREADS_MAX 64
21 struct stack_context
{
29 static int frame_callback(Dwfl_Frame
*frame
, void *userdata
) {
30 struct stack_context
*c
= userdata
;
31 Dwarf_Addr pc
, pc_adjusted
, bias
= 0;
32 _cleanup_free_ Dwarf_Die
*scopes
= NULL
;
33 const char *fname
= NULL
, *symbol
= NULL
;
40 if (c
->n_frame
>= FRAMES_MAX
)
41 return DWARF_CB_ABORT
;
43 if (!dwfl_frame_pc(frame
, &pc
, &is_activation
))
44 return DWARF_CB_ABORT
;
46 pc_adjusted
= pc
- (is_activation
? 0 : 1);
48 module
= dwfl_addrmodule(c
->dwfl
, pc_adjusted
);
53 cudie
= dwfl_module_addrdie(module
, pc_adjusted
, &bias
);
55 n
= dwarf_getscopes(cudie
, pc_adjusted
- bias
, &scopes
);
56 for (s
= scopes
; s
< scopes
+ n
; s
++) {
57 if (IN_SET(dwarf_tag(s
), DW_TAG_subprogram
, DW_TAG_inlined_subroutine
, DW_TAG_entry_point
)) {
58 Dwarf_Attribute
*a
, space
;
60 a
= dwarf_attr_integrate(s
, DW_AT_MIPS_linkage_name
, &space
);
62 a
= dwarf_attr_integrate(s
, DW_AT_linkage_name
, &space
);
64 symbol
= dwarf_formstring(a
);
66 symbol
= dwarf_diename(s
);
75 symbol
= dwfl_module_addrname(module
, pc_adjusted
);
77 fname
= dwfl_module_info(module
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
80 fprintf(c
->f
, "#%-2u 0x%016" PRIx64
" %s (%s)\n", c
->n_frame
, (uint64_t) pc
, strna(symbol
), strna(fname
));
86 static int thread_callback(Dwfl_Thread
*thread
, void *userdata
) {
87 struct stack_context
*c
= userdata
;
93 if (c
->n_thread
>= THREADS_MAX
)
94 return DWARF_CB_ABORT
;
101 tid
= dwfl_thread_tid(thread
);
102 fprintf(c
->f
, "Stack trace of thread " PID_FMT
":\n", tid
);
104 if (dwfl_thread_getframes(thread
, frame_callback
, c
) < 0)
105 return DWARF_CB_ABORT
;
112 int coredump_make_stack_trace(int fd
, const char *executable
, char **ret
) {
114 static const Dwfl_Callbacks callbacks
= {
115 .find_elf
= dwfl_build_id_find_elf
,
116 .find_debuginfo
= dwfl_standard_find_debuginfo
,
119 struct stack_context c
= {};
127 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1)
130 c
.f
= open_memstream(&buf
, &sz
);
134 (void) __fsetlocking(c
.f
, FSETLOCKING_BYCALLER
);
136 elf_version(EV_CURRENT
);
138 c
.elf
= elf_begin(fd
, ELF_C_READ_MMAP
, NULL
);
144 c
.dwfl
= dwfl_begin(&callbacks
);
150 if (dwfl_core_file_report(c
.dwfl
, c
.elf
, executable
) < 0) {
155 if (dwfl_report_end(c
.dwfl
, NULL
, NULL
) != 0) {
160 if (dwfl_core_file_attach(c
.dwfl
, c
.elf
) < 0) {
165 if (dwfl_getthreads(c
.dwfl
, thread_callback
, &c
) < 0) {
170 c
.f
= safe_fclose(c
.f
);
172 *ret
= TAKE_PTR(buf
);