Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 616 lines (541 sloc) 14.389 kb
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
1 /**********************************************************************
2
3 addr2line.h -
4
5 $Author$
6
7 Copyright (C) 2010 Shinichiro Hamaji
8
9 **********************************************************************/
10
eb78d22 @mame * addr2line.c: fix r32407 to check HAVE_ALLOCA_H.
mame authored
11 #include "ruby/config.h"
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
12 #include "addr2line.h"
13
14 #include <stdio.h>
e394ddd @nobu * addr2line.c: needs <errno.h>.
nobu authored
15 #include <errno.h>
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
16
e33183a @nurse * addr2line.c: use USE_ELF instead of __ELF__ because Solaris
nurse authored
17 #ifdef USE_ELF
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
18
4acff77 @nurse * addr2line.c: OpenBSD uses the elf_abi.h header file instead of the
nurse authored
19 #ifdef __OpenBSD__
20 #include <elf_abi.h>
21 #else
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
22 #include <elf.h>
4acff77 @nurse * addr2line.c: OpenBSD uses the elf_abi.h header file instead of the
nurse authored
23 #endif
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
24 #include <fcntl.h>
25 #include <limits.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/mman.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33
eb78d22 @mame * addr2line.c: fix r32407 to check HAVE_ALLOCA_H.
mame authored
34 #if defined(HAVE_ALLOCA_H)
35 #include <alloca.h>
36 #endif
37
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
38 #ifdef HAVE_DL_ITERATE_PHDR
39 # ifndef _GNU_SOURCE
40 # define _GNU_SOURCE
41 # endif
42 # include <link.h>
43 #endif
44
45 #define DW_LNS_copy 0x01
46 #define DW_LNS_advance_pc 0x02
47 #define DW_LNS_advance_line 0x03
48 #define DW_LNS_set_file 0x04
49 #define DW_LNS_set_column 0x05
50 #define DW_LNS_negate_stmt 0x06
51 #define DW_LNS_set_basic_block 0x07
52 #define DW_LNS_const_add_pc 0x08
53 #define DW_LNS_fixed_advance_pc 0x09
54 #define DW_LNS_set_prologue_end 0x0a /* DWARF3 */
55 #define DW_LNS_set_epilogue_begin 0x0b /* DWARF3 */
56 #define DW_LNS_set_isa 0x0c /* DWARF3 */
57
58 /* Line number extended opcode name. */
59 #define DW_LNE_end_sequence 0x01
60 #define DW_LNE_set_address 0x02
61 #define DW_LNE_define_file 0x03
62 #define DW_LNE_set_discriminator 0x04 /* DWARF4 */
63
39e7b2f @nurse * addr2line.c: apply a patch from shinichiro.h.
nurse authored
64 #ifndef ElfW
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
65 # if SIZEOF_VOIDP == 8
66 # define ElfW(x) Elf64##_##x
67 # else
68 # define ElfW(x) Elf32##_##x
69 # endif
39e7b2f @nurse * addr2line.c: apply a patch from shinichiro.h.
nurse authored
70 #endif
4342469 @nurse * addr2line.c (PATH_MAX): define if not defined. [ruby-core:40840]
nurse authored
71 #ifndef PATH_MAX
72 #define PATH_MAX 4096
73 #endif
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
74
75 typedef struct {
76 const char *dirname;
77 const char *filename;
78 int line;
79
80 int fd;
81 void *mapped;
82 size_t mapped_size;
83 unsigned long base_addr;
84 } line_info_t;
85
86 /* Avoid consuming stack as this module may be used from signal handler */
87 static char binary_filename[PATH_MAX];
88
89 static unsigned long
c037f1f @nobu * adjust style.
nobu authored
90 uleb128(char **p)
91 {
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
92 unsigned long r = 0;
93 int s = 0;
94 for (;;) {
95 unsigned char b = *(unsigned char *)(*p)++;
96 if (b < 0x80) {
6a288de @nurse * addr2line.c (uleb128): cast the value to unsigned long.
nurse authored
97 r += (unsigned long)b << s;
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
98 break;
99 }
100 r += (b & 0x7f) << s;
101 s += 7;
102 }
103 return r;
104 }
105
106 static long
c037f1f @nobu * adjust style.
nobu authored
107 sleb128(char **p)
108 {
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
109 long r = 0;
110 int s = 0;
111 for (;;) {
112 unsigned char b = *(unsigned char *)(*p)++;
113 if (b < 0x80) {
114 if (b & 0x40) {
115 r -= (0x80 - b) << s;
116 }
117 else {
118 r += (b & 0x3f) << s;
119 }
120 break;
121 }
122 r += (b & 0x7f) << s;
123 s += 7;
124 }
125 return r;
126 }
127
128 static const char *
48de1e2 @nurse * addr2line.c: suppressed shorten-64-to-32 warnings.
nurse authored
129 get_nth_dirname(unsigned long dir, char *p)
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
130 {
131 if (!dir--) {
132 return "";
133 }
e57215b @nurse * addr2line.c (get_nth_dirname): decrement the directory index
nurse authored
134 while (dir--) {
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
135 while (*p) p++;
136 p++;
137 if (!*p) {
48de1e2 @nurse * addr2line.c: suppressed shorten-64-to-32 warnings.
nurse authored
138 fprintf(stderr, "Unexpected directory number %lu in %s\n",
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
139 dir, binary_filename);
140 return "";
141 }
142 }
143 return p;
144 }
145
146 static void
147 fill_filename(int file, char *include_directories, char *filenames,
148 line_info_t *line)
149 {
150 int i;
151 char *p = filenames;
152 char *filename;
153 unsigned long dir;
154 for (i = 1; i <= file; i++) {
155 filename = p;
156 if (!*p) {
157 /* Need to output binary file name? */
158 fprintf(stderr, "Unexpected file number %d in %s\n",
159 file, binary_filename);
160 return;
161 }
162 while (*p) p++;
163 p++;
164 dir = uleb128(&p);
165 /* last modified. */
166 uleb128(&p);
167 /* size of the file. */
168 uleb128(&p);
169
170 if (i == file) {
171 line->filename = filename;
172 line->dirname = get_nth_dirname(dir, include_directories);
173 }
174 }
175 }
176
177 static int
178 get_path_from_symbol(const char *symbol, const char **p, size_t *len)
179 {
180 if (symbol[0] == '0') {
181 /* libexecinfo */
182 *p = strchr(symbol, '/');
183 if (*p == NULL) return 0;
184 *len = strlen(*p);
185 }
186 else {
187 /* glibc */
188 const char *q;
189 *p = symbol;
190 q = strchr(symbol, '(');
191 if (q == NULL) return 0;
192 *len = q - symbol;
193 }
194 return 1;
195 }
196
197 static void
198 fill_line(int num_traces, void **traces,
199 unsigned long addr, int file, int line,
200 char *include_directories, char *filenames, line_info_t *lines)
201 {
202 int i;
203 for (i = 0; i < num_traces; i++) {
204 unsigned long a = (unsigned long)traces[i] - lines[i].base_addr;
205 /* We assume one line code doesn't result >100 bytes of native code.
206 We may want more reliable way eventually... */
207 if (addr < a && a < addr + 100) {
208 fill_filename(file, include_directories, filenames, &lines[i]);
209 lines[i].line = line;
210 }
211 }
212 }
213
214 static void
215 parse_debug_line_cu(int num_traces, void **traces,
216 char **debug_line, line_info_t *lines)
217 {
218 char *p, *cu_end, *cu_start, *include_directories, *filenames;
219 unsigned long unit_length;
220 int default_is_stmt, line_base;
221 unsigned int header_length, minimum_instruction_length, line_range,
222 opcode_base;
6a7666e @nurse * io.c (io_encoding_set): suppress warnings. [ruby-dev:45627]
nurse authored
223 /* unsigned char *standard_opcode_lengths; */
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
224
225 /* The registers. */
226 unsigned long addr = 0;
227 unsigned int file = 1;
228 unsigned int line = 1;
6a7666e @nurse * io.c (io_encoding_set): suppress warnings. [ruby-dev:45627]
nurse authored
229 /* unsigned int column = 0; */
39e7b2f @nurse * addr2line.c: apply a patch from shinichiro.h.
nurse authored
230 int is_stmt;
6a7666e @nurse * io.c (io_encoding_set): suppress warnings. [ruby-dev:45627]
nurse authored
231 /* int basic_block = 0; */
232 /* int end_sequence = 0; */
233 /* int prologue_end = 0; */
234 /* int epilogue_begin = 0; */
235 /* unsigned int isa = 0; */
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
236
237 p = *debug_line;
238
239 unit_length = *(unsigned int *)p;
240 p += sizeof(unsigned int);
241 if (unit_length == 0xffffffff) {
242 unit_length = *(unsigned long *)p;
243 p += sizeof(unsigned long);
244 }
245
246 cu_end = p + unit_length;
247
248 /*dwarf_version = *(unsigned short *)p;*/
249 p += 2;
250
251 header_length = *(unsigned int *)p;
252 p += sizeof(unsigned int);
253
254 cu_start = p + header_length;
255
256 minimum_instruction_length = *(unsigned char *)p;
257 p++;
258
39e7b2f @nurse * addr2line.c: apply a patch from shinichiro.h.
nurse authored
259 is_stmt = default_is_stmt = *(unsigned char *)p;
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
260 p++;
261
262 line_base = *(char *)p;
263 p++;
264
265 line_range = *(unsigned char *)p;
266 p++;
267
268 opcode_base = *(unsigned char *)p;
269 p++;
270
6a7666e @nurse * io.c (io_encoding_set): suppress warnings. [ruby-dev:45627]
nurse authored
271 /* standard_opcode_lengths = (unsigned char *)p - 1; */
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
272 p += opcode_base - 1;
273
274 include_directories = p;
275
276 /* skip include directories */
277 while (*p) {
278 while (*p) p++;
279 p++;
280 }
281 p++;
282
283 filenames = p;
284
285 p = cu_start;
286
287 #define FILL_LINE() \
288 do { \
289 fill_line(num_traces, traces, addr, file, line, \
290 include_directories, filenames, lines); \
6a7666e @nurse * io.c (io_encoding_set): suppress warnings. [ruby-dev:45627]
nurse authored
291 /*basic_block = prologue_end = epilogue_begin = 0;*/ \
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
292 } while (0)
293
294 while (p < cu_end) {
295 unsigned long a;
296 unsigned char op = *p++;
297 switch (op) {
298 case DW_LNS_copy:
299 FILL_LINE();
300 break;
301 case DW_LNS_advance_pc:
302 a = uleb128(&p);
303 addr += a;
304 break;
305 case DW_LNS_advance_line: {
306 long a = sleb128(&p);
307 line += a;
308 break;
309 }
310 case DW_LNS_set_file:
48de1e2 @nurse * addr2line.c: suppressed shorten-64-to-32 warnings.
nurse authored
311 file = (unsigned int)uleb128(&p);
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
312 break;
313 case DW_LNS_set_column:
6a7666e @nurse * io.c (io_encoding_set): suppress warnings. [ruby-dev:45627]
nurse authored
314 /*column = (unsigned int)*/(void)uleb128(&p);
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
315 break;
316 case DW_LNS_negate_stmt:
317 is_stmt = !is_stmt;
318 break;
319 case DW_LNS_set_basic_block:
6a7666e @nurse * io.c (io_encoding_set): suppress warnings. [ruby-dev:45627]
nurse authored
320 /*basic_block = 1; */
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
321 break;
322 case DW_LNS_const_add_pc:
323 a = ((255 - opcode_base) / line_range) *
324 minimum_instruction_length;
325 addr += a;
326 break;
327 case DW_LNS_fixed_advance_pc:
328 a = *(unsigned char *)p++;
329 addr += a;
330 break;
331 case DW_LNS_set_prologue_end:
6a7666e @nurse * io.c (io_encoding_set): suppress warnings. [ruby-dev:45627]
nurse authored
332 /* prologue_end = 1; */
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
333 break;
334 case DW_LNS_set_epilogue_begin:
6a7666e @nurse * io.c (io_encoding_set): suppress warnings. [ruby-dev:45627]
nurse authored
335 /* epilogue_begin = 1; */
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
336 break;
337 case DW_LNS_set_isa:
6a7666e @nurse * io.c (io_encoding_set): suppress warnings. [ruby-dev:45627]
nurse authored
338 /* isa = (unsigned int)*/(void)uleb128(&p);
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
339 break;
340 case 0:
341 a = *(unsigned char *)p++;
342 op = *p++;
343 switch (op) {
344 case DW_LNE_end_sequence:
6a7666e @nurse * io.c (io_encoding_set): suppress warnings. [ruby-dev:45627]
nurse authored
345 /* end_sequence = 1; */
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
346 FILL_LINE();
347 addr = 0;
348 file = 1;
349 line = 1;
6a7666e @nurse * io.c (io_encoding_set): suppress warnings. [ruby-dev:45627]
nurse authored
350 /* column = 0; */
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
351 is_stmt = default_is_stmt;
6a7666e @nurse * io.c (io_encoding_set): suppress warnings. [ruby-dev:45627]
nurse authored
352 /* end_sequence = 0; */
353 /* isa = 0; */
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
354 break;
355 case DW_LNE_set_address:
356 addr = *(unsigned long *)p;
357 p += sizeof(unsigned long);
358 break;
359 case DW_LNE_define_file:
360 fprintf(stderr, "Unsupported operation in %s\n",
361 binary_filename);
362 break;
8770354 @nurse * addr2line.c (parse_debug_line_cu): ignore DW_LNE_set_discriminator.
nurse authored
363 case DW_LNE_set_discriminator:
364 /* TODO:currently ignore */
365 uleb128(&p);
366 break;
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
367 default:
368 fprintf(stderr, "Unknown extended opcode: %d in %s\n",
369 op, binary_filename);
370 }
371 break;
372 default: {
48de1e2 @nurse * addr2line.c: suppressed shorten-64-to-32 warnings.
nurse authored
373 unsigned long addr_incr;
374 unsigned long line_incr;
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
375 a = op - opcode_base;
376 addr_incr = (a / line_range) * minimum_instruction_length;
377 line_incr = line_base + (a % line_range);
48de1e2 @nurse * addr2line.c: suppressed shorten-64-to-32 warnings.
nurse authored
378 addr += (unsigned int)addr_incr;
379 line += (unsigned int)line_incr;
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
380 FILL_LINE();
381 }
382 }
383 }
384 *debug_line = p;
385 }
386
387 static void
388 parse_debug_line(int num_traces, void **traces,
389 char *debug_line, unsigned long size, line_info_t *lines)
390 {
391 char *debug_line_end = debug_line + size;
392 while (debug_line < debug_line_end) {
393 parse_debug_line_cu(num_traces, traces, &debug_line, lines);
394 }
395 if (debug_line != debug_line_end) {
396 fprintf(stderr, "Unexpected size of .debug_line in %s\n",
397 binary_filename);
398 }
399 }
400
401 /* read file and fill lines */
402 static void
22b2c63 @nurse * addr2line.c: Follow .gnu_debuglink section.
nurse authored
403 fill_lines(int num_traces, void **traces, char **syms, int check_debuglink,
404 line_info_t *current_line, line_info_t *lines);
405
406 static void
407 follow_debuglink(char *debuglink, int num_traces, void **traces, char **syms,
408 line_info_t *current_line, line_info_t *lines)
409 {
410 /* Ideally we should check 4 paths to follow gnu_debuglink,
411 but we handle only one case for now as this format is used
412 by some linux distributions. See GDB's info for detail. */
413 static const char global_debug_dir[] = "/usr/lib/debug";
414 char *p, *subdir;
415
416 p = strrchr(binary_filename, '/');
417 if (!p) {
418 return;
419 }
420 p[1] = '\0';
421
422 subdir = (char *)alloca(strlen(binary_filename) + 1);
423 strcpy(subdir, binary_filename);
424 strcpy(binary_filename, global_debug_dir);
425 strncat(binary_filename, subdir,
426 PATH_MAX - strlen(binary_filename) - 1);
427 strncat(binary_filename, debuglink,
428 PATH_MAX - strlen(binary_filename) - 1);
429
430 munmap(current_line->mapped, current_line->mapped_size);
431 close(current_line->fd);
432 fill_lines(num_traces, traces, syms, 0, current_line, lines);
433 }
434
435 /* read file and fill lines */
436 static void
437 fill_lines(int num_traces, void **traces, char **syms, int check_debuglink,
438 line_info_t *current_line, line_info_t *lines)
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
439 {
440 int i;
441 char *shstr;
442 char *section_name;
443 ElfW(Ehdr) *ehdr;
22b2c63 @nurse * addr2line.c: Follow .gnu_debuglink section.
nurse authored
444 ElfW(Shdr) *shdr, *shstr_shdr;
445 ElfW(Shdr) *debug_line_shdr = NULL, *gnu_debuglink_shdr = NULL;
446 int fd;
447 off_t filesize;
448 char *file;
449
450 fd = open(binary_filename, O_RDONLY);
451 if (fd < 0) {
452 return;
453 }
454 filesize = lseek(fd, 0, SEEK_END);
6a288de @nurse * addr2line.c (uleb128): cast the value to unsigned long.
nurse authored
455 if (filesize < 0) {
456 int e = errno;
457 close(fd);
458 fprintf(stderr, "lseek: %s\n", strerror(e));
459 return;
460 }
22b2c63 @nurse * addr2line.c: Follow .gnu_debuglink section.
nurse authored
461 lseek(fd, 0, SEEK_SET);
462 /* async-signal unsafe */
463 file = (char *)mmap(NULL, filesize, PROT_READ, MAP_SHARED, fd, 0);
464 if (file == MAP_FAILED) {
465 int e = errno;
466 close(fd);
467 fprintf(stderr, "mmap: %s\n", strerror(e));
468 return;
469 }
470
471 current_line->fd = fd;
472 current_line->mapped = file;
473 current_line->mapped_size = filesize;
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
474
475 for (i = 0; i < num_traces; i++) {
476 const char *path;
477 size_t len;
478 if (get_path_from_symbol(syms[i], &path, &len) &&
479 !strncmp(path, binary_filename, len)) {
480 lines[i].line = -1;
481 }
482 }
483
484 ehdr = (ElfW(Ehdr) *)file;
485 shdr = (ElfW(Shdr) *)(file + ehdr->e_shoff);
486
487 shstr_shdr = shdr + ehdr->e_shstrndx;
488 shstr = file + shstr_shdr->sh_offset;
489
490 for (i = 0; i < ehdr->e_shnum; i++) {
491 section_name = shstr + shdr[i].sh_name;
492 if (!strcmp(section_name, ".debug_line")) {
493 debug_line_shdr = shdr + i;
494 break;
22b2c63 @nurse * addr2line.c: Follow .gnu_debuglink section.
nurse authored
495 } else if (!strcmp(section_name, ".gnu_debuglink")) {
496 gnu_debuglink_shdr = shdr + i;
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
497 }
498 }
499
500 if (!debug_line_shdr) {
22b2c63 @nurse * addr2line.c: Follow .gnu_debuglink section.
nurse authored
501 /* This file doesn't have .debug_line section,
502 let's check .gnu_debuglink section instead. */
503 if (gnu_debuglink_shdr && check_debuglink) {
504 follow_debuglink(file + gnu_debuglink_shdr->sh_offset,
505 num_traces, traces, syms,
506 current_line, lines);
507 }
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
508 return;
509 }
510
511 parse_debug_line(num_traces, traces,
512 file + debug_line_shdr->sh_offset,
513 debug_line_shdr->sh_size,
514 lines);
515 }
516
517 #ifdef HAVE_DL_ITERATE_PHDR
518
519 typedef struct {
520 int num_traces;
521 char **syms;
522 line_info_t *lines;
523 } fill_base_addr_state_t;
524
525 static int
526 fill_base_addr(struct dl_phdr_info *info, size_t size, void *data)
527 {
528 int i;
529 fill_base_addr_state_t *st = (fill_base_addr_state_t *)data;
530 for (i = 0; i < st->num_traces; i++) {
531 const char *path;
532 size_t len;
533 size_t name_len = strlen(info->dlpi_name);
534
535 if (get_path_from_symbol(st->syms[i], &path, &len) &&
536 (len == name_len || (len > name_len && path[len-name_len-1] == '/')) &&
537 !strncmp(path+len-name_len, info->dlpi_name, name_len)) {
538 st->lines[i].base_addr = info->dlpi_addr;
539 }
540 }
541 return 0;
542 }
543
544 #endif /* HAVE_DL_ITERATE_PHDR */
545
546 void
547 rb_dump_backtrace_with_lines(int num_traces, void **trace, char **syms)
548 {
549 int i;
550 /* async-signal unsafe */
551 line_info_t *lines = (line_info_t *)calloc(num_traces,
552 sizeof(line_info_t));
553
554 /* Note that line info of shared objects might not be shown
555 if we don't have dl_iterate_phdr */
556 #ifdef HAVE_DL_ITERATE_PHDR
557 fill_base_addr_state_t fill_base_addr_state;
558
559 fill_base_addr_state.num_traces = num_traces;
560 fill_base_addr_state.syms = syms;
561 fill_base_addr_state.lines = lines;
562 /* maybe async-signal unsafe */
563 dl_iterate_phdr(fill_base_addr, &fill_base_addr_state);
564 #endif /* HAVE_DL_ITERATE_PHDR */
565
566 for (i = 0; i < num_traces; i++) {
567 const char *path;
568 size_t len;
569 if (lines[i].line) {
570 continue;
571 }
572
573 if (!get_path_from_symbol(syms[i], &path, &len)) {
574 continue;
575 }
576
577 strncpy(binary_filename, path, len);
578 binary_filename[len] = '\0';
579
22b2c63 @nurse * addr2line.c: Follow .gnu_debuglink section.
nurse authored
580 fill_lines(num_traces, trace, syms, 1, &lines[i], lines);
086301a @nurse * addr2line.c: added to show source filename and line number of
nurse authored
581 }
582
583 /* fprintf may not be async-signal safe */
584 for (i = 0; i < num_traces; i++) {
585 line_info_t *line = &lines[i];
586
587 if (line->line > 0) {
588 fprintf(stderr, "%s ", syms[i]);
589 if (line->filename) {
590 if (line->dirname && line->dirname[0]) {
591 fprintf(stderr, "%s/", line->dirname);
592 }
593 fprintf(stderr, "%s", line->filename);
594 } else {
595 fprintf(stderr, "???");
596 }
597 fprintf(stderr, ":%d\n", line->line);
598 } else {
599 fprintf(stderr, "%s\n", syms[i]);
600 }
601 }
602
603 for (i = 0; i < num_traces; i++) {
604 line_info_t *line = &lines[i];
605 if (line->fd) {
606 munmap(line->mapped, line->mapped_size);
607 close(line->fd);
608 }
609 }
610 free(lines);
611 }
612
e33183a @nurse * addr2line.c: use USE_ELF instead of __ELF__ because Solaris
nurse authored
613 #else /* defined(USE_ELF) */
3c36edc @nobu * configure.in: link addr2line only for ELF.
nobu authored
614 #error not supported
615 #endif
Something went wrong with that request. Please try again.