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