1 /* SPDX-License-Identifier: LGPL-2.1+ */
4 #include <elfutils/libdwfl.h>
7 #include "alloc-util.h"
9 #include "format-util.h"
11 #include "stacktrace.h"
12 #include "string-util.h"
16 #define THREADS_MAX 64
18 struct stack_context
{
26 static int frame_callback(Dwfl_Frame
*frame
, void *userdata
) {
27 struct stack_context
*c
= userdata
;
28 Dwarf_Addr pc
, pc_adjusted
, bias
= 0;
29 _cleanup_free_ Dwarf_Die
*scopes
= NULL
;
30 const char *fname
= NULL
, *symbol
= NULL
;
37 if (c
->n_frame
>= FRAMES_MAX
)
38 return DWARF_CB_ABORT
;
40 if (!dwfl_frame_pc(frame
, &pc
, &is_activation
))
41 return DWARF_CB_ABORT
;
43 pc_adjusted
= pc
- (is_activation
? 0 : 1);
45 module
= dwfl_addrmodule(c
->dwfl
, pc_adjusted
);
50 cudie
= dwfl_module_addrdie(module
, pc_adjusted
, &bias
);
52 n
= dwarf_getscopes(cudie
, pc_adjusted
- bias
, &scopes
);
53 for (s
= scopes
; s
< scopes
+ n
; s
++) {
54 if (IN_SET(dwarf_tag(s
), DW_TAG_subprogram
, DW_TAG_inlined_subroutine
, DW_TAG_entry_point
)) {
55 Dwarf_Attribute
*a
, space
;
57 a
= dwarf_attr_integrate(s
, DW_AT_MIPS_linkage_name
, &space
);
59 a
= dwarf_attr_integrate(s
, DW_AT_linkage_name
, &space
);
61 symbol
= dwarf_formstring(a
);
63 symbol
= dwarf_diename(s
);
72 symbol
= dwfl_module_addrname(module
, pc_adjusted
);
74 fname
= dwfl_module_info(module
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
77 fprintf(c
->f
, "#%-2u 0x%016" PRIx64
" %s (%s)\n", c
->n_frame
, (uint64_t) pc
, strna(symbol
), strna(fname
));
83 static int thread_callback(Dwfl_Thread
*thread
, void *userdata
) {
84 struct stack_context
*c
= userdata
;
90 if (c
->n_thread
>= THREADS_MAX
)
91 return DWARF_CB_ABORT
;
98 tid
= dwfl_thread_tid(thread
);
99 fprintf(c
->f
, "Stack trace of thread " PID_FMT
":\n", tid
);
101 if (dwfl_thread_getframes(thread
, frame_callback
, c
) < 0)
102 return DWARF_CB_ABORT
;
109 int coredump_make_stack_trace(int fd
, const char *executable
, char **ret
) {
111 static const Dwfl_Callbacks callbacks
= {
112 .find_elf
= dwfl_build_id_find_elf
,
113 .find_debuginfo
= dwfl_standard_find_debuginfo
,
116 struct stack_context c
= {};
124 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1)
127 c
.f
= open_memstream(&buf
, &sz
);
131 (void) __fsetlocking(c
.f
, FSETLOCKING_BYCALLER
);
133 elf_version(EV_CURRENT
);
135 c
.elf
= elf_begin(fd
, ELF_C_READ_MMAP
, NULL
);
141 c
.dwfl
= dwfl_begin(&callbacks
);
147 if (dwfl_core_file_report(c
.dwfl
, c
.elf
, executable
) < 0) {
152 if (dwfl_report_end(c
.dwfl
, NULL
, NULL
) != 0) {
157 if (dwfl_core_file_attach(c
.dwfl
, c
.elf
) < 0) {
162 if (dwfl_getthreads(c
.dwfl
, thread_callback
, &c
) < 0) {
167 c
.f
= safe_fclose(c
.f
);
169 *ret
= TAKE_PTR(buf
);