1 /* SPDX-License-Identifier: LGPL-2.1+ */
4 #include <elfutils/libdwfl.h>
9 #include "alloc-util.h"
11 #include "format-util.h"
13 #include "stacktrace.h"
14 #include "string-util.h"
18 #define THREADS_MAX 64
20 struct stack_context
{
28 static int frame_callback(Dwfl_Frame
*frame
, void *userdata
) {
29 struct stack_context
*c
= userdata
;
30 Dwarf_Addr pc
, pc_adjusted
, bias
= 0;
31 _cleanup_free_ Dwarf_Die
*scopes
= NULL
;
32 const char *fname
= NULL
, *symbol
= NULL
;
39 if (c
->n_frame
>= FRAMES_MAX
)
40 return DWARF_CB_ABORT
;
42 if (!dwfl_frame_pc(frame
, &pc
, &is_activation
))
43 return DWARF_CB_ABORT
;
45 pc_adjusted
= pc
- (is_activation
? 0 : 1);
47 module
= dwfl_addrmodule(c
->dwfl
, pc_adjusted
);
52 cudie
= dwfl_module_addrdie(module
, pc_adjusted
, &bias
);
54 n
= dwarf_getscopes(cudie
, pc_adjusted
- bias
, &scopes
);
55 for (s
= scopes
; s
< scopes
+ n
; s
++) {
56 if (IN_SET(dwarf_tag(s
), DW_TAG_subprogram
, DW_TAG_inlined_subroutine
, DW_TAG_entry_point
)) {
57 Dwarf_Attribute
*a
, space
;
59 a
= dwarf_attr_integrate(s
, DW_AT_MIPS_linkage_name
, &space
);
61 a
= dwarf_attr_integrate(s
, DW_AT_linkage_name
, &space
);
63 symbol
= dwarf_formstring(a
);
65 symbol
= dwarf_diename(s
);
74 symbol
= dwfl_module_addrname(module
, pc_adjusted
);
76 fname
= dwfl_module_info(module
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
79 fprintf(c
->f
, "#%-2u 0x%016" PRIx64
" %s (%s)\n", c
->n_frame
, (uint64_t) pc
, strna(symbol
), strna(fname
));
85 static int thread_callback(Dwfl_Thread
*thread
, void *userdata
) {
86 struct stack_context
*c
= userdata
;
92 if (c
->n_thread
>= THREADS_MAX
)
93 return DWARF_CB_ABORT
;
100 tid
= dwfl_thread_tid(thread
);
101 fprintf(c
->f
, "Stack trace of thread " PID_FMT
":\n", tid
);
103 if (dwfl_thread_getframes(thread
, frame_callback
, c
) < 0)
104 return DWARF_CB_ABORT
;
111 int coredump_make_stack_trace(int fd
, const char *executable
, char **ret
) {
113 static const Dwfl_Callbacks callbacks
= {
114 .find_elf
= dwfl_build_id_find_elf
,
115 .find_debuginfo
= dwfl_standard_find_debuginfo
,
118 struct stack_context c
= {};
126 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1)
129 c
.f
= open_memstream(&buf
, &sz
);
133 (void) __fsetlocking(c
.f
, FSETLOCKING_BYCALLER
);
135 elf_version(EV_CURRENT
);
137 c
.elf
= elf_begin(fd
, ELF_C_READ_MMAP
, NULL
);
143 c
.dwfl
= dwfl_begin(&callbacks
);
149 if (dwfl_core_file_report(c
.dwfl
, c
.elf
, executable
) < 0) {
154 if (dwfl_report_end(c
.dwfl
, NULL
, NULL
) != 0) {
159 if (dwfl_core_file_attach(c
.dwfl
, c
.elf
) < 0) {
164 if (dwfl_getthreads(c
.dwfl
, thread_callback
, &c
) < 0) {
169 c
.f
= safe_fclose(c
.f
);
171 *ret
= TAKE_PTR(buf
);