Ruby 4.1.0dev (2026-10-06 revision 6b1add1e701dcde4be05d63f3f423ef37c3893a4)
addr2line.c (6b1add1e701dcde4be05d63f3f423ef37c3893a4)
1/**********************************************************************
2
3 addr2line.c -
4
5 $Author$
6
7 Copyright (C) 2010 Shinichiro Hamaji
8
9**********************************************************************/
10
11#if defined(__clang__) && defined(__has_warning)
12#if __has_warning("-Wgnu-empty-initializer")
13#pragma clang diagnostic ignored "-Wgnu-empty-initializer"
14#endif
15#if __has_warning("-Wgcc-compat")
16#pragma clang diagnostic ignored "-Wgcc-compat"
17#endif
18#endif
19
20#include "ruby/internal/config.h"
21#include "ruby/defines.h"
22#include "ruby/missing.h"
23#include "addr2line.h"
24
25#include <stdio.h>
26#include <errno.h>
27
28#ifdef HAVE_LIBPROC_H
29#include <libproc.h>
30#endif
31
33
34#if defined(USE_ELF) || defined(HAVE_MACH_O_LOADER_H)
35
36#include <fcntl.h>
37#include <limits.h>
38#include <stdio.h>
39#include <stdint.h>
40#include <stdlib.h>
41#include <string.h>
42#include <sys/mman.h>
43#include <sys/types.h>
44#include <sys/stat.h>
45#include <unistd.h>
46
47/* Make alloca work the best possible way. */
48#ifdef __GNUC__
49# ifndef alloca
50# define alloca __builtin_alloca
51# endif
52#else
53# ifdef HAVE_ALLOCA_H
54# include <alloca.h>
55# else
56# ifdef _AIX
57#pragma alloca
58# else
59# ifndef alloca /* predefined by HP cc +Olibcalls */
60void *alloca();
61# endif
62# endif /* AIX */
63# endif /* HAVE_ALLOCA_H */
64# ifndef UNREACHABLE
65# define UNREACHABLE __builtin_unreachable()
66# endif
67# ifndef UNREACHABLE_RETURN
68# define UNREACHABLE_RETURN(_) __builtin_unreachable()
69# endif
70#endif /* __GNUC__ */
71
72#ifndef UNREACHABLE
73# define UNREACHABLE abort()
74#endif
75#ifndef UNREACHABLE_RETURN
76# define UNREACHABLE_RETURN(_) return (abort(), (_))
77#endif
78
79#ifdef HAVE_DLADDR
80# include <dlfcn.h>
81#endif
82
83#ifdef HAVE_MACH_O_LOADER_H
84# ifdef __LP64__
85# define LP(x) x##_64
86# else
87# define LP(x) x
88# endif
89# ifdef HAVE_CRT_EXTERNS_H
90# include <crt_externs.h>
91# else
92# include "missing/crt_externs.h"
93extern struct LP(mach_header) *_NSGetMachExecuteHeader(void);
94# endif
95# include <mach-o/fat.h>
96# include <mach-o/loader.h>
97# include <mach-o/nlist.h>
98# include <mach-o/stab.h>
99#endif
100
101#ifdef USE_ELF
102# ifdef __OpenBSD__
103# include <elf_abi.h>
104# else
105# include <elf.h>
106# endif
107
108#ifndef ElfW
109# if SIZEOF_VOIDP == 8
110# define ElfW(x) Elf64##_##x
111# else
112# define ElfW(x) Elf32##_##x
113# endif
114#endif
115#ifndef ELF_ST_TYPE
116# if SIZEOF_VOIDP == 8
117# define ELF_ST_TYPE ELF64_ST_TYPE
118# else
119# define ELF_ST_TYPE ELF32_ST_TYPE
120# endif
121#endif
122#endif
123
124#ifdef SHF_COMPRESSED
125# if defined(ELFCOMPRESS_ZLIB) && defined(HAVE_LIBZ)
126 /* FreeBSD 11.0 lacks ELFCOMPRESS_ZLIB */
127# include <zlib.h>
128# define SUPPORT_COMPRESSED_DEBUG_LINE
129# endif
130#else /* compatibility with glibc < 2.22 */
131# define SHF_COMPRESSED 0
132#endif
133
134#ifndef PATH_MAX
135#define PATH_MAX 4096
136#endif
137
138#define DW_LNS_copy 0x01
139#define DW_LNS_advance_pc 0x02
140#define DW_LNS_advance_line 0x03
141#define DW_LNS_set_file 0x04
142#define DW_LNS_set_column 0x05
143#define DW_LNS_negate_stmt 0x06
144#define DW_LNS_set_basic_block 0x07
145#define DW_LNS_const_add_pc 0x08
146#define DW_LNS_fixed_advance_pc 0x09
147#define DW_LNS_set_prologue_end 0x0a /* DWARF3 */
148#define DW_LNS_set_epilogue_begin 0x0b /* DWARF3 */
149#define DW_LNS_set_isa 0x0c /* DWARF3 */
150
151/* Line number extended opcode name. */
152#define DW_LNE_end_sequence 0x01
153#define DW_LNE_set_address 0x02
154#define DW_LNE_define_file 0x03
155#define DW_LNE_set_discriminator 0x04 /* DWARF4 */
156
157#define kprintf(...) fprintf(errout, "" __VA_ARGS__)
158
159typedef struct line_info {
160 const char *dirname;
161 const char *filename;
162 const char *path; /* object path */
163 int line;
164
165 uintptr_t base_addr;
166 uintptr_t saddr;
167 const char *sname; /* function name */
168
169 struct line_info *next;
170} line_info_t;
171
172struct dwarf_section {
173 char *ptr;
174 size_t size;
175 uint64_t flags;
176};
177
178typedef struct obj_info {
179 const char *path; /* object path */
180 char *mapped;
181 size_t mapped_size;
182 void *uncompressed;
183 uintptr_t base_addr;
184 uintptr_t vmaddr;
185 struct dwarf_section debug_abbrev;
186 struct dwarf_section debug_info;
187 struct dwarf_section debug_line;
188 struct dwarf_section debug_ranges;
189 struct dwarf_section debug_str_offsets;
190 struct dwarf_section debug_addr;
191 struct dwarf_section debug_rnglists;
192 struct dwarf_section debug_str;
193 struct dwarf_section debug_line_str;
194 struct obj_info *next;
195} obj_info_t;
196
197#define DWARF_SECTION_COUNT 9
198
199static struct dwarf_section *
200obj_dwarf_section_at(obj_info_t *obj, int n)
201{
202 struct dwarf_section *ary[] = {
203 &obj->debug_abbrev,
204 &obj->debug_info,
205 &obj->debug_line,
206 &obj->debug_ranges,
207 &obj->debug_str_offsets,
208 &obj->debug_addr,
209 &obj->debug_rnglists,
210 &obj->debug_str,
211 &obj->debug_line_str
212 };
213 if (n < 0 || DWARF_SECTION_COUNT <= n) {
215 }
216 return ary[n];
217}
218
219struct debug_section_definition {
220 const char *name;
221 struct dwarf_section *dwarf;
222};
223
224/* Avoid consuming stack as this module may be used from signal handler */
225static char binary_filename[PATH_MAX + 1];
226
227static unsigned long
228uleb128(const char **p)
229{
230 unsigned long r = 0;
231 int s = 0;
232 for (;;) {
233 unsigned char b = (unsigned char)*(*p)++;
234 if (b < 0x80) {
235 r += (unsigned long)b << s;
236 break;
237 }
238 r += (b & 0x7f) << s;
239 s += 7;
240 }
241 return r;
242}
243
244static long
245sleb128(const char **p)
246{
247 long r = 0;
248 int s = 0;
249 for (;;) {
250 unsigned char b = (unsigned char)*(*p)++;
251 if (b < 0x80) {
252 if (b & 0x40) {
253 r -= (0x80 - b) << s;
254 }
255 else {
256 r += (b & 0x3f) << s;
257 }
258 break;
259 }
260 r += (b & 0x7f) << s;
261 s += 7;
262 }
263 return r;
264}
265
266static const char *
267get_nth_dirname(unsigned long dir, const char *p, FILE *errout)
268{
269 if (!dir--) {
270 return "";
271 }
272 while (dir--) {
273 while (*p) p++;
274 p++;
275 if (!*p) {
276 kprintf("Unexpected directory number %lu in %s\n",
277 dir, binary_filename);
278 return "";
279 }
280 }
281 return p;
282}
283
284static const char *parse_ver5_debug_line_header(
285 const char *p, int idx, uint8_t format,
286 obj_info_t *obj, const char **out_path,
287 uint64_t *out_directory_index, FILE *errout);
288
289static void
290fill_filename(int file, uint8_t format, uint16_t version, const char *include_directories,
291 const char *filenames, line_info_t *line, obj_info_t *obj, FILE *errout)
292{
293 int i;
294 const char *p = filenames;
295 const char *filename;
296 unsigned long dir;
297 if (version >= 5) {
298 const char *path;
299 uint64_t directory_index = -1;
300 parse_ver5_debug_line_header(filenames, file, format, obj, &path, &directory_index, errout);
301 line->filename = path;
302 parse_ver5_debug_line_header(include_directories, (int)directory_index, format, obj, &path, NULL, errout);
303 line->dirname = path;
304 }
305 else {
306 for (i = 1; i <= file; i++) {
307 filename = p;
308 if (!*p) {
309#ifndef __APPLE__
310 /* Need to output binary file name? */
311 kprintf("Unexpected file number %d in %s at %tx\n",
312 file, binary_filename, filenames - obj->mapped);
313#endif
314 return;
315 }
316 while (*p) p++;
317 p++;
318 dir = uleb128(&p);
319 /* last modified. */
320 uleb128(&p);
321 /* size of the file. */
322 uleb128(&p);
323
324 if (i == file) {
325 line->filename = filename;
326 line->dirname = get_nth_dirname(dir, include_directories, errout);
327 }
328 }
329 }
330}
331
332static void
333fill_line(int num_traces, void **traces, uintptr_t addr, int file, int line,
334 uint8_t format, uint16_t version, const char *include_directories, const char *filenames,
335 obj_info_t *obj, line_info_t *lines, int offset, FILE *errout)
336{
337 int i;
338 addr += obj->base_addr - obj->vmaddr;
339 for (i = offset; i < num_traces; i++) {
340 uintptr_t a = (uintptr_t)traces[i];
341 /* We assume one line code doesn't result >100 bytes of native code.
342 We may want more reliable way eventually... */
343 if (addr < a && a < addr + 100) {
344 fill_filename(file, format, version, include_directories, filenames, &lines[i], obj, errout);
345 lines[i].line = line;
346 }
347 }
348}
349
350struct LineNumberProgramHeader {
351 uint64_t unit_length;
352 uint16_t version;
353 uint8_t format; /* 4 or 8 */
354 uint64_t header_length;
355 uint8_t minimum_instruction_length;
356 uint8_t maximum_operations_per_instruction;
357 uint8_t default_is_stmt;
358 int8_t line_base;
359 uint8_t line_range;
360 uint8_t opcode_base;
361 /* uint8_t standard_opcode_lengths[opcode_base-1]; */
362 const char *include_directories;
363 const char *filenames;
364 const char *cu_start;
365 const char *cu_end;
366};
367
368static int
369parse_debug_line_header(obj_info_t *obj, const char **pp, struct LineNumberProgramHeader *header, FILE *errout)
370{
371 const char *p = *pp;
372 header->unit_length = *(uint32_t *)p;
373 p += sizeof(uint32_t);
374
375 header->format = 4;
376 if (header->unit_length == 0xffffffff) {
377 header->unit_length = *(uint64_t *)p;
378 p += sizeof(uint64_t);
379 header->format = 8;
380 }
381
382 header->cu_end = p + header->unit_length;
383
384 header->version = *(uint16_t *)p;
385 p += sizeof(uint16_t);
386 if (header->version > 5) return -1;
387
388 if (header->version >= 5) {
389 /* address_size = *(uint8_t *)p++; */
390 /* segment_selector_size = *(uint8_t *)p++; */
391 p += 2;
392 }
393
394 header->header_length = header->format == 4 ? *(uint32_t *)p : *(uint64_t *)p;
395 p += header->format;
396 header->cu_start = p + header->header_length;
397
398 header->minimum_instruction_length = *(uint8_t *)p++;
399
400 if (header->version >= 4) {
401 /* maximum_operations_per_instruction = *(uint8_t *)p; */
402 if (*p != 1) return -1; /* For non-VLIW architectures, this field is 1 */
403 p++;
404 }
405
406 header->default_is_stmt = *(uint8_t *)p++;
407 header->line_base = *(int8_t *)p++;
408 header->line_range = *(uint8_t *)p++;
409 header->opcode_base = *(uint8_t *)p++;
410 /* header->standard_opcode_lengths = (uint8_t *)p - 1; */
411 p += header->opcode_base - 1;
412
413 if (header->version >= 5) {
414 header->include_directories = p;
415 p = parse_ver5_debug_line_header(p, -1, header->format, obj, NULL, NULL, errout);
416 header->filenames = p;
417 }
418 else {
419 header->include_directories = p;
420
421 /* temporary measure for compress-debug-sections */
422 if (p >= header->cu_end) return -1;
423
424 /* skip include directories */
425 while (*p) {
426 p = memchr(p, '\0', header->cu_end - p);
427 if (!p) return -1;
428 p++;
429 }
430 p++;
431
432 header->filenames = p;
433 }
434
435 *pp = header->cu_start;
436
437 return 0;
438}
439
440static int
441parse_debug_line_cu(int num_traces, void **traces, const char **debug_line,
442 obj_info_t *obj, line_info_t *lines, int offset, FILE *errout)
443{
444 const char *p = (const char *)*debug_line;
445 struct LineNumberProgramHeader header;
446
447 /* The registers. */
448 unsigned long addr = 0;
449 unsigned int file = 1;
450 unsigned int line = 1;
451 /* unsigned int column = 0; */
452 int is_stmt;
453 /* int basic_block = 0; */
454 /* int end_sequence = 0; */
455 /* int prologue_end = 0; */
456 /* int epilogue_begin = 0; */
457 /* unsigned int isa = 0; */
458
459 if (parse_debug_line_header(obj, &p, &header, errout))
460 return -1;
461 is_stmt = header.default_is_stmt;
462
463#define FILL_LINE() \
464 do { \
465 fill_line(num_traces, traces, addr, file, line, \
466 header.format, \
467 header.version, \
468 header.include_directories, \
469 header.filenames, \
470 obj, lines, offset, errout); \
471 /*basic_block = prologue_end = epilogue_begin = 0;*/ \
472 } while (0)
473
474 while (p < header.cu_end) {
475 unsigned long a;
476 unsigned char op = *p++;
477 switch (op) {
478 case DW_LNS_copy:
479 FILL_LINE();
480 break;
481 case DW_LNS_advance_pc:
482 a = uleb128(&p) * header.minimum_instruction_length;
483 addr += a;
484 break;
485 case DW_LNS_advance_line: {
486 long a = sleb128(&p);
487 line += a;
488 break;
489 }
490 case DW_LNS_set_file:
491 file = (unsigned int)uleb128(&p);
492 break;
493 case DW_LNS_set_column:
494 /*column = (unsigned int)*/(void)uleb128(&p);
495 break;
496 case DW_LNS_negate_stmt:
497 is_stmt = !is_stmt;
498 break;
499 case DW_LNS_set_basic_block:
500 /*basic_block = 1; */
501 break;
502 case DW_LNS_const_add_pc:
503 a = ((255UL - header.opcode_base) / header.line_range) *
504 header.minimum_instruction_length;
505 addr += a;
506 break;
507 case DW_LNS_fixed_advance_pc:
508 a = *(uint16_t *)p;
509 p += sizeof(uint16_t);
510 addr += a;
511 break;
512 case DW_LNS_set_prologue_end:
513 /* prologue_end = 1; */
514 break;
515 case DW_LNS_set_epilogue_begin:
516 /* epilogue_begin = 1; */
517 break;
518 case DW_LNS_set_isa:
519 /* isa = (unsigned int)*/(void)uleb128(&p);
520 break;
521 case 0:
522 a = uleb128(&p);
523 op = *p++;
524 switch (op) {
525 case DW_LNE_end_sequence:
526 /* end_sequence = 1; */
527 FILL_LINE();
528 addr = 0;
529 file = 1;
530 line = 1;
531 /* column = 0; */
532 is_stmt = header.default_is_stmt;
533 /* end_sequence = 0; */
534 /* isa = 0; */
535 break;
536 case DW_LNE_set_address:
537 addr = *(unsigned long *)p;
538 p += sizeof(unsigned long);
539 break;
540 case DW_LNE_define_file:
541 kprintf("Unsupported operation in %s\n",
542 binary_filename);
543 break;
544 case DW_LNE_set_discriminator:
545 /* TODO:currently ignore */
546 uleb128(&p);
547 break;
548 default:
549 kprintf("Unknown extended opcode: %d in %s\n",
550 op, binary_filename);
551 }
552 break;
553 default: {
554 uint8_t adjusted_opcode = op - header.opcode_base;
555 uint8_t operation_advance = adjusted_opcode / header.line_range;
556 /* NOTE: this code doesn't support VLIW */
557 addr += operation_advance * header.minimum_instruction_length;
558 line += header.line_base + (adjusted_opcode % header.line_range);
559 FILL_LINE();
560 }
561 }
562 }
563 *debug_line = (char *)p;
564 return 0;
565}
566
567static int
568parse_debug_line(int num_traces, void **traces,
569 const char *debug_line, unsigned long size,
570 obj_info_t *obj, line_info_t *lines, int offset, FILE *errout)
571{
572 const char *debug_line_end = debug_line + size;
573 while (debug_line < debug_line_end) {
574 if (parse_debug_line_cu(num_traces, traces, &debug_line, obj, lines, offset, errout))
575 return -1;
576 }
577 if (debug_line != debug_line_end) {
578 kprintf("Unexpected size of .debug_line in %s\n",
579 binary_filename);
580 }
581 return 0;
582}
583
584/* read file and fill lines */
585static uintptr_t
586fill_lines(int num_traces, void **traces, int check_debuglink,
587 obj_info_t **objp, line_info_t *lines, int offset, FILE *errout);
588
589static void
590append_obj(obj_info_t **objp)
591{
592 obj_info_t *newobj = calloc(1, sizeof(obj_info_t));
593 if (*objp) (*objp)->next = newobj;
594 *objp = newobj;
595}
596
597#ifdef USE_ELF
598/* Ideally we should check 4 paths to follow gnu_debuglink:
599 *
600 * - /usr/lib/debug/.build-id/ab/cdef1234.debug
601 * - /usr/bin/ruby.debug
602 * - /usr/bin/.debug/ruby.debug
603 * - /usr/lib/debug/usr/bin/ruby.debug.
604 *
605 * but we handle only two cases for now as the two formats are
606 * used by some linux distributions.
607 *
608 * See GDB's info for detail.
609 * https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
610 */
611
612// check the path pattern of "/usr/lib/debug/usr/bin/ruby.debug"
613static void
614follow_debuglink(const char *debuglink, int num_traces, void **traces,
615 obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
616{
617 static const char global_debug_dir[] = "/usr/lib/debug";
618 const size_t global_debug_dir_len = sizeof(global_debug_dir) - 1;
619 char *p;
620 obj_info_t *o1 = *objp, *o2;
621 size_t len;
622
623 p = strrchr(binary_filename, '/');
624 if (!p) {
625 return;
626 }
627 p[1] = '\0';
628
629 len = strlen(binary_filename);
630 if (len >= PATH_MAX - global_debug_dir_len)
631 len = PATH_MAX - global_debug_dir_len - 1;
632 memmove(binary_filename + global_debug_dir_len, binary_filename, len);
633 memcpy(binary_filename, global_debug_dir, global_debug_dir_len);
634 len += global_debug_dir_len;
635 strlcpy(binary_filename + len, debuglink, PATH_MAX - len);
636
637 append_obj(objp);
638 o2 = *objp;
639 o2->base_addr = o1->base_addr;
640 o2->path = o1->path;
641 fill_lines(num_traces, traces, 0, objp, lines, offset, errout);
642}
643
644// check the path pattern of "/usr/lib/debug/.build-id/ab/cdef1234.debug"
645static void
646follow_debuglink_build_id(const char *build_id, size_t build_id_size, int num_traces, void **traces,
647 obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
648{
649 static const char global_debug_dir[] = "/usr/lib/debug/.build-id/";
650 static const char debug_suffix[] = ".debug";
651 const size_t global_debug_dir_len = sizeof(global_debug_dir) - 1;
652 char *p;
653 obj_info_t *o1 = *objp, *o2;
654 size_t i;
655
656 if (PATH_MAX < global_debug_dir_len + build_id_size * 2 + sizeof(debug_suffix)) return;
657
658 memcpy(binary_filename, global_debug_dir, global_debug_dir_len);
659 p = binary_filename + global_debug_dir_len;
660 for (i = 0; i < build_id_size; i++) {
661 static const char tbl[] = "0123456789abcdef";
662 unsigned char n = build_id[i];
663 *p++ = tbl[n / 16];
664 *p++ = tbl[n % 16];
665 if (i == 0) *p++ = '/';
666 }
667 memcpy(p, debug_suffix, sizeof(debug_suffix));
668
669 append_obj(objp);
670 o2 = *objp;
671 o2->base_addr = o1->base_addr;
672 o2->path = o1->path;
673 fill_lines(num_traces, traces, 0, objp, lines, offset, errout);
674}
675#endif
676
677enum
678{
679 DW_TAG_compile_unit = 0x11,
680 DW_TAG_inlined_subroutine = 0x1d,
681 DW_TAG_subprogram = 0x2e,
682};
683
684/* Attributes encodings */
685enum
686{
687 DW_AT_sibling = 0x01,
688 DW_AT_location = 0x02,
689 DW_AT_name = 0x03,
690 /* Reserved 0x04 */
691 /* Reserved 0x05 */
692 /* Reserved 0x06 */
693 /* Reserved 0x07 */
694 /* Reserved 0x08 */
695 DW_AT_ordering = 0x09,
696 /* Reserved 0x0a */
697 DW_AT_byte_size = 0x0b,
698 /* Reserved 0x0c */
699 DW_AT_bit_size = 0x0d,
700 /* Reserved 0x0e */
701 /* Reserved 0x0f */
702 DW_AT_stmt_list = 0x10,
703 DW_AT_low_pc = 0x11,
704 DW_AT_high_pc = 0x12,
705 DW_AT_language = 0x13,
706 /* Reserved 0x14 */
707 DW_AT_discr = 0x15,
708 DW_AT_discr_value = 0x16,
709 DW_AT_visibility = 0x17,
710 DW_AT_import = 0x18,
711 DW_AT_string_length = 0x19,
712 DW_AT_common_reference = 0x1a,
713 DW_AT_comp_dir = 0x1b,
714 DW_AT_const_value = 0x1c,
715 DW_AT_containing_type = 0x1d,
716 DW_AT_default_value = 0x1e,
717 /* Reserved 0x1f */
718 DW_AT_inline = 0x20,
719 DW_AT_is_optional = 0x21,
720 DW_AT_lower_bound = 0x22,
721 /* Reserved 0x23 */
722 /* Reserved 0x24 */
723 DW_AT_producer = 0x25,
724 /* Reserved 0x26 */
725 DW_AT_prototyped = 0x27,
726 /* Reserved 0x28 */
727 /* Reserved 0x29 */
728 DW_AT_return_addr = 0x2a,
729 /* Reserved 0x2b */
730 DW_AT_start_scope = 0x2c,
731 /* Reserved 0x2d */
732 DW_AT_bit_stride = 0x2e,
733 DW_AT_upper_bound = 0x2f,
734 /* Reserved 0x30 */
735 DW_AT_abstract_origin = 0x31,
736 DW_AT_accessibility = 0x32,
737 DW_AT_address_class = 0x33,
738 DW_AT_artificial = 0x34,
739 DW_AT_base_types = 0x35,
740 DW_AT_calling_convention = 0x36,
741 DW_AT_count = 0x37,
742 DW_AT_data_member_location = 0x38,
743 DW_AT_decl_column = 0x39,
744 DW_AT_decl_file = 0x3a,
745 DW_AT_decl_line = 0x3b,
746 DW_AT_declaration = 0x3c,
747 DW_AT_discr_list = 0x3d,
748 DW_AT_encoding = 0x3e,
749 DW_AT_external = 0x3f,
750 DW_AT_frame_base = 0x40,
751 DW_AT_friend = 0x41,
752 DW_AT_identifier_case = 0x42,
753 /* Reserved 0x43 */
754 DW_AT_namelist_item = 0x44,
755 DW_AT_priority = 0x45,
756 DW_AT_segment = 0x46,
757 DW_AT_specification = 0x47,
758 DW_AT_static_link = 0x48,
759 DW_AT_type = 0x49,
760 DW_AT_use_location = 0x4a,
761 DW_AT_variable_parameter = 0x4b,
762 DW_AT_virtuality = 0x4c,
763 DW_AT_vtable_elem_location = 0x4d,
764 DW_AT_allocated = 0x4e,
765 DW_AT_associated = 0x4f,
766 DW_AT_data_location = 0x50,
767 DW_AT_byte_stride = 0x51,
768 DW_AT_entry_pc = 0x52,
769 DW_AT_use_UTF8 = 0x53,
770 DW_AT_extension = 0x54,
771 DW_AT_ranges = 0x55,
772 DW_AT_trampoline = 0x56,
773 DW_AT_call_column = 0x57,
774 DW_AT_call_file = 0x58,
775 DW_AT_call_line = 0x59,
776 DW_AT_description = 0x5a,
777 DW_AT_binary_scale = 0x5b,
778 DW_AT_decimal_scale = 0x5c,
779 DW_AT_small = 0x5d,
780 DW_AT_decimal_sign = 0x5e,
781 DW_AT_digit_count = 0x5f,
782 DW_AT_picture_string = 0x60,
783 DW_AT_mutable = 0x61,
784 DW_AT_threads_scaled = 0x62,
785 DW_AT_explicit = 0x63,
786 DW_AT_object_pointer = 0x64,
787 DW_AT_endianity = 0x65,
788 DW_AT_elemental = 0x66,
789 DW_AT_pure = 0x67,
790 DW_AT_recursive = 0x68,
791 DW_AT_signature = 0x69,
792 DW_AT_main_subprogram = 0x6a,
793 DW_AT_data_bit_offset = 0x6b,
794 DW_AT_const_expr = 0x6c,
795 DW_AT_enum_class = 0x6d,
796 DW_AT_linkage_name = 0x6e,
797 DW_AT_string_length_bit_size = 0x6f,
798 DW_AT_string_length_byte_size = 0x70,
799 DW_AT_rank = 0x71,
800 DW_AT_str_offsets_base = 0x72,
801 DW_AT_addr_base = 0x73,
802 DW_AT_rnglists_base = 0x74,
803 /* Reserved 0x75 */
804 DW_AT_dwo_name = 0x76,
805 DW_AT_reference = 0x77,
806 DW_AT_rvalue_reference = 0x78,
807 DW_AT_macros = 0x79,
808 DW_AT_call_all_calls = 0x7a,
809 DW_AT_call_all_source_calls = 0x7b,
810 DW_AT_call_all_tail_calls = 0x7c,
811 DW_AT_call_return_pc = 0x7d,
812 DW_AT_call_value = 0x7e,
813 DW_AT_call_origin = 0x7f,
814 DW_AT_call_parameter = 0x80,
815 DW_AT_call_pc = 0x81,
816 DW_AT_call_tail_call = 0x82,
817 DW_AT_call_target = 0x83,
818 DW_AT_call_target_clobbered = 0x84,
819 DW_AT_call_data_location = 0x85,
820 DW_AT_call_data_value = 0x86,
821 DW_AT_noreturn = 0x87,
822 DW_AT_alignment = 0x88,
823 DW_AT_export_symbols = 0x89,
824 DW_AT_deleted = 0x8a,
825 DW_AT_defaulted = 0x8b,
826 DW_AT_loclists_base = 0x8c,
827 DW_AT_lo_user = 0x2000,
828 DW_AT_hi_user = 0x3fff
829};
830
831/* Attribute form encodings */
832enum
833{
834 DW_FORM_addr = 0x01,
835 /* Reserved 0x02 */
836 DW_FORM_block2 = 0x03,
837 DW_FORM_block4 = 0x04,
838 DW_FORM_data2 = 0x05,
839 DW_FORM_data4 = 0x06,
840 DW_FORM_data8 = 0x07,
841 DW_FORM_string = 0x08,
842 DW_FORM_block = 0x09,
843 DW_FORM_block1 = 0x0a,
844 DW_FORM_data1 = 0x0b,
845 DW_FORM_flag = 0x0c,
846 DW_FORM_sdata = 0x0d,
847 DW_FORM_strp = 0x0e,
848 DW_FORM_udata = 0x0f,
849 DW_FORM_ref_addr = 0x10,
850 DW_FORM_ref1 = 0x11,
851 DW_FORM_ref2 = 0x12,
852 DW_FORM_ref4 = 0x13,
853 DW_FORM_ref8 = 0x14,
854 DW_FORM_ref_udata = 0x15,
855 DW_FORM_indirect = 0x16,
856 DW_FORM_sec_offset = 0x17,
857 DW_FORM_exprloc = 0x18,
858 DW_FORM_flag_present = 0x19,
859 DW_FORM_strx = 0x1a,
860 DW_FORM_addrx = 0x1b,
861 DW_FORM_ref_sup4 = 0x1c,
862 DW_FORM_strp_sup = 0x1d,
863 DW_FORM_data16 = 0x1e,
864 DW_FORM_line_strp = 0x1f,
865 DW_FORM_ref_sig8 = 0x20,
866 DW_FORM_implicit_const = 0x21,
867 DW_FORM_loclistx = 0x22,
868 DW_FORM_rnglistx = 0x23,
869 DW_FORM_ref_sup8 = 0x24,
870 DW_FORM_strx1 = 0x25,
871 DW_FORM_strx2 = 0x26,
872 DW_FORM_strx3 = 0x27,
873 DW_FORM_strx4 = 0x28,
874 DW_FORM_addrx1 = 0x29,
875 DW_FORM_addrx2 = 0x2a,
876 DW_FORM_addrx3 = 0x2b,
877 DW_FORM_addrx4 = 0x2c,
878
879 /* GNU extensions for referring to .gnu_debugaltlink dwz-compressed info */
880 DW_FORM_GNU_ref_alt = 0x1f20,
881 DW_FORM_GNU_strp_alt = 0x1f21
882};
883
884/* Range list entry encodings */
885enum {
886 DW_RLE_end_of_list = 0x00,
887 DW_RLE_base_addressx = 0x01,
888 DW_RLE_startx_endx = 0x02,
889 DW_RLE_startx_length = 0x03,
890 DW_RLE_offset_pair = 0x04,
891 DW_RLE_base_address = 0x05,
892 DW_RLE_start_end = 0x06,
893 DW_RLE_start_length = 0x07
894};
895
896enum {
897 VAL_none = 0,
898 VAL_cstr = 1,
899 VAL_data = 2,
900 VAL_uint = 3,
901 VAL_int = 4,
902 VAL_addr = 5
903};
904
905# define ABBREV_TABLE_SIZE 256
906typedef struct {
907 obj_info_t *obj;
908 const char *file;
909 uint8_t current_version;
910 const char *current_cu;
911 uint64_t current_low_pc;
912 uint64_t current_str_offsets_base;
913 uint64_t current_addr_base;
914 uint64_t current_rnglists_base;
915 const char *debug_line_cu_end;
916 uint8_t debug_line_format;
917 uint16_t debug_line_version;
918 const char *debug_line_files;
919 const char *debug_line_directories;
920 const char *p;
921 const char *cu_end;
922 const char *pend;
923 const char *q0;
924 const char *q;
925 int format; // 4 or 8
926 uint8_t address_size;
927 int level;
928 const char *abbrev_table[ABBREV_TABLE_SIZE];
929} DebugInfoReader;
930
931typedef struct {
932 ptrdiff_t pos;
933 int tag;
934 int has_children;
935} DIE;
936
937typedef struct {
938 union {
939 const char *ptr;
940 uint64_t uint64;
941 int64_t int64;
942 uint64_t addr_idx;
943 } as;
944 uint64_t off;
945 uint64_t at;
946 uint64_t form;
947 size_t size;
948 int type;
949} DebugInfoValue;
950
951#if defined(WORDS_BIGENDIAN)
952#define MERGE_2INTS(a,b,sz) (((uint64_t)(a)<<sz)|(b))
953#else
954#define MERGE_2INTS(a,b,sz) (((uint64_t)(b)<<sz)|(a))
955#endif
956
957static uint16_t
958get_uint16(const uint8_t *p)
959{
960 return (uint16_t)MERGE_2INTS(p[0],p[1],8);
961}
962
963static uint32_t
964get_uint32(const uint8_t *p)
965{
966 return (uint32_t)MERGE_2INTS(get_uint16(p),get_uint16(p+2),16);
967}
968
969static uint64_t
970get_uint64(const uint8_t *p)
971{
972 return MERGE_2INTS(get_uint32(p),get_uint32(p+4),32);
973}
974
975static uint8_t
976read_uint8(const char **ptr)
977{
978 const char *p = *ptr;
979 *ptr = (p + 1);
980 return (uint8_t)*p;
981}
982
983static uint16_t
984read_uint16(const char **ptr)
985{
986 const char *p = *ptr;
987 *ptr = (p + 2);
988 return get_uint16((const uint8_t *)p);
989}
990
991static uint32_t
992read_uint24(const char **ptr)
993{
994 const char *p = *ptr;
995 *ptr = (p + 3);
996 return ((uint8_t)*p << 16) | get_uint16((const uint8_t *)p+1);
997}
998
999static uint32_t
1000read_uint32(const char **ptr)
1001{
1002 const char *p = *ptr;
1003 *ptr = (p + 4);
1004 return get_uint32((const uint8_t *)p);
1005}
1006
1007static uint64_t
1008read_uint64(const char **ptr)
1009{
1010 const unsigned char *p = (const unsigned char *)*ptr;
1011 *ptr = (char *)(p + 8);
1012 return get_uint64(p);
1013}
1014
1015static uintptr_t
1016read_uintptr(const char **ptr)
1017{
1018 const unsigned char *p = (const unsigned char *)*ptr;
1019 *ptr = (char *)(p + SIZEOF_VOIDP);
1020#if SIZEOF_VOIDP == 8
1021 return get_uint64(p);
1022#else
1023 return get_uint32(p);
1024#endif
1025}
1026
1027static uint64_t
1028read_uint(DebugInfoReader *reader)
1029{
1030 if (reader->format == 4) {
1031 return read_uint32(&reader->p);
1032 } else { /* 64 bit */
1033 return read_uint64(&reader->p);
1034 }
1035}
1036
1037static uint64_t
1038read_uleb128(DebugInfoReader *reader)
1039{
1040 return uleb128(&reader->p);
1041}
1042
1043static int64_t
1044read_sleb128(DebugInfoReader *reader)
1045{
1046 return sleb128(&reader->p);
1047}
1048
1049static void
1050debug_info_reader_init(DebugInfoReader *reader, obj_info_t *obj)
1051{
1052 reader->file = obj->mapped;
1053 reader->obj = obj;
1054 reader->p = obj->debug_info.ptr;
1055 reader->pend = obj->debug_info.ptr + obj->debug_info.size;
1056 reader->debug_line_cu_end = obj->debug_line.ptr;
1057 reader->current_low_pc = 0;
1058 reader->current_str_offsets_base = 0;
1059 reader->current_addr_base = 0;
1060 reader->current_rnglists_base = 0;
1061}
1062
1063static void
1064di_skip_die_attributes(const char **p)
1065{
1066 for (;;) {
1067 uint64_t at = uleb128(p);
1068 uint64_t form = uleb128(p);
1069 if (!at && !form) break;
1070 switch (form) {
1071 default:
1072 break;
1073 case DW_FORM_implicit_const:
1074 sleb128(p);
1075 break;
1076 }
1077 }
1078}
1079
1080static void
1081di_read_debug_abbrev_cu(DebugInfoReader *reader)
1082{
1083 uint64_t prev = 0;
1084 const char *p = reader->q0;
1085 for (;;) {
1086 uint64_t abbrev_number = uleb128(&p);
1087 if (abbrev_number <= prev) break;
1088 if (abbrev_number < ABBREV_TABLE_SIZE) {
1089 reader->abbrev_table[abbrev_number] = p;
1090 }
1091 prev = abbrev_number;
1092 uleb128(&p); /* tag */
1093 p++; /* has_children */
1094 di_skip_die_attributes(&p);
1095 }
1096}
1097
1098static int
1099di_read_debug_line_cu(DebugInfoReader *reader, FILE *errout)
1100{
1101 const char *p;
1102 struct LineNumberProgramHeader header;
1103
1104 p = (const char *)reader->debug_line_cu_end;
1105 if (parse_debug_line_header(reader->obj, &p, &header, errout))
1106 return -1;
1107
1108 reader->debug_line_cu_end = (char *)header.cu_end;
1109 reader->debug_line_format = header.format;
1110 reader->debug_line_version = header.version;
1111 reader->debug_line_directories = (char *)header.include_directories;
1112 reader->debug_line_files = (char *)header.filenames;
1113
1114 return 0;
1115}
1116
1117static void
1118set_addr_idx_value(DebugInfoValue *v, uint64_t n)
1119{
1120 v->as.addr_idx = n;
1121 v->type = VAL_addr;
1122}
1123
1124static void
1125set_uint_value(DebugInfoValue *v, uint64_t n)
1126{
1127 v->as.uint64 = n;
1128 v->type = VAL_uint;
1129}
1130
1131static void
1132set_int_value(DebugInfoValue *v, int64_t n)
1133{
1134 v->as.int64 = n;
1135 v->type = VAL_int;
1136}
1137
1138static void
1139set_cstr_value(DebugInfoValue *v, const char *s)
1140{
1141 v->as.ptr = s;
1142 v->off = 0;
1143 v->type = VAL_cstr;
1144}
1145
1146static void
1147set_cstrp_value(DebugInfoValue *v, const char *s, uint64_t off)
1148{
1149 v->as.ptr = s;
1150 v->off = off;
1151 v->type = VAL_cstr;
1152}
1153
1154static void
1155set_data_value(DebugInfoValue *v, const char *s)
1156{
1157 v->as.ptr = s;
1158 v->type = VAL_data;
1159}
1160
1161static const char *
1162get_cstr_value(DebugInfoValue *v)
1163{
1164 if (v->as.ptr) {
1165 return v->as.ptr + v->off;
1166 } else {
1167 return NULL;
1168 }
1169}
1170
1171static const char *
1172resolve_strx(DebugInfoReader *reader, uint64_t idx)
1173{
1174 const char *p = reader->obj->debug_str_offsets.ptr + reader->current_str_offsets_base;
1175 uint64_t off;
1176 if (reader->format == 4) {
1177 off = ((uint32_t *)p)[idx];
1178 }
1179 else {
1180 off = ((uint64_t *)p)[idx];
1181 }
1182 return reader->obj->debug_str.ptr + off;
1183}
1184
1185static bool
1186debug_info_reader_read_addr_value_member(DebugInfoReader *reader, DebugInfoValue *v, int size)
1187{
1188 if (size == 4) {
1189 set_uint_value(v, read_uint32(&reader->p));
1190 } else if (size == 8) {
1191 set_uint_value(v, read_uint64(&reader->p));
1192 } else {
1193 return false;
1194 }
1195 return true;
1196}
1197
1198#define debug_info_reader_read_addr_value(reader, v, mem) \
1199 if (!debug_info_reader_read_addr_value_member((reader), (v), (reader)->mem)) { \
1200 kprintf("unknown " #mem ":%d", (reader)->mem); \
1201 return false; \
1202 }
1203
1204
1205static bool
1206debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoValue *v, FILE *errout)
1207{
1208 switch (form) {
1209 case DW_FORM_addr:
1210 debug_info_reader_read_addr_value(reader, v, address_size);
1211 break;
1212 case DW_FORM_block2:
1213 v->size = read_uint16(&reader->p);
1214 set_data_value(v, reader->p);
1215 reader->p += v->size;
1216 break;
1217 case DW_FORM_block4:
1218 v->size = read_uint32(&reader->p);
1219 set_data_value(v, reader->p);
1220 reader->p += v->size;
1221 break;
1222 case DW_FORM_data2:
1223 set_uint_value(v, read_uint16(&reader->p));
1224 break;
1225 case DW_FORM_data4:
1226 set_uint_value(v, read_uint32(&reader->p));
1227 break;
1228 case DW_FORM_data8:
1229 set_uint_value(v, read_uint64(&reader->p));
1230 break;
1231 case DW_FORM_string:
1232 v->size = strlen(reader->p);
1233 set_cstr_value(v, reader->p);
1234 reader->p += v->size + 1;
1235 break;
1236 case DW_FORM_block:
1237 v->size = uleb128(&reader->p);
1238 set_data_value(v, reader->p);
1239 reader->p += v->size;
1240 break;
1241 case DW_FORM_block1:
1242 v->size = read_uint8(&reader->p);
1243 set_data_value(v, reader->p);
1244 reader->p += v->size;
1245 break;
1246 case DW_FORM_data1:
1247 set_uint_value(v, read_uint8(&reader->p));
1248 break;
1249 case DW_FORM_flag:
1250 set_uint_value(v, read_uint8(&reader->p));
1251 break;
1252 case DW_FORM_sdata:
1253 set_int_value(v, read_sleb128(reader));
1254 break;
1255 case DW_FORM_strp:
1256 set_cstrp_value(v, reader->obj->debug_str.ptr, read_uint(reader));
1257 break;
1258 case DW_FORM_udata:
1259 set_uint_value(v, read_uleb128(reader));
1260 break;
1261 case DW_FORM_ref_addr:
1262 if (reader->current_version <= 2) {
1263 // DWARF Version 2 specifies that references have
1264 // the same size as an address on the target system
1265 debug_info_reader_read_addr_value(reader, v, address_size);
1266 } else {
1267 debug_info_reader_read_addr_value(reader, v, format);
1268 }
1269 break;
1270 case DW_FORM_ref1:
1271 set_uint_value(v, read_uint8(&reader->p));
1272 break;
1273 case DW_FORM_ref2:
1274 set_uint_value(v, read_uint16(&reader->p));
1275 break;
1276 case DW_FORM_ref4:
1277 set_uint_value(v, read_uint32(&reader->p));
1278 break;
1279 case DW_FORM_ref8:
1280 set_uint_value(v, read_uint64(&reader->p));
1281 break;
1282 case DW_FORM_ref_udata:
1283 set_uint_value(v, uleb128(&reader->p));
1284 break;
1285 case DW_FORM_indirect:
1286 /* TODO: read the referred value */
1287 set_uint_value(v, uleb128(&reader->p));
1288 break;
1289 case DW_FORM_sec_offset:
1290 set_uint_value(v, read_uint(reader)); /* offset */
1291 /* addrptr: debug_addr */
1292 /* lineptr: debug_line */
1293 /* loclist: debug_loclists */
1294 /* loclistptr: debug_loclists */
1295 /* macptr: debug_macro */
1296 /* rnglist: debug_rnglists */
1297 /* rnglistptr: debug_rnglists */
1298 /* stroffsetsptr: debug_str_offsets */
1299 break;
1300 case DW_FORM_exprloc:
1301 v->size = (size_t)read_uleb128(reader);
1302 set_data_value(v, reader->p);
1303 reader->p += v->size;
1304 break;
1305 case DW_FORM_flag_present:
1306 set_uint_value(v, 1);
1307 break;
1308 case DW_FORM_strx:
1309 set_cstr_value(v, resolve_strx(reader, uleb128(&reader->p)));
1310 break;
1311 case DW_FORM_addrx:
1312 set_addr_idx_value(v, uleb128(&reader->p));
1313 break;
1314 case DW_FORM_ref_sup4:
1315 set_uint_value(v, read_uint32(&reader->p));
1316 break;
1317 case DW_FORM_strp_sup:
1318 set_uint_value(v, read_uint(reader));
1319 /* *p = reader->sup_file + reader->sup_str->sh_offset + ret; */
1320 break;
1321 case DW_FORM_data16:
1322 v->size = 16;
1323 set_data_value(v, reader->p);
1324 reader->p += v->size;
1325 break;
1326 case DW_FORM_line_strp:
1327 set_cstrp_value(v, reader->obj->debug_line_str.ptr, read_uint(reader));
1328 break;
1329 case DW_FORM_ref_sig8:
1330 set_uint_value(v, read_uint64(&reader->p));
1331 break;
1332 case DW_FORM_implicit_const:
1333 set_int_value(v, sleb128(&reader->q));
1334 break;
1335 case DW_FORM_loclistx:
1336 set_uint_value(v, read_uleb128(reader));
1337 break;
1338 case DW_FORM_rnglistx:
1339 set_uint_value(v, read_uleb128(reader));
1340 break;
1341 case DW_FORM_ref_sup8:
1342 set_uint_value(v, read_uint64(&reader->p));
1343 break;
1344 case DW_FORM_strx1:
1345 set_cstr_value(v, resolve_strx(reader, read_uint8(&reader->p)));
1346 break;
1347 case DW_FORM_strx2:
1348 set_cstr_value(v, resolve_strx(reader, read_uint16(&reader->p)));
1349 break;
1350 case DW_FORM_strx3:
1351 set_cstr_value(v, resolve_strx(reader, read_uint24(&reader->p)));
1352 break;
1353 case DW_FORM_strx4:
1354 set_cstr_value(v, resolve_strx(reader, read_uint32(&reader->p)));
1355 break;
1356 case DW_FORM_addrx1:
1357 set_addr_idx_value(v, read_uint8(&reader->p));
1358 break;
1359 case DW_FORM_addrx2:
1360 set_addr_idx_value(v, read_uint16(&reader->p));
1361 break;
1362 case DW_FORM_addrx3:
1363 set_addr_idx_value(v, read_uint24(&reader->p));
1364 break;
1365 case DW_FORM_addrx4:
1366 set_addr_idx_value(v, read_uint32(&reader->p));
1367 break;
1368 /* we have no support for actually reading the real values of these refs out
1369 * of the .gnu_debugaltlink dwz-compressed debuginfo at the moment, but "read"
1370 * them anyway so that we advance the reader by the right amount. */
1371 case DW_FORM_GNU_ref_alt:
1372 case DW_FORM_GNU_strp_alt:
1373 read_uint(reader);
1374 set_uint_value(v, 0);
1375 break;
1376 case 0:
1377 goto fail;
1378 break;
1379 }
1380 return true;
1381
1382 fail:
1383 kprintf("%d: unsupported form: %#"PRIx64"\n", __LINE__, form);
1384 return false;
1385}
1386
1387/* find abbrev in current compilation unit */
1388static const char *
1389di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number, FILE *errout)
1390{
1391 const char *p;
1392 if (abbrev_number < ABBREV_TABLE_SIZE) {
1393 return reader->abbrev_table[abbrev_number];
1394 }
1395 p = reader->abbrev_table[ABBREV_TABLE_SIZE-1];
1396 /* skip 255th record */
1397 uleb128(&p); /* tag */
1398 p++; /* has_children */
1399 di_skip_die_attributes(&p);
1400 for (uint64_t n = uleb128(&p); abbrev_number != n; n = uleb128(&p)) {
1401 if (n == 0) {
1402 kprintf("%d: Abbrev Number %"PRId64" not found\n",__LINE__, abbrev_number);
1403 return NULL;
1404 }
1405 uleb128(&p); /* tag */
1406 p++; /* has_children */
1407 di_skip_die_attributes(&p);
1408 }
1409 return p;
1410}
1411
1412#if 0
1413static void
1414hexdump0(const unsigned char *p, size_t n, FILE *errout)
1415{
1416 size_t i;
1417 kprintf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
1418 for (i=0; i < n; i++){
1419 switch (i & 15) {
1420 case 0:
1421 kprintf("%02" PRIdSIZE ": %02X ", i/16, p[i]);
1422 break;
1423 case 15:
1424 kprintf("%02X\n", p[i]);
1425 break;
1426 default:
1427 kprintf("%02X ", p[i]);
1428 break;
1429 }
1430 }
1431 if ((i & 15) != 15) {
1432 kprintf("\n");
1433 }
1434}
1435#define hexdump(p,n,e) hexdump0((const unsigned char *)p, n, e)
1436
1437static void
1438div_inspect(DebugInfoValue *v, FILE *errout)
1439{
1440 switch (v->type) {
1441 case VAL_uint:
1442 kprintf("%d: type:%d size:%" PRIxSIZE " v:%"PRIx64"\n",__LINE__,v->type,v->size,v->as.uint64);
1443 break;
1444 case VAL_int:
1445 kprintf("%d: type:%d size:%" PRIxSIZE " v:%"PRId64"\n",__LINE__,v->type,v->size,(int64_t)v->as.uint64);
1446 break;
1447 case VAL_cstr:
1448 kprintf("%d: type:%d size:%" PRIxSIZE " v:'%s'\n",__LINE__,v->type,v->size,v->as.ptr);
1449 break;
1450 case VAL_data:
1451 kprintf("%d: type:%d size:%" PRIxSIZE " v:\n",__LINE__,v->type,v->size);
1452 hexdump(v->as.ptr, 16, errout);
1453 break;
1454 }
1455}
1456#endif
1457
1458static DIE *
1459di_read_die(DebugInfoReader *reader, DIE *die, FILE *errout)
1460{
1461 uint64_t abbrev_number = uleb128(&reader->p);
1462 if (abbrev_number == 0) {
1463 reader->level--;
1464 return NULL;
1465 }
1466
1467 if (!(reader->q = di_find_abbrev(reader, abbrev_number, errout))) return NULL;
1468
1469 die->pos = reader->p - reader->obj->debug_info.ptr - 1;
1470 die->tag = (int)uleb128(&reader->q); /* tag */
1471 die->has_children = *reader->q++; /* has_children */
1472 if (die->has_children) {
1473 reader->level++;
1474 }
1475 return die;
1476}
1477
1478static DebugInfoValue *
1479di_read_record(DebugInfoReader *reader, DebugInfoValue *vp, FILE *errout)
1480{
1481 uint64_t at = uleb128(&reader->q);
1482 uint64_t form = uleb128(&reader->q);
1483 if (!at || !form) return NULL;
1484 vp->at = at;
1485 vp->form = form;
1486 if (!debug_info_reader_read_value(reader, form, vp, errout)) return NULL;
1487 return vp;
1488}
1489
1490static bool
1491di_skip_records(DebugInfoReader *reader, FILE *errout)
1492{
1493 for (;;) {
1494 DebugInfoValue v = {{0}};
1495 uint64_t at = uleb128(&reader->q);
1496 uint64_t form = uleb128(&reader->q);
1497 if (!at || !form) return true;
1498 if (!debug_info_reader_read_value(reader, form, &v, errout)) return false;
1499 }
1500}
1501
1502typedef struct addr_header {
1503 const char *ptr;
1504 uint64_t unit_length;
1505 uint8_t format;
1506 uint8_t address_size;
1507 /* uint8_t segment_selector_size; */
1508} addr_header_t;
1509
1510static bool
1511addr_header_init(obj_info_t *obj, addr_header_t *header, FILE *errout)
1512{
1513 const char *p = obj->debug_addr.ptr;
1514
1515 header->ptr = p;
1516
1517 if (!p) return true;
1518
1519 header->unit_length = *(uint32_t *)p;
1520 p += sizeof(uint32_t);
1521
1522 header->format = 4;
1523 if (header->unit_length == 0xffffffff) {
1524 header->unit_length = *(uint64_t *)p;
1525 p += sizeof(uint64_t);
1526 header->format = 8;
1527 }
1528
1529 p += 2; /* version */
1530 header->address_size = *p++;
1531 if (header->address_size != 4 && header->address_size != 8) {
1532 kprintf("unknown address_size:%d", header->address_size);
1533 return false;
1534 }
1535 p++; /* segment_selector_size */
1536 return true;
1537}
1538
1539static uint64_t
1540read_addr(addr_header_t *header, uint64_t addr_base, uint64_t idx) {
1541 if (header->address_size == 4) {
1542 return ((uint32_t*)(header->ptr + addr_base))[idx];
1543 }
1544 else {
1545 return ((uint64_t*)(header->ptr + addr_base))[idx];
1546 }
1547}
1548
1549typedef struct rnglists_header {
1550 uint64_t unit_length;
1551 uint8_t format;
1552 uint8_t address_size;
1553 uint32_t offset_entry_count;
1554} rnglists_header_t;
1555
1556static bool
1557rnglists_header_init(obj_info_t *obj, rnglists_header_t *header, FILE *errout)
1558{
1559 const char *p = obj->debug_rnglists.ptr;
1560
1561 if (!p) return true;
1562
1563 header->unit_length = *(uint32_t *)p;
1564 p += sizeof(uint32_t);
1565
1566 header->format = 4;
1567 if (header->unit_length == 0xffffffff) {
1568 header->unit_length = *(uint64_t *)p;
1569 p += sizeof(uint64_t);
1570 header->format = 8;
1571 }
1572
1573 p += 2; /* version */
1574 header->address_size = *p++;
1575 if (header->address_size != 4 && header->address_size != 8) {
1576 kprintf("unknown address_size:%d", header->address_size);
1577 return false;
1578 }
1579 p++; /* segment_selector_size */
1580 header->offset_entry_count = *(uint32_t *)p;
1581 return true;
1582}
1583
1584typedef struct {
1585 uint64_t low_pc;
1586 uint64_t high_pc;
1587 uint64_t ranges;
1588 bool low_pc_set;
1589 bool high_pc_set;
1590 bool ranges_set;
1591} ranges_t;
1592
1593static void
1594ranges_set(ranges_t *ptr, DebugInfoValue *v, addr_header_t *addr_header, uint64_t addr_base)
1595{
1596 uint64_t n = 0;
1597 if (v->type == VAL_uint) {
1598 n = v->as.uint64;
1599 }
1600 else if (v->type == VAL_addr) {
1601 n = read_addr(addr_header, addr_base, v->as.addr_idx);
1602 }
1603 switch (v->at) {
1604 case DW_AT_low_pc:
1605 ptr->low_pc = n;
1606 ptr->low_pc_set = true;
1607 break;
1608 case DW_AT_high_pc:
1609 if (v->form == DW_FORM_addr) {
1610 ptr->high_pc = n;
1611 }
1612 else {
1613 ptr->high_pc = ptr->low_pc + n;
1614 }
1615 ptr->high_pc_set = true;
1616 break;
1617 case DW_AT_ranges:
1618 ptr->ranges = n;
1619 ptr->ranges_set = true;
1620 break;
1621 }
1622}
1623
1624static uint64_t
1625read_dw_form_addr(DebugInfoReader *reader, const char **ptr, FILE *errout)
1626{
1627 const char *p = *ptr;
1628 *ptr = p + reader->address_size;
1629 if (reader->address_size == 4) {
1630 return read_uint32(&p);
1631 } else {
1632 return read_uint64(&p);
1633 }
1634}
1635
1636static uintptr_t
1637ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr, rnglists_header_t *rnglists_header, FILE *errout)
1638{
1639 if (ptr->high_pc_set) {
1640 if (ptr->ranges_set || !ptr->low_pc_set) {
1641 return UINTPTR_MAX;
1642 }
1643 if (ptr->low_pc <= addr && addr <= ptr->high_pc) {
1644 return (uintptr_t)ptr->low_pc;
1645 }
1646 }
1647 else if (ptr->ranges_set) {
1648 /* TODO: support base address selection entry */
1649 const char *p;
1650 uint64_t base = ptr->low_pc_set ? ptr->low_pc : reader->current_low_pc;
1651 bool base_valid = true;
1652 if (reader->current_version >= 5) {
1653 if (rnglists_header->offset_entry_count == 0) {
1654 // DW_FORM_sec_offset
1655 p = reader->obj->debug_rnglists.ptr + ptr->ranges + reader->current_rnglists_base;
1656 }
1657 else {
1658 // DW_FORM_rnglistx
1659 const char *offset_array = reader->obj->debug_rnglists.ptr + reader->current_rnglists_base;
1660 if (rnglists_header->format == 4) {
1661 p = offset_array + ((uint32_t *)offset_array)[ptr->ranges];
1662 }
1663 else {
1664 p = offset_array + ((uint64_t *)offset_array)[ptr->ranges];
1665 }
1666 }
1667 for (;;) {
1668 uint8_t rle = read_uint8(&p);
1669 uintptr_t from = 0, to = 0;
1670 if (rle == DW_RLE_end_of_list) break;
1671 switch (rle) {
1672 case DW_RLE_base_addressx:
1673 uleb128(&p);
1674 base_valid = false; /* not supported yet */
1675 break;
1676 case DW_RLE_startx_endx:
1677 uleb128(&p);
1678 uleb128(&p);
1679 break;
1680 case DW_RLE_startx_length:
1681 uleb128(&p);
1682 uleb128(&p);
1683 break;
1684 case DW_RLE_offset_pair:
1685 if (!base_valid) break;
1686 from = (uintptr_t)base + uleb128(&p);
1687 to = (uintptr_t)base + uleb128(&p);
1688 break;
1689 case DW_RLE_base_address:
1690 base = read_dw_form_addr(reader, &p, errout);
1691 base_valid = true;
1692 break;
1693 case DW_RLE_start_end:
1694 from = (uintptr_t)read_dw_form_addr(reader, &p, errout);
1695 to = (uintptr_t)read_dw_form_addr(reader, &p, errout);
1696 break;
1697 case DW_RLE_start_length:
1698 from = (uintptr_t)read_dw_form_addr(reader, &p, errout);
1699 to = from + uleb128(&p);
1700 break;
1701 }
1702 if (from <= addr && addr < to) {
1703 return from;
1704 }
1705 }
1706 return 0;
1707 }
1708 p = reader->obj->debug_ranges.ptr + ptr->ranges;
1709 for (;;) {
1710 uintptr_t from = read_uintptr(&p);
1711 uintptr_t to = read_uintptr(&p);
1712 if (!from && !to) break;
1713 if (from == UINTPTR_MAX) {
1714 /* base address selection entry */
1715 base = to;
1716 }
1717 else if (base + from <= addr && addr < base + to) {
1718 return (uintptr_t)base + from;
1719 }
1720 }
1721 }
1722 else if (ptr->low_pc_set) {
1723 if (ptr->low_pc == addr) {
1724 return (uintptr_t)ptr->low_pc;
1725 }
1726 }
1727 return 0;
1728}
1729
1730#if 0
1731static void
1732ranges_inspect(DebugInfoReader *reader, ranges_t *ptr, FILE *errout)
1733{
1734 if (ptr->high_pc_set) {
1735 if (ptr->ranges_set || !ptr->low_pc_set) {
1736 kprintf("low_pc_set:%d high_pc_set:%d ranges_set:%d\n",ptr->low_pc_set,ptr->high_pc_set,ptr->ranges_set);
1737 return;
1738 }
1739 kprintf("low_pc:%"PRIx64" high_pc:%"PRIx64"\n",ptr->low_pc,ptr->high_pc);
1740 }
1741 else if (ptr->ranges_set) {
1742 char *p = reader->obj->debug_ranges.ptr + ptr->ranges;
1743 kprintf("low_pc:%"PRIx64" ranges:%"PRIx64" %lx ",ptr->low_pc,ptr->ranges, p-reader->obj->mapped);
1744 for (;;) {
1745 uintptr_t from = read_uintptr(&p);
1746 uintptr_t to = read_uintptr(&p);
1747 if (!from && !to) break;
1748 kprintf("%"PRIx64"-%"PRIx64" ",ptr->low_pc+from,ptr->low_pc+to);
1749 }
1750 kprintf("\n");
1751 }
1752 else if (ptr->low_pc_set) {
1753 kprintf("low_pc:%"PRIx64"\n",ptr->low_pc);
1754 }
1755 else {
1756 kprintf("empty\n");
1757 }
1758}
1759#endif
1760
1761static int
1762di_read_cu_context(DebugInfoReader *reader, FILE *errout)
1763{
1764 uint64_t unit_length;
1765 uint16_t version;
1766 uint64_t debug_abbrev_offset;
1767 reader->format = 4;
1768 reader->current_cu = reader->p;
1769 unit_length = read_uint32(&reader->p);
1770 if (unit_length == 0xffffffff) {
1771 unit_length = read_uint64(&reader->p);
1772 reader->format = 8;
1773 }
1774 reader->cu_end = reader->p + unit_length;
1775 version = read_uint16(&reader->p);
1776 reader->current_version = version;
1777 if (version > 5) {
1778 return -1;
1779 }
1780 else if (version == 5) {
1781 /* unit_type = */ read_uint8(&reader->p);
1782 reader->address_size = read_uint8(&reader->p);
1783 debug_abbrev_offset = read_uint(reader);
1784 }
1785 else {
1786 debug_abbrev_offset = read_uint(reader);
1787 reader->address_size = read_uint8(&reader->p);
1788 }
1789 if (reader->address_size != 4 && reader->address_size != 8) {
1790 kprintf("unknown address_size:%d", reader->address_size);
1791 return -1;
1792 }
1793 reader->q0 = reader->obj->debug_abbrev.ptr + debug_abbrev_offset;
1794
1795 reader->level = 0;
1796 di_read_debug_abbrev_cu(reader);
1797
1798 do {
1799 DIE die;
1800
1801 if (!di_read_die(reader, &die, errout)) continue;
1802
1803 if (die.tag != DW_TAG_compile_unit) {
1804 if (!di_skip_records(reader, errout)) return -1;
1805 break;
1806 }
1807
1808 reader->current_str_offsets_base = 0;
1809 reader->current_addr_base = 0;
1810 reader->current_rnglists_base = 0;
1811
1812 DebugInfoValue low_pc = {{0}};
1813 /* enumerate abbrev */
1814 for (;;) {
1815 DebugInfoValue v = {{0}};
1816 if (!di_read_record(reader, &v, errout)) break;
1817 switch (v.at) {
1818 case DW_AT_low_pc:
1819 // clang may output DW_AT_addr_base after DW_AT_low_pc.
1820 // We need to resolve the DW_FORM_addr* after DW_AT_addr_base is parsed.
1821 low_pc = v;
1822 break;
1823 case DW_AT_str_offsets_base:
1824 reader->current_str_offsets_base = v.as.uint64;
1825 break;
1826 case DW_AT_addr_base:
1827 reader->current_addr_base = v.as.uint64;
1828 break;
1829 case DW_AT_rnglists_base:
1830 reader->current_rnglists_base = v.as.uint64;
1831 break;
1832 }
1833 }
1834 // Resolve the DW_FORM_addr of DW_AT_low_pc
1835 switch (low_pc.type) {
1836 case VAL_uint:
1837 reader->current_low_pc = low_pc.as.uint64;
1838 break;
1839 case VAL_addr:
1840 {
1841 addr_header_t header = {0};
1842 if (!addr_header_init(reader->obj, &header, errout)) return -1;
1843 reader->current_low_pc = read_addr(&header, reader->current_addr_base, low_pc.as.addr_idx);
1844 }
1845 break;
1846 }
1847 } while (0);
1848
1849 return 0;
1850}
1851
1852static int
1853di_read_cu(DebugInfoReader *reader, FILE *errout)
1854{
1855 /* Keep di_read_cu_context separate so that it can be reused by di_read_cu_at
1856 * to set up arbitrary CUs without disturbing the .debug_line traversal. */
1857 if (di_read_cu_context(reader, errout)) return -1;
1858 if (di_read_debug_line_cu(reader, errout)) return -1;
1859 return 0;
1860}
1861
1862/* Find the .debug_info compilation unit containing the section-relative DIE
1863 * offset `die_offset`, initialize `reader` with that unit's abbrev/base context,
1864 * and leave reader->p pointing at the referenced DIE. Type units, split DWARF,
1865 * and supplementary debug objects are outside this parser's current scope. */
1866static bool
1867di_read_cu_at(DebugInfoReader *reader, uint64_t die_offset, FILE *errout)
1868{
1869 const uint64_t debug_info_size = reader->obj->debug_info.size;
1870 if (die_offset >= debug_info_size) return false;
1871
1872 const char *const info = reader->obj->debug_info.ptr;
1873 const char *const pend = reader->pend;
1874 const char *const target = info + die_offset;
1875 const char *cu = info;
1876
1877 while (pend - cu >= 4) {
1878 const char *hp = cu;
1879 uint64_t unit_length = read_uint32(&hp);
1880
1881 if (unit_length == 0xffffffff) {
1882 if (pend - hp < 8) return false;
1883 unit_length = read_uint64(&hp);
1884 }
1885 if (unit_length == 0 || unit_length > (uint64_t)(pend - hp)) return false;
1886
1887 const char *cu_end = hp + unit_length;
1888 if (target >= cu && target < cu_end) {
1889 reader->p = cu;
1890 if (di_read_cu_context(reader, errout)) return false;
1891 reader->p = target;
1892 return true;
1893 }
1894 cu = cu_end;
1895 }
1896 return false;
1897}
1898
1899static void
1900read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_origin, line_info_t *line, FILE *errout)
1901{
1902 DebugInfoReader saved = *reader; /* CU-scoped state may be rewritten below */
1903 DIE die;
1904
1905 switch (form) {
1906 case DW_FORM_ref1:
1907 case DW_FORM_ref2:
1908 case DW_FORM_ref4:
1909 case DW_FORM_ref8:
1910 case DW_FORM_ref_udata:
1911 reader->p = reader->current_cu + abstract_origin;
1912 break;
1913 case DW_FORM_ref_addr:
1914 /* Section-relative; target may be in another CU.
1915 * Switch to that CU's context.
1916 * di_read_cu_at leaves p at the target DIE. */
1917 if (!di_read_cu_at(reader, abstract_origin, errout)) goto finish;
1918 break;
1919 case DW_FORM_ref_sig8:
1920 goto finish; /* not supported yet */
1921 case DW_FORM_ref_sup4:
1922 case DW_FORM_ref_sup8:
1923 goto finish; /* not supported yet */
1924 default:
1925 goto finish;
1926 }
1927 if (!di_read_die(reader, &die, errout)) goto finish;
1928
1929 /* enumerate abbrev */
1930 for (;;) {
1931 DebugInfoValue v = {{0}};
1932 if (!di_read_record(reader, &v, errout)) break;
1933 switch (v.at) {
1934 case DW_AT_name:
1935 line->sname = get_cstr_value(&v);
1936 break;
1937 }
1938 }
1939
1940 finish:
1941 *reader = saved;
1942}
1943
1944static bool
1945debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
1946 line_info_t *lines, int offset, FILE *errout)
1947{
1948
1949 addr_header_t addr_header = {0};
1950 if (!addr_header_init(reader->obj, &addr_header, errout)) return false;
1951
1952 rnglists_header_t rnglists_header = {0};
1953 if (!rnglists_header_init(reader->obj, &rnglists_header, errout)) return false;
1954
1955 while (reader->p < reader->cu_end) {
1956 DIE die;
1957 ranges_t ranges = {0};
1958 line_info_t line = {0};
1959
1960 if (!di_read_die(reader, &die, errout)) continue;
1961 /* kprintf("%d:%tx: <%d>\n",__LINE__,die.pos,reader->level,die.tag); */
1962
1963 if (die.tag != DW_TAG_subprogram && die.tag != DW_TAG_inlined_subroutine) {
1964 skip_die:
1965 if (!di_skip_records(reader, errout)) return false;
1966 continue;
1967 }
1968
1969 /* enumerate abbrev */
1970 for (;;) {
1971 DebugInfoValue v = {{0}};
1972 /* ptrdiff_t pos = reader->p - reader->p0; */
1973 if (!di_read_record(reader, &v, errout)) break;
1974 /* kprintf("\n%d:%tx: AT:%lx FORM:%lx\n",__LINE__,pos,v.at,v.form); */
1975 /* div_inspect(&v, errout); */
1976 switch (v.at) {
1977 case DW_AT_name:
1978 line.sname = get_cstr_value(&v);
1979 break;
1980 case DW_AT_call_file:
1981 fill_filename((int)v.as.uint64, reader->debug_line_format, reader->debug_line_version, reader->debug_line_directories, reader->debug_line_files, &line, reader->obj, errout);
1982 break;
1983 case DW_AT_call_line:
1984 line.line = (int)v.as.uint64;
1985 break;
1986 case DW_AT_low_pc:
1987 case DW_AT_high_pc:
1988 case DW_AT_ranges:
1989 ranges_set(&ranges, &v, &addr_header, reader->current_addr_base);
1990 break;
1991 case DW_AT_declaration:
1992 goto skip_die;
1993 case DW_AT_inline:
1994 /* 1 or 3 */
1995 break; /* goto skip_die; */
1996 case DW_AT_abstract_origin:
1997 read_abstract_origin(reader, v.form, v.as.uint64, &line, errout);
1998 break; /* goto skip_die; */
1999 }
2000 }
2001 /* ranges_inspect(reader, &ranges, errout); */
2002 /* kprintf("%d:%tx: %x ",__LINE__,diepos,die.tag); */
2003 for (int i=offset; i < num_traces; i++) {
2004 uintptr_t addr = (uintptr_t)traces[i];
2005 uintptr_t offset = addr - reader->obj->base_addr + reader->obj->vmaddr;
2006 uintptr_t saddr = ranges_include(reader, &ranges, offset, &rnglists_header, errout);
2007 if (saddr == UINTPTR_MAX) return false;
2008 if (saddr) {
2009 /* kprintf("%d:%tx: %d %lx->%lx %x %s: %s/%s %d %s %s %s\n",__LINE__,die.pos, i,addr,offset, die.tag,line.sname,line.dirname,line.filename,line.line,reader->obj->path,line.sname,lines[i].sname); */
2010 if (lines[i].sname) {
2011 line_info_t *lp = malloc(sizeof(line_info_t));
2012 memcpy(lp, &lines[i], sizeof(line_info_t));
2013 lines[i].next = lp;
2014 lp->dirname = line.dirname;
2015 lp->filename = line.filename;
2016 lp->line = line.line;
2017 lp->saddr = 0;
2018 }
2019 lines[i].path = reader->obj->path;
2020 lines[i].base_addr = line.base_addr;
2021 lines[i].sname = line.sname;
2022 lines[i].saddr = saddr + reader->obj->base_addr - reader->obj->vmaddr;
2023 }
2024 }
2025 }
2026 return true;
2027}
2028
2029// This function parses the following attributes of Line Number Program Header in DWARF 5:
2030//
2031// * directory_entry_format_count
2032// * directory_entry_format
2033// * directories_count
2034// * directories
2035//
2036// or
2037//
2038// * file_name_entry_format_count
2039// * file_name_entry_format
2040// * file_names_count
2041// * file_names
2042//
2043// It records DW_LNCT_path and DW_LNCT_directory_index at the index "idx".
2044static const char *
2045parse_ver5_debug_line_header(const char *p, int idx, uint8_t format,
2046 obj_info_t *obj, const char **out_path,
2047 uint64_t *out_directory_index, FILE *errout)
2048{
2049 int i, j;
2050 int entry_format_count = *(uint8_t *)p++;
2051 const char *entry_format = p;
2052
2053 /* skip the part of entry_format */
2054 for (i = 0; i < entry_format_count * 2; i++) uleb128(&p);
2055
2056 int entry_count = (int)uleb128(&p);
2057
2058 DebugInfoReader reader = {0};
2059 debug_info_reader_init(&reader, obj);
2060 reader.format = format;
2061 reader.p = p;
2062 for (j = 0; j < entry_count; j++) {
2063 const char *format = entry_format;
2064 for (i = 0; i < entry_format_count; i++) {
2065 DebugInfoValue v = {{0}};
2066 unsigned long dw_lnct = uleb128(&format);
2067 unsigned long dw_form = uleb128(&format);
2068 if (!debug_info_reader_read_value(&reader, dw_form, &v, errout)) return 0;
2069 if (dw_lnct == 1 /* DW_LNCT_path */ && v.type == VAL_cstr && out_path)
2070 *out_path = v.as.ptr + v.off;
2071 if (dw_lnct == 2 /* DW_LNCT_directory_index */ && v.type == VAL_uint && out_directory_index)
2072 *out_directory_index = v.as.uint64;
2073 }
2074 if (j == idx) return 0;
2075 }
2076
2077 return reader.p;
2078}
2079
2080#ifdef USE_ELF
2081static unsigned long
2082uncompress_debug_section(ElfW(Shdr) *shdr, char *file, char **ptr)
2083{
2084 *ptr = NULL;
2085#ifdef SUPPORT_COMPRESSED_DEBUG_LINE
2086 ElfW(Chdr) *chdr = (ElfW(Chdr) *)(file + shdr->sh_offset);
2087 unsigned long destsize = chdr->ch_size;
2088 int ret = 0;
2089
2090 if (chdr->ch_type != ELFCOMPRESS_ZLIB) {
2091 /* unsupported compression type */
2092 return 0;
2093 }
2094
2095 *ptr = malloc(destsize);
2096 if (!*ptr) return 0;
2097 ret = uncompress((Bytef *)*ptr, &destsize,
2098 (const Bytef*)chdr + sizeof(ElfW(Chdr)),
2099 shdr->sh_size - sizeof(ElfW(Chdr)));
2100 if (ret != Z_OK) goto fail;
2101 return destsize;
2102
2103fail:
2104 free(*ptr);
2105 *ptr = NULL;
2106#endif
2107 return 0;
2108}
2109
2110/* read file and fill lines */
2111static uintptr_t
2112fill_lines(int num_traces, void **traces, int check_debuglink,
2113 obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
2114{
2115 int i, j;
2116 char *shstr;
2117 ElfW(Ehdr) *ehdr;
2118 ElfW(Shdr) *shdr, *shstr_shdr;
2119 ElfW(Shdr) *gnu_debuglink_shdr = NULL;
2120 ElfW(Shdr) *note_gnu_build_id = NULL;
2121 int fd;
2122 off_t filesize;
2123 char *file;
2124 ElfW(Shdr) *symtab_shdr = NULL, *strtab_shdr = NULL;
2125 ElfW(Shdr) *dynsym_shdr = NULL, *dynstr_shdr = NULL;
2126 obj_info_t *obj = *objp;
2127 uintptr_t dladdr_fbase = 0;
2128
2129 fd = open(binary_filename, O_RDONLY);
2130 if (fd < 0) {
2131 goto fail;
2132 }
2133 filesize = lseek(fd, 0, SEEK_END);
2134 if (filesize < 0) {
2135 int e = errno;
2136 close(fd);
2137 kprintf("lseek: %s\n", strerror(e));
2138 goto fail;
2139 }
2140#if SIZEOF_OFF_T > SIZEOF_SIZE_T
2141 if (filesize > (off_t)SIZE_MAX) {
2142 close(fd);
2143 kprintf("Too large file %s\n", binary_filename);
2144 goto fail;
2145 }
2146#endif
2147 lseek(fd, 0, SEEK_SET);
2148 /* async-signal unsafe */
2149 file = (char *)mmap(NULL, (size_t)filesize, PROT_READ, MAP_SHARED, fd, 0);
2150 if (file == MAP_FAILED) {
2151 int e = errno;
2152 close(fd);
2153 kprintf("mmap: %s\n", strerror(e));
2154 goto fail;
2155 }
2156 close(fd);
2157
2158 ehdr = (ElfW(Ehdr) *)file;
2159 if (memcmp(ehdr->e_ident, "\177ELF", 4) != 0) {
2160 /*
2161 * Huh? Maybe filename was overridden by setproctitle() and
2162 * it match non-elf file.
2163 */
2164 goto fail;
2165 }
2166 obj->mapped = file;
2167 obj->mapped_size = (size_t)filesize;
2168
2169 shdr = (ElfW(Shdr) *)(file + ehdr->e_shoff);
2170
2171 shstr_shdr = shdr + ehdr->e_shstrndx;
2172 shstr = file + shstr_shdr->sh_offset;
2173
2174 for (i = 0; i < ehdr->e_shnum; i++) {
2175 char *section_name = shstr + shdr[i].sh_name;
2176 switch (shdr[i].sh_type) {
2177 case SHT_STRTAB:
2178 if (!strcmp(section_name, ".strtab")) {
2179 strtab_shdr = shdr + i;
2180 }
2181 else if (!strcmp(section_name, ".dynstr")) {
2182 dynstr_shdr = shdr + i;
2183 }
2184 break;
2185 case SHT_SYMTAB:
2186 /* if (!strcmp(section_name, ".symtab")) */
2187 symtab_shdr = shdr + i;
2188 break;
2189 case SHT_DYNSYM:
2190 /* if (!strcmp(section_name, ".dynsym")) */
2191 dynsym_shdr = shdr + i;
2192 break;
2193 case SHT_NOTE:
2194 if (!strcmp(section_name, ".note.gnu.build-id")) {
2195 note_gnu_build_id = shdr + i;
2196 }
2197 break;
2198 case SHT_PROGBITS:
2199 if (!strcmp(section_name, ".gnu_debuglink")) {
2200 gnu_debuglink_shdr = shdr + i;
2201 }
2202 else {
2203 const char *debug_section_names[] = {
2204 ".debug_abbrev",
2205 ".debug_info",
2206 ".debug_line",
2207 ".debug_ranges",
2208 ".debug_str_offsets",
2209 ".debug_addr",
2210 ".debug_rnglists",
2211 ".debug_str",
2212 ".debug_line_str"
2213 };
2214
2215 for (j=0; j < DWARF_SECTION_COUNT; j++) {
2216 struct dwarf_section *s = obj_dwarf_section_at(obj, j);
2217
2218 if (strcmp(section_name, debug_section_names[j]) != 0)
2219 continue;
2220
2221 s->ptr = file + shdr[i].sh_offset;
2222 s->size = shdr[i].sh_size;
2223 s->flags = shdr[i].sh_flags;
2224 if (s->flags & SHF_COMPRESSED) {
2225 s->size = uncompress_debug_section(&shdr[i], file, &s->ptr);
2226 if (!s->size) goto fail;
2227 }
2228 break;
2229 }
2230 }
2231 break;
2232 }
2233 }
2234
2235 if (offset == 0) {
2236 /* main executable */
2237 if (dynsym_shdr && dynstr_shdr) {
2238 char *strtab = file + dynstr_shdr->sh_offset;
2239 ElfW(Sym) *symtab = (ElfW(Sym) *)(file + dynsym_shdr->sh_offset);
2240 int symtab_count = (int)(dynsym_shdr->sh_size / sizeof(ElfW(Sym)));
2241 void *handle = dlopen(NULL, RTLD_NOW|RTLD_LOCAL);
2242 if (handle) {
2243 for (j = 0; j < symtab_count; j++) {
2244 ElfW(Sym) *sym = &symtab[j];
2245 Dl_info info;
2246 void *s;
2247 if (ELF_ST_TYPE(sym->st_info) != STT_FUNC || sym->st_size == 0) continue;
2248 s = dlsym(handle, strtab + sym->st_name);
2249 if (s && dladdr(s, &info)) {
2250 obj->base_addr = dladdr_fbase;
2251 dladdr_fbase = (uintptr_t)info.dli_fbase;
2252 break;
2253 }
2254 }
2255 dlclose(handle);
2256 }
2257 if (ehdr->e_type == ET_EXEC) {
2258 obj->base_addr = 0;
2259 }
2260 else {
2261 /* PIE (position-independent executable) */
2262 obj->base_addr = dladdr_fbase;
2263 }
2264 }
2265 }
2266
2267 if (obj->debug_info.ptr && obj->debug_abbrev.ptr) {
2268 /* Static (not stack): ~2KB struct, runs on a small altstack.
2269 * Safe despite fill_lines re-entering via follow_debuglink: this
2270 * block's while loop fully consumes the reader before that
2271 * recursion point (in the separate !debug_line block below), and
2272 * debug_info_reader_init reinitializes on each entry. */
2273 static DebugInfoReader reader;
2274 debug_info_reader_init(&reader, obj);
2275 i = 0;
2276 while (reader.p < reader.pend) {
2277 /* kprintf("%d:%tx: CU[%d]\n", __LINE__, reader.p - reader.obj->debug_info.ptr, i++); */
2278 if (di_read_cu(&reader, errout)) goto use_symtab;
2279 if (!debug_info_read(&reader, num_traces, traces, lines, offset, errout))
2280 goto use_symtab;
2281 }
2282 }
2283 else {
2284 /* This file doesn't have dwarf, use symtab or dynsym */
2285use_symtab:
2286 if (!symtab_shdr) {
2287 /* This file doesn't have symtab, use dynsym instead */
2288 symtab_shdr = dynsym_shdr;
2289 strtab_shdr = dynstr_shdr;
2290 }
2291
2292 if (symtab_shdr && strtab_shdr) {
2293 char *strtab = file + strtab_shdr->sh_offset;
2294 ElfW(Sym) *symtab = (ElfW(Sym) *)(file + symtab_shdr->sh_offset);
2295 int symtab_count = (int)(symtab_shdr->sh_size / sizeof(ElfW(Sym)));
2296 for (j = 0; j < symtab_count; j++) {
2297 ElfW(Sym) *sym = &symtab[j];
2298 uintptr_t saddr = (uintptr_t)sym->st_value + obj->base_addr;
2299 if (ELF_ST_TYPE(sym->st_info) != STT_FUNC) continue;
2300 for (i = offset; i < num_traces; i++) {
2301 uintptr_t d = (uintptr_t)traces[i] - saddr;
2302 if (lines[i].line > 0 || d > (uintptr_t)sym->st_size)
2303 continue;
2304 /* fill symbol name and addr from .symtab */
2305 if (!lines[i].sname) lines[i].sname = strtab + sym->st_name;
2306 lines[i].saddr = saddr;
2307 lines[i].path = obj->path;
2308 lines[i].base_addr = obj->base_addr;
2309 }
2310 }
2311 }
2312 }
2313
2314 if (!obj->debug_line.ptr) {
2315 /* This file doesn't have .debug_line section,
2316 let's check .gnu_debuglink section instead. */
2317 if (gnu_debuglink_shdr && check_debuglink) {
2318 follow_debuglink(file + gnu_debuglink_shdr->sh_offset,
2319 num_traces, traces,
2320 objp, lines, offset, errout);
2321 }
2322 if (note_gnu_build_id && check_debuglink) {
2323 ElfW(Nhdr) *nhdr = (ElfW(Nhdr)*) (file + note_gnu_build_id->sh_offset);
2324 const char *build_id = (char *)(nhdr + 1) + nhdr->n_namesz;
2325 follow_debuglink_build_id(build_id, nhdr->n_descsz,
2326 num_traces, traces,
2327 objp, lines, offset, errout);
2328 }
2329 goto finish;
2330 }
2331
2332 if (parse_debug_line(num_traces, traces,
2333 obj->debug_line.ptr,
2334 obj->debug_line.size,
2335 obj, lines, offset, errout) == -1)
2336 goto fail;
2337
2338finish:
2339 return dladdr_fbase;
2340fail:
2341 return (uintptr_t)-1;
2342}
2343#else /* Mach-O */
2344/* read file and fill lines */
2345static uintptr_t
2346fill_lines(int num_traces, void **traces, int check_debuglink,
2347 obj_info_t **objp, line_info_t *lines, int offset, FILE *errout)
2348{
2349 int fd;
2350 off_t filesize;
2351 char *file, *p = NULL;
2352 obj_info_t *obj = *objp;
2353 struct LP(mach_header) *header;
2354 uintptr_t dladdr_fbase = 0;
2355
2356 {
2357 char *s = binary_filename;
2358 char *base = strrchr(binary_filename, '/')+1;
2359 size_t max = PATH_MAX;
2360 size_t size = strlen(binary_filename);
2361 size_t basesize = size - (base - binary_filename);
2362 s += size;
2363 max -= size;
2364 p = s;
2365 size = strlcpy(s, ".dSYM/Contents/Resources/DWARF/", max);
2366 if (size == 0) goto fail;
2367 s += size;
2368 max -= size;
2369 if (max <= basesize) goto fail;
2370 memcpy(s, base, basesize);
2371 s[basesize] = 0;
2372
2373 fd = open(binary_filename, O_RDONLY);
2374 if (fd < 0) {
2375 *p = 0; /* binary_filename becomes original file name */
2376 fd = open(binary_filename, O_RDONLY);
2377 if (fd < 0) {
2378 goto fail;
2379 }
2380 }
2381 }
2382
2383 filesize = lseek(fd, 0, SEEK_END);
2384 if (filesize < 0) {
2385 int e = errno;
2386 close(fd);
2387 kprintf("lseek: %s\n", strerror(e));
2388 goto fail;
2389 }
2390#if SIZEOF_OFF_T > SIZEOF_SIZE_T
2391 if (filesize > (off_t)SIZE_MAX) {
2392 close(fd);
2393 kprintf("Too large file %s\n", binary_filename);
2394 goto fail;
2395 }
2396#endif
2397 lseek(fd, 0, SEEK_SET);
2398 /* async-signal unsafe */
2399 file = (char *)mmap(NULL, (size_t)filesize, PROT_READ, MAP_SHARED, fd, 0);
2400 if (file == MAP_FAILED) {
2401 int e = errno;
2402 close(fd);
2403 kprintf("mmap: %s\n", strerror(e));
2404 goto fail;
2405 }
2406 close(fd);
2407
2408 obj->mapped = file;
2409 obj->mapped_size = (size_t)filesize;
2410
2411 header = (struct LP(mach_header) *)file;
2412 if (header->magic == LP(MH_MAGIC)) {
2413 /* non universal binary */
2414 p = file;
2415 }
2416 else if (header->magic == FAT_CIGAM) {
2417 struct LP(mach_header) *mhp = _NSGetMachExecuteHeader();
2418 struct fat_header *fat = (struct fat_header *)file;
2419 char *q = file + sizeof(*fat);
2420 uint32_t nfat_arch = __builtin_bswap32(fat->nfat_arch);
2421 /* kprintf("%d: fat:%s %d\n",__LINE__, binary_filename,nfat_arch); */
2422 for (uint32_t i = 0; i < nfat_arch; i++) {
2423 struct fat_arch *arch = (struct fat_arch *)q;
2424 cpu_type_t cputype = __builtin_bswap32(arch->cputype);
2425 cpu_subtype_t cpusubtype = __builtin_bswap32(arch->cpusubtype);
2426 uint32_t offset = __builtin_bswap32(arch->offset);
2427 /* kprintf("%d: fat %d %x/%x %x/%x\n",__LINE__, i, mhp->cputype,mhp->cpusubtype, cputype,cpusubtype); */
2428 if (mhp->cputype == cputype &&
2429 (cpu_subtype_t)(mhp->cpusubtype & ~CPU_SUBTYPE_MASK) == cpusubtype) {
2430 p = file + offset;
2431 file = p;
2432 header = (struct LP(mach_header) *)p;
2433 if (header->magic == LP(MH_MAGIC)) {
2434 goto found_mach_header;
2435 }
2436 break;
2437 }
2438 q += sizeof(*arch);
2439 }
2440 kprintf("'%s' is not a Mach-O universal binary file!\n",binary_filename);
2441 close(fd);
2442 goto fail;
2443 }
2444 else {
2445# ifdef __LP64__
2446# define bitsize "64"
2447# else
2448# define bitsize "32"
2449# endif
2450 kprintf("'%s' is not a " bitsize
2451 "-bit Mach-O file!\n",binary_filename);
2452# undef bitsize
2453 close(fd);
2454 goto fail;
2455 }
2456found_mach_header:
2457 p += sizeof(*header);
2458
2459 for (uint32_t i = 0; i < (uint32_t)header->ncmds; i++) {
2460 struct load_command *lcmd = (struct load_command *)p;
2461 switch (lcmd->cmd) {
2462 case LP(LC_SEGMENT):
2463 {
2464 static const char *debug_section_names[] = {
2465 "__debug_abbrev",
2466 "__debug_info",
2467 "__debug_line",
2468 "__debug_ranges",
2469 "__debug_str_offsets",
2470 "__debug_addr",
2471 "__debug_rnglists",
2472 "__debug_str",
2473 "__debug_line_str",
2474 };
2475 struct LP(segment_command) *scmd = (struct LP(segment_command) *)lcmd;
2476 if (strcmp(scmd->segname, "__TEXT") == 0) {
2477 obj->vmaddr = scmd->vmaddr;
2478 }
2479 else if (strcmp(scmd->segname, "__DWARF") == 0) {
2480 p += sizeof(struct LP(segment_command));
2481 for (uint64_t i = 0; i < scmd->nsects; i++) {
2482 struct LP(section) *sect = (struct LP(section) *)p;
2483 p += sizeof(struct LP(section));
2484 for (int j=0; j < DWARF_SECTION_COUNT; j++) {
2485 struct dwarf_section *s = obj_dwarf_section_at(obj, j);
2486
2487 if (strcmp(sect->sectname, debug_section_names[j]) != 0
2488#ifdef __APPLE__
2489 /* macOS clang 16 generates DWARF5, which have Mach-O
2490 * section names that are limited to 16 characters,
2491 * which causes sections with long names to be truncated
2492 * and not match above.
2493 * See: https://wiki.dwarfstd.org/Best_Practices.md#Mach-2d-O
2494 */
2495 && strncmp(sect->sectname, debug_section_names[j], 16) != 0
2496#endif
2497 )
2498 continue;
2499
2500 s->ptr = file + sect->offset;
2501 s->size = sect->size;
2502 s->flags = sect->flags;
2503 if (s->flags & SHF_COMPRESSED) {
2504 goto fail;
2505 }
2506 break;
2507 }
2508 }
2509 }
2510 }
2511 break;
2512
2513 case LC_SYMTAB:
2514 {
2515 struct symtab_command *cmd = (struct symtab_command *)lcmd;
2516 struct LP(nlist) *nl = (struct LP(nlist) *)(file + cmd->symoff);
2517 char *strtab = file + cmd->stroff, *sname = 0;
2518 uint32_t j;
2519 uintptr_t saddr = 0;
2520 /* kprintf("[%2d]: %x/symtab %p\n", i, cmd->cmd, (void *)p); */
2521 for (j = 0; j < cmd->nsyms; j++) {
2522 uintptr_t symsize, d;
2523 struct LP(nlist) *e = &nl[j];
2524 /* kprintf("[%2d][%4d]: %02x/%x/%x: %s %llx\n", i, j, e->n_type,e->n_sect,e->n_desc,strtab+e->n_un.n_strx,e->n_value); */
2525 if (e->n_type != N_FUN) continue;
2526 if (e->n_sect) {
2527 saddr = (uintptr_t)e->n_value + obj->base_addr - obj->vmaddr;
2528 sname = strtab + e->n_un.n_strx;
2529 /* kprintf("[%2d][%4d]: %02x/%x/%x: %s %llx\n", i, j, e->n_type,e->n_sect,e->n_desc,strtab+e->n_un.n_strx,e->n_value); */
2530 continue;
2531 }
2532 for (int k = offset; k < num_traces; k++) {
2533 d = (uintptr_t)traces[k] - saddr;
2534 symsize = e->n_value;
2535 /* kprintf("%lx %lx %lx\n",saddr,symsize,traces[k]); */
2536 if (lines[k].line > 0 || d > (uintptr_t)symsize)
2537 continue;
2538 /* fill symbol name and addr from .symtab */
2539 if (!lines[k].sname) lines[k].sname = sname;
2540 lines[k].saddr = saddr;
2541 lines[k].path = obj->path;
2542 lines[k].base_addr = obj->base_addr;
2543 }
2544 }
2545 }
2546 }
2547 p += lcmd->cmdsize;
2548 }
2549
2550 if (obj->debug_info.ptr && obj->debug_abbrev.ptr) {
2551 /* Static (not stack): ~2KB struct, runs on a small altstack. */
2552 static DebugInfoReader reader;
2553 debug_info_reader_init(&reader, obj);
2554 while (reader.p < reader.pend) {
2555 if (di_read_cu(&reader, errout)) goto fail;
2556 if (!debug_info_read(&reader, num_traces, traces, lines, offset, errout))
2557 goto fail;
2558 }
2559 }
2560
2561 if (parse_debug_line(num_traces, traces,
2562 obj->debug_line.ptr,
2563 obj->debug_line.size,
2564 obj, lines, offset, errout) == -1)
2565 goto fail;
2566
2567 return dladdr_fbase;
2568fail:
2569 return (uintptr_t)-1;
2570}
2571#endif
2572
2573#define HAVE_MAIN_EXE_PATH
2574#if defined(__FreeBSD__) || defined(__DragonFly__)
2575# include <sys/sysctl.h>
2576#endif
2577/* ssize_t main_exe_path(FILE *errout)
2578 *
2579 * store the path of the main executable to `binary_filename`,
2580 * and returns strlen(binary_filename).
2581 * it is NUL terminated.
2582 */
2583#if defined(__linux__) || defined(__NetBSD__)
2584static ssize_t
2585main_exe_path(FILE *errout)
2586{
2587# if defined(__linux__)
2588# define PROC_SELF_EXE "/proc/self/exe"
2589# elif defined(__NetBSD__)
2590# define PROC_SELF_EXE "/proc/curproc/exe"
2591# endif
2592 ssize_t len = readlink(PROC_SELF_EXE, binary_filename, PATH_MAX);
2593 if (len < 0) return 0;
2594 binary_filename[len] = 0;
2595 return len;
2596}
2597#elif defined(__FreeBSD__) || defined(__DragonFly__)
2598static ssize_t
2599main_exe_path(FILE *errout)
2600{
2601 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
2602 size_t len = PATH_MAX;
2603 int err = sysctl(mib, 4, binary_filename, &len, NULL, 0);
2604 if (err) {
2605 kprintf("Can't get the path of ruby");
2606 return -1;
2607 }
2608 len--; /* sysctl sets strlen+1 */
2609 return len;
2610}
2611#elif defined(HAVE_LIBPROC_H)
2612static ssize_t
2613main_exe_path(FILE *errout)
2614{
2615 int len = proc_pidpath(getpid(), binary_filename, PATH_MAX);
2616 if (len == 0) return 0;
2617 binary_filename[len] = 0;
2618 return len;
2619}
2620#else
2621#undef HAVE_MAIN_EXE_PATH
2622#endif
2623
2624static void
2625print_line0(line_info_t *line, void *address, FILE *errout)
2626{
2627 uintptr_t addr = (uintptr_t)address;
2628 uintptr_t d = addr - line->saddr;
2629 if (!address) {
2630 /* inlined */
2631 if (line->dirname && line->dirname[0]) {
2632 kprintf("%s(%s) %s/%s:%d\n", line->path, line->sname, line->dirname, line->filename, line->line);
2633 }
2634 else {
2635 kprintf("%s(%s) %s:%d\n", line->path, line->sname, line->filename, line->line);
2636 }
2637 }
2638 else if (!line->path) {
2639 kprintf("[0x%"PRIxPTR"]\n", addr);
2640 }
2641 else if (!line->sname) {
2642 kprintf("%s(0x%"PRIxPTR") [0x%"PRIxPTR"]\n", line->path, addr-line->base_addr, addr);
2643 }
2644 else if (!line->saddr) {
2645 kprintf("%s(%s) [0x%"PRIxPTR"]\n", line->path, line->sname, addr);
2646 }
2647 else if (line->line <= 0) {
2648 kprintf("%s(%s+0x%"PRIxPTR") [0x%"PRIxPTR"]\n", line->path, line->sname,
2649 d, addr);
2650 }
2651 else if (!line->filename) {
2652 kprintf("%s(%s+0x%"PRIxPTR") [0x%"PRIxPTR"] ???:%d\n", line->path, line->sname,
2653 d, addr, line->line);
2654 }
2655 else if (line->dirname && line->dirname[0]) {
2656 kprintf("%s(%s+0x%"PRIxPTR") [0x%"PRIxPTR"] %s/%s:%d\n", line->path, line->sname,
2657 d, addr, line->dirname, line->filename, line->line);
2658 }
2659 else {
2660 kprintf("%s(%s+0x%"PRIxPTR") [0x%"PRIxPTR"] %s:%d\n", line->path, line->sname,
2661 d, addr, line->filename, line->line);
2662 }
2663}
2664
2665static void
2666print_line(line_info_t *line, void *address, FILE *errout)
2667{
2668 print_line0(line, address, errout);
2669 if (line->next) {
2670 print_line(line->next, NULL, errout);
2671 }
2672}
2673
2674void
2675rb_dump_backtrace_with_lines(int num_traces, void **traces, FILE *errout)
2676{
2677 int i;
2678 /* async-signal unsafe */
2679 line_info_t *lines = (line_info_t *)calloc(num_traces, sizeof(line_info_t));
2680 obj_info_t *obj = NULL;
2681 /* 2 is NULL + main executable */
2682 void **dladdr_fbases = (void **)calloc(num_traces+2, sizeof(void *));
2683
2684#ifdef HAVE_MAIN_EXE_PATH
2685 char *main_path = NULL; /* used on printing backtrace */
2686 ssize_t len;
2687 if ((len = main_exe_path(errout)) > 0) {
2688 main_path = (char *)alloca(len + 1);
2689 if (main_path) {
2690 uintptr_t addr;
2691 memcpy(main_path, binary_filename, len+1);
2692 append_obj(&obj);
2693 obj->path = main_path;
2694 addr = fill_lines(num_traces, traces, 1, &obj, lines, 0, errout);
2695 if (addr != (uintptr_t)-1) {
2696 dladdr_fbases[0] = (void *)addr;
2697 }
2698 }
2699 }
2700#endif
2701
2702 /* fill source lines by reading dwarf */
2703 for (i = 0; i < num_traces; i++) {
2704 Dl_info info;
2705 if (lines[i].line) continue;
2706 if (dladdr(traces[i], &info)) {
2707 const char *path;
2708 void **p;
2709
2710 /* skip symbols which is in already checked objects */
2711 /* if the binary is strip-ed, this may effect */
2712 for (p=dladdr_fbases; *p; p++) {
2713 if (*p == info.dli_fbase) {
2714 if (info.dli_fname) lines[i].path = info.dli_fname;
2715 if (info.dli_sname) lines[i].sname = info.dli_sname;
2716 goto next_line;
2717 }
2718 }
2719 *p = info.dli_fbase;
2720
2721 append_obj(&obj);
2722 obj->base_addr = (uintptr_t)info.dli_fbase;
2723 path = info.dli_fname;
2724 obj->path = path;
2725 if (path) lines[i].path = path;
2726 if (info.dli_sname) {
2727 lines[i].sname = info.dli_sname;
2728 lines[i].saddr = (uintptr_t)info.dli_saddr;
2729 }
2730 strlcpy(binary_filename, path, PATH_MAX);
2731 if (fill_lines(num_traces, traces, 1, &obj, lines, i, errout) == (uintptr_t)-1)
2732 break;
2733 }
2734next_line:
2735 continue;
2736 }
2737
2738 /* output */
2739 for (i = 0; i < num_traces; i++) {
2740 print_line(&lines[i], traces[i], errout);
2741
2742 /* FreeBSD's backtrace may show _start and so on */
2743 if (lines[i].sname && strcmp("main", lines[i].sname) == 0)
2744 break;
2745 }
2746
2747 /* free */
2748 while (obj) {
2749 obj_info_t *o = obj;
2750 for (i=0; i < DWARF_SECTION_COUNT; i++) {
2751 struct dwarf_section *s = obj_dwarf_section_at(obj, i);
2752 if (s->flags & SHF_COMPRESSED) {
2753 free(s->ptr);
2754 }
2755 }
2756 if (obj->mapped_size) {
2757 munmap(obj->mapped, obj->mapped_size);
2758 }
2759 obj = o->next;
2760 free(o);
2761 }
2762 for (i = 0; i < num_traces; i++) {
2763 line_info_t *line = lines[i].next;
2764 while (line) {
2765 line_info_t *l = line;
2766 line = line->next;
2767 free(l);
2768 }
2769 }
2770 free(lines);
2771 free(dladdr_fbases);
2772}
2773
2774#undef kprintf
2775
2776#else /* defined(USE_ELF) */
2777#error not supported
2778#endif
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
int off
Offset inside of ptr.
Definition io.h:5
int len
Length of the buffer.
Definition io.h:8
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
C99 shim for <stdbool.h>