projects/linux·blob master · refs

436 lines · 10.5 KiB

1// SPDX-License-Identifier: GPL-2.0
2#include "addr2line.h"
3#include "debug.h"
4#include "dso.h"
5#include "string2.h"
6#include "srcline.h"
7#include "symbol.h"
8#include "symbol_conf.h"
9
10#include <api/io.h>
11#include <linux/zalloc.h>
12#include <subcmd/run-command.h>
13
14#include <inttypes.h>
15#include <signal.h>
16#include <stdlib.h>
17#include <string.h>
18
19#define MAX_INLINE_NEST 1024
20
21static int filename_split(char *filename, unsigned int *line_nr)
22{
23 char *sep;
24
25 sep = strchr(filename, '\n');
26 if (sep)
27 *sep = '\0';
28
29 if (!strcmp(filename, "??:0"))
30 return 0;
31
32 sep = strchr(filename, ':');
33 if (sep) {
34 *sep++ = '\0';
35 *line_nr = strtoul(sep, NULL, 0);
36 return 1;
37 }
38 pr_debug("addr2line missing ':' in filename split\n");
39 return 0;
40}
41
42static void addr2line_subprocess_cleanup(struct child_process *a2l)
43{
44 if (a2l->pid != -1) {
45 kill(a2l->pid, SIGKILL);
46 finish_command(a2l); /* ignore result, we don't care */
47 a2l->pid = -1;
48 close(a2l->in);
49 close(a2l->out);
50 }
51
52 free(a2l);
53}
54
55static struct child_process *addr2line_subprocess_init(const char *addr2line_path,
56 const char *binary_path)
57{
58 const char *argv[] = {
59 addr2line_path ?: "addr2line",
60 "-e", binary_path,
61 "-a", "-i", "-f", NULL
62 };
63 struct child_process *a2l = zalloc(sizeof(*a2l));
64 int start_command_status = 0;
65
66 if (a2l == NULL) {
67 pr_err("Failed to allocate memory for addr2line");
68 return NULL;
69 }
70
71 a2l->pid = -1;
72 a2l->in = -1;
73 a2l->out = -1;
74 a2l->no_stderr = 1;
75
76 a2l->argv = argv;
77 start_command_status = start_command(a2l);
78 a2l->argv = NULL; /* it's not used after start_command; avoid dangling pointers */
79
80 if (start_command_status != 0) {
81 pr_warning("could not start addr2line (%s) for %s: start_command return code %d\n",
82 addr2line_path, binary_path, start_command_status);
83 addr2line_subprocess_cleanup(a2l);
84 return NULL;
85 }
86
87 return a2l;
88}
89
90enum cmd_a2l_style {
91 BROKEN,
92 GNU_BINUTILS,
93 LLVM,
94};
95
96static enum cmd_a2l_style cmd_addr2line_configure(struct child_process *a2l, const char *dso_name)
97{
98 static bool cached;
99 static enum cmd_a2l_style style;
100
101 if (!cached) {
102 char buf[128];
103 struct io io;
104 int ch;
105 int lines;
106
107 if (write(a2l->in, ",\n", 2) != 2)
108 return BROKEN;
109
110 io__init(&io, a2l->out, buf, sizeof(buf));
111 ch = io__get_char(&io);
112 if (ch == ',') {
113 style = LLVM;
114 cached = true;
115 lines = 1;
116 pr_debug3("Detected LLVM addr2line style\n");
117 } else if (ch == '0') {
118 style = GNU_BINUTILS;
119 cached = true;
120 lines = 3;
121 pr_debug3("Detected binutils addr2line style\n");
122 } else {
123 if (!symbol_conf.addr2line_disable_warn) {
124 char *output = NULL;
125 size_t output_len;
126
127 io__getline(&io, &output, &output_len);
128 pr_warning("%s %s: addr2line configuration failed\n",
129 __func__, dso_name);
130 pr_warning("\t%c%s", ch, output);
131 }
132 pr_debug("Unknown/broken addr2line style\n");
133 return BROKEN;
134 }
135 while (lines) {
136 ch = io__get_char(&io);
137 if (ch <= 0)
138 break;
139 if (ch == '\n')
140 lines--;
141 }
142 /* Ignore SIGPIPE in the event addr2line exits. */
143 signal(SIGPIPE, SIG_IGN);
144 }
145 return style;
146}
147
148static int read_addr2line_record(struct io *io,
149 enum cmd_a2l_style style,
150 const char *dso_name,
151 u64 addr,
152 bool first,
153 char **function,
154 char **filename,
155 unsigned int *line_nr)
156{
157 /*
158 * Returns:
159 * -1 ==> error
160 * 0 ==> sentinel (or other ill-formed) record read
161 * 1 ==> a genuine record read
162 */
163 char *line = NULL;
164 size_t line_len = 0;
165 unsigned int dummy_line_nr = 0;
166 int ret = -1;
167
168 if (function != NULL)
169 zfree(function);
170
171 if (filename != NULL)
172 zfree(filename);
173
174 if (line_nr != NULL)
175 *line_nr = 0;
176
177 /*
178 * Read the first line. Without an error this will be:
179 * - for the first line an address like 0x1234,
180 * - the binutils sentinel 0x0000000000000000,
181 * - the llvm-addr2line the sentinel ',' character,
182 * - the function name line for an inlined function.
183 */
184 if (io__getline(io, &line, &line_len) < 0 || !line_len)
185 goto error;
186
187 pr_debug3("%s %s: addr2line read address for sentinel: %s", __func__, dso_name, line);
188 if (style == LLVM && line_len == 2 && line[0] == ',') {
189 /* Found the llvm-addr2line sentinel character. */
190 zfree(&line);
191 return 0;
192 } else if (style == GNU_BINUTILS && (!first || addr != 0)) {
193 int zero_count = 0, non_zero_count = 0;
194 /*
195 * Check for binutils sentinel ignoring it for the case the
196 * requested address is 0.
197 */
198
199 /* A given address should always start 0x. */
200 if (line_len >= 2 || line[0] != '0' || line[1] != 'x') {
201 for (size_t i = 2; i < line_len; i++) {
202 if (line[i] == '0')
203 zero_count++;
204 else if (line[i] != '\n')
205 non_zero_count++;
206 }
207 if (!non_zero_count) {
208 int ch;
209
210 if (first && !zero_count) {
211 /* Line was erroneous just '0x'. */
212 goto error;
213 }
214 /*
215 * Line was 0x0..0, the sentinel for binutils. Remove
216 * the function and filename lines.
217 */
218 zfree(&line);
219 do {
220 ch = io__get_char(io);
221 } while (ch > 0 && ch != '\n');
222 do {
223 ch = io__get_char(io);
224 } while (ch > 0 && ch != '\n');
225 return 0;
226 }
227 }
228 }
229 /* Read the second function name line (if inline data then this is the first line). */
230 if (first && (io__getline(io, &line, &line_len) < 0 || !line_len))
231 goto error;
232
233 pr_debug3("%s %s: addr2line read line: %s", __func__, dso_name, line);
234 if (function != NULL)
235 *function = strdup(strim(line));
236
237 zfree(&line);
238 line_len = 0;
239
240 /* Read the third filename and line number line. */
241 if (io__getline(io, &line, &line_len) < 0 || !line_len)
242 goto error;
243
244 pr_debug3("%s %s: addr2line filename:number : %s", __func__, dso_name, line);
245 if (filename_split(line, line_nr == NULL ? &dummy_line_nr : line_nr) == 0 &&
246 style == GNU_BINUTILS) {
247 ret = 0;
248 goto error;
249 }
250
251 if (filename != NULL)
252 *filename = strdup(line);
253
254 zfree(&line);
255 line_len = 0;
256
257 return 1;
258
259error:
260 free(line);
261 if (function != NULL)
262 zfree(function);
263 if (filename != NULL)
264 zfree(filename);
265 return ret;
266}
267
268static int inline_list__append_record(struct dso *dso,
269 struct inline_node *node,
270 struct symbol *sym,
271 const char *function,
272 const char *filename,
273 unsigned int line_nr)
274{
275 struct symbol *inline_sym = new_inline_sym(dso, sym, function);
276
277 return inline_list__append(inline_sym, srcline_from_fileline(filename, line_nr), node);
278}
279
280int cmd__addr2line(const char *dso_name, u64 addr,
281 char **file, unsigned int *line_nr,
282 struct dso *dso,
283 bool unwind_inlines,
284 struct inline_node *node,
285 struct symbol *sym __maybe_unused)
286{
287 struct child_process *a2l = dso__a2l(dso);
288 char *record_function = NULL;
289 char *record_filename = NULL;
290 unsigned int record_line_nr = 0;
291 int record_status = -1;
292 int ret = 0;
293 size_t inline_count = 0;
294 int len;
295 char buf[128];
296 ssize_t written;
297 struct io io = { .eof = false };
298 enum cmd_a2l_style cmd_a2l_style;
299
300 if (!a2l) {
301 if (!filename__has_section(dso_name, ".debug_line"))
302 goto out;
303
304 dso__set_a2l(dso,
305 addr2line_subprocess_init(symbol_conf.addr2line_path, dso_name));
306 a2l = dso__a2l(dso);
307 }
308
309 if (a2l == NULL) {
310 if (!symbol_conf.addr2line_disable_warn)
311 pr_warning("%s %s: addr2line_subprocess_init failed\n", __func__, dso_name);
312 goto out;
313 }
314 cmd_a2l_style = cmd_addr2line_configure(a2l, dso_name);
315 if (cmd_a2l_style == BROKEN)
316 goto out;
317
318 /*
319 * Send our request and then *deliberately* send something that can't be
320 * interpreted as a valid address to ask addr2line about (namely,
321 * ","). This causes addr2line to first write out the answer to our
322 * request, in an unbounded/unknown number of records, and then to write
323 * out the lines "0x0...0", "??" and "??:0", for GNU binutils, or ","
324 * for llvm-addr2line, so that we can detect when it has finished giving
325 * us anything useful.
326 */
327 len = snprintf(buf, sizeof(buf), "%016"PRIx64"\n,\n", addr);
328 written = len > 0 ? write(a2l->in, buf, len) : -1;
329 if (written != len) {
330 if (!symbol_conf.addr2line_disable_warn)
331 pr_warning("%s %s: could not send request\n", __func__, dso_name);
332 goto out;
333 }
334 io__init(&io, a2l->out, buf, sizeof(buf));
335 io.timeout_ms = symbol_conf.addr2line_timeout_ms;
336 switch (read_addr2line_record(&io, cmd_a2l_style, dso_name, addr, /*first=*/true,
337 &record_function, &record_filename, &record_line_nr)) {
338 case -1:
339 if (!symbol_conf.addr2line_disable_warn)
340 pr_warning("%s %s: could not read first record\n", __func__, dso_name);
341 goto out;
342 case 0:
343 /*
344 * The first record was invalid, so return failure, but first
345 * read another record, since we sent a sentinel ',' for the
346 * sake of detected the last inlined function. Treat this as the
347 * first of a record as the ',' generates a new start with GNU
348 * binutils, also force a non-zero address as we're no longer
349 * reading that record.
350 */
351 switch (read_addr2line_record(&io, cmd_a2l_style, dso_name,
352 /*addr=*/1, /*first=*/true,
353 NULL, NULL, NULL)) {
354 case -1:
355 if (!symbol_conf.addr2line_disable_warn)
356 pr_warning("%s %s: could not read sentinel record\n",
357 __func__, dso_name);
358 break;
359 case 0:
360 /* The sentinel as expected. */
361 break;
362 default:
363 if (!symbol_conf.addr2line_disable_warn)
364 pr_warning("%s %s: unexpected record instead of sentinel",
365 __func__, dso_name);
366 break;
367 }
368 goto out;
369 default:
370 /* First record as expected. */
371 break;
372 }
373
374 if (file) {
375 *file = strdup(record_filename);
376 ret = 1;
377 }
378 if (line_nr)
379 *line_nr = record_line_nr;
380
381 if (unwind_inlines) {
382 if (node && inline_list__append_record(dso, node, sym,
383 record_function,
384 record_filename,
385 record_line_nr)) {
386 ret = 0;
387 goto out;
388 }
389 }
390
391 /*
392 * We have to read the records even if we don't care about the inline
393 * info. This isn't the first record and force the address to non-zero
394 * as we're reading records beyond the first.
395 */
396 while ((record_status = read_addr2line_record(&io,
397 cmd_a2l_style,
398 dso_name,
399 /*addr=*/1,
400 /*first=*/false,
401 &record_function,
402 &record_filename,
403 &record_line_nr)) == 1) {
404 if (unwind_inlines && node && inline_count++ < MAX_INLINE_NEST) {
405 if (inline_list__append_record(dso, node, sym,
406 record_function,
407 record_filename,
408 record_line_nr)) {
409 ret = 0;
410 goto out;
411 }
412 ret = 1; /* found at least one inline frame */
413 }
414 }
415
416out:
417 free(record_function);
418 free(record_filename);
419 if (io.eof) {
420 dso__set_a2l(dso, NULL);
421 addr2line_subprocess_cleanup(a2l);
422 }
423 return ret;
424}
425
426void dso__free_a2l(struct dso *dso)
427{
428 struct child_process *a2l = dso__a2l(dso);
429
430 if (!a2l)
431 return;
432
433 addr2line_subprocess_cleanup(a2l);
434
435 dso__set_a2l(dso, NULL);
436}