11 #include "ruby/config.h"
31 #include <sys/types.h>
39 # define alloca __builtin_alloca
56 #ifdef HAVE_DL_ITERATE_PHDR
63 #define DW_LNS_copy 0x01
64 #define DW_LNS_advance_pc 0x02
65 #define DW_LNS_advance_line 0x03
66 #define DW_LNS_set_file 0x04
67 #define DW_LNS_set_column 0x05
68 #define DW_LNS_negate_stmt 0x06
69 #define DW_LNS_set_basic_block 0x07
70 #define DW_LNS_const_add_pc 0x08
71 #define DW_LNS_fixed_advance_pc 0x09
72 #define DW_LNS_set_prologue_end 0x0a
73 #define DW_LNS_set_epilogue_begin 0x0b
74 #define DW_LNS_set_isa 0x0c
77 #define DW_LNE_end_sequence 0x01
78 #define DW_LNE_set_address 0x02
79 #define DW_LNE_define_file 0x03
80 #define DW_LNE_set_discriminator 0x04
83 # if SIZEOF_VOIDP == 8
84 # define ElfW(x) Elf64##_##x
86 # define ElfW(x) Elf32##_##x
93 int kprintf(
const char *fmt, ...);
103 unsigned long base_addr;
107 static char binary_filename[
PATH_MAX];
115 unsigned char b = *(
unsigned char *)(*p)++;
117 r += (
unsigned long)b << s;
120 r += (b & 0x7f) << s;
132 unsigned char b = *(
unsigned char *)(*p)++;
135 r -= (0x80 - b) << s;
138 r += (b & 0x3f) << s;
142 r += (b & 0x7f) << s;
149 get_nth_dirname(
unsigned long dir,
char *p)
158 kprintf(
"Unexpected directory number %lu in %s\n",
159 dir, binary_filename);
167 fill_filename(
int file,
char *include_directories,
char *filenames,
174 for (i = 1; i <= file; i++) {
178 kprintf(
"Unexpected file number %d in %s\n",
179 file, binary_filename);
191 line->filename = filename;
192 line->dirname = get_nth_dirname(dir, include_directories);
198 get_path_from_symbol(
const char *symbol,
const char **p,
size_t *len)
200 if (symbol[0] ==
'0') {
203 if (*p ==
NULL)
return 0;
211 if (q ==
NULL)
return 0;
218 fill_line(
int num_traces,
void **traces,
219 unsigned long addr,
int file,
int line,
220 char *include_directories,
char *filenames, line_info_t *lines)
223 for (i = 0; i < num_traces; i++) {
224 unsigned long a = (
unsigned long)traces[i] - lines[i].base_addr;
227 if (addr < a && a < addr + 100) {
228 fill_filename(file, include_directories, filenames, &lines[i]);
229 lines[
i].line = line;
235 parse_debug_line_cu(
int num_traces,
void **traces,
236 char **debug_line, line_info_t *lines)
238 char *
p, *cu_end, *cu_start, *include_directories, *filenames;
239 unsigned long unit_length;
240 int default_is_stmt, line_base;
241 unsigned int header_length, minimum_instruction_length, line_range,
246 unsigned long addr = 0;
247 unsigned int file = 1;
248 unsigned int line = 1;
259 unit_length = *(
unsigned int *)p;
260 p +=
sizeof(
unsigned int);
261 if (unit_length == 0xffffffff) {
262 unit_length = *(
unsigned long *)p;
263 p +=
sizeof(
unsigned long);
266 cu_end = p + unit_length;
271 header_length = *(
unsigned int *)p;
272 p +=
sizeof(
unsigned int);
274 cu_start = p + header_length;
276 minimum_instruction_length = *(
unsigned char *)p;
279 is_stmt = default_is_stmt = *(
unsigned char *)p;
282 line_base = *(
char *)p;
285 line_range = *(
unsigned char *)p;
288 opcode_base = *(
unsigned char *)p;
292 p += opcode_base - 1;
294 include_directories =
p;
307 #define FILL_LINE() \
309 fill_line(num_traces, traces, addr, file, line, \
310 include_directories, filenames, lines); \
316 unsigned char op = *p++;
321 case DW_LNS_advance_pc:
325 case DW_LNS_advance_line: {
326 long a = sleb128(&p);
330 case DW_LNS_set_file:
331 file = (
unsigned int)uleb128(&p);
333 case DW_LNS_set_column:
336 case DW_LNS_negate_stmt:
339 case DW_LNS_set_basic_block:
342 case DW_LNS_const_add_pc:
343 a = ((255 - opcode_base) / line_range) *
344 minimum_instruction_length;
347 case DW_LNS_fixed_advance_pc:
348 a = *(
unsigned char *)p++;
351 case DW_LNS_set_prologue_end:
354 case DW_LNS_set_epilogue_begin:
361 a = *(
unsigned char *)p++;
364 case DW_LNE_end_sequence:
371 is_stmt = default_is_stmt;
375 case DW_LNE_set_address:
376 addr = *(
unsigned long *)p;
377 p +=
sizeof(
unsigned long);
379 case DW_LNE_define_file:
380 kprintf(
"Unsupported operation in %s\n",
383 case DW_LNE_set_discriminator:
388 kprintf(
"Unknown extended opcode: %d in %s\n",
389 op, binary_filename);
393 unsigned long addr_incr;
394 unsigned long line_incr;
395 a = op - opcode_base;
396 addr_incr = (a / line_range) * minimum_instruction_length;
397 line_incr = line_base + (a % line_range);
398 addr += (
unsigned int)addr_incr;
399 line += (
unsigned int)line_incr;
408 parse_debug_line(
int num_traces,
void **traces,
409 char *debug_line,
unsigned long size, line_info_t *lines)
411 char *debug_line_end = debug_line +
size;
412 while (debug_line < debug_line_end) {
413 parse_debug_line_cu(num_traces, traces, &debug_line, lines);
415 if (debug_line != debug_line_end) {
416 kprintf(
"Unexpected size of .debug_line in %s\n",
423 fill_lines(
int num_traces,
void **traces,
char **syms,
int check_debuglink,
424 line_info_t *current_line, line_info_t *lines);
427 follow_debuglink(
char *debuglink,
int num_traces,
void **traces,
char **syms,
428 line_info_t *current_line, line_info_t *lines)
433 static const char global_debug_dir[] =
"/usr/lib/debug";
436 p =
strrchr(binary_filename,
'/');
443 strcpy(subdir, binary_filename);
444 strcpy(binary_filename, global_debug_dir);
445 strncat(binary_filename, subdir,
447 strncat(binary_filename, debuglink,
450 munmap(current_line->mapped, current_line->mapped_size);
451 close(current_line->fd);
452 fill_lines(num_traces, traces, syms, 0, current_line, lines);
457 fill_lines(
int num_traces,
void **traces,
char **syms,
int check_debuglink,
458 line_info_t *current_line, line_info_t *lines)
464 ElfW(Shdr) *shdr, *shstr_shdr;
465 ElfW(Shdr) *debug_line_shdr =
NULL, *gnu_debuglink_shdr =
NULL;
470 fd = open(binary_filename, O_RDONLY);
478 kprintf(
"lseek: %s\n",
strerror(e));
481 #if SIZEOF_OFF_T > SIZEOF_SIZE_T
484 kprintf(
"Too large file %s\n", binary_filename);
490 file = (
char *)mmap(
NULL, (
size_t)filesize, PROT_READ, MAP_SHARED, fd, 0);
491 if (file == MAP_FAILED) {
498 ehdr = (ElfW(Ehdr) *)file;
499 if (
memcmp(ehdr->e_ident,
"\177ELF", 4) != 0) {
508 current_line->fd = fd;
509 current_line->mapped = file;
510 current_line->mapped_size = (size_t)filesize;
512 for (i = 0; i < num_traces; i++) {
515 if (get_path_from_symbol(syms[i], &path, &len) &&
516 !strncmp(path, binary_filename, len)) {
521 shdr = (ElfW(Shdr) *)(file + ehdr->e_shoff);
523 shstr_shdr = shdr + ehdr->e_shstrndx;
524 shstr = file + shstr_shdr->sh_offset;
526 for (i = 0; i < ehdr->e_shnum; i++) {
527 section_name = shstr + shdr[
i].sh_name;
528 if (!strcmp(section_name,
".debug_line")) {
529 debug_line_shdr = shdr +
i;
531 }
else if (!strcmp(section_name,
".gnu_debuglink")) {
532 gnu_debuglink_shdr = shdr +
i;
536 if (!debug_line_shdr) {
539 if (gnu_debuglink_shdr && check_debuglink) {
540 follow_debuglink(file + gnu_debuglink_shdr->sh_offset,
541 num_traces, traces, syms,
542 current_line, lines);
547 parse_debug_line(num_traces, traces,
548 file + debug_line_shdr->sh_offset,
549 debug_line_shdr->sh_size,
553 #ifdef HAVE_DL_ITERATE_PHDR
559 } fill_base_addr_state_t;
562 fill_base_addr(
struct dl_phdr_info *info,
size_t size,
void *data)
565 fill_base_addr_state_t *st = (fill_base_addr_state_t *)data;
566 for (i = 0; i < st->num_traces; i++) {
569 size_t name_len =
strlen(info->dlpi_name);
571 if (get_path_from_symbol(st->syms[i], &path, &len) &&
572 (len == name_len || (len > name_len && path[len-name_len-1] ==
'/')) &&
573 !strncmp(path+len-name_len, info->dlpi_name, name_len)) {
574 st->lines[
i].base_addr = info->dlpi_addr;
583 rb_dump_backtrace_with_lines(
int num_traces,
void **trace,
char **syms)
587 line_info_t *lines = (line_info_t *)
calloc(num_traces,
588 sizeof(line_info_t));
592 #ifdef HAVE_DL_ITERATE_PHDR
593 fill_base_addr_state_t fill_base_addr_state;
595 fill_base_addr_state.num_traces = num_traces;
596 fill_base_addr_state.syms = syms;
597 fill_base_addr_state.lines = lines;
599 dl_iterate_phdr(fill_base_addr, &fill_base_addr_state);
602 for (i = 0; i < num_traces; i++) {
609 if (!get_path_from_symbol(syms[i], &path, &len)) {
613 strncpy(binary_filename, path, len);
614 binary_filename[len] =
'\0';
616 fill_lines(num_traces, trace, syms, 1, &lines[i], lines);
619 for (i = 0; i < num_traces; i++) {
620 line_info_t *line = &lines[
i];
622 if (line->line > 0) {
623 if (line->filename) {
624 if (line->dirname && line->dirname[0]) {
625 kprintf(
"%s %s/%s:%d\n", syms[i], line->dirname, line->filename, line->line);
628 kprintf(
"%s %s:%d\n", syms[i], line->filename, line->line);
631 kprintf(
"%s ???:%d\n", syms[i], line->line);
634 kprintf(
"%s\n", syms[i]);
638 for (i = 0; i < num_traces; i++) {
639 line_info_t *line = &lines[
i];
641 munmap(line->mapped, line->mapped_size);
686 #define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1)
688 #define toupper(c) rb_toupper(c)
689 #define hex2ascii(hex) (hex2ascii_data[hex])
690 char const hex2ascii_data[] =
"0123456789abcdefghijklmnopqrstuvwxyz";
691 static inline int imax(
int a,
int b) {
return (a > b ? a : b); }
692 static int kvprintf(
char const *fmt,
void (*
func)(
int),
void *arg,
int radix, va_list ap);
694 static void putce(
int c)
700 ret = write(2, s, 1);
705 kprintf(
const char *fmt, ...)
711 retval = kvprintf(fmt, putce,
NULL, 10, ap);
723 ksprintn(
char *nbuf, uintmax_t num,
int base,
int *lenp,
int upper)
730 c = hex2ascii(num % base);
731 *++p = upper ? toupper(c) : c;
732 }
while (num /= base);
765 kvprintf(
char const *fmt,
void (*
func)(
int),
void *arg,
int radix, va_list ap)
767 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; }
770 const char *
p, *percent, *q;
774 int base, lflag, qflag, tmp, width, ladjust, sharpflag,
neg, sign, dot;
775 int cflag, hflag, jflag, tflag, zflag;
778 int stop = 0, retval = 0;
787 fmt =
"(fmt null)\n";
789 if (radix < 2 || radix > 36)
795 while ((ch = (
unsigned char)*fmt++) !=
'%' || stop) {
801 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
802 sign = 0; dot = 0; dwidth = 0; upper = 0;
803 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
804 reswitch:
switch (ch = (
unsigned char)*fmt++) {
822 width = va_arg(ap,
int);
828 dwidth = va_arg(ap,
int);
836 case '1':
case '2':
case '3':
case '4':
837 case '5':
case '6':
case '7':
case '8':
case '9':
838 for (n = 0;; ++fmt) {
839 n = n * 10 + ch -
'0';
841 if (ch < '0' || ch >
'9')
850 num = (
unsigned int)va_arg(ap,
int);
851 p = va_arg(ap,
char *);
852 for (q = ksprintn(nbuf, num, *p++,
NULL, 0); *q;)
860 if (num & (1 << (n - 1))) {
861 PCHAR(tmp ?
',' :
'<');
862 for (; (n = *
p) >
' '; ++
p)
866 for (; *p >
' '; ++
p)
873 PCHAR(va_arg(ap,
int));
876 up = va_arg(ap,
unsigned char *);
877 p = va_arg(ap,
char *);
881 PCHAR(hex2ascii(*up >> 4));
882 PCHAR(hex2ascii(*up & 0x0f));
913 *(va_arg(ap, intmax_t *)) = retval;
915 *(va_arg(ap, int64_t *)) = retval;
917 *(va_arg(ap,
long *)) = retval;
919 *(va_arg(ap,
size_t *)) = retval;
921 *(va_arg(ap,
short *)) = retval;
923 *(va_arg(ap,
char *)) = retval;
925 *(va_arg(ap,
int *)) = retval;
932 sharpflag = (width == 0);
945 p = va_arg(ap,
char *);
951 for (n = 0; n < dwidth && p[n]; n++)
956 if (!ladjust && width > 0)
961 if (ladjust && width > 0)
986 num = va_arg(ap, uintmax_t);
990 num = va_arg(ap, ptrdiff_t);
992 num = va_arg(ap,
unsigned long);
994 num = va_arg(ap,
size_t);
996 num = (
unsigned short)va_arg(ap,
int);
998 num = (
unsigned char)va_arg(ap,
int);
1000 num = va_arg(ap,
unsigned int);
1004 num = va_arg(ap, intmax_t);
1006 num = va_arg(ap, int64_t);
1008 num = va_arg(ap, ptrdiff_t);
1010 num = va_arg(ap,
long);
1012 num = va_arg(ap, ssize_t);
1014 num = (short)va_arg(ap,
int);
1016 num = (char)va_arg(ap,
int);
1018 num = va_arg(ap,
int);
1020 if (sign && (intmax_t)num < 0) {
1022 num = -(intmax_t)num;
1024 p = ksprintn(nbuf, num, base, &n, upper);
1026 if (sharpflag && num != 0) {
1029 else if (base == 16)
1035 if (!ladjust && padc ==
'0')
1036 dwidth = width - tmp;
1037 width -= tmp + imax(dwidth, n);
1044 if (sharpflag && num != 0) {
1047 }
else if (base == 16) {
1052 while (dwidth-- > 0)
1064 while (percent < fmt)
1079 #error not supported
size_t strlen(const char *)
SSL_METHOD *(* func)(void)
unsigned long long uint64_t
char * strchr(char *, char)
int memcmp(const void *s1, const void *s2, size_t len)
RUBY_EXTERN char * strerror(int)
char * strrchr(const char *, const char)