1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <elfutils/libdwfl.h>
25 #include "alloc-util.h"
27 #include "formats-util.h"
29 #include "stacktrace.h"
30 #include "string-util.h"
34 #define THREADS_MAX 64
36 struct stack_context
{
44 static int frame_callback(Dwfl_Frame
*frame
, void *userdata
) {
45 struct stack_context
*c
= userdata
;
46 Dwarf_Addr pc
, pc_adjusted
, bias
= 0;
47 _cleanup_free_ Dwarf_Die
*scopes
= NULL
;
48 const char *fname
= NULL
, *symbol
= NULL
;
55 if (c
->n_frame
>= FRAMES_MAX
)
56 return DWARF_CB_ABORT
;
58 if (!dwfl_frame_pc(frame
, &pc
, &is_activation
))
59 return DWARF_CB_ABORT
;
61 pc_adjusted
= pc
- (is_activation
? 0 : 1);
63 module
= dwfl_addrmodule(c
->dwfl
, pc_adjusted
);
68 cudie
= dwfl_module_addrdie(module
, pc_adjusted
, &bias
);
70 n
= dwarf_getscopes(cudie
, pc_adjusted
- bias
, &scopes
);
71 for (s
= scopes
; s
< scopes
+ n
; s
++) {
72 if (IN_SET(dwarf_tag(s
), DW_TAG_subprogram
, DW_TAG_inlined_subroutine
, DW_TAG_entry_point
)) {
73 Dwarf_Attribute
*a
, space
;
75 a
= dwarf_attr_integrate(s
, DW_AT_MIPS_linkage_name
, &space
);
77 a
= dwarf_attr_integrate(s
, DW_AT_linkage_name
, &space
);
79 symbol
= dwarf_formstring(a
);
81 symbol
= dwarf_diename(s
);
90 symbol
= dwfl_module_addrname(module
, pc_adjusted
);
92 fname
= dwfl_module_info(module
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
95 fprintf(c
->f
, "#%-2u 0x%016" PRIx64
" %s (%s)\n", c
->n_frame
, (uint64_t) pc
, strna(symbol
), strna(fname
));
101 static int thread_callback(Dwfl_Thread
*thread
, void *userdata
) {
102 struct stack_context
*c
= userdata
;
108 if (c
->n_thread
>= THREADS_MAX
)
109 return DWARF_CB_ABORT
;
111 if (c
->n_thread
!= 0)
116 tid
= dwfl_thread_tid(thread
);
117 fprintf(c
->f
, "Stack trace of thread " PID_FMT
":\n", tid
);
119 if (dwfl_thread_getframes(thread
, frame_callback
, c
) < 0)
120 return DWARF_CB_ABORT
;
127 int coredump_make_stack_trace(int fd
, const char *executable
, char **ret
) {
129 static const Dwfl_Callbacks callbacks
= {
130 .find_elf
= dwfl_build_id_find_elf
,
131 .find_debuginfo
= dwfl_standard_find_debuginfo
,
134 struct stack_context c
= {};
142 if (lseek(fd
, 0, SEEK_SET
) == (off_t
) -1)
145 c
.f
= open_memstream(&buf
, &sz
);
149 elf_version(EV_CURRENT
);
151 c
.elf
= elf_begin(fd
, ELF_C_READ_MMAP
, NULL
);
157 c
.dwfl
= dwfl_begin(&callbacks
);
163 if (dwfl_core_file_report(c
.dwfl
, c
.elf
, executable
) < 0) {
168 if (dwfl_report_end(c
.dwfl
, NULL
, NULL
) != 0) {
173 if (dwfl_core_file_attach(c
.dwfl
, c
.elf
) < 0) {
178 if (dwfl_getthreads(c
.dwfl
, thread_callback
, &c
) < 0) {
183 c
.f
= safe_fclose(c
.f
);