diff options
Diffstat (limited to 'lib/vsprintf.c')
-rw-r--r-- | lib/vsprintf.c | 110 |
1 files changed, 72 insertions, 38 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index b235c96167d3..3a1e0843f9a2 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -17,6 +17,7 @@ | |||
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <stdarg.h> | 19 | #include <stdarg.h> |
20 | #include <linux/clk-provider.h> | ||
20 | #include <linux/module.h> /* for KSYM_SYMBOL_LEN */ | 21 | #include <linux/module.h> /* for KSYM_SYMBOL_LEN */ |
21 | #include <linux/types.h> | 22 | #include <linux/types.h> |
22 | #include <linux/string.h> | 23 | #include <linux/string.h> |
@@ -340,11 +341,11 @@ int num_to_str(char *buf, int size, unsigned long long num) | |||
340 | return len; | 341 | return len; |
341 | } | 342 | } |
342 | 343 | ||
343 | #define ZEROPAD 1 /* pad with zero */ | 344 | #define SIGN 1 /* unsigned/signed, must be 1 */ |
344 | #define SIGN 2 /* unsigned/signed long */ | 345 | #define LEFT 2 /* left justified */ |
345 | #define PLUS 4 /* show plus */ | 346 | #define PLUS 4 /* show plus */ |
346 | #define SPACE 8 /* space if plus */ | 347 | #define SPACE 8 /* space if plus */ |
347 | #define LEFT 16 /* left justified */ | 348 | #define ZEROPAD 16 /* pad with zero, must be 16 == '0' - ' ' */ |
348 | #define SMALL 32 /* use lowercase in hex (must be 32 == 0x20) */ | 349 | #define SMALL 32 /* use lowercase in hex (must be 32 == 0x20) */ |
349 | #define SPECIAL 64 /* prefix hex with "0x", octal with "0" */ | 350 | #define SPECIAL 64 /* prefix hex with "0x", octal with "0" */ |
350 | 351 | ||
@@ -383,10 +384,7 @@ static noinline_for_stack | |||
383 | char *number(char *buf, char *end, unsigned long long num, | 384 | char *number(char *buf, char *end, unsigned long long num, |
384 | struct printf_spec spec) | 385 | struct printf_spec spec) |
385 | { | 386 | { |
386 | /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ | 387 | char tmp[3 * sizeof(num)]; |
387 | static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ | ||
388 | |||
389 | char tmp[66]; | ||
390 | char sign; | 388 | char sign; |
391 | char locase; | 389 | char locase; |
392 | int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); | 390 | int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); |
@@ -422,12 +420,7 @@ char *number(char *buf, char *end, unsigned long long num, | |||
422 | /* generate full string in tmp[], in reverse order */ | 420 | /* generate full string in tmp[], in reverse order */ |
423 | i = 0; | 421 | i = 0; |
424 | if (num < spec.base) | 422 | if (num < spec.base) |
425 | tmp[i++] = digits[num] | locase; | 423 | tmp[i++] = hex_asc_upper[num] | locase; |
426 | /* Generic code, for any base: | ||
427 | else do { | ||
428 | tmp[i++] = (digits[do_div(num,base)] | locase); | ||
429 | } while (num != 0); | ||
430 | */ | ||
431 | else if (spec.base != 10) { /* 8 or 16 */ | 424 | else if (spec.base != 10) { /* 8 or 16 */ |
432 | int mask = spec.base - 1; | 425 | int mask = spec.base - 1; |
433 | int shift = 3; | 426 | int shift = 3; |
@@ -435,7 +428,7 @@ char *number(char *buf, char *end, unsigned long long num, | |||
435 | if (spec.base == 16) | 428 | if (spec.base == 16) |
436 | shift = 4; | 429 | shift = 4; |
437 | do { | 430 | do { |
438 | tmp[i++] = (digits[((unsigned char)num) & mask] | locase); | 431 | tmp[i++] = (hex_asc_upper[((unsigned char)num) & mask] | locase); |
439 | num >>= shift; | 432 | num >>= shift; |
440 | } while (num); | 433 | } while (num); |
441 | } else { /* base 10 */ | 434 | } else { /* base 10 */ |
@@ -447,7 +440,7 @@ char *number(char *buf, char *end, unsigned long long num, | |||
447 | spec.precision = i; | 440 | spec.precision = i; |
448 | /* leading space padding */ | 441 | /* leading space padding */ |
449 | spec.field_width -= spec.precision; | 442 | spec.field_width -= spec.precision; |
450 | if (!(spec.flags & (ZEROPAD+LEFT))) { | 443 | if (!(spec.flags & (ZEROPAD | LEFT))) { |
451 | while (--spec.field_width >= 0) { | 444 | while (--spec.field_width >= 0) { |
452 | if (buf < end) | 445 | if (buf < end) |
453 | *buf = ' '; | 446 | *buf = ' '; |
@@ -475,7 +468,8 @@ char *number(char *buf, char *end, unsigned long long num, | |||
475 | } | 468 | } |
476 | /* zero or space padding */ | 469 | /* zero or space padding */ |
477 | if (!(spec.flags & LEFT)) { | 470 | if (!(spec.flags & LEFT)) { |
478 | char c = (spec.flags & ZEROPAD) ? '0' : ' '; | 471 | char c = ' ' + (spec.flags & ZEROPAD); |
472 | BUILD_BUG_ON(' ' + ZEROPAD != '0'); | ||
479 | while (--spec.field_width >= 0) { | 473 | while (--spec.field_width >= 0) { |
480 | if (buf < end) | 474 | if (buf < end) |
481 | *buf = c; | 475 | *buf = c; |
@@ -783,11 +777,19 @@ char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec, | |||
783 | if (spec.field_width > 0) | 777 | if (spec.field_width > 0) |
784 | len = min_t(int, spec.field_width, 64); | 778 | len = min_t(int, spec.field_width, 64); |
785 | 779 | ||
786 | for (i = 0; i < len && buf < end - 1; i++) { | 780 | for (i = 0; i < len; ++i) { |
787 | buf = hex_byte_pack(buf, addr[i]); | 781 | if (buf < end) |
782 | *buf = hex_asc_hi(addr[i]); | ||
783 | ++buf; | ||
784 | if (buf < end) | ||
785 | *buf = hex_asc_lo(addr[i]); | ||
786 | ++buf; | ||
788 | 787 | ||
789 | if (buf < end && separator && i != len - 1) | 788 | if (separator && i != len - 1) { |
790 | *buf++ = separator; | 789 | if (buf < end) |
790 | *buf = separator; | ||
791 | ++buf; | ||
792 | } | ||
791 | } | 793 | } |
792 | 794 | ||
793 | return buf; | 795 | return buf; |
@@ -1233,8 +1235,12 @@ char *escaped_string(char *buf, char *end, u8 *addr, struct printf_spec spec, | |||
1233 | 1235 | ||
1234 | len = spec.field_width < 0 ? 1 : spec.field_width; | 1236 | len = spec.field_width < 0 ? 1 : spec.field_width; |
1235 | 1237 | ||
1236 | /* Ignore the error. We print as many characters as we can */ | 1238 | /* |
1237 | string_escape_mem(addr, len, &buf, end - buf, flags, NULL); | 1239 | * string_escape_mem() writes as many characters as it can to |
1240 | * the given buffer, and returns the total size of the output | ||
1241 | * had the buffer been big enough. | ||
1242 | */ | ||
1243 | buf += string_escape_mem(addr, len, buf, buf < end ? end - buf : 0, flags, NULL); | ||
1238 | 1244 | ||
1239 | return buf; | 1245 | return buf; |
1240 | } | 1246 | } |
@@ -1322,6 +1328,30 @@ char *address_val(char *buf, char *end, const void *addr, | |||
1322 | return number(buf, end, num, spec); | 1328 | return number(buf, end, num, spec); |
1323 | } | 1329 | } |
1324 | 1330 | ||
1331 | static noinline_for_stack | ||
1332 | char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec, | ||
1333 | const char *fmt) | ||
1334 | { | ||
1335 | if (!IS_ENABLED(CONFIG_HAVE_CLK) || !clk) | ||
1336 | return string(buf, end, NULL, spec); | ||
1337 | |||
1338 | switch (fmt[1]) { | ||
1339 | case 'r': | ||
1340 | return number(buf, end, clk_get_rate(clk), spec); | ||
1341 | |||
1342 | case 'n': | ||
1343 | default: | ||
1344 | #ifdef CONFIG_COMMON_CLK | ||
1345 | return string(buf, end, __clk_get_name(clk), spec); | ||
1346 | #else | ||
1347 | spec.base = 16; | ||
1348 | spec.field_width = sizeof(unsigned long) * 2 + 2; | ||
1349 | spec.flags |= SPECIAL | SMALL | ZEROPAD; | ||
1350 | return number(buf, end, (unsigned long)clk, spec); | ||
1351 | #endif | ||
1352 | } | ||
1353 | } | ||
1354 | |||
1325 | int kptr_restrict __read_mostly; | 1355 | int kptr_restrict __read_mostly; |
1326 | 1356 | ||
1327 | /* | 1357 | /* |
@@ -1404,6 +1434,11 @@ int kptr_restrict __read_mostly; | |||
1404 | * (default assumed to be phys_addr_t, passed by reference) | 1434 | * (default assumed to be phys_addr_t, passed by reference) |
1405 | * - 'd[234]' For a dentry name (optionally 2-4 last components) | 1435 | * - 'd[234]' For a dentry name (optionally 2-4 last components) |
1406 | * - 'D[234]' Same as 'd' but for a struct file | 1436 | * - 'D[234]' Same as 'd' but for a struct file |
1437 | * - 'C' For a clock, it prints the name (Common Clock Framework) or address | ||
1438 | * (legacy clock framework) of the clock | ||
1439 | * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address | ||
1440 | * (legacy clock framework) of the clock | ||
1441 | * - 'Cr' For a clock, it prints the current rate of the clock | ||
1407 | * | 1442 | * |
1408 | * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 | 1443 | * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 |
1409 | * function pointers are really function descriptors, which contain a | 1444 | * function pointers are really function descriptors, which contain a |
@@ -1548,6 +1583,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, | |||
1548 | return address_val(buf, end, ptr, spec, fmt); | 1583 | return address_val(buf, end, ptr, spec, fmt); |
1549 | case 'd': | 1584 | case 'd': |
1550 | return dentry_name(buf, end, ptr, spec, fmt); | 1585 | return dentry_name(buf, end, ptr, spec, fmt); |
1586 | case 'C': | ||
1587 | return clock(buf, end, ptr, spec, fmt); | ||
1551 | case 'D': | 1588 | case 'D': |
1552 | return dentry_name(buf, end, | 1589 | return dentry_name(buf, end, |
1553 | ((const struct file *)ptr)->f_path.dentry, | 1590 | ((const struct file *)ptr)->f_path.dentry, |
@@ -1738,29 +1775,21 @@ qualifier: | |||
1738 | if (spec->qualifier == 'L') | 1775 | if (spec->qualifier == 'L') |
1739 | spec->type = FORMAT_TYPE_LONG_LONG; | 1776 | spec->type = FORMAT_TYPE_LONG_LONG; |
1740 | else if (spec->qualifier == 'l') { | 1777 | else if (spec->qualifier == 'l') { |
1741 | if (spec->flags & SIGN) | 1778 | BUILD_BUG_ON(FORMAT_TYPE_ULONG + SIGN != FORMAT_TYPE_LONG); |
1742 | spec->type = FORMAT_TYPE_LONG; | 1779 | spec->type = FORMAT_TYPE_ULONG + (spec->flags & SIGN); |
1743 | else | ||
1744 | spec->type = FORMAT_TYPE_ULONG; | ||
1745 | } else if (_tolower(spec->qualifier) == 'z') { | 1780 | } else if (_tolower(spec->qualifier) == 'z') { |
1746 | spec->type = FORMAT_TYPE_SIZE_T; | 1781 | spec->type = FORMAT_TYPE_SIZE_T; |
1747 | } else if (spec->qualifier == 't') { | 1782 | } else if (spec->qualifier == 't') { |
1748 | spec->type = FORMAT_TYPE_PTRDIFF; | 1783 | spec->type = FORMAT_TYPE_PTRDIFF; |
1749 | } else if (spec->qualifier == 'H') { | 1784 | } else if (spec->qualifier == 'H') { |
1750 | if (spec->flags & SIGN) | 1785 | BUILD_BUG_ON(FORMAT_TYPE_UBYTE + SIGN != FORMAT_TYPE_BYTE); |
1751 | spec->type = FORMAT_TYPE_BYTE; | 1786 | spec->type = FORMAT_TYPE_UBYTE + (spec->flags & SIGN); |
1752 | else | ||
1753 | spec->type = FORMAT_TYPE_UBYTE; | ||
1754 | } else if (spec->qualifier == 'h') { | 1787 | } else if (spec->qualifier == 'h') { |
1755 | if (spec->flags & SIGN) | 1788 | BUILD_BUG_ON(FORMAT_TYPE_USHORT + SIGN != FORMAT_TYPE_SHORT); |
1756 | spec->type = FORMAT_TYPE_SHORT; | 1789 | spec->type = FORMAT_TYPE_USHORT + (spec->flags & SIGN); |
1757 | else | ||
1758 | spec->type = FORMAT_TYPE_USHORT; | ||
1759 | } else { | 1790 | } else { |
1760 | if (spec->flags & SIGN) | 1791 | BUILD_BUG_ON(FORMAT_TYPE_UINT + SIGN != FORMAT_TYPE_INT); |
1761 | spec->type = FORMAT_TYPE_INT; | 1792 | spec->type = FORMAT_TYPE_UINT + (spec->flags & SIGN); |
1762 | else | ||
1763 | spec->type = FORMAT_TYPE_UINT; | ||
1764 | } | 1793 | } |
1765 | 1794 | ||
1766 | return ++fmt - start; | 1795 | return ++fmt - start; |
@@ -1800,6 +1829,11 @@ qualifier: | |||
1800 | * %*pE[achnops] print an escaped buffer | 1829 | * %*pE[achnops] print an escaped buffer |
1801 | * %*ph[CDN] a variable-length hex string with a separator (supports up to 64 | 1830 | * %*ph[CDN] a variable-length hex string with a separator (supports up to 64 |
1802 | * bytes of the input) | 1831 | * bytes of the input) |
1832 | * %pC output the name (Common Clock Framework) or address (legacy clock | ||
1833 | * framework) of a clock | ||
1834 | * %pCn output the name (Common Clock Framework) or address (legacy clock | ||
1835 | * framework) of a clock | ||
1836 | * %pCr output the current rate of a clock | ||
1803 | * %n is ignored | 1837 | * %n is ignored |
1804 | * | 1838 | * |
1805 | * ** Please update Documentation/printk-formats.txt when making changes ** | 1839 | * ** Please update Documentation/printk-formats.txt when making changes ** |