]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/stacktrace.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / journal / stacktrace.c
CommitLineData
8d4e028f
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
22#include <dwarf.h>
23#include <elfutils/libdwfl.h>
24
07630cea 25#include "formats-util.h"
8d4e028f 26#include "macro.h"
07630cea
LP
27#include "string-util.h"
28#include "util.h"
8d4e028f
LP
29#include "stacktrace.h"
30
31#define FRAMES_MAX 64
32#define THREADS_MAX 64
33
34struct stack_context {
35 FILE *f;
36 Dwfl *dwfl;
37 Elf *elf;
38 unsigned n_thread;
39 unsigned n_frame;
40};
41
42static 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;
47 Dwfl_Module *module;
48 bool is_activation;
49
50 assert(frame);
51 assert(c);
52
53 if (c->n_frame >= FRAMES_MAX)
54 return DWARF_CB_ABORT;
55
56 if (!dwfl_frame_pc(frame, &pc, &is_activation))
57 return DWARF_CB_ABORT;
58
59 pc_adjusted = pc - (is_activation ? 0 : 1);
60
61 module = dwfl_addrmodule(c->dwfl, pc_adjusted);
62 if (module) {
63 Dwarf_Die *s, *cudie;
64 int n;
65
66 cudie = dwfl_module_addrdie(module, pc_adjusted, &bias);
67 if (cudie) {
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;
72
73 a = dwarf_attr_integrate(s, DW_AT_MIPS_linkage_name, &space);
74 if (!a)
75 a = dwarf_attr_integrate(s, DW_AT_linkage_name, &space);
76 if (a)
77 symbol = dwarf_formstring(a);
78 if (!symbol)
79 symbol = dwarf_diename(s);
80
81 if (symbol)
82 break;
83 }
84 }
85 }
86
87 if (!symbol)
88 symbol = dwfl_module_addrname(module, pc_adjusted);
89
90 fname = dwfl_module_info(module, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
91 }
92
93 fprintf(c->f, "#%-2u 0x%016" PRIx64 " %s (%s)\n", c->n_frame, (uint64_t) pc, strna(symbol), strna(fname));
94 c->n_frame ++;
95
96 return DWARF_CB_OK;
97}
98
99static int thread_callback(Dwfl_Thread *thread, void *userdata) {
100 struct stack_context *c = userdata;
101 pid_t tid;
102
103 assert(thread);
104 assert(c);
105
106 if (c->n_thread >= THREADS_MAX)
107 return DWARF_CB_ABORT;
108
109 if (c->n_thread != 0)
110 fputc('\n', c->f);
111
112 c->n_frame = 0;
113
114 tid = dwfl_thread_tid(thread);
115 fprintf(c->f, "Stack trace of thread " PID_FMT ":\n", tid);
116
117 if (dwfl_thread_getframes(thread, frame_callback, c) < 0)
118 return DWARF_CB_ABORT;
119
120 c->n_thread ++;
121
122 return DWARF_CB_OK;
123}
124
125int coredump_make_stack_trace(int fd, const char *executable, char **ret) {
126
127 static const Dwfl_Callbacks callbacks = {
128 .find_elf = dwfl_build_id_find_elf,
129 .find_debuginfo = dwfl_standard_find_debuginfo,
130 };
131
132 struct stack_context c = {};
133 char *buf = NULL;
134 size_t sz = 0;
135 int r;
136
137 assert(fd >= 0);
138 assert(ret);
139
140 if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
141 return -errno;
142
143 c.f = open_memstream(&buf, &sz);
144 if (!c.f)
145 return -ENOMEM;
146
147 elf_version(EV_CURRENT);
148
149 c.elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
150 if (!c.elf) {
151 r = -EINVAL;
152 goto finish;
153 }
154
155 c.dwfl = dwfl_begin(&callbacks);
156 if (!c.dwfl) {
157 r = -EINVAL;
158 goto finish;
159 }
160
161 if (dwfl_core_file_report(c.dwfl, c.elf, executable) < 0) {
162 r = -EINVAL;
163 goto finish;
164 }
165
166 if (dwfl_report_end(c.dwfl, NULL, NULL) != 0) {
167 r = -EINVAL;
168 goto finish;
169 }
170
171 if (dwfl_core_file_attach(c.dwfl, c.elf) < 0) {
172 r = -EINVAL;
173 goto finish;
174 }
175
176 if (dwfl_getthreads(c.dwfl, thread_callback, &c) < 0) {
177 r = -EINVAL;
178 goto finish;
179 }
180
74ca738f 181 c.f = safe_fclose(c.f);
8d4e028f
LP
182
183 *ret = buf;
184 buf = NULL;
185
186 r = 0;
187
188finish:
189 if (c.dwfl)
190 dwfl_end(c.dwfl);
191
192 if (c.elf)
193 elf_end(c.elf);
194
74ca738f 195 safe_fclose(c.f);
8d4e028f
LP
196
197 free(buf);
198
199 return r;
200}