2 This file is part of systemd.
4 Copyright 2014 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <elfutils/libdwfl.h>
23 #include "alloc-util.h"
25 #include "formats-util.h"
27 #include "stacktrace.h"
28 #include "string-util.h"
32 #define THREADS_MAX 64
34 struct stack_context
{
42 static int frame_callback(Dwfl_Frame
*frame
, void *userdata
) {
43 struct stack_context
*c
= userdata
;
44 Dwarf_Addr pc
, pc_adjusted
, bias
= 0;
45 _cleanup_free_ Dwarf_Die
*scopes
= NULL
;
46 const char *fname
= NULL
, *symbol
= NULL
;
53 if (c
->n_frame
>= FRAMES_MAX
)
54 return DWARF_CB_ABORT
;
56 if (!dwfl_frame_pc(frame
, &pc
, &is_activation
))
57 return DWARF_CB_ABORT
;
59 pc_adjusted
= pc
- (is_activation
? 0 : 1);
61 module
= dwfl_addrmodule(c
->dwfl
, pc_adjusted
);
66 cudie
= dwfl_module_addrdie(module
, pc_adjusted
, &bias
);
68 n
= dwarf_getscopes(cudie
, pc_adjusted
- bias
, &scopes
);
69 for (s
= scopes
; s
< scopes
+ n
; s
++) {
70 if (IN_SET(dwarf_tag(s
), DW_TAG_subprogram
, DW_TAG_inlined_subroutine
, DW_TAG_entry_point
)) {
71 Dwarf_Attribute
*a
, space
;
73 a
= dwarf_attr_integrate(s
, DW_AT_MIPS_linkage_name
, &space
);
75 a
= dwarf_attr_integrate(s
, DW_AT_linkage_name
, &space
);
77 symbol
= dwarf_formstring(a
);
79 symbol
= dwarf_diename(s
);
88 symbol
= dwfl_module_addrname(module
, pc_adjusted
);
90 fname
= dwfl_module_info(module
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
93 fprintf(c
->f
, "#%-2u 0x%016" PRIx64
" %s (%s)\n", c
->n_frame
, (uint64_t) pc
, strna(symbol
), strna(fname
));
99 static int thread_callback(Dwfl_Thread
*thread
, void *userdata
) {
100 struct stack_context
*c
= userdata
;
106 if (c
->n_thread
>= THREADS_MAX
)
107 return DWARF_CB_ABORT
;
109 if (c
->n_thread
!= 0)
114 tid
= dwfl_thread_tid(thread
);
115 fprintf(c
->f
, "Stack trace of thread " PID_FMT
":\n", tid
);
117 if (dwfl_thread_getframes(thread
, frame_callback
, c
) < 0)
118 return DWARF_CB_ABORT
;
125 int coredump_make_stack_trace(int fd
, const char *executable
, char **ret
) {
127 static const Dwfl_Callbacks callbacks
= {
128 .find_elf
= dwfl_build_id_find_elf
,
129 .find_debuginfo
= dwfl_standard_find_debuginfo
,
132 struct stack_context c
= {};
140 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1)
143 c
.f
= open_memstream(&buf
, &sz
);
147 elf_version(EV_CURRENT
);
149 c
.elf
= elf_begin(fd
, ELF_C_READ_MMAP
, NULL
);
155 c
.dwfl
= dwfl_begin(&callbacks
);
161 if (dwfl_core_file_report(c
.dwfl
, c
.elf
, executable
) < 0) {
166 if (dwfl_report_end(c
.dwfl
, NULL
, NULL
) != 0) {
171 if (dwfl_core_file_attach(c
.dwfl
, c
.elf
) < 0) {
176 if (dwfl_getthreads(c
.dwfl
, thread_callback
, &c
) < 0) {
181 c
.f
= safe_fclose(c
.f
);