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