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