1 /**********************************************************************
7 Copyright (C) 2010 Shinichiro Hamaji
9 **********************************************************************/
11 #if defined(__clang__)
12 #pragma clang diagnostic ignored "-Wgnu-empty-initializer"
13 #pragma clang diagnostic ignored "-Wgcc-compat"
16 #include "ruby/internal/config.h"
17 #include "ruby/defines.h"
18 #include "ruby/missing.h"
19 #include "addr2line.h"
28 #include "ruby/internal/stdbool.h"
30 #if defined(USE_ELF) || defined(HAVE_MACH_O_LOADER_H)
39 #include <sys/types.h>
43 /* Make alloca work the best possible way. */
46 # define alloca __builtin_alloca
55 # ifndef alloca /* predefined by HP cc +Olibcalls */
59 # endif /* HAVE_ALLOCA_H */
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>
82 # if SIZEOF_VOIDP == 8
83 # define ElfW(x) Elf64##_##x
85 # define ElfW(x) Elf32##_##x
89 # if SIZEOF_VOIDP == 8
90 # define ELF_ST_TYPE ELF64_ST_TYPE
92 # define ELF_ST_TYPE ELF32_ST_TYPE
98 # if defined(ELFCOMPRESS_ZLIB) && defined(HAVE_LIBZ)
99 /* FreeBSD 11.0 lacks ELFCOMPRESS_ZLIB */
101 # define SUPPORT_COMPRESSED_DEBUG_LINE
103 #else /* compatibility with glibc < 2.22 */
104 # define SHF_COMPRESSED 0
108 #define PATH_MAX 4096
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 */
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 */
130 PRINTF_ARGS(static int kprintf(const char *fmt
, ...), 1, 2);
132 typedef struct line_info
{
134 const char *filename
;
135 const char *path
; /* object path */
140 const char *sname
; /* function name */
142 struct line_info
*next
;
145 struct dwarf_section
{
151 typedef struct obj_info
{
152 const char *path
; /* object path */
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_rnglists
;
163 struct dwarf_section debug_str
;
164 struct obj_info
*next
;
167 #define DWARF_SECTION_COUNT 6
169 static struct dwarf_section
*
170 obj_dwarf_section_at(obj_info_t
*obj
, int n
)
172 struct dwarf_section
*ary
[] = {
177 &obj
->debug_rnglists
,
180 if (n
< 0 || DWARF_SECTION_COUNT
<= n
) {
186 struct debug_section_definition
{
188 struct dwarf_section
*dwarf
;
191 /* Avoid consuming stack as this module may be used from signal handler */
192 static char binary_filename
[PATH_MAX
+ 1];
195 uleb128(const char **p
)
200 unsigned char b
= (unsigned char)*(*p
)++;
202 r
+= (unsigned long)b
<< s
;
205 r
+= (b
& 0x7f) << s
;
212 sleb128(const char **p
)
217 unsigned char b
= (unsigned char)*(*p
)++;
220 r
-= (0x80 - b
) << s
;
223 r
+= (b
& 0x3f) << s
;
227 r
+= (b
& 0x7f) << s
;
234 get_nth_dirname(unsigned long dir
, const char *p
)
243 kprintf("Unexpected directory number %lu in %s\n",
244 dir
, binary_filename
);
252 fill_filename(int file
, const char *include_directories
, const char *filenames
, line_info_t
*line
, obj_info_t
*obj
)
255 const char *p
= filenames
;
256 const char *filename
;
258 for (i
= 1; i
<= file
; i
++) {
261 /* Need to output binary file name? */
262 kprintf("Unexpected file number %d in %s at %tx\n",
263 file
, binary_filename
, filenames
- obj
->mapped
);
271 /* size of the file. */
275 line
->filename
= filename
;
276 line
->dirname
= get_nth_dirname(dir
, include_directories
);
282 fill_line(int num_traces
, void **traces
, uintptr_t addr
, int file
, int line
,
283 const char *include_directories
, const char *filenames
,
284 obj_info_t
*obj
, line_info_t
*lines
, int offset
)
287 addr
+= obj
->base_addr
- obj
->vmaddr
;
288 for (i
= offset
; i
< num_traces
; i
++) {
289 uintptr_t a
= (uintptr_t)traces
[i
];
290 /* We assume one line code doesn't result >100 bytes of native code.
291 We may want more reliable way eventually... */
292 if (addr
< a
&& a
< addr
+ 100) {
293 fill_filename(file
, include_directories
, filenames
, &lines
[i
], obj
);
294 lines
[i
].line
= line
;
299 struct LineNumberProgramHeader
{
300 uint64_t unit_length
;
302 uint8_t format
; /* 4 or 8 */
303 uint64_t header_length
;
304 uint8_t minimum_instruction_length
;
305 uint8_t maximum_operations_per_instruction
;
306 uint8_t default_is_stmt
;
310 /* uint8_t standard_opcode_lengths[opcode_base-1]; */
311 const char *include_directories
;
312 const char *filenames
;
313 const char *cu_start
;
318 parse_debug_line_header(const char **pp
, struct LineNumberProgramHeader
*header
)
321 header
->unit_length
= *(uint32_t *)p
;
322 p
+= sizeof(uint32_t);
325 if (header
->unit_length
== 0xffffffff) {
326 header
->unit_length
= *(uint64_t *)p
;
327 p
+= sizeof(uint64_t);
331 header
->cu_end
= p
+ header
->unit_length
;
333 header
->version
= *(uint16_t *)p
;
334 p
+= sizeof(uint16_t);
335 if (header
->version
> 4) return -1;
337 header
->header_length
= header
->format
== 4 ? *(uint32_t *)p
: *(uint64_t *)p
;
339 header
->cu_start
= p
+ header
->header_length
;
341 header
->minimum_instruction_length
= *(uint8_t *)p
++;
343 if (header
->version
>= 4) {
344 /* maximum_operations_per_instruction = *(uint8_t *)p; */
345 if (*p
!= 1) return -1; /* For non-VLIW architectures, this field is 1 */
349 header
->default_is_stmt
= *(uint8_t *)p
++;
350 header
->line_base
= *(int8_t *)p
++;
351 header
->line_range
= *(uint8_t *)p
++;
352 header
->opcode_base
= *(uint8_t *)p
++;
353 /* header->standard_opcode_lengths = (uint8_t *)p - 1; */
354 p
+= header
->opcode_base
- 1;
356 header
->include_directories
= p
;
358 /* temporary measure for compress-debug-sections */
359 if (p
>= header
->cu_end
) return -1;
361 /* skip include directories */
363 p
= memchr(p
, '\0', header
->cu_end
- p
);
369 header
->filenames
= p
;
371 *pp
= header
->cu_start
;
377 parse_debug_line_cu(int num_traces
, void **traces
, const char **debug_line
,
378 obj_info_t
*obj
, line_info_t
*lines
, int offset
)
380 const char *p
= (const char *)*debug_line
;
381 struct LineNumberProgramHeader header
;
384 unsigned long addr
= 0;
385 unsigned int file
= 1;
386 unsigned int line
= 1;
387 /* unsigned int column = 0; */
389 /* int basic_block = 0; */
390 /* int end_sequence = 0; */
391 /* int prologue_end = 0; */
392 /* int epilogue_begin = 0; */
393 /* unsigned int isa = 0; */
395 if (parse_debug_line_header(&p
, &header
))
397 is_stmt
= header
.default_is_stmt
;
399 #define FILL_LINE() \
401 fill_line(num_traces, traces, addr, file, line, \
402 header.include_directories, \
404 obj, lines, offset); \
405 /*basic_block = prologue_end = epilogue_begin = 0;*/ \
408 while (p
< header
.cu_end
) {
410 unsigned char op
= *p
++;
415 case DW_LNS_advance_pc
:
416 a
= uleb128(&p
) * header
.minimum_instruction_length
;
419 case DW_LNS_advance_line
: {
420 long a
= sleb128(&p
);
424 case DW_LNS_set_file
:
425 file
= (unsigned int)uleb128(&p
);
427 case DW_LNS_set_column
:
428 /*column = (unsigned int)*/(void)uleb128(&p
);
430 case DW_LNS_negate_stmt
:
433 case DW_LNS_set_basic_block
:
434 /*basic_block = 1; */
436 case DW_LNS_const_add_pc
:
437 a
= ((255UL - header
.opcode_base
) / header
.line_range
) *
438 header
.minimum_instruction_length
;
441 case DW_LNS_fixed_advance_pc
:
443 p
+= sizeof(uint16_t);
446 case DW_LNS_set_prologue_end
:
447 /* prologue_end = 1; */
449 case DW_LNS_set_epilogue_begin
:
450 /* epilogue_begin = 1; */
453 /* isa = (unsigned int)*/(void)uleb128(&p
);
459 case DW_LNE_end_sequence
:
460 /* end_sequence = 1; */
466 is_stmt
= header
.default_is_stmt
;
467 /* end_sequence = 0; */
470 case DW_LNE_set_address
:
471 addr
= *(unsigned long *)p
;
472 p
+= sizeof(unsigned long);
474 case DW_LNE_define_file
:
475 kprintf("Unsupported operation in %s\n",
478 case DW_LNE_set_discriminator
:
479 /* TODO:currently ignore */
483 kprintf("Unknown extended opcode: %d in %s\n",
484 op
, binary_filename
);
488 uint8_t adjusted_opcode
= op
- header
.opcode_base
;
489 uint8_t operation_advance
= adjusted_opcode
/ header
.line_range
;
490 /* NOTE: this code doesn't support VLIW */
491 addr
+= operation_advance
* header
.minimum_instruction_length
;
492 line
+= header
.line_base
+ (adjusted_opcode
% header
.line_range
);
497 *debug_line
= (char *)p
;
502 parse_debug_line(int num_traces
, void **traces
,
503 const char *debug_line
, unsigned long size
,
504 obj_info_t
*obj
, line_info_t
*lines
, int offset
)
506 const char *debug_line_end
= debug_line
+ size
;
507 while (debug_line
< debug_line_end
) {
508 if (parse_debug_line_cu(num_traces
, traces
, &debug_line
, obj
, lines
, offset
))
511 if (debug_line
!= debug_line_end
) {
512 kprintf("Unexpected size of .debug_line in %s\n",
518 /* read file and fill lines */
520 fill_lines(int num_traces
, void **traces
, int check_debuglink
,
521 obj_info_t
**objp
, line_info_t
*lines
, int offset
);
524 append_obj(obj_info_t
**objp
)
526 obj_info_t
*newobj
= calloc(1, sizeof(obj_info_t
));
527 if (*objp
) (*objp
)->next
= newobj
;
532 /* Ideally we should check 4 paths to follow gnu_debuglink:
534 * - /usr/lib/debug/.build-id/ab/cdef1234.debug
535 * - /usr/bin/ruby.debug
536 * - /usr/bin/.debug/ruby.debug
537 * - /usr/lib/debug/usr/bin/ruby.debug.
539 * but we handle only two cases for now as the two formats are
540 * used by some linux distributions.
542 * See GDB's info for detail.
543 * https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
546 // check the path pattern of "/usr/lib/debug/usr/bin/ruby.debug"
548 follow_debuglink(const char *debuglink
, int num_traces
, void **traces
,
549 obj_info_t
**objp
, line_info_t
*lines
, int offset
)
551 static const char global_debug_dir
[] = "/usr/lib/debug";
552 const size_t global_debug_dir_len
= sizeof(global_debug_dir
) - 1;
554 obj_info_t
*o1
= *objp
, *o2
;
557 p
= strrchr(binary_filename
, '/');
563 len
= strlen(binary_filename
);
564 if (len
>= PATH_MAX
- global_debug_dir_len
)
565 len
= PATH_MAX
- global_debug_dir_len
- 1;
566 memmove(binary_filename
+ global_debug_dir_len
, binary_filename
, len
);
567 memcpy(binary_filename
, global_debug_dir
, global_debug_dir_len
);
568 len
+= global_debug_dir_len
;
569 strlcpy(binary_filename
+ len
, debuglink
, PATH_MAX
- len
);
573 o2
->base_addr
= o1
->base_addr
;
575 fill_lines(num_traces
, traces
, 0, objp
, lines
, offset
);
578 // check the path pattern of "/usr/lib/debug/.build-id/ab/cdef1234.debug"
580 follow_debuglink_build_id(const char *build_id
, size_t build_id_size
, int num_traces
, void **traces
,
581 obj_info_t
**objp
, line_info_t
*lines
, int offset
)
583 static const char global_debug_dir
[] = "/usr/lib/debug/.build-id/";
584 const size_t global_debug_dir_len
= sizeof(global_debug_dir
) - 1;
586 obj_info_t
*o1
= *objp
, *o2
;
589 if (PATH_MAX
< global_debug_dir_len
+ 1 + build_id_size
* 2 + 6) return;
591 memcpy(binary_filename
, global_debug_dir
, global_debug_dir_len
);
592 p
= binary_filename
+ global_debug_dir_len
;
593 for (i
= 0; i
< build_id_size
; i
++) {
594 static const char tbl
[] = "0123456789abcdef";
595 unsigned char n
= build_id
[i
];
598 if (i
== 0) *p
++ = '/';
604 o2
->base_addr
= o1
->base_addr
;
606 fill_lines(num_traces
, traces
, 0, objp
, lines
, offset
);
612 DW_TAG_compile_unit
= 0x11,
613 DW_TAG_inlined_subroutine
= 0x1d,
614 DW_TAG_subprogram
= 0x2e,
617 /* Attributes encodings */
620 DW_AT_sibling
= 0x01,
621 DW_AT_location
= 0x02,
628 DW_AT_ordering
= 0x09,
630 DW_AT_byte_size
= 0x0b,
632 DW_AT_bit_size
= 0x0d,
635 DW_AT_stmt_list
= 0x10,
637 DW_AT_high_pc
= 0x12,
638 DW_AT_language
= 0x13,
641 DW_AT_discr_value
= 0x16,
642 DW_AT_visibility
= 0x17,
644 DW_AT_string_length
= 0x19,
645 DW_AT_common_reference
= 0x1a,
646 DW_AT_comp_dir
= 0x1b,
647 DW_AT_const_value
= 0x1c,
648 DW_AT_containing_type
= 0x1d,
649 DW_AT_default_value
= 0x1e,
652 DW_AT_is_optional
= 0x21,
653 DW_AT_lower_bound
= 0x22,
656 DW_AT_producer
= 0x25,
658 DW_AT_prototyped
= 0x27,
661 DW_AT_return_addr
= 0x2a,
663 DW_AT_start_scope
= 0x2c,
665 DW_AT_bit_stride
= 0x2e,
666 DW_AT_upper_bound
= 0x2f,
668 DW_AT_abstract_origin
= 0x31,
669 DW_AT_accessibility
= 0x32,
670 DW_AT_address_class
= 0x33,
671 DW_AT_artificial
= 0x34,
672 DW_AT_base_types
= 0x35,
673 DW_AT_calling_convention
= 0x36,
675 DW_AT_data_member_location
= 0x38,
676 DW_AT_decl_column
= 0x39,
677 DW_AT_decl_file
= 0x3a,
678 DW_AT_decl_line
= 0x3b,
679 DW_AT_declaration
= 0x3c,
680 DW_AT_discr_list
= 0x3d,
681 DW_AT_encoding
= 0x3e,
682 DW_AT_external
= 0x3f,
683 DW_AT_frame_base
= 0x40,
685 DW_AT_identifier_case
= 0x42,
687 DW_AT_namelist_item
= 0x44,
688 DW_AT_priority
= 0x45,
689 DW_AT_segment
= 0x46,
690 DW_AT_specification
= 0x47,
691 DW_AT_static_link
= 0x48,
693 DW_AT_use_location
= 0x4a,
694 DW_AT_variable_parameter
= 0x4b,
695 DW_AT_virtuality
= 0x4c,
696 DW_AT_vtable_elem_location
= 0x4d,
697 DW_AT_allocated
= 0x4e,
698 DW_AT_associated
= 0x4f,
699 DW_AT_data_location
= 0x50,
700 DW_AT_byte_stride
= 0x51,
701 DW_AT_entry_pc
= 0x52,
702 DW_AT_use_UTF8
= 0x53,
703 DW_AT_extension
= 0x54,
705 DW_AT_trampoline
= 0x56,
706 DW_AT_call_column
= 0x57,
707 DW_AT_call_file
= 0x58,
708 DW_AT_call_line
= 0x59,
709 DW_AT_description
= 0x5a,
710 DW_AT_binary_scale
= 0x5b,
711 DW_AT_decimal_scale
= 0x5c,
713 DW_AT_decimal_sign
= 0x5e,
714 DW_AT_digit_count
= 0x5f,
715 DW_AT_picture_string
= 0x60,
716 DW_AT_mutable
= 0x61,
717 DW_AT_threads_scaled
= 0x62,
718 DW_AT_explicit
= 0x63,
719 DW_AT_object_pointer
= 0x64,
720 DW_AT_endianity
= 0x65,
721 DW_AT_elemental
= 0x66,
723 DW_AT_recursive
= 0x68,
724 DW_AT_signature
= 0x69,
725 DW_AT_main_subprogram
= 0x6a,
726 DW_AT_data_bit_offset
= 0x6b,
727 DW_AT_const_expr
= 0x6c,
728 DW_AT_enum_class
= 0x6d,
729 DW_AT_linkage_name
= 0x6e,
730 DW_AT_string_length_bit_size
= 0x6f,
731 DW_AT_string_length_byte_size
= 0x70,
733 DW_AT_str_offsets_base
= 0x72,
734 DW_AT_addr_base
= 0x73,
735 DW_AT_rnglists_base
= 0x74,
737 DW_AT_dwo_name
= 0x76,
738 DW_AT_reference
= 0x77,
739 DW_AT_rvalue_reference
= 0x78,
741 DW_AT_call_all_calls
= 0x7a,
742 DW_AT_call_all_source_calls
= 0x7b,
743 DW_AT_call_all_tail_calls
= 0x7c,
744 DW_AT_call_return_pc
= 0x7d,
745 DW_AT_call_value
= 0x7e,
746 DW_AT_call_origin
= 0x7f,
747 DW_AT_call_parameter
= 0x80,
748 DW_AT_call_pc
= 0x81,
749 DW_AT_call_tail_call
= 0x82,
750 DW_AT_call_target
= 0x83,
751 DW_AT_call_target_clobbered
= 0x84,
752 DW_AT_call_data_location
= 0x85,
753 DW_AT_call_data_value
= 0x86,
754 DW_AT_noreturn
= 0x87,
755 DW_AT_alignment
= 0x88,
756 DW_AT_export_symbols
= 0x89,
757 DW_AT_deleted
= 0x8a,
758 DW_AT_defaulted
= 0x8b,
759 DW_AT_loclists_base
= 0x8c,
760 DW_AT_lo_user
= 0x2000,
761 DW_AT_hi_user
= 0x3fff
764 /* Attribute form encodings */
769 DW_FORM_block2
= 0x03,
770 DW_FORM_block4
= 0x04,
771 DW_FORM_data2
= 0x05,
772 DW_FORM_data4
= 0x06,
773 DW_FORM_data8
= 0x07,
774 DW_FORM_string
= 0x08,
775 DW_FORM_block
= 0x09,
776 DW_FORM_block1
= 0x0a,
777 DW_FORM_data1
= 0x0b,
779 DW_FORM_sdata
= 0x0d,
781 DW_FORM_udata
= 0x0f,
782 DW_FORM_ref_addr
= 0x10,
787 DW_FORM_ref_udata
= 0x15,
788 DW_FORM_indirect
= 0x16,
789 DW_FORM_sec_offset
= 0x17,
790 DW_FORM_exprloc
= 0x18,
791 DW_FORM_flag_present
= 0x19,
793 DW_FORM_addrx
= 0x1b,
794 DW_FORM_ref_sup4
= 0x1c,
795 DW_FORM_strp_sup
= 0x1d,
796 DW_FORM_data16
= 0x1e,
797 DW_FORM_line_strp
= 0x1f,
798 DW_FORM_ref_sig8
= 0x20,
799 DW_FORM_implicit_const
= 0x21,
800 DW_FORM_loclistx
= 0x22,
801 DW_FORM_rnglistx
= 0x23,
802 DW_FORM_ref_sup8
= 0x24,
803 DW_FORM_strx1
= 0x25,
804 DW_FORM_strx2
= 0x26,
805 DW_FORM_strx3
= 0x27,
806 DW_FORM_strx4
= 0x28,
807 DW_FORM_addrx1
= 0x29,
808 DW_FORM_addrx2
= 0x2a,
809 DW_FORM_addrx3
= 0x2b,
810 DW_FORM_addrx4
= 0x2c
813 /* Range list entry encodings */
815 DW_RLE_end_of_list
= 0x00,
816 DW_RLE_base_addressx
= 0x01,
817 DW_RLE_startx_endx
= 0x02,
818 DW_RLE_startx_length
= 0x03,
819 DW_RLE_offset_pair
= 0x04,
820 DW_RLE_base_address
= 0x05,
821 DW_RLE_start_end
= 0x06,
822 DW_RLE_start_length
= 0x07
833 # define ABBREV_TABLE_SIZE 256
837 const char *current_cu
;
838 uint64_t current_low_pc
;
839 const char *debug_line_cu_end
;
840 const char *debug_line_files
;
841 const char *debug_line_directories
;
847 int format
; // 4 or 8
848 uint8_t address_size
;
850 const char *abbrev_table
[ABBREV_TABLE_SIZE
];
872 /* TODO: Big Endian */
873 #define MERGE_2INTS(a,b,sz) (((uint64_t)(b)<<sz)|(a))
876 get_uint16(const uint8_t *p
)
878 return (uint16_t)MERGE_2INTS(p
[0],p
[1],8);
882 get_uint32(const uint8_t *p
)
884 return (uint32_t)MERGE_2INTS(get_uint16(p
),get_uint16(p
+2),16);
888 get_uint64(const uint8_t *p
)
890 return MERGE_2INTS(get_uint32(p
),get_uint32(p
+4),32);
894 read_uint8(const char **ptr
)
896 const char *p
= *ptr
;
902 read_uint16(const char **ptr
)
904 const char *p
= *ptr
;
906 return get_uint16((const uint8_t *)p
);
910 read_uint24(const char **ptr
)
912 const char *p
= *ptr
;
914 return ((uint8_t)*p
<< 16) | get_uint16((const uint8_t *)p
+1);
918 read_uint32(const char **ptr
)
920 const char *p
= *ptr
;
922 return get_uint32((const uint8_t *)p
);
926 read_uint64(const char **ptr
)
928 const unsigned char *p
= (const unsigned char *)*ptr
;
929 *ptr
= (char *)(p
+ 8);
930 return get_uint64(p
);
934 read_uintptr(const char **ptr
)
936 const unsigned char *p
= (const unsigned char *)*ptr
;
937 *ptr
= (char *)(p
+ SIZEOF_VOIDP
);
938 #if SIZEOF_VOIDP == 8
939 return get_uint64(p
);
941 return get_uint32(p
);
946 read_uint(DebugInfoReader
*reader
)
948 if (reader
->format
== 4) {
949 return read_uint32(&reader
->p
);
950 } else { /* 64 bit */
951 return read_uint64(&reader
->p
);
956 read_uleb128(DebugInfoReader
*reader
)
958 return uleb128(&reader
->p
);
962 read_sleb128(DebugInfoReader
*reader
)
964 return sleb128(&reader
->p
);
968 debug_info_reader_init(DebugInfoReader
*reader
, obj_info_t
*obj
)
970 reader
->file
= obj
->mapped
;
972 reader
->p
= obj
->debug_info
.ptr
;
973 reader
->pend
= obj
->debug_info
.ptr
+ obj
->debug_info
.size
;
974 reader
->debug_line_cu_end
= obj
->debug_line
.ptr
;
975 reader
->current_low_pc
= 0;
979 di_skip_die_attributes(const char **p
)
982 uint64_t at
= uleb128(p
);
983 uint64_t form
= uleb128(p
);
984 if (!at
&& !form
) break;
988 case DW_FORM_implicit_const
:
996 di_read_debug_abbrev_cu(DebugInfoReader
*reader
)
999 const char *p
= reader
->q0
;
1001 uint64_t abbrev_number
= uleb128(&p
);
1002 if (abbrev_number
<= prev
) break;
1003 if (abbrev_number
< ABBREV_TABLE_SIZE
) {
1004 reader
->abbrev_table
[abbrev_number
] = p
;
1006 prev
= abbrev_number
;
1007 uleb128(&p
); /* tag */
1008 p
++; /* has_children */
1009 di_skip_die_attributes(&p
);
1014 di_read_debug_line_cu(DebugInfoReader
*reader
)
1017 struct LineNumberProgramHeader header
;
1019 p
= (const char *)reader
->debug_line_cu_end
;
1020 if (parse_debug_line_header(&p
, &header
))
1023 reader
->debug_line_cu_end
= (char *)header
.cu_end
;
1024 reader
->debug_line_directories
= (char *)header
.include_directories
;
1025 reader
->debug_line_files
= (char *)header
.filenames
;
1031 set_uint_value(DebugInfoValue
*v
, uint64_t n
)
1038 set_int_value(DebugInfoValue
*v
, int64_t n
)
1045 set_cstr_value(DebugInfoValue
*v
, const char *s
)
1053 set_cstrp_value(DebugInfoValue
*v
, const char *s
, uint64_t off
)
1061 set_data_value(DebugInfoValue
*v
, const char *s
)
1068 get_cstr_value(DebugInfoValue
*v
)
1071 return v
->as
.ptr
+ v
->off
;
1078 debug_info_reader_read_value(DebugInfoReader
*reader
, uint64_t form
, DebugInfoValue
*v
)
1082 if (reader
->address_size
== 4) {
1083 set_uint_value(v
, read_uint32(&reader
->p
));
1084 } else if (reader
->address_size
== 8) {
1085 set_uint_value(v
, read_uint64(&reader
->p
));
1087 fprintf(stderr
,"unknown address_size:%d", reader
->address_size
);
1091 case DW_FORM_block2
:
1092 v
->size
= read_uint16(&reader
->p
);
1093 set_data_value(v
, reader
->p
);
1094 reader
->p
+= v
->size
;
1096 case DW_FORM_block4
:
1097 v
->size
= read_uint32(&reader
->p
);
1098 set_data_value(v
, reader
->p
);
1099 reader
->p
+= v
->size
;
1102 set_uint_value(v
, read_uint16(&reader
->p
));
1105 set_uint_value(v
, read_uint32(&reader
->p
));
1108 set_uint_value(v
, read_uint64(&reader
->p
));
1110 case DW_FORM_string
:
1111 v
->size
= strlen(reader
->p
);
1112 set_cstr_value(v
, reader
->p
);
1113 reader
->p
+= v
->size
+ 1;
1116 v
->size
= uleb128(&reader
->p
);
1117 set_data_value(v
, reader
->p
);
1118 reader
->p
+= v
->size
;
1120 case DW_FORM_block1
:
1121 v
->size
= read_uint8(&reader
->p
);
1122 set_data_value(v
, reader
->p
);
1123 reader
->p
+= v
->size
;
1126 set_uint_value(v
, read_uint8(&reader
->p
));
1129 set_uint_value(v
, read_uint8(&reader
->p
));
1132 set_int_value(v
, read_sleb128(reader
));
1135 set_cstrp_value(v
, reader
->obj
->debug_str
.ptr
, read_uint(reader
));
1138 set_uint_value(v
, read_uleb128(reader
));
1140 case DW_FORM_ref_addr
:
1141 if (reader
->format
== 4) {
1142 set_uint_value(v
, read_uint32(&reader
->p
));
1143 } else if (reader
->format
== 8) {
1144 set_uint_value(v
, read_uint64(&reader
->p
));
1146 fprintf(stderr
,"unknown format:%d", reader
->format
);
1151 set_uint_value(v
, read_uint8(&reader
->p
));
1154 set_uint_value(v
, read_uint16(&reader
->p
));
1157 set_uint_value(v
, read_uint32(&reader
->p
));
1160 set_uint_value(v
, read_uint64(&reader
->p
));
1162 case DW_FORM_ref_udata
:
1163 set_uint_value(v
, uleb128(&reader
->p
));
1165 case DW_FORM_indirect
:
1166 /* TODO: read the referred value */
1167 set_uint_value(v
, uleb128(&reader
->p
));
1169 case DW_FORM_sec_offset
:
1170 set_uint_value(v
, read_uint(reader
)); /* offset */
1171 /* addrptr: debug_addr */
1172 /* lineptr: debug_line */
1173 /* loclist: debug_loclists */
1174 /* loclistptr: debug_loclists */
1175 /* macptr: debug_macro */
1176 /* rnglist: debug_rnglists */
1177 /* rnglistptr: debug_rnglists */
1178 /* stroffsetsptr: debug_str_offsets */
1180 case DW_FORM_exprloc
:
1181 v
->size
= (size_t)read_uleb128(reader
);
1182 set_data_value(v
, reader
->p
);
1183 reader
->p
+= v
->size
;
1185 case DW_FORM_flag_present
:
1186 set_uint_value(v
, 1);
1189 set_uint_value(v
, uleb128(&reader
->p
));
1192 /* TODO: read .debug_addr */
1193 set_uint_value(v
, uleb128(&reader
->p
));
1195 case DW_FORM_ref_sup4
:
1196 set_uint_value(v
, read_uint32(&reader
->p
));
1198 case DW_FORM_strp_sup
:
1199 set_uint_value(v
, read_uint(reader
));
1200 /* *p = reader->sup_file + reader->sup_str->sh_offset + ret; */
1202 case DW_FORM_data16
:
1204 set_data_value(v
, reader
->p
);
1205 reader
->p
+= v
->size
;
1207 case DW_FORM_line_strp
:
1208 set_uint_value(v
, read_uint(reader
));
1209 /* *p = reader->file + reader->line->sh_offset + ret; */
1211 case DW_FORM_ref_sig8
:
1212 set_uint_value(v
, read_uint64(&reader
->p
));
1214 case DW_FORM_implicit_const
:
1215 set_int_value(v
, sleb128(&reader
->q
));
1217 case DW_FORM_loclistx
:
1218 set_uint_value(v
, read_uleb128(reader
));
1220 case DW_FORM_rnglistx
:
1221 set_uint_value(v
, read_uleb128(reader
));
1223 case DW_FORM_ref_sup8
:
1224 set_uint_value(v
, read_uint64(&reader
->p
));
1227 set_uint_value(v
, read_uint8(&reader
->p
));
1230 set_uint_value(v
, read_uint16(&reader
->p
));
1233 set_uint_value(v
, read_uint24(&reader
->p
));
1236 set_uint_value(v
, read_uint32(&reader
->p
));
1238 case DW_FORM_addrx1
:
1239 set_uint_value(v
, read_uint8(&reader
->p
));
1241 case DW_FORM_addrx2
:
1242 set_uint_value(v
, read_uint16(&reader
->p
));
1244 case DW_FORM_addrx3
:
1245 set_uint_value(v
, read_uint24(&reader
->p
));
1247 case DW_FORM_addrx4
:
1248 set_uint_value(v
, read_uint32(&reader
->p
));
1257 fprintf(stderr
, "%d: unsupported form: %#"PRIx64
"\n", __LINE__
, form
);
1261 /* find abbrev in current compilation unit */
1263 di_find_abbrev(DebugInfoReader
*reader
, uint64_t abbrev_number
)
1266 if (abbrev_number
< ABBREV_TABLE_SIZE
) {
1267 return reader
->abbrev_table
[abbrev_number
];
1269 p
= reader
->abbrev_table
[ABBREV_TABLE_SIZE
-1];
1270 /* skip 255th record */
1271 uleb128(&p
); /* tag */
1272 p
++; /* has_children */
1273 di_skip_die_attributes(&p
);
1274 for (uint64_t n
= uleb128(&p
); abbrev_number
!= n
; n
= uleb128(&p
)) {
1276 fprintf(stderr
,"%d: Abbrev Number %"PRId64
" not found\n",__LINE__
, abbrev_number
);
1279 uleb128(&p
); /* tag */
1280 p
++; /* has_children */
1281 di_skip_die_attributes(&p
);
1288 hexdump0(const unsigned char *p
, size_t n
)
1291 fprintf(stderr
, " 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
1292 for (i
=0; i
< n
; i
++){
1295 fprintf(stderr
, "%02zd: %02X ", i
/16, p
[i
]);
1298 fprintf(stderr
, "%02X\n", p
[i
]);
1301 fprintf(stderr
, "%02X ", p
[i
]);
1305 if ((i
& 15) != 15) {
1306 fprintf(stderr
, "\n");
1309 #define hexdump(p,n) hexdump0((const unsigned char *)p, n)
1312 div_inspect(DebugInfoValue
*v
)
1316 fprintf(stderr
,"%d: type:%d size:%zx v:%"PRIx64
"\n",__LINE__
,v
->type
,v
->size
,v
->as
.uint64
);
1319 fprintf(stderr
,"%d: type:%d size:%zx v:%"PRId64
"\n",__LINE__
,v
->type
,v
->size
,(int64_t)v
->as
.uint64
);
1322 fprintf(stderr
,"%d: type:%d size:%zx v:'%s'\n",__LINE__
,v
->type
,v
->size
,v
->as
.ptr
);
1325 fprintf(stderr
,"%d: type:%d size:%zx v:\n",__LINE__
,v
->type
,v
->size
);
1326 hexdump(v
->as
.ptr
, 16);
1333 di_read_die(DebugInfoReader
*reader
, DIE
*die
)
1335 uint64_t abbrev_number
= uleb128(&reader
->p
);
1336 if (abbrev_number
== 0) {
1341 reader
->q
= di_find_abbrev(reader
, abbrev_number
);
1343 die
->pos
= reader
->p
- reader
->obj
->debug_info
.ptr
- 1;
1344 die
->tag
= (int)uleb128(&reader
->q
); /* tag */
1345 die
->has_children
= *reader
->q
++; /* has_children */
1346 if (die
->has_children
) {
1352 static DebugInfoValue
*
1353 di_read_record(DebugInfoReader
*reader
, DebugInfoValue
*vp
)
1355 uint64_t at
= uleb128(&reader
->q
);
1356 uint64_t form
= uleb128(&reader
->q
);
1357 if (!at
|| !form
) return NULL
;
1360 debug_info_reader_read_value(reader
, form
, vp
);
1365 di_skip_records(DebugInfoReader
*reader
)
1368 DebugInfoValue v
= {{}};
1369 uint64_t at
= uleb128(&reader
->q
);
1370 uint64_t form
= uleb128(&reader
->q
);
1371 if (!at
|| !form
) return;
1372 debug_info_reader_read_value(reader
, form
, &v
);
1386 ranges_set(ranges_t
*ptr
, DebugInfoValue
*v
)
1390 ptr
->low_pc
= v
->as
.uint64
;
1391 ptr
->low_pc_set
= true;
1394 if (v
->form
== DW_FORM_addr
) {
1395 ptr
->high_pc
= v
->as
.uint64
;
1398 ptr
->high_pc
= ptr
->low_pc
+ v
->as
.uint64
;
1400 ptr
->high_pc_set
= true;
1403 ptr
->ranges
= v
->as
.uint64
;
1404 ptr
->ranges_set
= true;
1410 read_dw_form_addr(DebugInfoReader
*reader
, const char **ptr
)
1412 const char *p
= *ptr
;
1413 *ptr
= p
+ reader
->address_size
;
1414 if (reader
->address_size
== 4) {
1415 return read_uint32(&p
);
1416 } else if (reader
->address_size
== 8) {
1417 return read_uint64(&p
);
1419 fprintf(stderr
,"unknown address_size:%d", reader
->address_size
);
1425 ranges_include(DebugInfoReader
*reader
, ranges_t
*ptr
, uint64_t addr
)
1427 if (ptr
->high_pc_set
) {
1428 if (ptr
->ranges_set
|| !ptr
->low_pc_set
) {
1431 if (ptr
->low_pc
<= addr
&& addr
<= ptr
->high_pc
) {
1432 return (uintptr_t)ptr
->low_pc
;
1435 else if (ptr
->ranges_set
) {
1436 /* TODO: support base address selection entry */
1438 uint64_t base
= ptr
->low_pc_set
? ptr
->low_pc
: reader
->current_low_pc
;
1439 bool base_valid
= true;
1440 if (reader
->obj
->debug_rnglists
.ptr
) {
1441 p
= reader
->obj
->debug_rnglists
.ptr
+ ptr
->ranges
;
1443 uint8_t rle
= read_uint8(&p
);
1444 uintptr_t from
= 0, to
= 0;
1445 if (rle
== DW_RLE_end_of_list
) break;
1447 case DW_RLE_base_addressx
:
1449 base_valid
= false; /* not supported yet */
1451 case DW_RLE_startx_endx
:
1455 case DW_RLE_startx_length
:
1459 case DW_RLE_offset_pair
:
1460 if (!base_valid
) break;
1461 from
= (uintptr_t)base
+ uleb128(&p
);
1462 to
= (uintptr_t)base
+ uleb128(&p
);
1464 case DW_RLE_base_address
:
1465 base
= read_dw_form_addr(reader
, &p
);
1468 case DW_RLE_start_end
:
1469 from
= (uintptr_t)read_dw_form_addr(reader
, &p
);
1470 to
= (uintptr_t)read_dw_form_addr(reader
, &p
);
1472 case DW_RLE_start_length
:
1473 from
= (uintptr_t)read_dw_form_addr(reader
, &p
);
1474 to
= from
+ uleb128(&p
);
1477 if (from
<= addr
&& addr
< to
) {
1483 p
= reader
->obj
->debug_ranges
.ptr
+ ptr
->ranges
;
1485 uintptr_t from
= read_uintptr(&p
);
1486 uintptr_t to
= read_uintptr(&p
);
1487 if (!from
&& !to
) break;
1488 if (from
== UINTPTR_MAX
) {
1489 /* base address selection entry */
1492 else if (base
+ from
<= addr
&& addr
< base
+ to
) {
1493 return (uintptr_t)base
+ from
;
1497 else if (ptr
->low_pc_set
) {
1498 if (ptr
->low_pc
== addr
) {
1499 return (uintptr_t)ptr
->low_pc
;
1507 ranges_inspect(DebugInfoReader
*reader
, ranges_t
*ptr
)
1509 if (ptr
->high_pc_set
) {
1510 if (ptr
->ranges_set
|| !ptr
->low_pc_set
) {
1511 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
);
1514 fprintf(stderr
,"low_pc:%"PRIx64
" high_pc:%"PRIx64
"\n",ptr
->low_pc
,ptr
->high_pc
);
1516 else if (ptr
->ranges_set
) {
1517 char *p
= reader
->obj
->debug_ranges
.ptr
+ ptr
->ranges
;
1518 fprintf(stderr
,"low_pc:%"PRIx64
" ranges:%"PRIx64
" %lx ",ptr
->low_pc
,ptr
->ranges
, p
-reader
->obj
->mapped
);
1520 uintptr_t from
= read_uintptr(&p
);
1521 uintptr_t to
= read_uintptr(&p
);
1522 if (!from
&& !to
) break;
1523 fprintf(stderr
,"%"PRIx64
"-%"PRIx64
" ",ptr
->low_pc
+from
,ptr
->low_pc
+to
);
1525 fprintf(stderr
,"\n");
1527 else if (ptr
->low_pc_set
) {
1528 fprintf(stderr
,"low_pc:%"PRIx64
"\n",ptr
->low_pc
);
1531 fprintf(stderr
,"empty\n");
1537 di_read_cu(DebugInfoReader
*reader
)
1539 uint64_t unit_length
;
1541 uint64_t debug_abbrev_offset
;
1543 reader
->current_cu
= reader
->p
;
1544 unit_length
= read_uint32(&reader
->p
);
1545 if (unit_length
== 0xffffffff) {
1546 unit_length
= read_uint64(&reader
->p
);
1549 reader
->cu_end
= reader
->p
+ unit_length
;
1550 version
= read_uint16(&reader
->p
);
1554 else if (version
== 5) {
1555 /* unit_type = */ read_uint8(&reader
->p
);
1556 reader
->address_size
= read_uint8(&reader
->p
);
1557 debug_abbrev_offset
= read_uint(reader
);
1560 debug_abbrev_offset
= read_uint(reader
);
1561 reader
->address_size
= read_uint8(&reader
->p
);
1563 reader
->q0
= reader
->obj
->debug_abbrev
.ptr
+ debug_abbrev_offset
;
1566 di_read_debug_abbrev_cu(reader
);
1567 if (di_read_debug_line_cu(reader
)) return -1;
1569 #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER_BUILD_DATE)
1570 /* Though DWARF specifies "the applicable base address defaults to the base
1571 address of the compilation unit", but GCC seems to use zero as default */
1576 if (!di_read_die(reader
, &die
)) continue;
1578 if (die
.tag
!= DW_TAG_compile_unit
) {
1579 di_skip_records(reader
);
1583 /* enumerate abbrev */
1585 DebugInfoValue v
= {{}};
1586 if (!di_read_record(reader
, &v
)) break;
1589 reader
->current_low_pc
= v
.as
.uint64
;
1599 read_abstract_origin(DebugInfoReader
*reader
, uint64_t form
, uint64_t abstract_origin
, line_info_t
*line
)
1601 const char *p
= reader
->p
;
1602 const char *q
= reader
->q
;
1603 int level
= reader
->level
;
1611 case DW_FORM_ref_udata
:
1612 reader
->p
= reader
->current_cu
+ abstract_origin
;
1614 case DW_FORM_ref_addr
:
1615 goto finish
; /* not supported yet */
1616 case DW_FORM_ref_sig8
:
1617 goto finish
; /* not supported yet */
1618 case DW_FORM_ref_sup4
:
1619 case DW_FORM_ref_sup8
:
1620 goto finish
; /* not supported yet */
1624 if (!di_read_die(reader
, &die
)) goto finish
;
1626 /* enumerate abbrev */
1628 DebugInfoValue v
= {{}};
1629 if (!di_read_record(reader
, &v
)) break;
1632 line
->sname
= get_cstr_value(&v
);
1640 reader
->level
= level
;
1644 debug_info_read(DebugInfoReader
*reader
, int num_traces
, void **traces
,
1645 line_info_t
*lines
, int offset
) {
1646 while (reader
->p
< reader
->cu_end
) {
1648 ranges_t ranges
= {};
1649 line_info_t line
= {};
1651 if (!di_read_die(reader
, &die
)) continue;
1652 /* fprintf(stderr,"%d:%tx: <%d>\n",__LINE__,die.pos,reader->level,die.tag); */
1654 if (die
.tag
!= DW_TAG_subprogram
&& die
.tag
!= DW_TAG_inlined_subroutine
) {
1656 di_skip_records(reader
);
1660 /* enumerate abbrev */
1662 DebugInfoValue v
= {{}};
1663 /* ptrdiff_t pos = reader->p - reader->p0; */
1664 if (!di_read_record(reader
, &v
)) break;
1665 /* fprintf(stderr,"\n%d:%tx: AT:%lx FORM:%lx\n",__LINE__,pos,v.at,v.form); */
1666 /* div_inspect(&v); */
1669 line
.sname
= get_cstr_value(&v
);
1671 case DW_AT_call_file
:
1672 fill_filename((int)v
.as
.uint64
, reader
->debug_line_directories
, reader
->debug_line_files
, &line
, reader
->obj
);
1674 case DW_AT_call_line
:
1675 line
.line
= (int)v
.as
.uint64
;
1680 ranges_set(&ranges
, &v
);
1682 case DW_AT_declaration
:
1686 break; /* goto skip_die; */
1687 case DW_AT_abstract_origin
:
1688 read_abstract_origin(reader
, v
.form
, v
.as
.uint64
, &line
);
1689 break; /* goto skip_die; */
1692 /* ranges_inspect(reader, &ranges); */
1693 /* fprintf(stderr,"%d:%tx: %x ",__LINE__,diepos,die.tag); */
1694 for (int i
=offset
; i
< num_traces
; i
++) {
1695 uintptr_t addr
= (uintptr_t)traces
[i
];
1696 uintptr_t offset
= addr
- reader
->obj
->base_addr
+ reader
->obj
->vmaddr
;
1697 uintptr_t saddr
= ranges_include(reader
, &ranges
, offset
);
1699 /* 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); */
1700 if (lines
[i
].sname
) {
1701 line_info_t
*lp
= malloc(sizeof(line_info_t
));
1702 memcpy(lp
, &lines
[i
], sizeof(line_info_t
));
1704 lp
->dirname
= line
.dirname
;
1705 lp
->filename
= line
.filename
;
1706 lp
->line
= line
.line
;
1709 lines
[i
].path
= reader
->obj
->path
;
1710 lines
[i
].base_addr
= line
.base_addr
;
1711 lines
[i
].sname
= line
.sname
;
1712 lines
[i
].saddr
= saddr
+ reader
->obj
->base_addr
- reader
->obj
->vmaddr
;
1719 static unsigned long
1720 uncompress_debug_section(ElfW(Shdr
) *shdr
, char *file
, char **ptr
)
1723 #ifdef SUPPORT_COMPRESSED_DEBUG_LINE
1724 ElfW(Chdr
) *chdr
= (ElfW(Chdr
) *)(file
+ shdr
->sh_offset
);
1725 unsigned long destsize
= chdr
->ch_size
;
1728 if (chdr
->ch_type
!= ELFCOMPRESS_ZLIB
) {
1729 /* unsupported compression type */
1733 *ptr
= malloc(destsize
);
1734 if (!*ptr
) return 0;
1735 ret
= uncompress((Bytef
*)*ptr
, &destsize
,
1736 (const Bytef
*)chdr
+ sizeof(ElfW(Chdr
)),
1737 shdr
->sh_size
- sizeof(ElfW(Chdr
)));
1738 if (ret
!= Z_OK
) goto fail
;
1748 /* read file and fill lines */
1750 fill_lines(int num_traces
, void **traces
, int check_debuglink
,
1751 obj_info_t
**objp
, line_info_t
*lines
, int offset
)
1756 ElfW(Shdr
) *shdr
, *shstr_shdr
;
1757 ElfW(Shdr
) *gnu_debuglink_shdr
= NULL
;
1758 ElfW(Shdr
) *note_gnu_build_id
= NULL
;
1762 ElfW(Shdr
) *symtab_shdr
= NULL
, *strtab_shdr
= NULL
;
1763 ElfW(Shdr
) *dynsym_shdr
= NULL
, *dynstr_shdr
= NULL
;
1764 obj_info_t
*obj
= *objp
;
1765 uintptr_t dladdr_fbase
= 0;
1767 fd
= open(binary_filename
, O_RDONLY
);
1771 filesize
= lseek(fd
, 0, SEEK_END
);
1775 kprintf("lseek: %s\n", strerror(e
));
1778 #if SIZEOF_OFF_T > SIZEOF_SIZE_T
1779 if (filesize
> (off_t
)SIZE_MAX
) {
1781 kprintf("Too large file %s\n", binary_filename
);
1785 lseek(fd
, 0, SEEK_SET
);
1786 /* async-signal unsafe */
1787 file
= (char *)mmap(NULL
, (size_t)filesize
, PROT_READ
, MAP_SHARED
, fd
, 0);
1788 if (file
== MAP_FAILED
) {
1791 kprintf("mmap: %s\n", strerror(e
));
1796 ehdr
= (ElfW(Ehdr
) *)file
;
1797 if (memcmp(ehdr
->e_ident
, "\177ELF", 4) != 0) {
1799 * Huh? Maybe filename was overridden by setproctitle() and
1800 * it match non-elf file.
1805 obj
->mapped_size
= (size_t)filesize
;
1807 shdr
= (ElfW(Shdr
) *)(file
+ ehdr
->e_shoff
);
1809 shstr_shdr
= shdr
+ ehdr
->e_shstrndx
;
1810 shstr
= file
+ shstr_shdr
->sh_offset
;
1812 for (i
= 0; i
< ehdr
->e_shnum
; i
++) {
1813 char *section_name
= shstr
+ shdr
[i
].sh_name
;
1814 switch (shdr
[i
].sh_type
) {
1816 if (!strcmp(section_name
, ".strtab")) {
1817 strtab_shdr
= shdr
+ i
;
1819 else if (!strcmp(section_name
, ".dynstr")) {
1820 dynstr_shdr
= shdr
+ i
;
1824 /* if (!strcmp(section_name, ".symtab")) */
1825 symtab_shdr
= shdr
+ i
;
1828 /* if (!strcmp(section_name, ".dynsym")) */
1829 dynsym_shdr
= shdr
+ i
;
1832 if (!strcmp(section_name
, ".note.gnu.build-id")) {
1833 note_gnu_build_id
= shdr
+ i
;
1837 if (!strcmp(section_name
, ".gnu_debuglink")) {
1838 gnu_debuglink_shdr
= shdr
+ i
;
1841 const char *debug_section_names
[] = {
1850 for (j
=0; j
< DWARF_SECTION_COUNT
; j
++) {
1851 struct dwarf_section
*s
= obj_dwarf_section_at(obj
, j
);
1853 if (strcmp(section_name
, debug_section_names
[j
]) != 0)
1856 s
->ptr
= file
+ shdr
[i
].sh_offset
;
1857 s
->size
= shdr
[i
].sh_size
;
1858 s
->flags
= shdr
[i
].sh_flags
;
1859 if (s
->flags
& SHF_COMPRESSED
) {
1860 s
->size
= uncompress_debug_section(&shdr
[i
], file
, &s
->ptr
);
1861 if (!s
->size
) goto fail
;
1871 /* main executable */
1873 if (dynsym_shdr
&& dynstr_shdr
) {
1874 char *strtab
= file
+ dynstr_shdr
->sh_offset
;
1875 ElfW(Sym
) *symtab
= (ElfW(Sym
) *)(file
+ dynsym_shdr
->sh_offset
);
1876 int symtab_count
= (int)(dynsym_shdr
->sh_size
/ sizeof(ElfW(Sym
)));
1877 void *handle
= dlopen(NULL
, RTLD_NOW
|RTLD_LOCAL
);
1879 for (j
= 0; j
< symtab_count
; j
++) {
1880 ElfW(Sym
) *sym
= &symtab
[j
];
1883 if (ELF_ST_TYPE(sym
->st_info
) != STT_FUNC
|| sym
->st_size
== 0) continue;
1884 s
= dlsym(handle
, strtab
+ sym
->st_name
);
1885 if (s
&& dladdr(s
, &info
)) {
1886 obj
->base_addr
= dladdr_fbase
;
1887 dladdr_fbase
= (uintptr_t)info
.dli_fbase
;
1893 if (ehdr
->e_type
== ET_EXEC
) {
1897 /* PIE (position-independent executable) */
1898 obj
->base_addr
= dladdr_fbase
;
1903 if (obj
->debug_info
.ptr
&& obj
->debug_abbrev
.ptr
) {
1904 DebugInfoReader reader
;
1905 debug_info_reader_init(&reader
, obj
);
1907 while (reader
.p
< reader
.pend
) {
1908 /* fprintf(stderr, "%d:%tx: CU[%d]\n", __LINE__, reader.p - reader.obj->debug_info.ptr, i++); */
1909 if (di_read_cu(&reader
)) goto use_symtab
;
1910 debug_info_read(&reader
, num_traces
, traces
, lines
, offset
);
1914 /* This file doesn't have dwarf, use symtab or dynsym */
1917 /* This file doesn't have symtab, use dynsym instead */
1918 symtab_shdr
= dynsym_shdr
;
1919 strtab_shdr
= dynstr_shdr
;
1922 if (symtab_shdr
&& strtab_shdr
) {
1923 char *strtab
= file
+ strtab_shdr
->sh_offset
;
1924 ElfW(Sym
) *symtab
= (ElfW(Sym
) *)(file
+ symtab_shdr
->sh_offset
);
1925 int symtab_count
= (int)(symtab_shdr
->sh_size
/ sizeof(ElfW(Sym
)));
1926 for (j
= 0; j
< symtab_count
; j
++) {
1927 ElfW(Sym
) *sym
= &symtab
[j
];
1928 uintptr_t saddr
= (uintptr_t)sym
->st_value
+ obj
->base_addr
;
1929 if (ELF_ST_TYPE(sym
->st_info
) != STT_FUNC
) continue;
1930 for (i
= offset
; i
< num_traces
; i
++) {
1931 uintptr_t d
= (uintptr_t)traces
[i
] - saddr
;
1932 if (lines
[i
].line
> 0 || d
> (uintptr_t)sym
->st_size
)
1934 /* fill symbol name and addr from .symtab */
1935 if (!lines
[i
].sname
) lines
[i
].sname
= strtab
+ sym
->st_name
;
1936 lines
[i
].saddr
= saddr
;
1937 lines
[i
].path
= obj
->path
;
1938 lines
[i
].base_addr
= obj
->base_addr
;
1944 if (!obj
->debug_line
.ptr
) {
1945 /* This file doesn't have .debug_line section,
1946 let's check .gnu_debuglink section instead. */
1947 if (gnu_debuglink_shdr
&& check_debuglink
) {
1948 follow_debuglink(file
+ gnu_debuglink_shdr
->sh_offset
,
1950 objp
, lines
, offset
);
1952 if (note_gnu_build_id
&& check_debuglink
) {
1953 ElfW(Nhdr
) *nhdr
= (ElfW(Nhdr
)*) (file
+ note_gnu_build_id
->sh_offset
);
1954 const char *build_id
= (char *)(nhdr
+ 1) + nhdr
->n_namesz
;
1955 follow_debuglink_build_id(build_id
, nhdr
->n_descsz
,
1957 objp
, lines
, offset
);
1962 if (parse_debug_line(num_traces
, traces
,
1963 obj
->debug_line
.ptr
,
1964 obj
->debug_line
.size
,
1965 obj
, lines
, offset
) == -1)
1969 return dladdr_fbase
;
1971 return (uintptr_t)-1;
1974 /* read file and fill lines */
1976 fill_lines(int num_traces
, void **traces
, int check_debuglink
,
1977 obj_info_t
**objp
, line_info_t
*lines
, int offset
)
1980 # define LP(x) x##_64
1986 char *file
, *p
= NULL
;
1987 obj_info_t
*obj
= *objp
;
1988 struct LP(mach_header
) *header
;
1989 uintptr_t dladdr_fbase
= 0;
1992 char *s
= binary_filename
;
1993 char *base
= strrchr(binary_filename
, '/')+1;
1994 size_t max
= PATH_MAX
;
1995 size_t size
= strlen(binary_filename
);
1996 size_t basesize
= size
- (base
- binary_filename
);
2000 size
= strlcpy(s
, ".dSYM/Contents/Resources/DWARF/", max
);
2001 if (size
== 0) goto fail
;
2004 if (max
<= basesize
) goto fail
;
2005 memcpy(s
, base
, basesize
);
2008 fd
= open(binary_filename
, O_RDONLY
);
2010 *p
= 0; /* binary_filename becomes original file name */
2011 fd
= open(binary_filename
, O_RDONLY
);
2018 filesize
= lseek(fd
, 0, SEEK_END
);
2022 kprintf("lseek: %s\n", strerror(e
));
2025 #if SIZEOF_OFF_T > SIZEOF_SIZE_T
2026 if (filesize
> (off_t
)SIZE_MAX
) {
2028 kprintf("Too large file %s\n", binary_filename
);
2032 lseek(fd
, 0, SEEK_SET
);
2033 /* async-signal unsafe */
2034 file
= (char *)mmap(NULL
, (size_t)filesize
, PROT_READ
, MAP_SHARED
, fd
, 0);
2035 if (file
== MAP_FAILED
) {
2038 kprintf("mmap: %s\n", strerror(e
));
2044 obj
->mapped_size
= (size_t)filesize
;
2046 header
= (struct LP(mach_header
) *)file
;
2047 if (header
->magic
== LP(MH_MAGIC
)) {
2048 /* non universal binary */
2051 else if (header
->magic
== FAT_CIGAM
) {
2052 struct LP(mach_header
) *mhp
= _NSGetMachExecuteHeader();
2053 struct fat_header
*fat
= (struct fat_header
*)file
;
2054 char *q
= file
+ sizeof(*fat
);
2055 uint32_t nfat_arch
= __builtin_bswap32(fat
->nfat_arch
);
2056 /* fprintf(stderr,"%d: fat:%s %d\n",__LINE__, binary_filename,nfat_arch); */
2057 for (uint32_t i
= 0; i
< nfat_arch
; i
++) {
2058 struct fat_arch
*arch
= (struct fat_arch
*)q
;
2059 cpu_type_t cputype
= __builtin_bswap32(arch
->cputype
);
2060 cpu_subtype_t cpusubtype
= __builtin_bswap32(arch
->cpusubtype
);
2061 uint32_t offset
= __builtin_bswap32(arch
->offset
);
2062 /* fprintf(stderr,"%d: fat %d %x/%x %x/%x\n",__LINE__, i, mhp->cputype,mhp->cpusubtype, cputype,cpusubtype); */
2063 if (mhp
->cputype
== cputype
&&
2064 (cpu_subtype_t
)(mhp
->cpusubtype
& ~CPU_SUBTYPE_MASK
) == cpusubtype
) {
2067 header
= (struct LP(mach_header
) *)p
;
2068 if (header
->magic
== LP(MH_MAGIC
)) {
2069 goto found_mach_header
;
2075 kprintf("'%s' is not a Mach-O universal binary file!\n",binary_filename
);
2080 kprintf("'%s' is not a "
2086 "-bit Mach-O file!\n",binary_filename
);
2091 p
+= sizeof(*header
);
2093 for (uint32_t i
= 0; i
< (uint32_t)header
->ncmds
; i
++) {
2094 struct load_command
*lcmd
= (struct load_command
*)p
;
2095 switch (lcmd
->cmd
) {
2096 case LP(LC_SEGMENT
):
2098 static const char *debug_section_names
[] = {
2106 struct LP(segment_command
) *scmd
= (struct LP(segment_command
) *)lcmd
;
2107 if (strcmp(scmd
->segname
, "__TEXT") == 0) {
2108 obj
->vmaddr
= scmd
->vmaddr
;
2110 else if (strcmp(scmd
->segname
, "__DWARF") == 0) {
2111 p
+= sizeof(struct LP(segment_command
));
2112 for (uint64_t i
= 0; i
< scmd
->nsects
; i
++) {
2113 struct LP(section
) *sect
= (struct LP(section
) *)p
;
2114 p
+= sizeof(struct LP(section
));
2115 for (int j
=0; j
< DWARF_SECTION_COUNT
; j
++) {
2116 struct dwarf_section
*s
= obj_dwarf_section_at(obj
, j
);
2118 if (strcmp(sect
->sectname
, debug_section_names
[j
]) != 0)
2121 s
->ptr
= file
+ sect
->offset
;
2122 s
->size
= sect
->size
;
2123 s
->flags
= sect
->flags
;
2124 if (s
->flags
& SHF_COMPRESSED
) {
2136 struct symtab_command
*cmd
= (struct symtab_command
*)lcmd
;
2137 struct LP(nlist
) *nl
= (struct LP(nlist
) *)(file
+ cmd
->symoff
);
2138 char *strtab
= file
+ cmd
->stroff
, *sname
= 0;
2140 uintptr_t saddr
= 0;
2141 /* kprintf("[%2d]: %x/symtab %p\n", i, cmd->cmd, (void *)p); */
2142 for (j
= 0; j
< cmd
->nsyms
; j
++) {
2143 uintptr_t symsize
, d
;
2144 struct LP(nlist
) *e
= &nl
[j
];
2145 /* 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); */
2146 if (e
->n_type
!= N_FUN
) continue;
2148 saddr
= (uintptr_t)e
->n_value
+ obj
->base_addr
- obj
->vmaddr
;
2149 sname
= strtab
+ e
->n_un
.n_strx
;
2150 /* 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); */
2153 for (int k
= offset
; k
< num_traces
; k
++) {
2154 d
= (uintptr_t)traces
[k
] - saddr
;
2155 symsize
= e
->n_value
;
2156 /* kprintf("%lx %lx %lx\n",saddr,symsize,traces[k]); */
2157 if (lines
[k
].line
> 0 || d
> (uintptr_t)symsize
)
2159 /* fill symbol name and addr from .symtab */
2160 if (!lines
[k
].sname
) lines
[k
].sname
= sname
;
2161 lines
[k
].saddr
= saddr
;
2162 lines
[k
].path
= obj
->path
;
2163 lines
[k
].base_addr
= obj
->base_addr
;
2171 if (obj
->debug_info
.ptr
&& obj
->debug_abbrev
.ptr
) {
2172 DebugInfoReader reader
;
2173 debug_info_reader_init(&reader
, obj
);
2174 while (reader
.p
< reader
.pend
) {
2175 if (di_read_cu(&reader
)) goto fail
;
2176 debug_info_read(&reader
, num_traces
, traces
, lines
, offset
);
2180 if (parse_debug_line(num_traces
, traces
,
2181 obj
->debug_line
.ptr
,
2182 obj
->debug_line
.size
,
2183 obj
, lines
, offset
) == -1)
2186 return dladdr_fbase
;
2188 return (uintptr_t)-1;
2192 #define HAVE_MAIN_EXE_PATH
2193 #if defined(__FreeBSD__) || defined(__DragonFly__)
2194 # include <sys/sysctl.h>
2196 /* ssize_t main_exe_path(void)
2198 * store the path of the main executable to `binary_filename`,
2199 * and returns strlen(binary_filename).
2200 * it is NUL terminated.
2202 #if defined(__linux__) || defined(__NetBSD__)
2206 # if defined(__linux__)
2207 # define PROC_SELF_EXE "/proc/self/exe"
2208 # elif defined(__NetBSD__)
2209 # define PROC_SELF_EXE "/proc/curproc/exe"
2211 ssize_t len
= readlink(PROC_SELF_EXE
, binary_filename
, PATH_MAX
);
2212 if (len
< 0) return 0;
2213 binary_filename
[len
] = 0;
2216 #elif defined(__FreeBSD__) || defined(__DragonFly__)
2220 int mib
[4] = {CTL_KERN
, KERN_PROC
, KERN_PROC_PATHNAME
, -1};
2221 size_t len
= PATH_MAX
;
2222 int err
= sysctl(mib
, 4, binary_filename
, &len
, NULL
, 0);
2224 kprintf("Can't get the path of ruby");
2227 len
--; /* sysctl sets strlen+1 */
2230 #elif defined(HAVE_LIBPROC_H)
2234 int len
= proc_pidpath(getpid(), binary_filename
, PATH_MAX
);
2235 if (len
== 0) return 0;
2236 binary_filename
[len
] = 0;
2240 #undef HAVE_MAIN_EXE_PATH
2244 print_line0(line_info_t
*line
, void *address
)
2246 uintptr_t addr
= (uintptr_t)address
;
2247 uintptr_t d
= addr
- line
->saddr
;
2250 if (line
->dirname
&& line
->dirname
[0]) {
2251 kprintf("%s(%s) %s/%s:%d\n", line
->path
, line
->sname
, line
->dirname
, line
->filename
, line
->line
);
2254 kprintf("%s(%s) %s:%d\n", line
->path
, line
->sname
, line
->filename
, line
->line
);
2257 else if (!line
->path
) {
2258 kprintf("[0x%"PRIxPTR
"]\n", addr
);
2260 else if (!line
->saddr
|| !line
->sname
) {
2261 kprintf("%s(0x%"PRIxPTR
") [0x%"PRIxPTR
"]\n", line
->path
, addr
-line
->base_addr
, addr
);
2263 else if (line
->line
<= 0) {
2264 kprintf("%s(%s+0x%"PRIxPTR
") [0x%"PRIxPTR
"]\n", line
->path
, line
->sname
,
2267 else if (!line
->filename
) {
2268 kprintf("%s(%s+0x%"PRIxPTR
") [0x%"PRIxPTR
"] ???:%d\n", line
->path
, line
->sname
,
2269 d
, addr
, line
->line
);
2271 else if (line
->dirname
&& line
->dirname
[0]) {
2272 kprintf("%s(%s+0x%"PRIxPTR
") [0x%"PRIxPTR
"] %s/%s:%d\n", line
->path
, line
->sname
,
2273 d
, addr
, line
->dirname
, line
->filename
, line
->line
);
2276 kprintf("%s(%s+0x%"PRIxPTR
") [0x%"PRIxPTR
"] %s:%d\n", line
->path
, line
->sname
,
2277 d
, addr
, line
->filename
, line
->line
);
2282 print_line(line_info_t
*line
, void *address
)
2284 print_line0(line
, address
);
2286 print_line(line
->next
, NULL
);
2291 rb_dump_backtrace_with_lines(int num_traces
, void **traces
)
2294 /* async-signal unsafe */
2295 line_info_t
*lines
= (line_info_t
*)calloc(num_traces
, sizeof(line_info_t
));
2296 obj_info_t
*obj
= NULL
;
2297 /* 2 is NULL + main executable */
2298 void **dladdr_fbases
= (void **)calloc(num_traces
+2, sizeof(void *));
2299 #ifdef HAVE_MAIN_EXE_PATH
2300 char *main_path
= NULL
; /* used on printing backtrace */
2302 if ((len
= main_exe_path()) > 0) {
2303 main_path
= (char *)alloca(len
+ 1);
2306 memcpy(main_path
, binary_filename
, len
+1);
2308 obj
->path
= main_path
;
2309 addr
= fill_lines(num_traces
, traces
, 1, &obj
, lines
, -1);
2310 if (addr
!= (uintptr_t)-1) {
2311 dladdr_fbases
[0] = (void *)addr
;
2317 /* fill source lines by reading dwarf */
2318 for (i
= 0; i
< num_traces
; i
++) {
2320 if (lines
[i
].line
) continue;
2321 if (dladdr(traces
[i
], &info
)) {
2325 /* skip symbols which is in already checked objects */
2326 /* if the binary is strip-ed, this may effect */
2327 for (p
=dladdr_fbases
; *p
; p
++) {
2328 if (*p
== info
.dli_fbase
) {
2329 lines
[i
].path
= info
.dli_fname
;
2330 lines
[i
].sname
= info
.dli_sname
;
2334 *p
= info
.dli_fbase
;
2337 obj
->base_addr
= (uintptr_t)info
.dli_fbase
;
2338 path
= info
.dli_fname
;
2340 lines
[i
].path
= path
;
2341 lines
[i
].sname
= info
.dli_sname
;
2342 lines
[i
].saddr
= (uintptr_t)info
.dli_saddr
;
2343 strlcpy(binary_filename
, path
, PATH_MAX
);
2344 if (fill_lines(num_traces
, traces
, 1, &obj
, lines
, i
) == (uintptr_t)-1)
2352 for (i
= 0; i
< num_traces
; i
++) {
2353 print_line(&lines
[i
], traces
[i
]);
2355 /* FreeBSD's backtrace may show _start and so on */
2356 if (lines
[i
].sname
&& strcmp("main", lines
[i
].sname
) == 0)
2362 obj_info_t
*o
= obj
;
2363 for (i
=0; i
< DWARF_SECTION_COUNT
; i
++) {
2364 struct dwarf_section
*s
= obj_dwarf_section_at(obj
, i
);
2365 if (s
->flags
& SHF_COMPRESSED
) {
2369 if (obj
->mapped_size
) {
2370 munmap(obj
->mapped
, obj
->mapped_size
);
2375 for (i
= 0; i
< num_traces
; i
++) {
2376 line_info_t
*line
= lines
[i
].next
;
2378 line_info_t
*l
= line
;
2384 free(dladdr_fbases
);
2387 /* From FreeBSD's lib/libstand/printf.c */
2389 * Copyright (c) 1986, 1988, 1991, 1993
2390 * The Regents of the University of California. All rights reserved.
2391 * (c) UNIX System Laboratories, Inc.
2392 * All or some portions of this file are derived from material licensed
2393 * to the University of California by American Telephone and Telegraph
2394 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
2395 * the permission of UNIX System Laboratories, Inc.
2397 * Redistribution and use in source and binary forms, with or without
2398 * modification, are permitted provided that the following conditions
2400 * 1. Redistributions of source code must retain the above copyright
2401 * notice, this list of conditions and the following disclaimer.
2402 * 2. Redistributions in binary form must reproduce the above copyright
2403 * notice, this list of conditions and the following disclaimer in the
2404 * documentation and/or other materials provided with the distribution.
2405 * 4. Neither the name of the University nor the names of its contributors
2406 * may be used to endorse or promote products derived from this software
2407 * without specific prior written permission.
2409 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2410 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2411 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2412 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2413 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2414 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2415 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2416 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2417 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2418 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2421 * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
2425 #define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1)
2426 static inline int toupper(int c
) { return ('A' <= c
&& c
<= 'Z') ? (c
&0x5f) : c
; }
2427 #define hex2ascii(hex) (hex2ascii_data[hex])
2428 static const char hex2ascii_data
[] = "0123456789abcdefghijklmnopqrstuvwxyz";
2429 static inline int imax(int a
, int b
) { return (a
> b
? a
: b
); }
2430 static int kvprintf(char const *fmt
, void (*func
)(int), void *arg
, int radix
, va_list ap
);
2432 static void putce(int c
)
2438 ret
= write(2, s
, 1);
2443 kprintf(const char *fmt
, ...)
2449 retval
= kvprintf(fmt
, putce
, NULL
, 10, ap
);
2455 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
2456 * order; return an optional length and a pointer to the last character
2457 * written in the buffer (i.e., the first character of the string).
2458 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
2461 ksprintn(char *nbuf
, uintmax_t num
, int base
, int *lenp
, int upper
)
2468 c
= hex2ascii(num
% base
);
2469 *++p
= upper
? toupper(c
) : c
;
2470 } while (num
/= base
);
2472 *lenp
= (int)(p
- nbuf
);
2477 * Scaled down version of printf(3).
2479 * Two additional formats:
2481 * The format %b is supported to decode error registers.
2484 * printf("reg=%b\n", regval, "<base><arg>*");
2486 * where <base> is the output base expressed as a control character, e.g.
2487 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
2488 * the first of which gives the bit number to be inspected (origin 1), and
2489 * the next characters (up to a control character, i.e. a character <= 32),
2490 * give the name of the register. Thus:
2492 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
2494 * would produce output:
2496 * reg=3<BITTWO,BITONE>
2498 * XXX: %D -- Hexdump, takes pointer and separator string:
2499 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
2500 * ("%*D", len, ptr, " " -> XX XX XX XX ...
2503 kvprintf(char const *fmt
, void (*func
)(int), void *arg
, int radix
, va_list ap
)
2505 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; }
2508 const char *p
, *percent
, *q
;
2512 int base
, lflag
, qflag
, tmp
, width
, ladjust
, sharpflag
, neg
, sign
, dot
;
2513 int cflag
, hflag
, jflag
, tflag
, zflag
;
2516 int stop
= 0, retval
= 0;
2525 fmt
= "(fmt null)\n";
2527 if (radix
< 2 || radix
> 36)
2533 while ((ch
= (unsigned char)*fmt
++) != '%' || stop
) {
2539 qflag
= 0; lflag
= 0; ladjust
= 0; sharpflag
= 0; neg
= 0;
2540 sign
= 0; dot
= 0; dwidth
= 0; upper
= 0;
2541 cflag
= 0; hflag
= 0; jflag
= 0; tflag
= 0; zflag
= 0;
2542 reswitch
: switch (ch
= (unsigned char)*fmt
++) {
2560 width
= va_arg(ap
, int);
2566 dwidth
= va_arg(ap
, int);
2574 case '1': case '2': case '3': case '4':
2575 case '5': case '6': case '7': case '8': case '9':
2576 for (n
= 0;; ++fmt
) {
2577 n
= n
* 10 + ch
- '0';
2579 if (ch
< '0' || ch
> '9')
2588 num
= (unsigned int)va_arg(ap
, int);
2589 p
= va_arg(ap
, char *);
2590 for (q
= ksprintn(nbuf
, num
, *p
++, NULL
, 0); *q
;)
2596 for (tmp
= 0; *p
;) {
2598 if (num
& (1 << (n
- 1))) {
2599 PCHAR(tmp
? ',' : '<');
2600 for (; (n
= *p
) > ' '; ++p
)
2604 for (; *p
> ' '; ++p
)
2611 PCHAR(va_arg(ap
, int));
2614 up
= va_arg(ap
, unsigned char *);
2615 p
= va_arg(ap
, char *);
2619 PCHAR(hex2ascii(*up
>> 4));
2620 PCHAR(hex2ascii(*up
& 0x0f));
2651 *(va_arg(ap
, intmax_t *)) = retval
;
2653 *(va_arg(ap
, int64_t *)) = retval
;
2655 *(va_arg(ap
, long *)) = retval
;
2657 *(va_arg(ap
, size_t *)) = retval
;
2659 *(va_arg(ap
, short *)) = retval
;
2661 *(va_arg(ap
, char *)) = retval
;
2663 *(va_arg(ap
, int *)) = retval
;
2670 sharpflag
= (width
== 0);
2672 num
= (uintptr_t)va_arg(ap
, void *);
2683 p
= va_arg(ap
, char *);
2687 n
= (int)strlen (p
);
2689 for (n
= 0; n
< dwidth
&& p
[n
]; n
++)
2694 if (!ladjust
&& width
> 0)
2699 if (ladjust
&& width
> 0)
2724 num
= va_arg(ap
, uintmax_t);
2726 num
= va_arg(ap
, uint64_t);
2728 num
= va_arg(ap
, ptrdiff_t);
2730 num
= va_arg(ap
, unsigned long);
2732 num
= va_arg(ap
, size_t);
2734 num
= (unsigned short)va_arg(ap
, int);
2736 num
= (unsigned char)va_arg(ap
, int);
2738 num
= va_arg(ap
, unsigned int);
2742 num
= va_arg(ap
, intmax_t);
2744 num
= va_arg(ap
, int64_t);
2746 num
= va_arg(ap
, ptrdiff_t);
2748 num
= va_arg(ap
, long);
2750 num
= va_arg(ap
, ssize_t
);
2752 num
= (short)va_arg(ap
, int);
2754 num
= (char)va_arg(ap
, int);
2756 num
= va_arg(ap
, int);
2758 if (sign
&& (intmax_t)num
< 0) {
2760 num
= -(intmax_t)num
;
2762 p
= ksprintn(nbuf
, num
, base
, &n
, upper
);
2764 if (sharpflag
&& num
!= 0) {
2767 else if (base
== 16)
2773 if (!ladjust
&& padc
== '0')
2774 dwidth
= width
- tmp
;
2775 width
-= tmp
+ imax(dwidth
, n
);
2782 if (sharpflag
&& num
!= 0) {
2785 } else if (base
== 16) {
2790 while (dwidth
-- > 0)
2802 while (percent
< fmt
)
2805 * Since we ignore an formatting argument it is no
2806 * longer safe to obey the remaining formatting
2807 * arguments as the arguments will no longer match
2816 #else /* defined(USE_ELF) */
2817 #error not supported