Ruby  2.1.10p492(2016-04-01revision54464)
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 #include "ruby/config.h"
12 #include "ruby/missing.h"
13 #include "addr2line.h"
14 
15 #include <stdio.h>
16 #include <errno.h>
17 
18 #ifdef USE_ELF
19 
20 #include <fcntl.h>
21 #include <limits.h>
22 #include <stdio.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/mman.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 
31 #ifdef __OpenBSD__
32 #include <elf_abi.h>
33 #else
34 #include <elf.h>
35 #endif
36 
37 /* Make alloca work the best possible way. */
38 #ifdef __GNUC__
39 # ifndef atarist
40 # ifndef alloca
41 # define alloca __builtin_alloca
42 # endif
43 # endif /* atarist */
44 #else
45 # ifdef HAVE_ALLOCA_H
46 # include <alloca.h>
47 # else
48 # ifdef _AIX
49 #pragma alloca
50 # else
51 # ifndef alloca /* predefined by HP cc +Olibcalls */
52 void *alloca();
53 # endif
54 # endif /* AIX */
55 # endif /* HAVE_ALLOCA_H */
56 #endif /* __GNUC__ */
57 
58 #ifdef HAVE_DL_ITERATE_PHDR
59 # ifndef _GNU_SOURCE
60 # define _GNU_SOURCE
61 # endif
62 # include <link.h>
63 #endif
64 
65 #define DW_LNS_copy 0x01
66 #define DW_LNS_advance_pc 0x02
67 #define DW_LNS_advance_line 0x03
68 #define DW_LNS_set_file 0x04
69 #define DW_LNS_set_column 0x05
70 #define DW_LNS_negate_stmt 0x06
71 #define DW_LNS_set_basic_block 0x07
72 #define DW_LNS_const_add_pc 0x08
73 #define DW_LNS_fixed_advance_pc 0x09
74 #define DW_LNS_set_prologue_end 0x0a /* DWARF3 */
75 #define DW_LNS_set_epilogue_begin 0x0b /* DWARF3 */
76 #define DW_LNS_set_isa 0x0c /* DWARF3 */
77 
78 /* Line number extended opcode name. */
79 #define DW_LNE_end_sequence 0x01
80 #define DW_LNE_set_address 0x02
81 #define DW_LNE_define_file 0x03
82 #define DW_LNE_set_discriminator 0x04 /* DWARF4 */
83 
84 #ifndef ElfW
85 # if SIZEOF_VOIDP == 8
86 # define ElfW(x) Elf64##_##x
87 # else
88 # define ElfW(x) Elf32##_##x
89 # endif
90 #endif
91 #ifndef PATH_MAX
92 #define PATH_MAX 4096
93 #endif
94 
95 int kprintf(const char *fmt, ...);
96 
97 typedef struct {
98  const char *dirname;
99  const char *filename;
100  int line;
101 
102  int fd;
103  void *mapped;
104  size_t mapped_size;
105  unsigned long base_addr;
106 } line_info_t;
107 
108 /* Avoid consuming stack as this module may be used from signal handler */
109 static char binary_filename[PATH_MAX];
110 
111 static unsigned long
112 uleb128(char **p)
113 {
114  unsigned long r = 0;
115  int s = 0;
116  for (;;) {
117  unsigned char b = *(unsigned char *)(*p)++;
118  if (b < 0x80) {
119  r += (unsigned long)b << s;
120  break;
121  }
122  r += (b & 0x7f) << s;
123  s += 7;
124  }
125  return r;
126 }
127 
128 static long
129 sleb128(char **p)
130 {
131  long r = 0;
132  int s = 0;
133  for (;;) {
134  unsigned char b = *(unsigned char *)(*p)++;
135  if (b < 0x80) {
136  if (b & 0x40) {
137  r -= (0x80 - b) << s;
138  }
139  else {
140  r += (b & 0x3f) << s;
141  }
142  break;
143  }
144  r += (b & 0x7f) << s;
145  s += 7;
146  }
147  return r;
148 }
149 
150 static const char *
151 get_nth_dirname(unsigned long dir, char *p)
152 {
153  if (!dir--) {
154  return "";
155  }
156  while (dir--) {
157  while (*p) p++;
158  p++;
159  if (!*p) {
160  kprintf("Unexpected directory number %lu in %s\n",
161  dir, binary_filename);
162  return "";
163  }
164  }
165  return p;
166 }
167 
168 static void
169 fill_filename(int file, char *include_directories, char *filenames,
170  line_info_t *line)
171 {
172  int i;
173  char *p = filenames;
174  char *filename;
175  unsigned long dir;
176  for (i = 1; i <= file; i++) {
177  filename = p;
178  if (!*p) {
179  /* Need to output binary file name? */
180  kprintf("Unexpected file number %d in %s\n",
181  file, binary_filename);
182  return;
183  }
184  while (*p) p++;
185  p++;
186  dir = uleb128(&p);
187  /* last modified. */
188  uleb128(&p);
189  /* size of the file. */
190  uleb128(&p);
191 
192  if (i == file) {
193  line->filename = filename;
194  line->dirname = get_nth_dirname(dir, include_directories);
195  }
196  }
197 }
198 
199 static int
200 get_path_from_symbol(const char *symbol, const char **p, size_t *len)
201 {
202  if (symbol[0] == '0') {
203  /* libexecinfo */
204  *p = strchr(symbol, '/');
205  if (*p == NULL) return 0;
206  *len = strlen(*p);
207  }
208  else {
209  /* glibc */
210  const char *q;
211  *p = symbol;
212  q = strchr(symbol, '(');
213  if (q == NULL) return 0;
214  *len = q - symbol;
215  }
216  return 1;
217 }
218 
219 static void
220 fill_line(int num_traces, void **traces,
221  unsigned long addr, int file, int line,
222  char *include_directories, char *filenames, line_info_t *lines)
223 {
224  int i;
225  for (i = 0; i < num_traces; i++) {
226  unsigned long a = (unsigned long)traces[i] - lines[i].base_addr;
227  /* We assume one line code doesn't result >100 bytes of native code.
228  We may want more reliable way eventually... */
229  if (addr < a && a < addr + 100) {
230  fill_filename(file, include_directories, filenames, &lines[i]);
231  lines[i].line = line;
232  }
233  }
234 }
235 
236 static void
237 parse_debug_line_cu(int num_traces, void **traces,
238  char **debug_line, line_info_t *lines)
239 {
240  char *p, *cu_end, *cu_start, *include_directories, *filenames;
241  unsigned long unit_length;
242  int default_is_stmt, line_base;
243  unsigned int header_length, minimum_instruction_length, line_range,
244  opcode_base;
245  /* unsigned char *standard_opcode_lengths; */
246 
247  /* The registers. */
248  unsigned long addr = 0;
249  unsigned int file = 1;
250  unsigned int line = 1;
251  /* unsigned int column = 0; */
252  int is_stmt;
253  /* int basic_block = 0; */
254  /* int end_sequence = 0; */
255  /* int prologue_end = 0; */
256  /* int epilogue_begin = 0; */
257  /* unsigned int isa = 0; */
258 
259  p = *debug_line;
260 
261  unit_length = *(unsigned int *)p;
262  p += sizeof(unsigned int);
263  if (unit_length == 0xffffffff) {
264  unit_length = *(unsigned long *)p;
265  p += sizeof(unsigned long);
266  }
267 
268  cu_end = p + unit_length;
269 
270  /*dwarf_version = *(unsigned short *)p;*/
271  p += 2;
272 
273  header_length = *(unsigned int *)p;
274  p += sizeof(unsigned int);
275 
276  cu_start = p + header_length;
277 
278  minimum_instruction_length = *(unsigned char *)p;
279  p++;
280 
281  is_stmt = default_is_stmt = *(unsigned char *)p;
282  p++;
283 
284  line_base = *(char *)p;
285  p++;
286 
287  line_range = *(unsigned char *)p;
288  p++;
289 
290  opcode_base = *(unsigned char *)p;
291  p++;
292 
293  /* standard_opcode_lengths = (unsigned char *)p - 1; */
294  p += opcode_base - 1;
295 
296  include_directories = p;
297 
298  /* skip include directories */
299  while (*p) {
300  while (*p) p++;
301  p++;
302  }
303  p++;
304 
305  filenames = p;
306 
307  p = cu_start;
308 
309 #define FILL_LINE() \
310  do { \
311  fill_line(num_traces, traces, addr, file, line, \
312  include_directories, filenames, lines); \
313  /*basic_block = prologue_end = epilogue_begin = 0;*/ \
314  } while (0)
315 
316  while (p < cu_end) {
317  unsigned long a;
318  unsigned char op = *p++;
319  switch (op) {
320  case DW_LNS_copy:
321  FILL_LINE();
322  break;
323  case DW_LNS_advance_pc:
324  a = uleb128(&p);
325  addr += a;
326  break;
327  case DW_LNS_advance_line: {
328  long a = sleb128(&p);
329  line += a;
330  break;
331  }
332  case DW_LNS_set_file:
333  file = (unsigned int)uleb128(&p);
334  break;
335  case DW_LNS_set_column:
336  /*column = (unsigned int)*/(void)uleb128(&p);
337  break;
338  case DW_LNS_negate_stmt:
339  is_stmt = !is_stmt;
340  break;
341  case DW_LNS_set_basic_block:
342  /*basic_block = 1; */
343  break;
344  case DW_LNS_const_add_pc:
345  a = ((255 - opcode_base) / line_range) *
346  minimum_instruction_length;
347  addr += a;
348  break;
349  case DW_LNS_fixed_advance_pc:
350  a = *(unsigned char *)p++;
351  addr += a;
352  break;
353  case DW_LNS_set_prologue_end:
354  /* prologue_end = 1; */
355  break;
356  case DW_LNS_set_epilogue_begin:
357  /* epilogue_begin = 1; */
358  break;
359  case DW_LNS_set_isa:
360  /* isa = (unsigned int)*/(void)uleb128(&p);
361  break;
362  case 0:
363  a = *(unsigned char *)p++;
364  op = *p++;
365  switch (op) {
366  case DW_LNE_end_sequence:
367  /* end_sequence = 1; */
368  FILL_LINE();
369  addr = 0;
370  file = 1;
371  line = 1;
372  /* column = 0; */
373  is_stmt = default_is_stmt;
374  /* end_sequence = 0; */
375  /* isa = 0; */
376  break;
377  case DW_LNE_set_address:
378  addr = *(unsigned long *)p;
379  p += sizeof(unsigned long);
380  break;
381  case DW_LNE_define_file:
382  kprintf("Unsupported operation in %s\n",
383  binary_filename);
384  break;
385  case DW_LNE_set_discriminator:
386  /* TODO:currently ignore */
387  uleb128(&p);
388  break;
389  default:
390  kprintf("Unknown extended opcode: %d in %s\n",
391  op, binary_filename);
392  }
393  break;
394  default: {
395  unsigned long addr_incr;
396  unsigned long line_incr;
397  a = op - opcode_base;
398  addr_incr = (a / line_range) * minimum_instruction_length;
399  line_incr = line_base + (a % line_range);
400  addr += (unsigned int)addr_incr;
401  line += (unsigned int)line_incr;
402  FILL_LINE();
403  }
404  }
405  }
406  *debug_line = p;
407 }
408 
409 static void
410 parse_debug_line(int num_traces, void **traces,
411  char *debug_line, unsigned long size, line_info_t *lines)
412 {
413  char *debug_line_end = debug_line + size;
414  while (debug_line < debug_line_end) {
415  parse_debug_line_cu(num_traces, traces, &debug_line, lines);
416  }
417  if (debug_line != debug_line_end) {
418  kprintf("Unexpected size of .debug_line in %s\n",
419  binary_filename);
420  }
421 }
422 
423 /* read file and fill lines */
424 static void
425 fill_lines(int num_traces, void **traces, char **syms, int check_debuglink,
426  line_info_t *current_line, line_info_t *lines);
427 
428 static void
429 follow_debuglink(char *debuglink, int num_traces, void **traces, char **syms,
430  line_info_t *current_line, line_info_t *lines)
431 {
432  /* Ideally we should check 4 paths to follow gnu_debuglink,
433  but we handle only one case for now as this format is used
434  by some linux distributions. See GDB's info for detail. */
435  static const char global_debug_dir[] = "/usr/lib/debug";
436  char *p, *subdir;
437 
438  p = strrchr(binary_filename, '/');
439  if (!p) {
440  return;
441  }
442  p[1] = '\0';
443 
444  subdir = (char *)alloca(strlen(binary_filename) + 1);
445  strcpy(subdir, binary_filename);
446  strcpy(binary_filename, global_debug_dir);
447  strncat(binary_filename, subdir,
448  PATH_MAX - strlen(binary_filename) - 1);
449  strncat(binary_filename, debuglink,
450  PATH_MAX - strlen(binary_filename) - 1);
451 
452  munmap(current_line->mapped, current_line->mapped_size);
453  close(current_line->fd);
454  fill_lines(num_traces, traces, syms, 0, current_line, lines);
455 }
456 
457 /* read file and fill lines */
458 static void
459 fill_lines(int num_traces, void **traces, char **syms, int check_debuglink,
460  line_info_t *current_line, line_info_t *lines)
461 {
462  int i;
463  char *shstr;
464  char *section_name;
465  ElfW(Ehdr) *ehdr;
466  ElfW(Shdr) *shdr, *shstr_shdr;
467  ElfW(Shdr) *debug_line_shdr = NULL, *gnu_debuglink_shdr = NULL;
468  int fd;
469  off_t filesize;
470  char *file;
471 
472  fd = open(binary_filename, O_RDONLY);
473  if (fd < 0) {
474  return;
475  }
476  filesize = lseek(fd, 0, SEEK_END);
477  if (filesize < 0) {
478  int e = errno;
479  close(fd);
480  kprintf("lseek: %s\n", strerror(e));
481  return;
482  }
483 #if SIZEOF_OFF_T > SIZEOF_SIZE_T
484  if (filesize > (off_t)SIZE_MAX) {
485  close(fd);
486  kprintf("Too large file %s\n", binary_filename);
487  return;
488  }
489 #endif
490  lseek(fd, 0, SEEK_SET);
491  /* async-signal unsafe */
492  file = (char *)mmap(NULL, (size_t)filesize, PROT_READ, MAP_SHARED, fd, 0);
493  if (file == MAP_FAILED) {
494  int e = errno;
495  close(fd);
496  kprintf("mmap: %s\n", strerror(e));
497  return;
498  }
499 
500  ehdr = (ElfW(Ehdr) *)file;
501  if (memcmp(ehdr->e_ident, "\177ELF", 4) != 0) {
502  /*
503  * Huh? Maybe filename was overridden by setproctitle() and
504  * it match non-elf file.
505  */
506  close(fd);
507  return;
508  }
509 
510  current_line->fd = fd;
511  current_line->mapped = file;
512  current_line->mapped_size = (size_t)filesize;
513 
514  for (i = 0; i < num_traces; i++) {
515  const char *path;
516  size_t len;
517  if (get_path_from_symbol(syms[i], &path, &len) &&
518  !strncmp(path, binary_filename, len)) {
519  lines[i].line = -1;
520  }
521  }
522 
523  shdr = (ElfW(Shdr) *)(file + ehdr->e_shoff);
524 
525  shstr_shdr = shdr + ehdr->e_shstrndx;
526  shstr = file + shstr_shdr->sh_offset;
527 
528  for (i = 0; i < ehdr->e_shnum; i++) {
529  section_name = shstr + shdr[i].sh_name;
530  if (!strcmp(section_name, ".debug_line")) {
531  debug_line_shdr = shdr + i;
532  break;
533  } else if (!strcmp(section_name, ".gnu_debuglink")) {
534  gnu_debuglink_shdr = shdr + i;
535  }
536  }
537 
538  if (!debug_line_shdr) {
539  /* This file doesn't have .debug_line section,
540  let's check .gnu_debuglink section instead. */
541  if (gnu_debuglink_shdr && check_debuglink) {
542  follow_debuglink(file + gnu_debuglink_shdr->sh_offset,
543  num_traces, traces, syms,
544  current_line, lines);
545  }
546  return;
547  }
548 
549  parse_debug_line(num_traces, traces,
550  file + debug_line_shdr->sh_offset,
551  debug_line_shdr->sh_size,
552  lines);
553 }
554 
555 #ifdef HAVE_DL_ITERATE_PHDR
556 
557 typedef struct {
558  int num_traces;
559  char **syms;
560  line_info_t *lines;
561 } fill_base_addr_state_t;
562 
563 static int
564 fill_base_addr(struct dl_phdr_info *info, size_t size, void *data)
565 {
566  int i;
567  fill_base_addr_state_t *st = (fill_base_addr_state_t *)data;
568  for (i = 0; i < st->num_traces; i++) {
569  const char *path;
570  size_t len;
571  size_t name_len = strlen(info->dlpi_name);
572 
573  if (get_path_from_symbol(st->syms[i], &path, &len) &&
574  (len == name_len || (len > name_len && path[len-name_len-1] == '/')) &&
575  !strncmp(path+len-name_len, info->dlpi_name, name_len)) {
576  st->lines[i].base_addr = info->dlpi_addr;
577  }
578  }
579  return 0;
580 }
581 
582 #endif /* HAVE_DL_ITERATE_PHDR */
583 
584 void
585 rb_dump_backtrace_with_lines(int num_traces, void **trace, char **syms)
586 {
587  int i;
588  /* async-signal unsafe */
589  line_info_t *lines = (line_info_t *)calloc(num_traces,
590  sizeof(line_info_t));
591 
592  /* Note that line info of shared objects might not be shown
593  if we don't have dl_iterate_phdr */
594 #ifdef HAVE_DL_ITERATE_PHDR
595  fill_base_addr_state_t fill_base_addr_state;
596 
597  fill_base_addr_state.num_traces = num_traces;
598  fill_base_addr_state.syms = syms;
599  fill_base_addr_state.lines = lines;
600  /* maybe async-signal unsafe */
601  dl_iterate_phdr(fill_base_addr, &fill_base_addr_state);
602 #endif /* HAVE_DL_ITERATE_PHDR */
603 
604  for (i = 0; i < num_traces; i++) {
605  const char *path;
606  size_t len;
607  if (lines[i].line) {
608  continue;
609  }
610 
611  if (!get_path_from_symbol(syms[i], &path, &len)) {
612  continue;
613  }
614 
615  strncpy(binary_filename, path, len);
616  binary_filename[len] = '\0';
617 
618  fill_lines(num_traces, trace, syms, 1, &lines[i], lines);
619  }
620 
621  for (i = 0; i < num_traces; i++) {
622  line_info_t *line = &lines[i];
623 
624  if (line->line > 0) {
625  if (line->filename) {
626  if (line->dirname && line->dirname[0]) {
627  kprintf("%s %s/%s:%d\n", syms[i], line->dirname, line->filename, line->line);
628  }
629  else {
630  kprintf("%s %s:%d\n", syms[i], line->filename, line->line);
631  }
632  } else {
633  kprintf("%s ???:%d\n", syms[i], line->line);
634  }
635  } else {
636  kprintf("%s\n", syms[i]);
637  }
638  }
639 
640  for (i = 0; i < num_traces; i++) {
641  line_info_t *line = &lines[i];
642  if (line->fd) {
643  munmap(line->mapped, line->mapped_size);
644  close(line->fd);
645  }
646  }
647  free(lines);
648 }
649 
650 /* From FreeBSD's lib/libstand/printf.c */
651 /*-
652  * Copyright (c) 1986, 1988, 1991, 1993
653  * The Regents of the University of California. All rights reserved.
654  * (c) UNIX System Laboratories, Inc.
655  * All or some portions of this file are derived from material licensed
656  * to the University of California by American Telephone and Telegraph
657  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
658  * the permission of UNIX System Laboratories, Inc.
659  *
660  * Redistribution and use in source and binary forms, with or without
661  * modification, are permitted provided that the following conditions
662  * are met:
663  * 1. Redistributions of source code must retain the above copyright
664  * notice, this list of conditions and the following disclaimer.
665  * 2. Redistributions in binary form must reproduce the above copyright
666  * notice, this list of conditions and the following disclaimer in the
667  * documentation and/or other materials provided with the distribution.
668  * 4. Neither the name of the University nor the names of its contributors
669  * may be used to endorse or promote products derived from this software
670  * without specific prior written permission.
671  *
672  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
673  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
674  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
675  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
676  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
677  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
678  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
679  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
680  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
681  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
682  * SUCH DAMAGE.
683  *
684  * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
685  */
686 
687 #include <stdarg.h>
688 #define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1)
689 extern int rb_toupper(int c);
690 #define toupper(c) rb_toupper(c)
691 #define hex2ascii(hex) (hex2ascii_data[hex])
692 char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
693 static inline int imax(int a, int b) { return (a > b ? a : b); }
694 static int kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap);
695 
696 static void putce(int c)
697 {
698  char s[1];
699  ssize_t ret;
700 
701  s[0] = (char)c;
702  ret = write(2, s, 1);
703  (void)ret;
704 }
705 
706 int
707 kprintf(const char *fmt, ...)
708 {
709  va_list ap;
710  int retval;
711 
712  va_start(ap, fmt);
713  retval = kvprintf(fmt, putce, NULL, 10, ap);
714  va_end(ap);
715  return retval;
716 }
717 
718 /*
719  * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
720  * order; return an optional length and a pointer to the last character
721  * written in the buffer (i.e., the first character of the string).
722  * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
723  */
724 static char *
725 ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
726 {
727  char *p, c;
728 
729  p = nbuf;
730  *p = '\0';
731  do {
732  c = hex2ascii(num % base);
733  *++p = upper ? toupper(c) : c;
734  } while (num /= base);
735  if (lenp)
736  *lenp = (int)(p - nbuf);
737  return (p);
738 }
739 
740 /*
741  * Scaled down version of printf(3).
742  *
743  * Two additional formats:
744  *
745  * The format %b is supported to decode error registers.
746  * Its usage is:
747  *
748  * printf("reg=%b\n", regval, "<base><arg>*");
749  *
750  * where <base> is the output base expressed as a control character, e.g.
751  * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
752  * the first of which gives the bit number to be inspected (origin 1), and
753  * the next characters (up to a control character, i.e. a character <= 32),
754  * give the name of the register. Thus:
755  *
756  * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
757  *
758  * would produce output:
759  *
760  * reg=3<BITTWO,BITONE>
761  *
762  * XXX: %D -- Hexdump, takes pointer and separator string:
763  * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
764  * ("%*D", len, ptr, " " -> XX XX XX XX ...
765  */
766 static int
767 kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap)
768 {
769 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; }
770  char nbuf[MAXNBUF];
771  char *d;
772  const char *p, *percent, *q;
773  unsigned char *up;
774  int ch, n;
775  uintmax_t num;
776  int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
777  int cflag, hflag, jflag, tflag, zflag;
778  int dwidth, upper;
779  char padc;
780  int stop = 0, retval = 0;
781 
782  num = 0;
783  if (!func)
784  d = (char *) arg;
785  else
786  d = NULL;
787 
788  if (fmt == NULL)
789  fmt = "(fmt null)\n";
790 
791  if (radix < 2 || radix > 36)
792  radix = 10;
793 
794  for (;;) {
795  padc = ' ';
796  width = 0;
797  while ((ch = (unsigned char)*fmt++) != '%' || stop) {
798  if (ch == '\0')
799  return (retval);
800  PCHAR(ch);
801  }
802  percent = fmt - 1;
803  qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
804  sign = 0; dot = 0; dwidth = 0; upper = 0;
805  cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
806 reswitch: switch (ch = (unsigned char)*fmt++) {
807  case '.':
808  dot = 1;
809  goto reswitch;
810  case '#':
811  sharpflag = 1;
812  goto reswitch;
813  case '+':
814  sign = 1;
815  goto reswitch;
816  case '-':
817  ladjust = 1;
818  goto reswitch;
819  case '%':
820  PCHAR(ch);
821  break;
822  case '*':
823  if (!dot) {
824  width = va_arg(ap, int);
825  if (width < 0) {
826  ladjust = !ladjust;
827  width = -width;
828  }
829  } else {
830  dwidth = va_arg(ap, int);
831  }
832  goto reswitch;
833  case '0':
834  if (!dot) {
835  padc = '0';
836  goto reswitch;
837  }
838  case '1': case '2': case '3': case '4':
839  case '5': case '6': case '7': case '8': case '9':
840  for (n = 0;; ++fmt) {
841  n = n * 10 + ch - '0';
842  ch = *fmt;
843  if (ch < '0' || ch > '9')
844  break;
845  }
846  if (dot)
847  dwidth = n;
848  else
849  width = n;
850  goto reswitch;
851  case 'b':
852  num = (unsigned int)va_arg(ap, int);
853  p = va_arg(ap, char *);
854  for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
855  PCHAR(*q--);
856 
857  if (num == 0)
858  break;
859 
860  for (tmp = 0; *p;) {
861  n = *p++;
862  if (num & (1 << (n - 1))) {
863  PCHAR(tmp ? ',' : '<');
864  for (; (n = *p) > ' '; ++p)
865  PCHAR(n);
866  tmp = 1;
867  } else
868  for (; *p > ' '; ++p)
869  continue;
870  }
871  if (tmp)
872  PCHAR('>');
873  break;
874  case 'c':
875  PCHAR(va_arg(ap, int));
876  break;
877  case 'D':
878  up = va_arg(ap, unsigned char *);
879  p = va_arg(ap, char *);
880  if (!width)
881  width = 16;
882  while(width--) {
883  PCHAR(hex2ascii(*up >> 4));
884  PCHAR(hex2ascii(*up & 0x0f));
885  up++;
886  if (width)
887  for (q=p;*q;q++)
888  PCHAR(*q);
889  }
890  break;
891  case 'd':
892  case 'i':
893  base = 10;
894  sign = 1;
895  goto handle_sign;
896  case 'h':
897  if (hflag) {
898  hflag = 0;
899  cflag = 1;
900  } else
901  hflag = 1;
902  goto reswitch;
903  case 'j':
904  jflag = 1;
905  goto reswitch;
906  case 'l':
907  if (lflag) {
908  lflag = 0;
909  qflag = 1;
910  } else
911  lflag = 1;
912  goto reswitch;
913  case 'n':
914  if (jflag)
915  *(va_arg(ap, intmax_t *)) = retval;
916  else if (qflag)
917  *(va_arg(ap, int64_t *)) = retval;
918  else if (lflag)
919  *(va_arg(ap, long *)) = retval;
920  else if (zflag)
921  *(va_arg(ap, size_t *)) = retval;
922  else if (hflag)
923  *(va_arg(ap, short *)) = retval;
924  else if (cflag)
925  *(va_arg(ap, char *)) = retval;
926  else
927  *(va_arg(ap, int *)) = retval;
928  break;
929  case 'o':
930  base = 8;
931  goto handle_nosign;
932  case 'p':
933  base = 16;
934  sharpflag = (width == 0);
935  sign = 0;
936  num = (uintptr_t)va_arg(ap, void *);
937  goto number;
938  case 'q':
939  qflag = 1;
940  goto reswitch;
941  case 'r':
942  base = radix;
943  if (sign)
944  goto handle_sign;
945  goto handle_nosign;
946  case 's':
947  p = va_arg(ap, char *);
948  if (p == NULL)
949  p = "(null)";
950  if (!dot)
951  n = (int)strlen (p);
952  else
953  for (n = 0; n < dwidth && p[n]; n++)
954  continue;
955 
956  width -= n;
957 
958  if (!ladjust && width > 0)
959  while (width--)
960  PCHAR(padc);
961  while (n--)
962  PCHAR(*p++);
963  if (ladjust && width > 0)
964  while (width--)
965  PCHAR(padc);
966  break;
967  case 't':
968  tflag = 1;
969  goto reswitch;
970  case 'u':
971  base = 10;
972  goto handle_nosign;
973  case 'X':
974  upper = 1;
975  case 'x':
976  base = 16;
977  goto handle_nosign;
978  case 'y':
979  base = 16;
980  sign = 1;
981  goto handle_sign;
982  case 'z':
983  zflag = 1;
984  goto reswitch;
985 handle_nosign:
986  sign = 0;
987  if (jflag)
988  num = va_arg(ap, uintmax_t);
989  else if (qflag)
990  num = va_arg(ap, uint64_t);
991  else if (tflag)
992  num = va_arg(ap, ptrdiff_t);
993  else if (lflag)
994  num = va_arg(ap, unsigned long);
995  else if (zflag)
996  num = va_arg(ap, size_t);
997  else if (hflag)
998  num = (unsigned short)va_arg(ap, int);
999  else if (cflag)
1000  num = (unsigned char)va_arg(ap, int);
1001  else
1002  num = va_arg(ap, unsigned int);
1003  goto number;
1004 handle_sign:
1005  if (jflag)
1006  num = va_arg(ap, intmax_t);
1007  else if (qflag)
1008  num = va_arg(ap, int64_t);
1009  else if (tflag)
1010  num = va_arg(ap, ptrdiff_t);
1011  else if (lflag)
1012  num = va_arg(ap, long);
1013  else if (zflag)
1014  num = va_arg(ap, ssize_t);
1015  else if (hflag)
1016  num = (short)va_arg(ap, int);
1017  else if (cflag)
1018  num = (char)va_arg(ap, int);
1019  else
1020  num = va_arg(ap, int);
1021 number:
1022  if (sign && (intmax_t)num < 0) {
1023  neg = 1;
1024  num = -(intmax_t)num;
1025  }
1026  p = ksprintn(nbuf, num, base, &n, upper);
1027  tmp = 0;
1028  if (sharpflag && num != 0) {
1029  if (base == 8)
1030  tmp++;
1031  else if (base == 16)
1032  tmp += 2;
1033  }
1034  if (neg)
1035  tmp++;
1036 
1037  if (!ladjust && padc == '0')
1038  dwidth = width - tmp;
1039  width -= tmp + imax(dwidth, n);
1040  dwidth -= n;
1041  if (!ladjust)
1042  while (width-- > 0)
1043  PCHAR(' ');
1044  if (neg)
1045  PCHAR('-');
1046  if (sharpflag && num != 0) {
1047  if (base == 8) {
1048  PCHAR('0');
1049  } else if (base == 16) {
1050  PCHAR('0');
1051  PCHAR('x');
1052  }
1053  }
1054  while (dwidth-- > 0)
1055  PCHAR('0');
1056 
1057  while (*p)
1058  PCHAR(*p--);
1059 
1060  if (ladjust)
1061  while (width-- > 0)
1062  PCHAR(' ');
1063 
1064  break;
1065  default:
1066  while (percent < fmt)
1067  PCHAR(*percent++);
1068  /*
1069  * Since we ignore an formatting argument it is no
1070  * longer safe to obey the remaining formatting
1071  * arguments as the arguments will no longer match
1072  * the format specs.
1073  */
1074  stop = 1;
1075  break;
1076  }
1077  }
1078 #undef PCHAR
1079 }
1080 #else /* defined(USE_ELF) */
1081 #error not supported
1082 #endif
size_t strlen(const char *)
#define PATH_MAX
int rb_toupper(int c)
Definition: encoding.c:1958
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:113
#define neg(x)
Definition: time.c:171
unsigned long long uint64_t
Definition: sha2.h:102
#define calloc
Definition: ripper.c:98
int errno
#define off_t
Definition: io.c:65
unsigned int uintptr_t
Definition: win32.h:103
char * strchr(char *, char)
int memcmp(const void *s1, const void *s2, size_t len)
Definition: memcmp.c:7
#define SEEK_END
Definition: io.c:762
int size
Definition: encoding.c:49
#define SIZE_MAX
Definition: ruby.h:274
RUBY_EXTERN char * strerror(int)
Definition: strerror.c:11
RUBY_SYMBOL_EXPORT_BEGIN void * alloca()
#define NULL
Definition: _sdbm.c:102
free(psz)
#define SEEK_SET
Definition: io.c:760
char * strrchr(const char *, const char)