diff options
Diffstat (limited to 'lib/vsprintf.c')
| -rw-r--r-- | lib/vsprintf.c | 128 |
1 files changed, 93 insertions, 35 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 6021757a4496..1dc2d1d18fa8 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
| @@ -22,6 +22,8 @@ | |||
| 22 | #include <linux/string.h> | 22 | #include <linux/string.h> |
| 23 | #include <linux/ctype.h> | 23 | #include <linux/ctype.h> |
| 24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
| 25 | #include <linux/kallsyms.h> | ||
| 26 | #include <linux/uaccess.h> | ||
| 25 | 27 | ||
| 26 | #include <asm/page.h> /* for PAGE_SIZE */ | 28 | #include <asm/page.h> /* for PAGE_SIZE */ |
| 27 | #include <asm/div64.h> | 29 | #include <asm/div64.h> |
| @@ -482,6 +484,89 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int | |||
| 482 | return buf; | 484 | return buf; |
| 483 | } | 485 | } |
| 484 | 486 | ||
| 487 | static char *string(char *buf, char *end, char *s, int field_width, int precision, int flags) | ||
| 488 | { | ||
| 489 | int len, i; | ||
| 490 | |||
| 491 | if ((unsigned long)s < PAGE_SIZE) | ||
| 492 | s = "<NULL>"; | ||
| 493 | |||
| 494 | len = strnlen(s, precision); | ||
| 495 | |||
| 496 | if (!(flags & LEFT)) { | ||
| 497 | while (len < field_width--) { | ||
| 498 | if (buf < end) | ||
| 499 | *buf = ' '; | ||
| 500 | ++buf; | ||
| 501 | } | ||
| 502 | } | ||
| 503 | for (i = 0; i < len; ++i) { | ||
| 504 | if (buf < end) | ||
| 505 | *buf = *s; | ||
| 506 | ++buf; ++s; | ||
| 507 | } | ||
| 508 | while (len < field_width--) { | ||
| 509 | if (buf < end) | ||
| 510 | *buf = ' '; | ||
| 511 | ++buf; | ||
| 512 | } | ||
| 513 | return buf; | ||
| 514 | } | ||
| 515 | |||
| 516 | static inline void *dereference_function_descriptor(void *ptr) | ||
| 517 | { | ||
| 518 | #if defined(CONFIG_IA64) || defined(CONFIG_PPC64) | ||
| 519 | void *p; | ||
| 520 | if (!probe_kernel_address(ptr, p)) | ||
| 521 | ptr = p; | ||
| 522 | #endif | ||
| 523 | return ptr; | ||
| 524 | } | ||
| 525 | |||
| 526 | static char *symbol_string(char *buf, char *end, void *ptr, int field_width, int precision, int flags) | ||
| 527 | { | ||
| 528 | unsigned long value = (unsigned long) ptr; | ||
| 529 | #ifdef CONFIG_KALLSYMS | ||
| 530 | char sym[KSYM_SYMBOL_LEN]; | ||
| 531 | sprint_symbol(sym, value); | ||
| 532 | return string(buf, end, sym, field_width, precision, flags); | ||
| 533 | #else | ||
| 534 | field_width = 2*sizeof(void *); | ||
| 535 | flags |= SPECIAL | SMALL | ZEROPAD; | ||
| 536 | return number(buf, end, value, 16, field_width, precision, flags); | ||
| 537 | #endif | ||
| 538 | } | ||
| 539 | |||
| 540 | /* | ||
| 541 | * Show a '%p' thing. A kernel extension is that the '%p' is followed | ||
| 542 | * by an extra set of alphanumeric characters that are extended format | ||
| 543 | * specifiers. | ||
| 544 | * | ||
| 545 | * Right now we just handle 'F' (for symbolic Function descriptor pointers) | ||
| 546 | * and 'S' (for Symbolic direct pointers), but this can easily be | ||
| 547 | * extended in the future (network address types etc). | ||
| 548 | * | ||
| 549 | * The difference between 'S' and 'F' is that on ia64 and ppc64 function | ||
| 550 | * pointers are really function descriptors, which contain a pointer the | ||
| 551 | * real address. | ||
| 552 | */ | ||
| 553 | static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field_width, int precision, int flags) | ||
| 554 | { | ||
| 555 | switch (*fmt) { | ||
| 556 | case 'F': | ||
| 557 | ptr = dereference_function_descriptor(ptr); | ||
| 558 | /* Fallthrough */ | ||
| 559 | case 'S': | ||
| 560 | return symbol_string(buf, end, ptr, field_width, precision, flags); | ||
| 561 | } | ||
| 562 | flags |= SMALL; | ||
| 563 | if (field_width == -1) { | ||
| 564 | field_width = 2*sizeof(void *); | ||
| 565 | flags |= ZEROPAD; | ||
| 566 | } | ||
| 567 | return number(buf, end, (unsigned long) ptr, 16, field_width, precision, flags); | ||
| 568 | } | ||
| 569 | |||
| 485 | /** | 570 | /** |
| 486 | * vsnprintf - Format a string and place it in a buffer | 571 | * vsnprintf - Format a string and place it in a buffer |
| 487 | * @buf: The buffer to place the result into | 572 | * @buf: The buffer to place the result into |
| @@ -502,11 +587,9 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int | |||
| 502 | */ | 587 | */ |
| 503 | int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) | 588 | int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) |
| 504 | { | 589 | { |
| 505 | int len; | ||
| 506 | unsigned long long num; | 590 | unsigned long long num; |
| 507 | int i, base; | 591 | int base; |
| 508 | char *str, *end, c; | 592 | char *str, *end, c; |
| 509 | const char *s; | ||
| 510 | 593 | ||
| 511 | int flags; /* flags to number() */ | 594 | int flags; /* flags to number() */ |
| 512 | 595 | ||
| @@ -622,43 +705,18 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) | |||
| 622 | continue; | 705 | continue; |
| 623 | 706 | ||
| 624 | case 's': | 707 | case 's': |
| 625 | s = va_arg(args, char *); | 708 | str = string(str, end, va_arg(args, char *), field_width, precision, flags); |
| 626 | if ((unsigned long)s < PAGE_SIZE) | ||
| 627 | s = "<NULL>"; | ||
| 628 | |||
| 629 | len = strnlen(s, precision); | ||
| 630 | |||
| 631 | if (!(flags & LEFT)) { | ||
| 632 | while (len < field_width--) { | ||
| 633 | if (str < end) | ||
| 634 | *str = ' '; | ||
| 635 | ++str; | ||
| 636 | } | ||
| 637 | } | ||
| 638 | for (i = 0; i < len; ++i) { | ||
| 639 | if (str < end) | ||
| 640 | *str = *s; | ||
| 641 | ++str; ++s; | ||
| 642 | } | ||
| 643 | while (len < field_width--) { | ||
| 644 | if (str < end) | ||
| 645 | *str = ' '; | ||
| 646 | ++str; | ||
| 647 | } | ||
| 648 | continue; | 709 | continue; |
| 649 | 710 | ||
| 650 | case 'p': | 711 | case 'p': |
| 651 | flags |= SMALL; | 712 | str = pointer(fmt+1, str, end, |
| 652 | if (field_width == -1) { | 713 | va_arg(args, void *), |
| 653 | field_width = 2*sizeof(void *); | 714 | field_width, precision, flags); |
| 654 | flags |= ZEROPAD; | 715 | /* Skip all alphanumeric pointer suffixes */ |
| 655 | } | 716 | while (isalnum(fmt[1])) |
| 656 | str = number(str, end, | 717 | fmt++; |
| 657 | (unsigned long) va_arg(args, void *), | ||
| 658 | 16, field_width, precision, flags); | ||
| 659 | continue; | 718 | continue; |
| 660 | 719 | ||
| 661 | |||
| 662 | case 'n': | 720 | case 'n': |
| 663 | /* FIXME: | 721 | /* FIXME: |
| 664 | * What does C99 say about the overflow case here? */ | 722 | * What does C99 say about the overflow case here? */ |
