00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "ruby/config.h"
00012 #include "ruby/missing.h"
00013 #include "addr2line.h"
00014
00015 #include <stdio.h>
00016 #include <errno.h>
00017
00018 #ifdef USE_ELF
00019
00020 #include <fcntl.h>
00021 #include <limits.h>
00022 #include <stdio.h>
00023 #include <stdint.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <sys/mman.h>
00027 #include <sys/types.h>
00028 #include <sys/stat.h>
00029 #include <unistd.h>
00030
00031 #ifdef __OpenBSD__
00032 #include <elf_abi.h>
00033 #else
00034 #include <elf.h>
00035 #endif
00036
00037
00038 #ifdef __GNUC__
00039 # ifndef atarist
00040 # ifndef alloca
00041 # define alloca __builtin_alloca
00042 # endif
00043 # endif
00044 #else
00045 # ifdef HAVE_ALLOCA_H
00046 # include <alloca.h>
00047 # else
00048 # ifdef _AIX
00049 #pragma alloca
00050 # else
00051 # ifndef alloca
00052 void *alloca();
00053 # endif
00054 # endif
00055 # endif
00056 #endif
00057
00058 #ifdef HAVE_DL_ITERATE_PHDR
00059 # ifndef _GNU_SOURCE
00060 # define _GNU_SOURCE
00061 # endif
00062 # include <link.h>
00063 #endif
00064
00065 #define DW_LNS_copy 0x01
00066 #define DW_LNS_advance_pc 0x02
00067 #define DW_LNS_advance_line 0x03
00068 #define DW_LNS_set_file 0x04
00069 #define DW_LNS_set_column 0x05
00070 #define DW_LNS_negate_stmt 0x06
00071 #define DW_LNS_set_basic_block 0x07
00072 #define DW_LNS_const_add_pc 0x08
00073 #define DW_LNS_fixed_advance_pc 0x09
00074 #define DW_LNS_set_prologue_end 0x0a
00075 #define DW_LNS_set_epilogue_begin 0x0b
00076 #define DW_LNS_set_isa 0x0c
00077
00078
00079 #define DW_LNE_end_sequence 0x01
00080 #define DW_LNE_set_address 0x02
00081 #define DW_LNE_define_file 0x03
00082 #define DW_LNE_set_discriminator 0x04
00083
00084 #ifndef ElfW
00085 # if SIZEOF_VOIDP == 8
00086 # define ElfW(x) Elf64##_##x
00087 # else
00088 # define ElfW(x) Elf32##_##x
00089 # endif
00090 #endif
00091 #ifndef PATH_MAX
00092 #define PATH_MAX 4096
00093 #endif
00094
00095 int kprintf(const char *fmt, ...);
00096
00097 typedef struct {
00098 const char *dirname;
00099 const char *filename;
00100 int line;
00101
00102 int fd;
00103 void *mapped;
00104 size_t mapped_size;
00105 unsigned long base_addr;
00106 } line_info_t;
00107
00108
00109 static char binary_filename[PATH_MAX];
00110
00111 static unsigned long
00112 uleb128(char **p)
00113 {
00114 unsigned long r = 0;
00115 int s = 0;
00116 for (;;) {
00117 unsigned char b = *(unsigned char *)(*p)++;
00118 if (b < 0x80) {
00119 r += (unsigned long)b << s;
00120 break;
00121 }
00122 r += (b & 0x7f) << s;
00123 s += 7;
00124 }
00125 return r;
00126 }
00127
00128 static long
00129 sleb128(char **p)
00130 {
00131 long r = 0;
00132 int s = 0;
00133 for (;;) {
00134 unsigned char b = *(unsigned char *)(*p)++;
00135 if (b < 0x80) {
00136 if (b & 0x40) {
00137 r -= (0x80 - b) << s;
00138 }
00139 else {
00140 r += (b & 0x3f) << s;
00141 }
00142 break;
00143 }
00144 r += (b & 0x7f) << s;
00145 s += 7;
00146 }
00147 return r;
00148 }
00149
00150 static const char *
00151 get_nth_dirname(unsigned long dir, char *p)
00152 {
00153 if (!dir--) {
00154 return "";
00155 }
00156 while (dir--) {
00157 while (*p) p++;
00158 p++;
00159 if (!*p) {
00160 kprintf("Unexpected directory number %lu in %s\n",
00161 dir, binary_filename);
00162 return "";
00163 }
00164 }
00165 return p;
00166 }
00167
00168 static void
00169 fill_filename(int file, char *include_directories, char *filenames,
00170 line_info_t *line)
00171 {
00172 int i;
00173 char *p = filenames;
00174 char *filename;
00175 unsigned long dir;
00176 for (i = 1; i <= file; i++) {
00177 filename = p;
00178 if (!*p) {
00179
00180 kprintf("Unexpected file number %d in %s\n",
00181 file, binary_filename);
00182 return;
00183 }
00184 while (*p) p++;
00185 p++;
00186 dir = uleb128(&p);
00187
00188 uleb128(&p);
00189
00190 uleb128(&p);
00191
00192 if (i == file) {
00193 line->filename = filename;
00194 line->dirname = get_nth_dirname(dir, include_directories);
00195 }
00196 }
00197 }
00198
00199 static int
00200 get_path_from_symbol(const char *symbol, const char **p, size_t *len)
00201 {
00202 if (symbol[0] == '0') {
00203
00204 *p = strchr(symbol, '/');
00205 if (*p == NULL) return 0;
00206 *len = strlen(*p);
00207 }
00208 else {
00209
00210 const char *q;
00211 *p = symbol;
00212 q = strchr(symbol, '(');
00213 if (q == NULL) return 0;
00214 *len = q - symbol;
00215 }
00216 return 1;
00217 }
00218
00219 static void
00220 fill_line(int num_traces, void **traces,
00221 unsigned long addr, int file, int line,
00222 char *include_directories, char *filenames, line_info_t *lines)
00223 {
00224 int i;
00225 for (i = 0; i < num_traces; i++) {
00226 unsigned long a = (unsigned long)traces[i] - lines[i].base_addr;
00227
00228
00229 if (addr < a && a < addr + 100) {
00230 fill_filename(file, include_directories, filenames, &lines[i]);
00231 lines[i].line = line;
00232 }
00233 }
00234 }
00235
00236 static void
00237 parse_debug_line_cu(int num_traces, void **traces,
00238 char **debug_line, line_info_t *lines)
00239 {
00240 char *p, *cu_end, *cu_start, *include_directories, *filenames;
00241 unsigned long unit_length;
00242 int default_is_stmt, line_base;
00243 unsigned int header_length, minimum_instruction_length, line_range,
00244 opcode_base;
00245
00246
00247
00248 unsigned long addr = 0;
00249 unsigned int file = 1;
00250 unsigned int line = 1;
00251
00252 int is_stmt;
00253
00254
00255
00256
00257
00258
00259 p = *debug_line;
00260
00261 unit_length = *(unsigned int *)p;
00262 p += sizeof(unsigned int);
00263 if (unit_length == 0xffffffff) {
00264 unit_length = *(unsigned long *)p;
00265 p += sizeof(unsigned long);
00266 }
00267
00268 cu_end = p + unit_length;
00269
00270
00271 p += 2;
00272
00273 header_length = *(unsigned int *)p;
00274 p += sizeof(unsigned int);
00275
00276 cu_start = p + header_length;
00277
00278 minimum_instruction_length = *(unsigned char *)p;
00279 p++;
00280
00281 is_stmt = default_is_stmt = *(unsigned char *)p;
00282 p++;
00283
00284 line_base = *(char *)p;
00285 p++;
00286
00287 line_range = *(unsigned char *)p;
00288 p++;
00289
00290 opcode_base = *(unsigned char *)p;
00291 p++;
00292
00293
00294 p += opcode_base - 1;
00295
00296 include_directories = p;
00297
00298
00299 while (*p) {
00300 while (*p) p++;
00301 p++;
00302 }
00303 p++;
00304
00305 filenames = p;
00306
00307 p = cu_start;
00308
00309 #define FILL_LINE() \
00310 do { \
00311 fill_line(num_traces, traces, addr, file, line, \
00312 include_directories, filenames, lines); \
00313 \
00314 } while (0)
00315
00316 while (p < cu_end) {
00317 unsigned long a;
00318 unsigned char op = *p++;
00319 switch (op) {
00320 case DW_LNS_copy:
00321 FILL_LINE();
00322 break;
00323 case DW_LNS_advance_pc:
00324 a = uleb128(&p);
00325 addr += a;
00326 break;
00327 case DW_LNS_advance_line: {
00328 long a = sleb128(&p);
00329 line += a;
00330 break;
00331 }
00332 case DW_LNS_set_file:
00333 file = (unsigned int)uleb128(&p);
00334 break;
00335 case DW_LNS_set_column:
00336 (void)uleb128(&p);
00337 break;
00338 case DW_LNS_negate_stmt:
00339 is_stmt = !is_stmt;
00340 break;
00341 case DW_LNS_set_basic_block:
00342
00343 break;
00344 case DW_LNS_const_add_pc:
00345 a = ((255 - opcode_base) / line_range) *
00346 minimum_instruction_length;
00347 addr += a;
00348 break;
00349 case DW_LNS_fixed_advance_pc:
00350 a = *(unsigned char *)p++;
00351 addr += a;
00352 break;
00353 case DW_LNS_set_prologue_end:
00354
00355 break;
00356 case DW_LNS_set_epilogue_begin:
00357
00358 break;
00359 case DW_LNS_set_isa:
00360 (void)uleb128(&p);
00361 break;
00362 case 0:
00363 a = *(unsigned char *)p++;
00364 op = *p++;
00365 switch (op) {
00366 case DW_LNE_end_sequence:
00367
00368 FILL_LINE();
00369 addr = 0;
00370 file = 1;
00371 line = 1;
00372
00373 is_stmt = default_is_stmt;
00374
00375
00376 break;
00377 case DW_LNE_set_address:
00378 addr = *(unsigned long *)p;
00379 p += sizeof(unsigned long);
00380 break;
00381 case DW_LNE_define_file:
00382 kprintf("Unsupported operation in %s\n",
00383 binary_filename);
00384 break;
00385 case DW_LNE_set_discriminator:
00386
00387 uleb128(&p);
00388 break;
00389 default:
00390 kprintf("Unknown extended opcode: %d in %s\n",
00391 op, binary_filename);
00392 }
00393 break;
00394 default: {
00395 unsigned long addr_incr;
00396 unsigned long line_incr;
00397 a = op - opcode_base;
00398 addr_incr = (a / line_range) * minimum_instruction_length;
00399 line_incr = line_base + (a % line_range);
00400 addr += (unsigned int)addr_incr;
00401 line += (unsigned int)line_incr;
00402 FILL_LINE();
00403 }
00404 }
00405 }
00406 *debug_line = p;
00407 }
00408
00409 static void
00410 parse_debug_line(int num_traces, void **traces,
00411 char *debug_line, unsigned long size, line_info_t *lines)
00412 {
00413 char *debug_line_end = debug_line + size;
00414 while (debug_line < debug_line_end) {
00415 parse_debug_line_cu(num_traces, traces, &debug_line, lines);
00416 }
00417 if (debug_line != debug_line_end) {
00418 kprintf("Unexpected size of .debug_line in %s\n",
00419 binary_filename);
00420 }
00421 }
00422
00423
00424 static void
00425 fill_lines(int num_traces, void **traces, char **syms, int check_debuglink,
00426 line_info_t *current_line, line_info_t *lines);
00427
00428 static void
00429 follow_debuglink(char *debuglink, int num_traces, void **traces, char **syms,
00430 line_info_t *current_line, line_info_t *lines)
00431 {
00432
00433
00434
00435 static const char global_debug_dir[] = "/usr/lib/debug";
00436 char *p, *subdir;
00437
00438 p = strrchr(binary_filename, '/');
00439 if (!p) {
00440 return;
00441 }
00442 p[1] = '\0';
00443
00444 subdir = (char *)alloca(strlen(binary_filename) + 1);
00445 strcpy(subdir, binary_filename);
00446 strcpy(binary_filename, global_debug_dir);
00447 strncat(binary_filename, subdir,
00448 PATH_MAX - strlen(binary_filename) - 1);
00449 strncat(binary_filename, debuglink,
00450 PATH_MAX - strlen(binary_filename) - 1);
00451
00452 munmap(current_line->mapped, current_line->mapped_size);
00453 close(current_line->fd);
00454 fill_lines(num_traces, traces, syms, 0, current_line, lines);
00455 }
00456
00457
00458 static void
00459 fill_lines(int num_traces, void **traces, char **syms, int check_debuglink,
00460 line_info_t *current_line, line_info_t *lines)
00461 {
00462 int i;
00463 char *shstr;
00464 char *section_name;
00465 ElfW(Ehdr) *ehdr;
00466 ElfW(Shdr) *shdr, *shstr_shdr;
00467 ElfW(Shdr) *debug_line_shdr = NULL, *gnu_debuglink_shdr = NULL;
00468 int fd;
00469 off_t filesize;
00470 char *file;
00471
00472 fd = open(binary_filename, O_RDONLY);
00473 if (fd < 0) {
00474 return;
00475 }
00476 filesize = lseek(fd, 0, SEEK_END);
00477 if (filesize < 0) {
00478 int e = errno;
00479 close(fd);
00480 kprintf("lseek: %s\n", strerror(e));
00481 return;
00482 }
00483 #if SIZEOF_OFF_T > SIZEOF_SIZE_T
00484 if (filesize > (off_t)SIZE_MAX) {
00485 close(fd);
00486 kprintf("Too large file %s\n", binary_filename);
00487 return;
00488 }
00489 #endif
00490 lseek(fd, 0, SEEK_SET);
00491
00492 file = (char *)mmap(NULL, (size_t)filesize, PROT_READ, MAP_SHARED, fd, 0);
00493 if (file == MAP_FAILED) {
00494 int e = errno;
00495 close(fd);
00496 kprintf("mmap: %s\n", strerror(e));
00497 return;
00498 }
00499
00500 ehdr = (ElfW(Ehdr) *)file;
00501 if (memcmp(ehdr->e_ident, "\177ELF", 4) != 0) {
00502
00503
00504
00505
00506 close(fd);
00507 return;
00508 }
00509
00510 current_line->fd = fd;
00511 current_line->mapped = file;
00512 current_line->mapped_size = (size_t)filesize;
00513
00514 for (i = 0; i < num_traces; i++) {
00515 const char *path;
00516 size_t len;
00517 if (get_path_from_symbol(syms[i], &path, &len) &&
00518 !strncmp(path, binary_filename, len)) {
00519 lines[i].line = -1;
00520 }
00521 }
00522
00523 shdr = (ElfW(Shdr) *)(file + ehdr->e_shoff);
00524
00525 shstr_shdr = shdr + ehdr->e_shstrndx;
00526 shstr = file + shstr_shdr->sh_offset;
00527
00528 for (i = 0; i < ehdr->e_shnum; i++) {
00529 section_name = shstr + shdr[i].sh_name;
00530 if (!strcmp(section_name, ".debug_line")) {
00531 debug_line_shdr = shdr + i;
00532 break;
00533 } else if (!strcmp(section_name, ".gnu_debuglink")) {
00534 gnu_debuglink_shdr = shdr + i;
00535 }
00536 }
00537
00538 if (!debug_line_shdr) {
00539
00540
00541 if (gnu_debuglink_shdr && check_debuglink) {
00542 follow_debuglink(file + gnu_debuglink_shdr->sh_offset,
00543 num_traces, traces, syms,
00544 current_line, lines);
00545 }
00546 return;
00547 }
00548
00549 parse_debug_line(num_traces, traces,
00550 file + debug_line_shdr->sh_offset,
00551 debug_line_shdr->sh_size,
00552 lines);
00553 }
00554
00555 #ifdef HAVE_DL_ITERATE_PHDR
00556
00557 typedef struct {
00558 int num_traces;
00559 char **syms;
00560 line_info_t *lines;
00561 } fill_base_addr_state_t;
00562
00563 static int
00564 fill_base_addr(struct dl_phdr_info *info, size_t size, void *data)
00565 {
00566 int i;
00567 fill_base_addr_state_t *st = (fill_base_addr_state_t *)data;
00568 for (i = 0; i < st->num_traces; i++) {
00569 const char *path;
00570 size_t len;
00571 size_t name_len = strlen(info->dlpi_name);
00572
00573 if (get_path_from_symbol(st->syms[i], &path, &len) &&
00574 (len == name_len || (len > name_len && path[len-name_len-1] == '/')) &&
00575 !strncmp(path+len-name_len, info->dlpi_name, name_len)) {
00576 st->lines[i].base_addr = info->dlpi_addr;
00577 }
00578 }
00579 return 0;
00580 }
00581
00582 #endif
00583
00584 void
00585 rb_dump_backtrace_with_lines(int num_traces, void **trace, char **syms)
00586 {
00587 int i;
00588
00589 line_info_t *lines = (line_info_t *)calloc(num_traces,
00590 sizeof(line_info_t));
00591
00592
00593
00594 #ifdef HAVE_DL_ITERATE_PHDR
00595 fill_base_addr_state_t fill_base_addr_state;
00596
00597 fill_base_addr_state.num_traces = num_traces;
00598 fill_base_addr_state.syms = syms;
00599 fill_base_addr_state.lines = lines;
00600
00601 dl_iterate_phdr(fill_base_addr, &fill_base_addr_state);
00602 #endif
00603
00604 for (i = 0; i < num_traces; i++) {
00605 const char *path;
00606 size_t len;
00607 if (lines[i].line) {
00608 continue;
00609 }
00610
00611 if (!get_path_from_symbol(syms[i], &path, &len)) {
00612 continue;
00613 }
00614
00615 strncpy(binary_filename, path, len);
00616 binary_filename[len] = '\0';
00617
00618 fill_lines(num_traces, trace, syms, 1, &lines[i], lines);
00619 }
00620
00621 for (i = 0; i < num_traces; i++) {
00622 line_info_t *line = &lines[i];
00623
00624 if (line->line > 0) {
00625 if (line->filename) {
00626 if (line->dirname && line->dirname[0]) {
00627 kprintf("%s %s/%s:%d\n", syms[i], line->dirname, line->filename, line->line);
00628 }
00629 else {
00630 kprintf("%s %s:%d\n", syms[i], line->filename, line->line);
00631 }
00632 } else {
00633 kprintf("%s ???:%d\n", syms[i], line->line);
00634 }
00635 } else {
00636 kprintf("%s\n", syms[i]);
00637 }
00638 }
00639
00640 for (i = 0; i < num_traces; i++) {
00641 line_info_t *line = &lines[i];
00642 if (line->fd) {
00643 munmap(line->mapped, line->mapped_size);
00644 close(line->fd);
00645 }
00646 }
00647 free(lines);
00648 }
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687 #include <stdarg.h>
00688 #define MAXNBUF (sizeof(intmax_t) * CHAR_BIT + 1)
00689 extern int rb_toupper(int c);
00690 #define toupper(c) rb_toupper(c)
00691 #define hex2ascii(hex) (hex2ascii_data[hex])
00692 char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
00693 static inline int imax(int a, int b) { return (a > b ? a : b); }
00694 static int kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap);
00695
00696 static void putce(int c)
00697 {
00698 char s[1];
00699 ssize_t ret;
00700
00701 s[0] = (char)c;
00702 ret = write(2, s, 1);
00703 (void)ret;
00704 }
00705
00706 int
00707 kprintf(const char *fmt, ...)
00708 {
00709 va_list ap;
00710 int retval;
00711
00712 va_start(ap, fmt);
00713 retval = kvprintf(fmt, putce, NULL, 10, ap);
00714 va_end(ap);
00715 return retval;
00716 }
00717
00718
00719
00720
00721
00722
00723
00724 static char *
00725 ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
00726 {
00727 char *p, c;
00728
00729 p = nbuf;
00730 *p = '\0';
00731 do {
00732 c = hex2ascii(num % base);
00733 *++p = upper ? toupper(c) : c;
00734 } while (num /= base);
00735 if (lenp)
00736 *lenp = (int)(p - nbuf);
00737 return (p);
00738 }
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766 static int
00767 kvprintf(char const *fmt, void (*func)(int), void *arg, int radix, va_list ap)
00768 {
00769 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc); else *d++ = cc; retval++; }
00770 char nbuf[MAXNBUF];
00771 char *d;
00772 const char *p, *percent, *q;
00773 unsigned char *up;
00774 int ch, n;
00775 uintmax_t num;
00776 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
00777 int cflag, hflag, jflag, tflag, zflag;
00778 int dwidth, upper;
00779 char padc;
00780 int stop = 0, retval = 0;
00781
00782 num = 0;
00783 if (!func)
00784 d = (char *) arg;
00785 else
00786 d = NULL;
00787
00788 if (fmt == NULL)
00789 fmt = "(fmt null)\n";
00790
00791 if (radix < 2 || radix > 36)
00792 radix = 10;
00793
00794 for (;;) {
00795 padc = ' ';
00796 width = 0;
00797 while ((ch = (unsigned char)*fmt++) != '%' || stop) {
00798 if (ch == '\0')
00799 return (retval);
00800 PCHAR(ch);
00801 }
00802 percent = fmt - 1;
00803 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
00804 sign = 0; dot = 0; dwidth = 0; upper = 0;
00805 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
00806 reswitch: switch (ch = (unsigned char)*fmt++) {
00807 case '.':
00808 dot = 1;
00809 goto reswitch;
00810 case '#':
00811 sharpflag = 1;
00812 goto reswitch;
00813 case '+':
00814 sign = 1;
00815 goto reswitch;
00816 case '-':
00817 ladjust = 1;
00818 goto reswitch;
00819 case '%':
00820 PCHAR(ch);
00821 break;
00822 case '*':
00823 if (!dot) {
00824 width = va_arg(ap, int);
00825 if (width < 0) {
00826 ladjust = !ladjust;
00827 width = -width;
00828 }
00829 } else {
00830 dwidth = va_arg(ap, int);
00831 }
00832 goto reswitch;
00833 case '0':
00834 if (!dot) {
00835 padc = '0';
00836 goto reswitch;
00837 }
00838 case '1': case '2': case '3': case '4':
00839 case '5': case '6': case '7': case '8': case '9':
00840 for (n = 0;; ++fmt) {
00841 n = n * 10 + ch - '0';
00842 ch = *fmt;
00843 if (ch < '0' || ch > '9')
00844 break;
00845 }
00846 if (dot)
00847 dwidth = n;
00848 else
00849 width = n;
00850 goto reswitch;
00851 case 'b':
00852 num = (unsigned int)va_arg(ap, int);
00853 p = va_arg(ap, char *);
00854 for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
00855 PCHAR(*q--);
00856
00857 if (num == 0)
00858 break;
00859
00860 for (tmp = 0; *p;) {
00861 n = *p++;
00862 if (num & (1 << (n - 1))) {
00863 PCHAR(tmp ? ',' : '<');
00864 for (; (n = *p) > ' '; ++p)
00865 PCHAR(n);
00866 tmp = 1;
00867 } else
00868 for (; *p > ' '; ++p)
00869 continue;
00870 }
00871 if (tmp)
00872 PCHAR('>');
00873 break;
00874 case 'c':
00875 PCHAR(va_arg(ap, int));
00876 break;
00877 case 'D':
00878 up = va_arg(ap, unsigned char *);
00879 p = va_arg(ap, char *);
00880 if (!width)
00881 width = 16;
00882 while(width--) {
00883 PCHAR(hex2ascii(*up >> 4));
00884 PCHAR(hex2ascii(*up & 0x0f));
00885 up++;
00886 if (width)
00887 for (q=p;*q;q++)
00888 PCHAR(*q);
00889 }
00890 break;
00891 case 'd':
00892 case 'i':
00893 base = 10;
00894 sign = 1;
00895 goto handle_sign;
00896 case 'h':
00897 if (hflag) {
00898 hflag = 0;
00899 cflag = 1;
00900 } else
00901 hflag = 1;
00902 goto reswitch;
00903 case 'j':
00904 jflag = 1;
00905 goto reswitch;
00906 case 'l':
00907 if (lflag) {
00908 lflag = 0;
00909 qflag = 1;
00910 } else
00911 lflag = 1;
00912 goto reswitch;
00913 case 'n':
00914 if (jflag)
00915 *(va_arg(ap, intmax_t *)) = retval;
00916 else if (qflag)
00917 *(va_arg(ap, int64_t *)) = retval;
00918 else if (lflag)
00919 *(va_arg(ap, long *)) = retval;
00920 else if (zflag)
00921 *(va_arg(ap, size_t *)) = retval;
00922 else if (hflag)
00923 *(va_arg(ap, short *)) = retval;
00924 else if (cflag)
00925 *(va_arg(ap, char *)) = retval;
00926 else
00927 *(va_arg(ap, int *)) = retval;
00928 break;
00929 case 'o':
00930 base = 8;
00931 goto handle_nosign;
00932 case 'p':
00933 base = 16;
00934 sharpflag = (width == 0);
00935 sign = 0;
00936 num = (uintptr_t)va_arg(ap, void *);
00937 goto number;
00938 case 'q':
00939 qflag = 1;
00940 goto reswitch;
00941 case 'r':
00942 base = radix;
00943 if (sign)
00944 goto handle_sign;
00945 goto handle_nosign;
00946 case 's':
00947 p = va_arg(ap, char *);
00948 if (p == NULL)
00949 p = "(null)";
00950 if (!dot)
00951 n = (int)strlen (p);
00952 else
00953 for (n = 0; n < dwidth && p[n]; n++)
00954 continue;
00955
00956 width -= n;
00957
00958 if (!ladjust && width > 0)
00959 while (width--)
00960 PCHAR(padc);
00961 while (n--)
00962 PCHAR(*p++);
00963 if (ladjust && width > 0)
00964 while (width--)
00965 PCHAR(padc);
00966 break;
00967 case 't':
00968 tflag = 1;
00969 goto reswitch;
00970 case 'u':
00971 base = 10;
00972 goto handle_nosign;
00973 case 'X':
00974 upper = 1;
00975 case 'x':
00976 base = 16;
00977 goto handle_nosign;
00978 case 'y':
00979 base = 16;
00980 sign = 1;
00981 goto handle_sign;
00982 case 'z':
00983 zflag = 1;
00984 goto reswitch;
00985 handle_nosign:
00986 sign = 0;
00987 if (jflag)
00988 num = va_arg(ap, uintmax_t);
00989 else if (qflag)
00990 num = va_arg(ap, uint64_t);
00991 else if (tflag)
00992 num = va_arg(ap, ptrdiff_t);
00993 else if (lflag)
00994 num = va_arg(ap, unsigned long);
00995 else if (zflag)
00996 num = va_arg(ap, size_t);
00997 else if (hflag)
00998 num = (unsigned short)va_arg(ap, int);
00999 else if (cflag)
01000 num = (unsigned char)va_arg(ap, int);
01001 else
01002 num = va_arg(ap, unsigned int);
01003 goto number;
01004 handle_sign:
01005 if (jflag)
01006 num = va_arg(ap, intmax_t);
01007 else if (qflag)
01008 num = va_arg(ap, int64_t);
01009 else if (tflag)
01010 num = va_arg(ap, ptrdiff_t);
01011 else if (lflag)
01012 num = va_arg(ap, long);
01013 else if (zflag)
01014 num = va_arg(ap, ssize_t);
01015 else if (hflag)
01016 num = (short)va_arg(ap, int);
01017 else if (cflag)
01018 num = (char)va_arg(ap, int);
01019 else
01020 num = va_arg(ap, int);
01021 number:
01022 if (sign && (intmax_t)num < 0) {
01023 neg = 1;
01024 num = -(intmax_t)num;
01025 }
01026 p = ksprintn(nbuf, num, base, &n, upper);
01027 tmp = 0;
01028 if (sharpflag && num != 0) {
01029 if (base == 8)
01030 tmp++;
01031 else if (base == 16)
01032 tmp += 2;
01033 }
01034 if (neg)
01035 tmp++;
01036
01037 if (!ladjust && padc == '0')
01038 dwidth = width - tmp;
01039 width -= tmp + imax(dwidth, n);
01040 dwidth -= n;
01041 if (!ladjust)
01042 while (width-- > 0)
01043 PCHAR(' ');
01044 if (neg)
01045 PCHAR('-');
01046 if (sharpflag && num != 0) {
01047 if (base == 8) {
01048 PCHAR('0');
01049 } else if (base == 16) {
01050 PCHAR('0');
01051 PCHAR('x');
01052 }
01053 }
01054 while (dwidth-- > 0)
01055 PCHAR('0');
01056
01057 while (*p)
01058 PCHAR(*p--);
01059
01060 if (ladjust)
01061 while (width-- > 0)
01062 PCHAR(' ');
01063
01064 break;
01065 default:
01066 while (percent < fmt)
01067 PCHAR(*percent++);
01068
01069
01070
01071
01072
01073
01074 stop = 1;
01075 break;
01076 }
01077 }
01078 #undef PCHAR
01079 }
01080 #else
01081 #error not supported
01082 #endif
01083