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