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