Ruby 2.0.0p353(2013-11-22revision43784)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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
data
VALUE data
Definition: tcltklib.c:3368
tmp
volatile VALUE tmp
Definition: tcltklib.c:10209
n
ssize_t n
Definition: bigdecimal.c:5655
int
VP_EXPORT int
Definition: bigdecimal.c:5050
strlen
size_t strlen(const char *)
p
Win32OLEIDispatch * p
Definition: win32ole.c:786
PATH_MAX
#define PATH_MAX
func
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:108
rb_toupper
int rb_toupper(int c)
Definition: encoding.c:1904
i
ssize_t i
Definition: bigdecimal.c:5655
info
Tcl_CmdInfo * info
Definition: tcltklib.c:1463
ret
int ret
Definition: tcltklib.c:280
a
Real * a
Definition: bigdecimal.c:1182
path
gz path
Definition: zlib.c:2279
r
r
Definition: bigdecimal.c:1196
alloca
void * alloca()
d
d
Definition: strlcat.c:58
fmt
const char * fmt
Definition: tcltklib.c:841
strcpy
strcpy(cmd2, cmd)
neg
#define neg(x)
Definition: time.c:171
uint64_t
unsigned long long uint64_t
Definition: sha2.h:102
va_end
va_end(args)
calloc
#define calloc
Definition: ripper.c:100
unistd.h
errno
int errno
off_t
#define off_t
Definition: io.c:65
s
register char * s
Definition: os2.c:56
void
VP_EXPORT void
Definition: bigdecimal.c:5083
retval
VALUE retval
Definition: tcltklib.c:7830
uintptr_t
unsigned int uintptr_t
Definition: win32.h:94
strchr
char * strchr(char *, char)
memcmp
int memcmp(const void *s1, const void *s2, size_t len)
Definition: memcmp.c:7
b
Real * b
Definition: bigdecimal.c:1182
free
#define free(x)
Definition: dln.c:50
c
VpDivd * c
Definition: bigdecimal.c:1205
strerror
RUBY_EXTERN char * strerror(int)
Definition: strerror.c:11
SEEK_END
#define SEEK_END
Definition: io.c:749
arg
arg
Definition: ripper.y:1315
size
int size
Definition: encoding.c:52
SIZE_MAX
#define SIZE_MAX
Definition: ruby.h:282
e
BDIGIT e
Definition: bigdecimal.c:5085
addr2line.h
NULL
#define NULL
Definition: _sdbm.c:103
q
q
Definition: tcltklib.c:2968
SEEK_SET
#define SEEK_SET
Definition: io.c:747
st
Tcl_Interp *int * st
Definition: stubs.c:510
strrchr
char * strrchr(const char *, const char)
len
size_t len
Definition: tcltklib.c:3568