11 #include "ruby/config.h" 27 #include <sys/types.h> 40 # define alloca __builtin_alloca 60 #define DW_LNS_copy 0x01 61 #define DW_LNS_advance_pc 0x02 62 #define DW_LNS_advance_line 0x03 63 #define DW_LNS_set_file 0x04 64 #define DW_LNS_set_column 0x05 65 #define DW_LNS_negate_stmt 0x06 66 #define DW_LNS_set_basic_block 0x07 67 #define DW_LNS_const_add_pc 0x08 68 #define DW_LNS_fixed_advance_pc 0x09 69 #define DW_LNS_set_prologue_end 0x0a 70 #define DW_LNS_set_epilogue_begin 0x0b 71 #define DW_LNS_set_isa 0x0c 74 #define DW_LNE_end_sequence 0x01 75 #define DW_LNE_set_address 0x02 76 #define DW_LNE_define_file 0x03 77 #define DW_LNE_set_discriminator 0x04 80 # if SIZEOF_VOIDP == 8 81 # define ElfW(x) Elf64##_##x 83 # define ElfW(x) Elf32##_##x 87 # if SIZEOF_VOIDP == 8 88 # define ELF_ST_TYPE ELF64_ST_TYPE 90 # define ELF_ST_TYPE ELF32_ST_TYPE 97 int kprintf(
const char *fmt, ...);
101 const char *filename;
109 typedef struct obj_info obj_info_t;
120 static char binary_filename[
PATH_MAX];
128 unsigned char b = *(
unsigned char *)(*p)++;
130 r += (
unsigned long)b << s;
133 r += (b & 0x7f) << s;
145 unsigned char b = *(
unsigned char *)(*p)++;
148 r -= (0x80 - b) << s;
151 r += (b & 0x3f) << s;
155 r += (b & 0x7f) << s;
162 get_nth_dirname(
unsigned long dir,
char *p)
171 kprintf(
"Unexpected directory number %lu in %s\n",
172 dir, binary_filename);
180 fill_filename(
int file,
char *include_directories,
char *filenames,
187 for (i = 1; i <= file; i++) {
191 kprintf(
"Unexpected file number %d in %s\n",
192 file, binary_filename);
204 line->filename = filename;
205 line->dirname = get_nth_dirname(dir, include_directories);
211 fill_line(
int num_traces,
void **traces,
uintptr_t addr,
int file,
int line,
212 char *include_directories,
char *filenames,
213 obj_info_t *obj, line_info_t *lines,
int offset)
216 addr += obj->base_addr;
217 for (i = offset; i < num_traces; i++) {
221 if (addr < a && a < addr + 100) {
222 fill_filename(file, include_directories, filenames, &lines[i]);
223 lines[i].line = line;
229 parse_debug_line_cu(
int num_traces,
void **traces,
char **debug_line,
230 obj_info_t *obj, line_info_t *lines,
int offset)
232 char *p, *cu_end, *cu_start, *include_directories, *filenames;
233 unsigned long unit_length;
234 int default_is_stmt, line_base;
235 unsigned int header_length, minimum_instruction_length, line_range,
240 unsigned long addr = 0;
241 unsigned int file = 1;
242 unsigned int line = 1;
253 unit_length = *(
unsigned int *)p;
254 p +=
sizeof(
unsigned int);
255 if (unit_length == 0xffffffff) {
256 unit_length = *(
unsigned long *)p;
257 p +=
sizeof(
unsigned long);
260 cu_end = p + unit_length;
265 header_length = *(
unsigned int *)p;
266 p +=
sizeof(
unsigned int);
268 cu_start = p + header_length;
270 minimum_instruction_length = *(
unsigned char *)p;
273 is_stmt = default_is_stmt = *(
unsigned char *)p;
276 line_base = *(
signed char *)p;
279 line_range = *(
unsigned char *)p;
282 opcode_base = *(
unsigned char *)p;
286 p += opcode_base - 1;
288 include_directories = p;
291 if (p >= cu_end)
return -1;
295 p = memchr(p,
'\0', cu_end - p);
305 #define FILL_LINE() \ 307 fill_line(num_traces, traces, addr, file, line, \ 308 include_directories, filenames, \ 309 obj, lines, offset); \ 315 unsigned char op = *p++;
320 case DW_LNS_advance_pc:
324 case DW_LNS_advance_line: {
325 long a = sleb128(&p);
329 case DW_LNS_set_file:
330 file = (
unsigned int)uleb128(&p);
332 case DW_LNS_set_column:
335 case DW_LNS_negate_stmt:
338 case DW_LNS_set_basic_block:
341 case DW_LNS_const_add_pc:
342 a = ((255 - opcode_base) / line_range) *
343 minimum_instruction_length;
346 case DW_LNS_fixed_advance_pc:
347 a = *(
unsigned char *)p++;
350 case DW_LNS_set_prologue_end:
353 case DW_LNS_set_epilogue_begin:
360 a = *(
unsigned char *)p++;
363 case DW_LNE_end_sequence:
370 is_stmt = default_is_stmt;
374 case DW_LNE_set_address:
375 addr = *(
unsigned long *)p;
376 p +=
sizeof(
unsigned long);
378 case DW_LNE_define_file:
379 kprintf(
"Unsupported operation in %s\n",
382 case DW_LNE_set_discriminator:
387 kprintf(
"Unknown extended opcode: %d in %s\n",
388 op, binary_filename);
392 unsigned long addr_incr;
393 unsigned long line_incr;
394 a = op - opcode_base;
395 addr_incr = (a / line_range) * minimum_instruction_length;
396 line_incr = line_base + (a % line_range);
397 addr += (
unsigned int)addr_incr;
398 line += (
unsigned int)line_incr;
408 parse_debug_line(
int num_traces,
void **traces,
409 char *debug_line,
unsigned long size,
410 obj_info_t *obj, line_info_t *lines,
int offset)
412 char *debug_line_end = debug_line +
size;
413 while (debug_line < debug_line_end) {
414 if (parse_debug_line_cu(num_traces, traces, &debug_line, obj, lines, offset))
417 if (debug_line != debug_line_end) {
418 kprintf(
"Unexpected size of .debug_line in %s\n",
426 fill_lines(
int num_traces,
void **traces,
int check_debuglink,
427 obj_info_t **objp, line_info_t *lines,
int offset);
430 append_obj(obj_info_t **objp)
432 obj_info_t *newobj =
calloc(1,
sizeof(obj_info_t));
433 if (*objp) (*objp)->next = newobj;
438 follow_debuglink(
const char *debuglink,
int num_traces,
void **traces,
439 obj_info_t **objp, line_info_t *lines,
int offset)
444 static const char global_debug_dir[] =
"/usr/lib/debug";
445 const size_t global_debug_dir_len =
sizeof(global_debug_dir) - 1;
447 obj_info_t *
o1 = *objp, *
o2;
450 p =
strrchr(binary_filename,
'/');
456 len =
strlen(binary_filename);
457 if (len >=
PATH_MAX - global_debug_dir_len)
458 len =
PATH_MAX - global_debug_dir_len - 1;
459 memmove(binary_filename + global_debug_dir_len, binary_filename, len);
460 memcpy(binary_filename, global_debug_dir, global_debug_dir_len);
461 len += global_debug_dir_len;
466 o2->base_addr = o1->base_addr;
468 fill_lines(num_traces, traces, 0, objp, lines, offset);
473 fill_lines(
int num_traces,
void **traces,
int check_debuglink,
474 obj_info_t **objp, line_info_t *lines,
int offset)
480 ElfW(Shdr) *shdr, *shstr_shdr;
481 ElfW(Shdr) *debug_line_shdr =
NULL, *gnu_debuglink_shdr =
NULL;
485 ElfW(Shdr) *symtab_shdr =
NULL, *strtab_shdr =
NULL;
486 ElfW(Shdr) *dynsym_shdr =
NULL, *dynstr_shdr =
NULL;
487 obj_info_t *obj = *objp;
490 fd = open(binary_filename, O_RDONLY);
498 kprintf(
"lseek: %s\n",
strerror(e));
501 #if SIZEOF_OFF_T > SIZEOF_SIZE_T 504 kprintf(
"Too large file %s\n", binary_filename);
510 file = (
char *)mmap(
NULL, (
size_t)filesize, PROT_READ, MAP_SHARED, fd, 0);
511 if (file == MAP_FAILED) {
518 ehdr = (ElfW(Ehdr) *)file;
519 if (
memcmp(ehdr->e_ident,
"\177ELF", 4) != 0) {
530 obj->mapped_size = (size_t)filesize;
532 shdr = (ElfW(Shdr) *)(file + ehdr->e_shoff);
534 shstr_shdr = shdr + ehdr->e_shstrndx;
535 shstr = file + shstr_shdr->sh_offset;
537 for (i = 0; i < ehdr->e_shnum; i++) {
538 section_name = shstr + shdr[i].sh_name;
539 switch (shdr[i].sh_type) {
541 if (!strcmp(section_name,
".strtab")) {
542 strtab_shdr = shdr + i;
544 else if (!strcmp(section_name,
".dynstr")) {
545 dynstr_shdr = shdr + i;
550 symtab_shdr = shdr + i;
554 dynsym_shdr = shdr + i;
557 if (!strcmp(section_name,
".debug_line")) {
558 debug_line_shdr = shdr + i;
560 else if (!strcmp(section_name,
".gnu_debuglink")) {
561 gnu_debuglink_shdr = shdr + i;
570 if (dynsym_shdr && dynstr_shdr) {
571 char *strtab = file + dynstr_shdr->sh_offset;
572 ElfW(Sym) *symtab = (ElfW(Sym) *)(file + dynsym_shdr->sh_offset);
573 int symtab_count = (int)(dynsym_shdr->sh_size /
sizeof(ElfW(Sym)));
574 for (j = 0; j < symtab_count; j++) {
575 ElfW(Sym) *
sym = &symtab[j];
578 if (ELF_ST_TYPE(
sym->st_info) != STT_FUNC ||
sym->st_size <= 0)
continue;
579 h = dlopen(
NULL, RTLD_NOW|RTLD_LOCAL);
581 s = dlsym(h, strtab +
sym->st_name);
583 if (dladdr(s, &info)) {
584 dladdr_fbase = (
uintptr_t)info.dli_fbase;
588 if (ehdr->e_type == ET_EXEC) {
593 obj->base_addr = dladdr_fbase;
599 symtab_shdr = dynsym_shdr;
600 strtab_shdr = dynstr_shdr;
603 if (symtab_shdr && strtab_shdr) {
604 char *strtab = file + strtab_shdr->sh_offset;
605 ElfW(Sym) *symtab = (ElfW(Sym) *)(file + symtab_shdr->sh_offset);
606 int symtab_count = (int)(symtab_shdr->sh_size /
sizeof(ElfW(Sym)));
607 for (j = 0; j < symtab_count; j++) {
608 ElfW(Sym) *
sym = &symtab[j];
610 if (ELF_ST_TYPE(
sym->st_info) != STT_FUNC ||
sym->st_size <= 0)
continue;
611 for (i = offset; i < num_traces; i++) {
613 if (lines[i].line > 0 || d <= 0 || d > (
uintptr_t)
sym->st_size)
616 lines[i].sname = strtab +
sym->st_name;
617 lines[i].saddr = saddr;
618 lines[i].path = obj->path;
619 lines[i].base_addr = obj->base_addr;
624 if (!debug_line_shdr) {
627 if (gnu_debuglink_shdr && check_debuglink) {
628 follow_debuglink(file + gnu_debuglink_shdr->sh_offset,
630 objp, lines, offset);
635 if (parse_debug_line(num_traces, traces,
636 file + debug_line_shdr->sh_offset,
637 debug_line_shdr->sh_size,
646 #define HAVE_MAIN_EXE_PATH 647 #if defined(__FreeBSD__) 648 # include <sys/sysctl.h> 656 #if defined(__linux__) 660 # define PROC_SELF_EXE "/proc/self/exe" 662 binary_filename[
len] = 0;
665 #elif defined(__FreeBSD__) 669 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
671 int err = sysctl(mib, 4, binary_filename, &len,
NULL, 0);
673 kprintf(
"Can't get the path of ruby");
680 #undef HAVE_MAIN_EXE_PATH 684 rb_dump_backtrace_with_lines(
int num_traces,
void **traces)
688 line_info_t *lines = (line_info_t *)
calloc(num_traces,
sizeof(line_info_t));
689 obj_info_t *obj =
NULL;
691 void **dladdr_fbases = (
void **)
calloc(num_traces+2,
sizeof(
void *));
692 #ifdef HAVE_MAIN_EXE_PATH 693 char *main_path =
NULL;
695 if ((len = main_exe_path()) > 0) {
696 main_path = (
char *)
alloca(len + 1);
699 memcpy(main_path, binary_filename, len+1);
701 obj->path = main_path;
702 addr = fill_lines(num_traces, traces, 1, &obj, lines, -1);
704 dladdr_fbases[0] = (
void *)addr;
711 for (i = 0; i < num_traces; i++) {
713 if (lines[i].line)
continue;
714 if (dladdr(traces[i], &info)) {
720 for (p=dladdr_fbases; *p; p++) {
721 if (*p == info.dli_fbase) {
722 lines[i].path = info.dli_fname;
723 lines[i].sname = info.dli_sname;
730 obj->base_addr = (
uintptr_t)info.dli_fbase;
731 path = info.dli_fname;
733 lines[i].path = path;
735 if (fill_lines(num_traces, traces, 1, &obj, lines, i) == (
uintptr_t)-1)
743 for (i = 0; i < num_traces; i++) {
744 line_info_t *line = &lines[i];
748 kprintf(
"[0x%lx]\n", addr);
750 else if (!line->saddr || !line->sname) {
751 kprintf(
"%s [0x%lx]\n", line->path, addr);
753 else if (line->line <= 0) {
754 kprintf(
"%s(%s+0x%lx) [0x%lx]\n", line->path, line->sname,
757 else if (!line->filename) {
758 kprintf(
"%s(%s+0x%lx) [0x%lx] ???:%d\n", line->path, line->sname,
759 d, addr, line->line);
761 else if (line->dirname && line->dirname[0]) {
762 kprintf(
"%s(%s+0x%lx) [0x%lx] %s/%s:%d\n", line->path, line->sname,
763 d, addr, line->dirname, line->filename, line->line);
766 kprintf(
"%s(%s+0x%lx) [0x%lx] %s:%d\n", line->path, line->sname,
767 d, addr, line->filename, line->line);
770 if (line->sname && strcmp(
"main", line->sname) == 0)
779 munmap(o->mapped, o->mapped_size);
826 #define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1) 827 static inline int toupper(
int c) {
return (
'A' <= c && c <=
'Z') ? (c&0x5f) : c; }
828 #define hex2ascii(hex) (hex2ascii_data[hex]) 829 char const hex2ascii_data[] =
"0123456789abcdefghijklmnopqrstuvwxyz";
830 static inline int imax(
int a,
int b) {
return (a > b ? a : b); }
831 static int kvprintf(
char const *fmt,
void (*func)(
int),
void *arg,
int radix, va_list ap);
833 static void putce(
int c)
839 ret = write(2, s, 1);
844 kprintf(
const char *fmt, ...)
850 retval = kvprintf(fmt, putce,
NULL, 10, ap);
862 ksprintn(
char *nbuf, uintmax_t num,
int base,
int *lenp,
int upper)
869 c = hex2ascii(num % base);
870 *++p = upper ? toupper(c) : c;
871 }
while (num /= base);
873 *lenp = (int)(p - nbuf);
904 kvprintf(
char const *fmt,
void (*func)(
int),
void *arg,
int radix, va_list ap)
906 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; } 909 const char *p, *percent, *q;
913 int base, lflag, qflag, tmp, width, ladjust, sharpflag,
neg, sign, dot;
914 int cflag, hflag, jflag, tflag, zflag;
917 int stop = 0, retval = 0;
926 fmt =
"(fmt null)\n";
928 if (radix < 2 || radix > 36)
934 while ((ch = (
unsigned char)*fmt++) !=
'%' || stop) {
940 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
941 sign = 0; dot = 0; dwidth = 0; upper = 0;
942 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
943 reswitch:
switch (ch = (
unsigned char)*fmt++) {
961 width = va_arg(ap,
int);
967 dwidth = va_arg(ap,
int);
975 case '1':
case '2':
case '3':
case '4':
976 case '5':
case '6':
case '7':
case '8':
case '9':
977 for (n = 0;; ++fmt) {
978 n = n * 10 + ch -
'0';
980 if (ch < '0' || ch >
'9')
989 num = (
unsigned int)va_arg(ap,
int);
990 p = va_arg(ap,
char *);
991 for (q = ksprintn(nbuf, num, *p++,
NULL, 0); *q;)
999 if (num & (1 << (n - 1))) {
1000 PCHAR(tmp ?
',' :
'<');
1001 for (; (n = *p) >
' '; ++p)
1005 for (; *p >
' '; ++p)
1012 PCHAR(va_arg(ap,
int));
1015 up = va_arg(ap,
unsigned char *);
1016 p = va_arg(ap,
char *);
1020 PCHAR(hex2ascii(*up >> 4));
1021 PCHAR(hex2ascii(*up & 0x0f));
1052 *(va_arg(ap, intmax_t *)) = retval;
1054 *(va_arg(ap, int64_t *)) = retval;
1056 *(va_arg(ap,
long *)) = retval;
1058 *(va_arg(ap,
size_t *)) = retval;
1060 *(va_arg(ap,
short *)) = retval;
1062 *(va_arg(ap,
char *)) = retval;
1064 *(va_arg(ap,
int *)) = retval;
1071 sharpflag = (width == 0);
1084 p = va_arg(ap,
char *);
1090 for (n = 0; n < dwidth && p[n]; n++)
1095 if (!ladjust && width > 0)
1100 if (ladjust && width > 0)
1125 num = va_arg(ap, uintmax_t);
1129 num = va_arg(ap, ptrdiff_t);
1131 num = va_arg(ap,
unsigned long);
1133 num = va_arg(ap,
size_t);
1135 num = (
unsigned short)va_arg(ap,
int);
1137 num = (
unsigned char)va_arg(ap,
int);
1139 num = va_arg(ap,
unsigned int);
1143 num = va_arg(ap, intmax_t);
1145 num = va_arg(ap, int64_t);
1147 num = va_arg(ap, ptrdiff_t);
1149 num = va_arg(ap,
long);
1151 num = va_arg(ap, ssize_t);
1153 num = (short)va_arg(ap,
int);
1155 num = (char)va_arg(ap,
int);
1157 num = va_arg(ap,
int);
1159 if (sign && (intmax_t)num < 0) {
1161 num = -(intmax_t)num;
1163 p = ksprintn(nbuf, num, base, &n, upper);
1165 if (sharpflag && num != 0) {
1168 else if (base == 16)
1174 if (!ladjust && padc ==
'0')
1175 dwidth = width - tmp;
1176 width -= tmp + imax(dwidth, n);
1183 if (sharpflag && num != 0) {
1186 }
else if (base == 16) {
1191 while (dwidth-- > 0)
1203 while (percent < fmt)
1218 #error not supported
size_t strlen(const char *)
ssize_t readlink(const char *, char *, size_t)
if(len<=MAX_WORD_LENGTH &&len >=MIN_WORD_LENGTH)
RUBY_EXTERN void * memmove(void *, const void *, size_t)
unsigned long long uint64_t
RUBY_EXTERN size_t strlcpy(char *, const char *, size_t)
int memcmp(const void *s1, const void *s2, size_t len)
register unsigned int len
RUBY_EXTERN char * strerror(int)
RUBY_SYMBOL_EXPORT_BEGIN void * alloca()
char * strrchr(const char *, const char)