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;
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) {
431 obj_info_t *newobj =
calloc(1,
sizeof(obj_info_t));
432 if (*objp) (*objp)->next = newobj;
437 follow_debuglink(
char *debuglink,
int num_traces,
void **traces,
438 obj_info_t **objp, line_info_t *lines,
int offset)
443 static const char global_debug_dir[] =
"/usr/lib/debug";
445 obj_info_t *
o1 = *objp, *
o2;
447 p =
strrchr(binary_filename,
'/');
454 strcpy(subdir, binary_filename);
455 strcpy(binary_filename, global_debug_dir);
461 o2->base_addr = o1->base_addr;
463 fill_lines(num_traces, traces, 0, objp, lines, offset);
468 fill_lines(
int num_traces,
void **traces,
int check_debuglink,
469 obj_info_t **objp, line_info_t *lines,
int offset)
475 ElfW(Shdr) *shdr, *shstr_shdr;
476 ElfW(Shdr) *debug_line_shdr =
NULL, *gnu_debuglink_shdr =
NULL;
480 ElfW(Shdr) *symtab_shdr =
NULL, *strtab_shdr =
NULL;
481 ElfW(Shdr) *dynsym_shdr =
NULL, *dynstr_shdr =
NULL;
482 obj_info_t *obj = *objp;
485 fd = open(binary_filename, O_RDONLY);
493 kprintf(
"lseek: %s\n",
strerror(e));
496 #if SIZEOF_OFF_T > SIZEOF_SIZE_T 499 kprintf(
"Too large file %s\n", binary_filename);
505 file = (
char *)mmap(
NULL, (
size_t)filesize, PROT_READ, MAP_SHARED, fd, 0);
506 if (file == MAP_FAILED) {
513 ehdr = (ElfW(Ehdr) *)file;
514 if (
memcmp(ehdr->e_ident,
"\177ELF", 4) != 0) {
525 obj->mapped_size = (size_t)filesize;
527 shdr = (ElfW(Shdr) *)(file + ehdr->e_shoff);
529 shstr_shdr = shdr + ehdr->e_shstrndx;
530 shstr = file + shstr_shdr->sh_offset;
532 for (i = 0; i < ehdr->e_shnum; i++) {
533 section_name = shstr + shdr[i].sh_name;
534 switch (shdr[i].sh_type) {
536 if (!strcmp(section_name,
".strtab")) {
537 strtab_shdr = shdr + i;
539 else if (!strcmp(section_name,
".dynstr")) {
540 dynstr_shdr = shdr + i;
545 symtab_shdr = shdr + i;
549 dynsym_shdr = shdr + i;
552 if (!strcmp(section_name,
".debug_line")) {
553 debug_line_shdr = shdr + i;
555 else if (!strcmp(section_name,
".gnu_debuglink")) {
556 gnu_debuglink_shdr = shdr + i;
565 if (dynsym_shdr && dynstr_shdr) {
566 char *strtab = file + dynstr_shdr->sh_offset;
567 ElfW(Sym) *symtab = (ElfW(Sym) *)(file + dynsym_shdr->sh_offset);
568 int symtab_count = (int)(dynsym_shdr->sh_size /
sizeof(ElfW(Sym)));
569 for (j = 0; j < symtab_count; j++) {
570 ElfW(Sym) *
sym = &symtab[j];
573 if (ELF_ST_TYPE(
sym->st_info) != STT_FUNC ||
sym->st_size <= 0)
continue;
574 h = dlopen(
NULL, RTLD_NOW|RTLD_LOCAL);
576 s = dlsym(h, strtab +
sym->st_name);
578 if (dladdr(s, &info)) {
579 dladdr_fbase = (
uintptr_t)info.dli_fbase;
583 if (ehdr->e_type == ET_EXEC) {
588 obj->base_addr = dladdr_fbase;
594 symtab_shdr = dynsym_shdr;
595 strtab_shdr = dynstr_shdr;
598 if (symtab_shdr && strtab_shdr) {
599 char *strtab = file + strtab_shdr->sh_offset;
600 ElfW(Sym) *symtab = (ElfW(Sym) *)(file + symtab_shdr->sh_offset);
601 int symtab_count = (int)(symtab_shdr->sh_size /
sizeof(ElfW(Sym)));
602 for (j = 0; j < symtab_count; j++) {
603 ElfW(Sym) *
sym = &symtab[j];
605 if (ELF_ST_TYPE(
sym->st_info) != STT_FUNC ||
sym->st_size <= 0)
continue;
606 for (i = offset; i < num_traces; i++) {
608 if (lines[i].line > 0 || d <= 0 || d > (
uintptr_t)
sym->st_size)
611 lines[i].sname = strtab +
sym->st_name;
612 lines[i].saddr = saddr;
613 lines[i].path = obj->path;
614 lines[i].base_addr = obj->base_addr;
619 if (!debug_line_shdr) {
622 if (gnu_debuglink_shdr && check_debuglink) {
623 follow_debuglink(file + gnu_debuglink_shdr->sh_offset,
625 objp, lines, offset);
630 if (parse_debug_line(num_traces, traces,
631 file + debug_line_shdr->sh_offset,
632 debug_line_shdr->sh_size,
641 #define HAVE_MAIN_EXE_PATH 642 #if defined(__FreeBSD__) 643 # include <sys/sysctl.h> 651 #if defined(__linux__) 655 # define PROC_SELF_EXE "/proc/self/exe" 657 binary_filename[
len] = 0;
660 #elif defined(__FreeBSD__) 664 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
666 int err = sysctl(mib, 4, binary_filename, &len,
NULL, 0);
668 kprintf(
"Can't get the path of ruby");
675 #undef HAVE_MAIN_EXE_PATH 679 rb_dump_backtrace_with_lines(
int num_traces,
void **traces)
683 line_info_t *lines = (line_info_t *)
calloc(num_traces,
sizeof(line_info_t));
684 obj_info_t *obj =
NULL;
686 void **dladdr_fbases = (
void **)
calloc(num_traces+2,
sizeof(
void *));
687 #ifdef HAVE_MAIN_EXE_PATH 688 char *main_path =
NULL;
690 if ((len = main_exe_path()) > 0) {
691 main_path = (
char *)
alloca(len + 1);
694 memcpy(main_path, binary_filename, len+1);
696 obj->path = main_path;
697 addr = fill_lines(num_traces, traces, 1, &obj, lines, -1);
699 dladdr_fbases[0] = (
void *)addr;
706 for (i = 0; i < num_traces; i++) {
708 if (lines[i].line)
continue;
709 if (dladdr(traces[i], &info)) {
715 for (p=dladdr_fbases; *p; p++) {
716 if (*p == info.dli_fbase) {
717 lines[i].path = info.dli_fname;
718 lines[i].sname = info.dli_sname;
725 obj->base_addr = (
uintptr_t)info.dli_fbase;
726 path = info.dli_fname;
728 lines[i].path = path;
729 strcpy(binary_filename, path);
730 if (fill_lines(num_traces, traces, 1, &obj, lines, i) == (
uintptr_t)-1)
738 for (i = 0; i < num_traces; i++) {
739 line_info_t *line = &lines[i];
743 kprintf(
"[0x%lx]\n", addr);
745 else if (!line->saddr || !line->sname) {
746 kprintf(
"%s [0x%lx]\n", line->path, addr);
748 else if (line->line <= 0) {
749 kprintf(
"%s(%s+0x%lx) [0x%lx]\n", line->path, line->sname,
752 else if (!line->filename) {
753 kprintf(
"%s(%s+0x%lx) [0x%lx] ???:%d\n", line->path, line->sname,
754 d, addr, line->line);
756 else if (line->dirname && line->dirname[0]) {
757 kprintf(
"%s(%s+0x%lx) [0x%lx] %s/%s:%d\n", line->path, line->sname,
758 d, addr, line->dirname, line->filename, line->line);
761 kprintf(
"%s(%s+0x%lx) [0x%lx] %s:%d\n", line->path, line->sname,
762 d, addr, line->filename, line->line);
765 if (line->sname && strcmp(
"main", line->sname) == 0)
774 munmap(o->mapped, o->mapped_size);
821 #define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1) 822 static inline int toupper(
int c) {
return (
'A' <= c && c <=
'Z') ? (c&0x5f) : c; }
823 #define hex2ascii(hex) (hex2ascii_data[hex]) 824 char const hex2ascii_data[] =
"0123456789abcdefghijklmnopqrstuvwxyz";
825 static inline int imax(
int a,
int b) {
return (a > b ? a : b); }
826 static int kvprintf(
char const *fmt,
void (*
func)(
int),
void *arg,
int radix, va_list ap);
828 static void putce(
int c)
834 ret = write(2, s, 1);
839 kprintf(
const char *fmt, ...)
845 retval = kvprintf(fmt, putce,
NULL, 10, ap);
857 ksprintn(
char *nbuf, uintmax_t num,
int base,
int *lenp,
int upper)
864 c = hex2ascii(num % base);
865 *++p = upper ? toupper(c) : c;
866 }
while (num /= base);
868 *lenp = (int)(p - nbuf);
899 kvprintf(
char const *fmt,
void (*
func)(
int),
void *arg,
int radix, va_list ap)
901 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; } 904 const char *p, *percent, *q;
908 int base, lflag, qflag, tmp, width, ladjust, sharpflag,
neg, sign, dot;
909 int cflag, hflag, jflag, tflag, zflag;
912 int stop = 0, retval = 0;
921 fmt =
"(fmt null)\n";
923 if (radix < 2 || radix > 36)
929 while ((ch = (
unsigned char)*fmt++) !=
'%' || stop) {
935 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
936 sign = 0; dot = 0; dwidth = 0; upper = 0;
937 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
938 reswitch:
switch (ch = (
unsigned char)*fmt++) {
956 width = va_arg(ap,
int);
962 dwidth = va_arg(ap,
int);
970 case '1':
case '2':
case '3':
case '4':
971 case '5':
case '6':
case '7':
case '8':
case '9':
972 for (n = 0;; ++fmt) {
973 n = n * 10 + ch -
'0';
975 if (ch < '0' || ch >
'9')
984 num = (
unsigned int)va_arg(ap,
int);
985 p = va_arg(ap,
char *);
986 for (q = ksprintn(nbuf, num, *p++,
NULL, 0); *q;)
994 if (num & (1 << (n - 1))) {
995 PCHAR(tmp ?
',' :
'<');
996 for (; (n = *p) >
' '; ++p)
1000 for (; *p >
' '; ++p)
1007 PCHAR(va_arg(ap,
int));
1010 up = va_arg(ap,
unsigned char *);
1011 p = va_arg(ap,
char *);
1015 PCHAR(hex2ascii(*up >> 4));
1016 PCHAR(hex2ascii(*up & 0x0f));
1047 *(va_arg(ap, intmax_t *)) = retval;
1049 *(va_arg(ap, int64_t *)) = retval;
1051 *(va_arg(ap,
long *)) = retval;
1053 *(va_arg(ap,
size_t *)) = retval;
1055 *(va_arg(ap,
short *)) = retval;
1057 *(va_arg(ap,
char *)) = retval;
1059 *(va_arg(ap,
int *)) = retval;
1066 sharpflag = (width == 0);
1079 p = va_arg(ap,
char *);
1085 for (n = 0; n < dwidth && p[n]; n++)
1090 if (!ladjust && width > 0)
1095 if (ladjust && width > 0)
1120 num = va_arg(ap, uintmax_t);
1124 num = va_arg(ap, ptrdiff_t);
1126 num = va_arg(ap,
unsigned long);
1128 num = va_arg(ap,
size_t);
1130 num = (
unsigned short)va_arg(ap,
int);
1132 num = (
unsigned char)va_arg(ap,
int);
1134 num = va_arg(ap,
unsigned int);
1138 num = va_arg(ap, intmax_t);
1140 num = va_arg(ap, int64_t);
1142 num = va_arg(ap, ptrdiff_t);
1144 num = va_arg(ap,
long);
1146 num = va_arg(ap, ssize_t);
1148 num = (short)va_arg(ap,
int);
1150 num = (char)va_arg(ap,
int);
1152 num = va_arg(ap,
int);
1154 if (sign && (intmax_t)num < 0) {
1156 num = -(intmax_t)num;
1158 p = ksprintn(nbuf, num, base, &n, upper);
1160 if (sharpflag && num != 0) {
1163 else if (base == 16)
1169 if (!ladjust && padc ==
'0')
1170 dwidth = width - tmp;
1171 width -= tmp + imax(dwidth, n);
1178 if (sharpflag && num != 0) {
1181 }
else if (base == 16) {
1186 while (dwidth-- > 0)
1198 while (percent < fmt)
1213 #error not supported
size_t strlen(const char *)
ssize_t readlink(const char *, char *, size_t)
SSL_METHOD *(* func)(void)
if(len<=MAX_WORD_LENGTH &&len >=MIN_WORD_LENGTH)
unsigned long long uint64_t
static const char * obj_info(VALUE obj)
int memcmp(const void *s1, const void *s2, size_t len)
register unsigned int len
RUBY_EXTERN char * strerror(int)
RUBY_EXTERN size_t strlcat(char *, const char *, size_t)
char * strrchr(const char *, const char)