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