Blame view
lib/vsprintf.c
52.6 KB
1da177e4c
|
1 2 3 4 5 6 7 8 9 10 |
/* * linux/lib/vsprintf.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ /* * Wirzenius wrote this portably, Torvalds fucked it up :-) */ |
7b9186f5e
|
11 |
/* |
1da177e4c
|
12 13 14 15 16 17 18 |
* Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com> * - changed to provide snprintf and vsnprintf functions * So Feb 1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de> * - scnprintf and vscnprintf */ #include <stdarg.h> |
8bc3bcc93
|
19 |
#include <linux/module.h> /* for KSYM_SYMBOL_LEN */ |
1da177e4c
|
20 21 22 23 |
#include <linux/types.h> #include <linux/string.h> #include <linux/ctype.h> #include <linux/kernel.h> |
0fe1ef24f
|
24 25 |
#include <linux/kallsyms.h> #include <linux/uaccess.h> |
332d2e783
|
26 |
#include <linux/ioport.h> |
8a27f7c90
|
27 |
#include <net/addrconf.h> |
1da177e4c
|
28 |
|
4e57b6817
|
29 |
#include <asm/page.h> /* for PAGE_SIZE */ |
1da177e4c
|
30 |
#include <asm/div64.h> |
deac93df2
|
31 |
#include <asm/sections.h> /* for dereference_function_descriptor() */ |
1da177e4c
|
32 |
|
1dff46d69
|
33 |
#include "kstrtox.h" |
aa46a63ef
|
34 |
|
1da177e4c
|
35 |
/** |
922ac25c9
|
36 |
* simple_strtoull - convert a string to an unsigned long long |
1da177e4c
|
37 38 39 40 |
* @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use */ |
922ac25c9
|
41 |
unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base) |
1da177e4c
|
42 |
{ |
1dff46d69
|
43 44 |
unsigned long long result; unsigned int rv; |
aa46a63ef
|
45 |
|
1dff46d69
|
46 47 48 49 |
cp = _parse_integer_fixup_radix(cp, &base); rv = _parse_integer(cp, base, &result); /* FIXME */ cp += (rv & ~KSTRTOX_OVERFLOW); |
aa46a63ef
|
50 |
|
1da177e4c
|
51 52 |
if (endp) *endp = (char *)cp; |
7b9186f5e
|
53 |
|
1da177e4c
|
54 55 |
return result; } |
922ac25c9
|
56 |
EXPORT_SYMBOL(simple_strtoull); |
1da177e4c
|
57 58 |
/** |
922ac25c9
|
59 |
* simple_strtoul - convert a string to an unsigned long |
1da177e4c
|
60 61 62 63 |
* @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use */ |
922ac25c9
|
64 |
unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) |
1da177e4c
|
65 |
{ |
922ac25c9
|
66 |
return simple_strtoull(cp, endp, base); |
1da177e4c
|
67 |
} |
922ac25c9
|
68 |
EXPORT_SYMBOL(simple_strtoul); |
1da177e4c
|
69 70 |
/** |
922ac25c9
|
71 |
* simple_strtol - convert a string to a signed long |
1da177e4c
|
72 73 74 75 |
* @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use */ |
922ac25c9
|
76 |
long simple_strtol(const char *cp, char **endp, unsigned int base) |
1da177e4c
|
77 |
{ |
922ac25c9
|
78 79 |
if (*cp == '-') return -simple_strtoul(cp + 1, endp, base); |
7b9186f5e
|
80 |
|
922ac25c9
|
81 |
return simple_strtoul(cp, endp, base); |
1da177e4c
|
82 |
} |
922ac25c9
|
83 |
EXPORT_SYMBOL(simple_strtol); |
1da177e4c
|
84 85 86 87 88 89 90 |
/** * simple_strtoll - convert a string to a signed long long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use */ |
22d27051b
|
91 |
long long simple_strtoll(const char *cp, char **endp, unsigned int base) |
1da177e4c
|
92 |
{ |
7b9186f5e
|
93 |
if (*cp == '-') |
22d27051b
|
94 |
return -simple_strtoull(cp + 1, endp, base); |
7b9186f5e
|
95 |
|
22d27051b
|
96 |
return simple_strtoull(cp, endp, base); |
1da177e4c
|
97 |
} |
98d5ce0d0
|
98 |
EXPORT_SYMBOL(simple_strtoll); |
1da177e4c
|
99 |
|
cf3b429b0
|
100 101 |
static noinline_for_stack int skip_atoi(const char **s) |
1da177e4c
|
102 |
{ |
7b9186f5e
|
103 |
int i = 0; |
1da177e4c
|
104 105 106 |
while (isdigit(**s)) i = i*10 + *((*s)++) - '0'; |
7b9186f5e
|
107 |
|
1da177e4c
|
108 109 |
return i; } |
4277eedd7
|
110 111 112 |
/* Decimal conversion is by far the most typical, and is used * for /proc and /sys data. This directly impacts e.g. top performance * with many processes running. We optimize it for speed |
133fd9f5c
|
113 114 115 |
* using ideas described at <http://www.cs.uiowa.edu/~jones/bcd/divide.html> * (with permission from the author, Douglas W. Jones). */ |
4277eedd7
|
116 |
|
133fd9f5c
|
117 118 |
#if BITS_PER_LONG != 32 || BITS_PER_LONG_LONG != 64 /* Formats correctly any integer in [0, 999999999] */ |
cf3b429b0
|
119 |
static noinline_for_stack |
133fd9f5c
|
120 |
char *put_dec_full9(char *buf, unsigned q) |
4277eedd7
|
121 |
{ |
133fd9f5c
|
122 |
unsigned r; |
7b9186f5e
|
123 |
|
133fd9f5c
|
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
/* * Possible ways to approx. divide by 10 * (x * 0x1999999a) >> 32 x < 1073741829 (multiply must be 64-bit) * (x * 0xcccd) >> 19 x < 81920 (x < 262149 when 64-bit mul) * (x * 0x6667) >> 18 x < 43699 * (x * 0x3334) >> 17 x < 16389 * (x * 0x199a) >> 16 x < 16389 * (x * 0x0ccd) >> 15 x < 16389 * (x * 0x0667) >> 14 x < 2739 * (x * 0x0334) >> 13 x < 1029 * (x * 0x019a) >> 12 x < 1029 * (x * 0x00cd) >> 11 x < 1029 shorter code than * 0x67 (on i386) * (x * 0x0067) >> 10 x < 179 * (x * 0x0034) >> 9 x < 69 same * (x * 0x001a) >> 8 x < 69 same * (x * 0x000d) >> 7 x < 69 same, shortest code (on i386) * (x * 0x0007) >> 6 x < 19 * See <http://www.cs.uiowa.edu/~jones/bcd/divide.html> */ r = (q * (uint64_t)0x1999999a) >> 32; *buf++ = (q - 10 * r) + '0'; /* 1 */ q = (r * (uint64_t)0x1999999a) >> 32; *buf++ = (r - 10 * q) + '0'; /* 2 */ r = (q * (uint64_t)0x1999999a) >> 32; *buf++ = (q - 10 * r) + '0'; /* 3 */ q = (r * (uint64_t)0x1999999a) >> 32; *buf++ = (r - 10 * q) + '0'; /* 4 */ r = (q * (uint64_t)0x1999999a) >> 32; *buf++ = (q - 10 * r) + '0'; /* 5 */ /* Now value is under 10000, can avoid 64-bit multiply */ q = (r * 0x199a) >> 16; *buf++ = (r - 10 * q) + '0'; /* 6 */ r = (q * 0xcd) >> 11; *buf++ = (q - 10 * r) + '0'; /* 7 */ q = (r * 0xcd) >> 11; *buf++ = (r - 10 * q) + '0'; /* 8 */ *buf++ = q + '0'; /* 9 */ |
4277eedd7
|
161 162 |
return buf; } |
133fd9f5c
|
163 164 165 166 167 168 |
#endif /* Similar to above but do not pad with zeros. * Code can be easily arranged to print 9 digits too, but our callers * always call put_dec_full9() instead when the number has 9 decimal digits. */ |
cf3b429b0
|
169 |
static noinline_for_stack |
133fd9f5c
|
170 |
char *put_dec_trunc8(char *buf, unsigned r) |
4277eedd7
|
171 |
{ |
133fd9f5c
|
172 173 174 |
unsigned q; /* Copy of previous function's body with added early returns */ |
cb239d0a9
|
175 176 177 178 179 |
while (r >= 10000) { q = r + '0'; r = (r * (uint64_t)0x1999999a) >> 32; *buf++ = q - 10*r; } |
f40005165
|
180 181 |
q = (r * 0x199a) >> 16; /* r <= 9999 */ *buf++ = (r - 10 * q) + '0'; |
133fd9f5c
|
182 183 |
if (q == 0) return buf; |
f40005165
|
184 185 |
r = (q * 0xcd) >> 11; /* q <= 999 */ *buf++ = (q - 10 * r) + '0'; |
133fd9f5c
|
186 187 |
if (r == 0) return buf; |
f40005165
|
188 189 |
q = (r * 0xcd) >> 11; /* r <= 99 */ *buf++ = (r - 10 * q) + '0'; |
133fd9f5c
|
190 191 |
if (q == 0) return buf; |
f40005165
|
192 |
*buf++ = q + '0'; /* q <= 9 */ |
133fd9f5c
|
193 194 |
return buf; } |
4277eedd7
|
195 |
|
133fd9f5c
|
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
/* There are two algorithms to print larger numbers. * One is generic: divide by 1000000000 and repeatedly print * groups of (up to) 9 digits. It's conceptually simple, * but requires a (unsigned long long) / 1000000000 division. * * Second algorithm splits 64-bit unsigned long long into 16-bit chunks, * manipulates them cleverly and generates groups of 4 decimal digits. * It so happens that it does NOT require long long division. * * If long is > 32 bits, division of 64-bit values is relatively easy, * and we will use the first algorithm. * If long long is > 64 bits (strange architecture with VERY large long long), * second algorithm can't be used, and we again use the first one. * * Else (if long is 32 bits and long long is 64 bits) we use second one. */ |
7b9186f5e
|
212 |
|
133fd9f5c
|
213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
#if BITS_PER_LONG != 32 || BITS_PER_LONG_LONG != 64 /* First algorithm: generic */ static char *put_dec(char *buf, unsigned long long n) { if (n >= 100*1000*1000) { while (n >= 1000*1000*1000) buf = put_dec_full9(buf, do_div(n, 1000*1000*1000)); if (n >= 100*1000*1000) return put_dec_full9(buf, n); } return put_dec_trunc8(buf, n); |
4277eedd7
|
227 |
} |
133fd9f5c
|
228 229 230 231 |
#else /* Second algorithm: valid only for 64-bit long longs */ |
e49317d41
|
232 |
/* See comment in put_dec_full9 for choice of constants */ |
cf3b429b0
|
233 |
static noinline_for_stack |
2359172a7
|
234 |
void put_dec_full4(char *buf, unsigned q) |
4277eedd7
|
235 |
{ |
133fd9f5c
|
236 |
unsigned r; |
e49317d41
|
237 |
r = (q * 0xccd) >> 15; |
2359172a7
|
238 |
buf[0] = (q - 10 * r) + '0'; |
e49317d41
|
239 |
q = (r * 0xcd) >> 11; |
2359172a7
|
240 |
buf[1] = (r - 10 * q) + '0'; |
133fd9f5c
|
241 |
r = (q * 0xcd) >> 11; |
2359172a7
|
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
buf[2] = (q - 10 * r) + '0'; buf[3] = r + '0'; } /* * Call put_dec_full4 on x % 10000, return x / 10000. * The approximation x/10000 == (x * 0x346DC5D7) >> 43 * holds for all x < 1,128,869,999. The largest value this * helper will ever be asked to convert is 1,125,520,955. * (d1 in the put_dec code, assuming n is all-ones). */ static unsigned put_dec_helper4(char *buf, unsigned x) { uint32_t q = (x * (uint64_t)0x346DC5D7) >> 43; put_dec_full4(buf, x - q * 10000); return q; |
4277eedd7
|
260 |
} |
133fd9f5c
|
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
/* Based on code by Douglas W. Jones found at * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour> * (with permission from the author). * Performs no 64-bit division and hence should be fast on 32-bit machines. */ static char *put_dec(char *buf, unsigned long long n) { uint32_t d3, d2, d1, q, h; if (n < 100*1000*1000) return put_dec_trunc8(buf, n); d1 = ((uint32_t)n >> 16); /* implicit "& 0xffff" */ h = (n >> 32); d2 = (h ) & 0xffff; d3 = (h >> 16); /* implicit "& 0xffff" */ q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff); |
2359172a7
|
280 281 282 283 284 285 286 |
q = put_dec_helper4(buf, q); q += 7671 * d3 + 9496 * d2 + 6 * d1; q = put_dec_helper4(buf+4, q); q += 4749 * d3 + 42 * d2; q = put_dec_helper4(buf+8, q); |
133fd9f5c
|
287 |
|
2359172a7
|
288 289 290 291 292 |
q += 281 * d3; buf += 12; if (q) buf = put_dec_trunc8(buf, q); else while (buf[-1] == '0') |
133fd9f5c
|
293 294 295 296 297 298 |
--buf; return buf; } #endif |
1ac101a5d
|
299 300 301 302 303 304 305 306 |
/* * Convert passed number to decimal string. * Returns the length of string. On buffer overflow, returns 0. * * If speed is not important, use snprintf(). It's easy to read the code. */ int num_to_str(char *buf, int size, unsigned long long num) { |
133fd9f5c
|
307 |
char tmp[sizeof(num) * 3]; |
1ac101a5d
|
308 |
int idx, len; |
133fd9f5c
|
309 310 311 312 313 314 315 |
/* put_dec() may work incorrectly for num = 0 (generate "", not "0") */ if (num <= 9) { tmp[0] = '0' + num; len = 1; } else { len = put_dec(tmp, num) - tmp; } |
1ac101a5d
|
316 317 318 319 320 |
if (len > size) return 0; for (idx = 0; idx < len; ++idx) buf[idx] = tmp[len - idx - 1]; |
133fd9f5c
|
321 |
return len; |
1ac101a5d
|
322 |
} |
1da177e4c
|
323 324 325 326 327 |
#define ZEROPAD 1 /* pad with zero */ #define SIGN 2 /* unsigned/signed long */ #define PLUS 4 /* show plus */ #define SPACE 8 /* space if plus */ #define LEFT 16 /* left justified */ |
b89dc5d6b
|
328 329 |
#define SMALL 32 /* use lowercase in hex (must be 32 == 0x20) */ #define SPECIAL 64 /* prefix hex with "0x", octal with "0" */ |
1da177e4c
|
330 |
|
fef20d9c1
|
331 332 |
enum format_type { FORMAT_TYPE_NONE, /* Just a string part */ |
ed681a91a
|
333 |
FORMAT_TYPE_WIDTH, |
fef20d9c1
|
334 335 336 337 338 339 340 341 342 |
FORMAT_TYPE_PRECISION, FORMAT_TYPE_CHAR, FORMAT_TYPE_STR, FORMAT_TYPE_PTR, FORMAT_TYPE_PERCENT_CHAR, FORMAT_TYPE_INVALID, FORMAT_TYPE_LONG_LONG, FORMAT_TYPE_ULONG, FORMAT_TYPE_LONG, |
a4e94ef0d
|
343 344 |
FORMAT_TYPE_UBYTE, FORMAT_TYPE_BYTE, |
fef20d9c1
|
345 346 347 348 349 350 351 352 353 354 |
FORMAT_TYPE_USHORT, FORMAT_TYPE_SHORT, FORMAT_TYPE_UINT, FORMAT_TYPE_INT, FORMAT_TYPE_NRCHARS, FORMAT_TYPE_SIZE_T, FORMAT_TYPE_PTRDIFF }; struct printf_spec { |
4e310fda9
|
355 |
u8 type; /* format_type enum */ |
ef0658f3d
|
356 |
u8 flags; /* flags to number() */ |
4e310fda9
|
357 358 359 360 |
u8 base; /* number base, 8, 10 or 16 only */ u8 qualifier; /* number qualifier, one of 'hHlLtzZ' */ s16 field_width; /* width of output field */ s16 precision; /* # of digits/chars */ |
fef20d9c1
|
361 |
}; |
cf3b429b0
|
362 363 364 |
static noinline_for_stack char *number(char *buf, char *end, unsigned long long num, struct printf_spec spec) |
1da177e4c
|
365 |
{ |
9b706aee7
|
366 367 368 369 370 371 |
/* we are called with base 8, 10 or 16, only, thus don't need "G..." */ static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ char tmp[66]; char sign; char locase; |
fef20d9c1
|
372 |
int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); |
1da177e4c
|
373 |
int i; |
7c2034223
|
374 |
bool is_zero = num == 0LL; |
1da177e4c
|
375 |
|
9b706aee7
|
376 377 |
/* locase = 0 or 0x20. ORing digits or letters with 'locase' * produces same digits or (maybe lowercased) letters */ |
fef20d9c1
|
378 379 380 |
locase = (spec.flags & SMALL); if (spec.flags & LEFT) spec.flags &= ~ZEROPAD; |
1da177e4c
|
381 |
sign = 0; |
fef20d9c1
|
382 |
if (spec.flags & SIGN) { |
7b9186f5e
|
383 |
if ((signed long long)num < 0) { |
1da177e4c
|
384 |
sign = '-'; |
7b9186f5e
|
385 |
num = -(signed long long)num; |
fef20d9c1
|
386 387 |
spec.field_width--; } else if (spec.flags & PLUS) { |
1da177e4c
|
388 |
sign = '+'; |
fef20d9c1
|
389 390 |
spec.field_width--; } else if (spec.flags & SPACE) { |
1da177e4c
|
391 |
sign = ' '; |
fef20d9c1
|
392 |
spec.field_width--; |
1da177e4c
|
393 394 |
} } |
b39a73409
|
395 |
if (need_pfx) { |
fef20d9c1
|
396 |
if (spec.base == 16) |
7c2034223
|
397 398 |
spec.field_width -= 2; else if (!is_zero) |
fef20d9c1
|
399 |
spec.field_width--; |
1da177e4c
|
400 |
} |
b39a73409
|
401 402 |
/* generate full string in tmp[], in reverse order */ |
1da177e4c
|
403 |
i = 0; |
133fd9f5c
|
404 405 |
if (num < spec.base) tmp[i++] = digits[num] | locase; |
4277eedd7
|
406 407 |
/* Generic code, for any base: else do { |
9b706aee7
|
408 |
tmp[i++] = (digits[do_div(num,base)] | locase); |
4277eedd7
|
409 410 |
} while (num != 0); */ |
fef20d9c1
|
411 412 |
else if (spec.base != 10) { /* 8 or 16 */ int mask = spec.base - 1; |
b39a73409
|
413 |
int shift = 3; |
7b9186f5e
|
414 415 416 |
if (spec.base == 16) shift = 4; |
b39a73409
|
417 |
do { |
9b706aee7
|
418 |
tmp[i++] = (digits[((unsigned char)num) & mask] | locase); |
b39a73409
|
419 420 |
num >>= shift; } while (num); |
4277eedd7
|
421 422 423 |
} else { /* base 10 */ i = put_dec(tmp, num) - tmp; } |
b39a73409
|
424 425 |
/* printing 100 using %2d gives "100", not "00" */ |
fef20d9c1
|
426 427 |
if (i > spec.precision) spec.precision = i; |
b39a73409
|
428 |
/* leading space padding */ |
fef20d9c1
|
429 430 |
spec.field_width -= spec.precision; if (!(spec.flags & (ZEROPAD+LEFT))) { |
7b9186f5e
|
431 |
while (--spec.field_width >= 0) { |
f796937a0
|
432 |
if (buf < end) |
1da177e4c
|
433 434 435 436 |
*buf = ' '; ++buf; } } |
b39a73409
|
437 |
/* sign */ |
1da177e4c
|
438 |
if (sign) { |
f796937a0
|
439 |
if (buf < end) |
1da177e4c
|
440 441 442 |
*buf = sign; ++buf; } |
b39a73409
|
443 444 |
/* "0x" / "0" prefix */ if (need_pfx) { |
7c2034223
|
445 446 447 448 449 |
if (spec.base == 16 || !is_zero) { if (buf < end) *buf = '0'; ++buf; } |
fef20d9c1
|
450 |
if (spec.base == 16) { |
f796937a0
|
451 |
if (buf < end) |
9b706aee7
|
452 |
*buf = ('X' | locase); |
1da177e4c
|
453 454 455 |
++buf; } } |
b39a73409
|
456 |
/* zero or space padding */ |
fef20d9c1
|
457 458 459 |
if (!(spec.flags & LEFT)) { char c = (spec.flags & ZEROPAD) ? '0' : ' '; while (--spec.field_width >= 0) { |
f796937a0
|
460 |
if (buf < end) |
1da177e4c
|
461 462 463 464 |
*buf = c; ++buf; } } |
b39a73409
|
465 |
/* hmm even more zero padding? */ |
fef20d9c1
|
466 |
while (i <= --spec.precision) { |
f796937a0
|
467 |
if (buf < end) |
1da177e4c
|
468 469 470 |
*buf = '0'; ++buf; } |
b39a73409
|
471 472 |
/* actual digits of result */ while (--i >= 0) { |
f796937a0
|
473 |
if (buf < end) |
1da177e4c
|
474 475 476 |
*buf = tmp[i]; ++buf; } |
b39a73409
|
477 |
/* trailing space padding */ |
fef20d9c1
|
478 |
while (--spec.field_width >= 0) { |
f796937a0
|
479 |
if (buf < end) |
1da177e4c
|
480 481 482 |
*buf = ' '; ++buf; } |
7b9186f5e
|
483 |
|
1da177e4c
|
484 485 |
return buf; } |
cf3b429b0
|
486 487 |
static noinline_for_stack char *string(char *buf, char *end, const char *s, struct printf_spec spec) |
0f9bfa569
|
488 489 490 491 |
{ int len, i; if ((unsigned long)s < PAGE_SIZE) |
0f4f81dce
|
492 |
s = "(null)"; |
0f9bfa569
|
493 |
|
fef20d9c1
|
494 |
len = strnlen(s, spec.precision); |
0f9bfa569
|
495 |
|
fef20d9c1
|
496 497 |
if (!(spec.flags & LEFT)) { while (len < spec.field_width--) { |
0f9bfa569
|
498 499 500 501 502 503 504 505 506 507 |
if (buf < end) *buf = ' '; ++buf; } } for (i = 0; i < len; ++i) { if (buf < end) *buf = *s; ++buf; ++s; } |
fef20d9c1
|
508 |
while (len < spec.field_width--) { |
0f9bfa569
|
509 510 511 512 |
if (buf < end) *buf = ' '; ++buf; } |
7b9186f5e
|
513 |
|
0f9bfa569
|
514 515 |
return buf; } |
cf3b429b0
|
516 517 518 |
static noinline_for_stack char *symbol_string(char *buf, char *end, void *ptr, struct printf_spec spec, char ext) |
0fe1ef24f
|
519 520 521 522 |
{ unsigned long value = (unsigned long) ptr; #ifdef CONFIG_KALLSYMS char sym[KSYM_SYMBOL_LEN]; |
0f77a8d37
|
523 524 525 |
if (ext == 'B') sprint_backtrace(sym, value); else if (ext != 'f' && ext != 's') |
0c8b946e3
|
526 527 |
sprint_symbol(sym, value); else |
4796dd200
|
528 |
sprint_symbol_no_offset(sym, value); |
7b9186f5e
|
529 |
|
fef20d9c1
|
530 |
return string(buf, end, sym, spec); |
0fe1ef24f
|
531 |
#else |
7b9186f5e
|
532 |
spec.field_width = 2 * sizeof(void *); |
fef20d9c1
|
533 534 |
spec.flags |= SPECIAL | SMALL | ZEROPAD; spec.base = 16; |
7b9186f5e
|
535 |
|
fef20d9c1
|
536 |
return number(buf, end, value, spec); |
0fe1ef24f
|
537 538 |
#endif } |
cf3b429b0
|
539 540 541 |
static noinline_for_stack char *resource_string(char *buf, char *end, struct resource *res, struct printf_spec spec, const char *fmt) |
332d2e783
|
542 543 |
{ #ifndef IO_RSRC_PRINTK_SIZE |
284053722
|
544 |
#define IO_RSRC_PRINTK_SIZE 6 |
332d2e783
|
545 546 547 |
#endif #ifndef MEM_RSRC_PRINTK_SIZE |
284053722
|
548 |
#define MEM_RSRC_PRINTK_SIZE 10 |
332d2e783
|
549 |
#endif |
4da0b66c6
|
550 |
static const struct printf_spec io_spec = { |
fef20d9c1
|
551 |
.base = 16, |
4da0b66c6
|
552 |
.field_width = IO_RSRC_PRINTK_SIZE, |
fef20d9c1
|
553 554 555 |
.precision = -1, .flags = SPECIAL | SMALL | ZEROPAD, }; |
4da0b66c6
|
556 557 558 559 560 561 |
static const struct printf_spec mem_spec = { .base = 16, .field_width = MEM_RSRC_PRINTK_SIZE, .precision = -1, .flags = SPECIAL | SMALL | ZEROPAD, }; |
0f4050c7d
|
562 563 564 565 566 567 |
static const struct printf_spec bus_spec = { .base = 16, .field_width = 2, .precision = -1, .flags = SMALL | ZEROPAD, }; |
4da0b66c6
|
568 |
static const struct printf_spec dec_spec = { |
c91d3376e
|
569 570 571 572 |
.base = 10, .precision = -1, .flags = 0, }; |
4da0b66c6
|
573 |
static const struct printf_spec str_spec = { |
fd95541e2
|
574 575 576 577 |
.field_width = -1, .precision = 10, .flags = LEFT, }; |
4da0b66c6
|
578 |
static const struct printf_spec flag_spec = { |
fd95541e2
|
579 580 581 582 |
.base = 16, .precision = -1, .flags = SPECIAL | SMALL, }; |
c7dabef8a
|
583 584 585 586 587 |
/* 32-bit res (sizeof==4): 10 chars in dec, 10 in hex ("0x" + 8) * 64-bit res (sizeof==8): 20 chars in dec, 18 in hex ("0x" + 16) */ #define RSRC_BUF_SIZE ((2 * sizeof(resource_size_t)) + 4) #define FLAG_BUF_SIZE (2 * sizeof(res->flags)) |
9d7cca042
|
588 |
#define DECODED_BUF_SIZE sizeof("[mem - 64bit pref window disabled]") |
c7dabef8a
|
589 590 591 |
#define RAW_BUF_SIZE sizeof("[mem - flags 0x]") char sym[max(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE, 2*RSRC_BUF_SIZE + FLAG_BUF_SIZE + RAW_BUF_SIZE)]; |
332d2e783
|
592 |
char *p = sym, *pend = sym + sizeof(sym); |
c7dabef8a
|
593 |
int decode = (fmt[0] == 'R') ? 1 : 0; |
4da0b66c6
|
594 |
const struct printf_spec *specp; |
332d2e783
|
595 596 |
*p++ = '['; |
4da0b66c6
|
597 |
if (res->flags & IORESOURCE_IO) { |
c7dabef8a
|
598 |
p = string(p, pend, "io ", str_spec); |
4da0b66c6
|
599 600 |
specp = &io_spec; } else if (res->flags & IORESOURCE_MEM) { |
c7dabef8a
|
601 |
p = string(p, pend, "mem ", str_spec); |
4da0b66c6
|
602 603 |
specp = &mem_spec; } else if (res->flags & IORESOURCE_IRQ) { |
c7dabef8a
|
604 |
p = string(p, pend, "irq ", str_spec); |
4da0b66c6
|
605 606 |
specp = &dec_spec; } else if (res->flags & IORESOURCE_DMA) { |
c7dabef8a
|
607 |
p = string(p, pend, "dma ", str_spec); |
4da0b66c6
|
608 |
specp = &dec_spec; |
0f4050c7d
|
609 610 611 |
} else if (res->flags & IORESOURCE_BUS) { p = string(p, pend, "bus ", str_spec); specp = &bus_spec; |
4da0b66c6
|
612 |
} else { |
c7dabef8a
|
613 |
p = string(p, pend, "??? ", str_spec); |
4da0b66c6
|
614 |
specp = &mem_spec; |
c7dabef8a
|
615 |
decode = 0; |
fd95541e2
|
616 |
} |
4da0b66c6
|
617 |
p = number(p, pend, res->start, *specp); |
c91d3376e
|
618 619 |
if (res->start != res->end) { *p++ = '-'; |
4da0b66c6
|
620 |
p = number(p, pend, res->end, *specp); |
c91d3376e
|
621 |
} |
c7dabef8a
|
622 |
if (decode) { |
fd95541e2
|
623 624 625 626 |
if (res->flags & IORESOURCE_MEM_64) p = string(p, pend, " 64bit", str_spec); if (res->flags & IORESOURCE_PREFETCH) p = string(p, pend, " pref", str_spec); |
9d7cca042
|
627 628 |
if (res->flags & IORESOURCE_WINDOW) p = string(p, pend, " window", str_spec); |
fd95541e2
|
629 630 |
if (res->flags & IORESOURCE_DISABLED) p = string(p, pend, " disabled", str_spec); |
c7dabef8a
|
631 632 633 |
} else { p = string(p, pend, " flags ", str_spec); p = number(p, pend, res->flags, flag_spec); |
fd95541e2
|
634 |
} |
332d2e783
|
635 |
*p++ = ']'; |
c7dabef8a
|
636 |
*p = '\0'; |
332d2e783
|
637 |
|
fef20d9c1
|
638 |
return string(buf, end, sym, spec); |
332d2e783
|
639 |
} |
cf3b429b0
|
640 |
static noinline_for_stack |
31550a16a
|
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 |
char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec, const char *fmt) { int i, len = 1; /* if we pass '%ph[CDN]', field witdh remains negative value, fallback to the default */ char separator; if (spec.field_width == 0) /* nothing to print */ return buf; if (ZERO_OR_NULL_PTR(addr)) /* NULL pointer */ return string(buf, end, NULL, spec); switch (fmt[1]) { case 'C': separator = ':'; break; case 'D': separator = '-'; break; case 'N': separator = 0; break; default: separator = ' '; break; } if (spec.field_width > 0) len = min_t(int, spec.field_width, 64); for (i = 0; i < len && buf < end - 1; i++) { buf = hex_byte_pack(buf, addr[i]); if (buf < end && separator && i != len - 1) *buf++ = separator; } return buf; } static noinline_for_stack |
cf3b429b0
|
685 686 |
char *mac_address_string(char *buf, char *end, u8 *addr, struct printf_spec spec, const char *fmt) |
dd45c9cf6
|
687 |
{ |
8a27f7c90
|
688 |
char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")]; |
dd45c9cf6
|
689 690 |
char *p = mac_addr; int i; |
bc7259a2c
|
691 |
char separator; |
76597ff98
|
692 |
bool reversed = false; |
bc7259a2c
|
693 |
|
76597ff98
|
694 695 |
switch (fmt[1]) { case 'F': |
bc7259a2c
|
696 |
separator = '-'; |
76597ff98
|
697 698 699 700 701 702 703 |
break; case 'R': reversed = true; /* fall through */ default: |
bc7259a2c
|
704 |
separator = ':'; |
76597ff98
|
705 |
break; |
bc7259a2c
|
706 |
} |
dd45c9cf6
|
707 708 |
for (i = 0; i < 6; i++) { |
76597ff98
|
709 710 711 712 |
if (reversed) p = hex_byte_pack(p, addr[5 - i]); else p = hex_byte_pack(p, addr[i]); |
8a27f7c90
|
713 |
if (fmt[0] == 'M' && i != 5) |
bc7259a2c
|
714 |
*p++ = separator; |
dd45c9cf6
|
715 716 |
} *p = '\0'; |
fef20d9c1
|
717 |
return string(buf, end, mac_addr, spec); |
dd45c9cf6
|
718 |
} |
cf3b429b0
|
719 720 |
static noinline_for_stack char *ip4_string(char *p, const u8 *addr, const char *fmt) |
8a27f7c90
|
721 722 |
{ int i; |
0159f24ee
|
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 |
bool leading_zeros = (fmt[0] == 'i'); int index; int step; switch (fmt[2]) { case 'h': #ifdef __BIG_ENDIAN index = 0; step = 1; #else index = 3; step = -1; #endif break; case 'l': index = 3; step = -1; break; case 'n': case 'b': default: index = 0; step = 1; break; } |
8a27f7c90
|
748 749 |
for (i = 0; i < 4; i++) { char temp[3]; /* hold each IP quad in reverse order */ |
133fd9f5c
|
750 |
int digits = put_dec_trunc8(temp, addr[index]) - temp; |
8a27f7c90
|
751 752 753 754 755 756 757 758 759 760 761 |
if (leading_zeros) { if (digits < 3) *p++ = '0'; if (digits < 2) *p++ = '0'; } /* reverse the digits in the quad */ while (digits--) *p++ = temp[digits]; if (i < 3) *p++ = '.'; |
0159f24ee
|
762 |
index += step; |
8a27f7c90
|
763 |
} |
8a27f7c90
|
764 |
*p = '\0'; |
7b9186f5e
|
765 |
|
8a27f7c90
|
766 767 |
return p; } |
cf3b429b0
|
768 769 |
static noinline_for_stack char *ip6_compressed_string(char *p, const char *addr) |
689afa7da
|
770 |
{ |
7b9186f5e
|
771 |
int i, j, range; |
8a27f7c90
|
772 773 774 775 |
unsigned char zerolength[8]; int longest = 1; int colonpos = -1; u16 word; |
7b9186f5e
|
776 |
u8 hi, lo; |
8a27f7c90
|
777 |
bool needcolon = false; |
eb78cd26b
|
778 779 780 781 782 783 |
bool useIPv4; struct in6_addr in6; memcpy(&in6, addr, sizeof(struct in6_addr)); useIPv4 = ipv6_addr_v4mapped(&in6) || ipv6_addr_is_isatap(&in6); |
8a27f7c90
|
784 785 786 787 788 789 790 791 792 793 794 |
memset(zerolength, 0, sizeof(zerolength)); if (useIPv4) range = 6; else range = 8; /* find position of longest 0 run */ for (i = 0; i < range; i++) { for (j = i; j < range; j++) { |
eb78cd26b
|
795 |
if (in6.s6_addr16[j] != 0) |
8a27f7c90
|
796 797 798 799 800 801 802 803 804 805 |
break; zerolength[i]++; } } for (i = 0; i < range; i++) { if (zerolength[i] > longest) { longest = zerolength[i]; colonpos = i; } } |
29cf519ee
|
806 807 |
if (longest == 1) /* don't compress a single 0 */ colonpos = -1; |
689afa7da
|
808 |
|
8a27f7c90
|
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 |
/* emit address */ for (i = 0; i < range; i++) { if (i == colonpos) { if (needcolon || i == 0) *p++ = ':'; *p++ = ':'; needcolon = false; i += longest - 1; continue; } if (needcolon) { *p++ = ':'; needcolon = false; } /* hex u16 without leading 0s */ |
eb78cd26b
|
824 |
word = ntohs(in6.s6_addr16[i]); |
8a27f7c90
|
825 826 827 828 |
hi = word >> 8; lo = word & 0xff; if (hi) { if (hi > 0x0f) |
55036ba76
|
829 |
p = hex_byte_pack(p, hi); |
8a27f7c90
|
830 831 |
else *p++ = hex_asc_lo(hi); |
55036ba76
|
832 |
p = hex_byte_pack(p, lo); |
8a27f7c90
|
833 |
} |
b5ff992b0
|
834 |
else if (lo > 0x0f) |
55036ba76
|
835 |
p = hex_byte_pack(p, lo); |
8a27f7c90
|
836 837 838 839 840 841 842 843 |
else *p++ = hex_asc_lo(lo); needcolon = true; } if (useIPv4) { if (needcolon) *p++ = ':'; |
0159f24ee
|
844 |
p = ip4_string(p, &in6.s6_addr[12], "I4"); |
8a27f7c90
|
845 |
} |
8a27f7c90
|
846 |
*p = '\0'; |
7b9186f5e
|
847 |
|
8a27f7c90
|
848 849 |
return p; } |
cf3b429b0
|
850 851 |
static noinline_for_stack char *ip6_string(char *p, const char *addr, const char *fmt) |
8a27f7c90
|
852 853 |
{ int i; |
7b9186f5e
|
854 |
|
689afa7da
|
855 |
for (i = 0; i < 8; i++) { |
55036ba76
|
856 857 |
p = hex_byte_pack(p, *addr++); p = hex_byte_pack(p, *addr++); |
8a27f7c90
|
858 |
if (fmt[0] == 'I' && i != 7) |
689afa7da
|
859 860 861 |
*p++ = ':'; } *p = '\0'; |
7b9186f5e
|
862 |
|
8a27f7c90
|
863 864 |
return p; } |
cf3b429b0
|
865 866 867 |
static noinline_for_stack char *ip6_addr_string(char *buf, char *end, const u8 *addr, struct printf_spec spec, const char *fmt) |
8a27f7c90
|
868 869 870 871 |
{ char ip6_addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")]; if (fmt[0] == 'I' && fmt[2] == 'c') |
eb78cd26b
|
872 |
ip6_compressed_string(ip6_addr, addr); |
8a27f7c90
|
873 |
else |
eb78cd26b
|
874 |
ip6_string(ip6_addr, addr, fmt); |
689afa7da
|
875 |
|
fef20d9c1
|
876 |
return string(buf, end, ip6_addr, spec); |
689afa7da
|
877 |
} |
cf3b429b0
|
878 879 880 |
static noinline_for_stack char *ip4_addr_string(char *buf, char *end, const u8 *addr, struct printf_spec spec, const char *fmt) |
4aa996066
|
881 |
{ |
8a27f7c90
|
882 |
char ip4_addr[sizeof("255.255.255.255")]; |
4aa996066
|
883 |
|
0159f24ee
|
884 |
ip4_string(ip4_addr, addr, fmt); |
4aa996066
|
885 |
|
fef20d9c1
|
886 |
return string(buf, end, ip4_addr, spec); |
4aa996066
|
887 |
} |
cf3b429b0
|
888 889 890 |
static noinline_for_stack char *uuid_string(char *buf, char *end, const u8 *addr, struct printf_spec spec, const char *fmt) |
9ac6e44ee
|
891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 |
{ char uuid[sizeof("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]; char *p = uuid; int i; static const u8 be[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; static const u8 le[16] = {3,2,1,0,5,4,7,6,8,9,10,11,12,13,14,15}; const u8 *index = be; bool uc = false; switch (*(++fmt)) { case 'L': uc = true; /* fall-through */ case 'l': index = le; break; case 'B': uc = true; break; } for (i = 0; i < 16; i++) { |
55036ba76
|
912 |
p = hex_byte_pack(p, addr[index[i]]); |
9ac6e44ee
|
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 |
switch (i) { case 3: case 5: case 7: case 9: *p++ = '-'; break; } } *p = 0; if (uc) { p = uuid; do { *p = toupper(*p); } while (*(++p)); } return string(buf, end, uuid, spec); } |
c8f44affb
|
934 935 936 937 938 939 940 941 942 943 944 |
static char *netdev_feature_string(char *buf, char *end, const u8 *addr, struct printf_spec spec) { spec.flags |= SPECIAL | SMALL | ZEROPAD; if (spec.field_width == -1) spec.field_width = 2 + 2 * sizeof(netdev_features_t); spec.base = 16; return number(buf, end, *(const netdev_features_t *)addr, spec); } |
411f05f12
|
945 |
int kptr_restrict __read_mostly; |
455cd5ab3
|
946 |
|
4d8a743cd
|
947 948 949 950 951 |
/* * Show a '%p' thing. A kernel extension is that the '%p' is followed * by an extra set of alphanumeric characters that are extended format * specifiers. * |
332d2e783
|
952 953 |
* Right now we handle: * |
0c8b946e3
|
954 955 |
* - 'F' For symbolic function descriptor pointers with offset * - 'f' For simple symbolic function names without offset |
0efb4d207
|
956 957 |
* - 'S' For symbolic direct pointers with offset * - 's' For symbolic direct pointers without offset |
0f77a8d37
|
958 |
* - 'B' For backtraced symbolic direct pointers with offset |
c7dabef8a
|
959 960 |
* - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref] * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201] |
dd45c9cf6
|
961 962 |
* - 'M' For a 6-byte MAC address, it prints the address in the * usual colon-separated hex notation |
8a27f7c90
|
963 |
* - 'm' For a 6-byte MAC address, it prints the hex address without colons |
bc7259a2c
|
964 |
* - 'MF' For a 6-byte MAC FDDI address, it prints the address |
c8e000604
|
965 |
* with a dash-separated hex notation |
7c59154e7
|
966 |
* - '[mM]R' For a 6-byte MAC address, Reverse order (Bluetooth) |
8a27f7c90
|
967 968 969 970 971 972 |
* - 'I' [46] for IPv4/IPv6 addresses printed in the usual way * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4) * IPv6 uses colon separated network-order 16 bit hex with leading 0's * - 'i' [46] for 'raw' IPv4/IPv6 addresses * IPv6 omits the colons (01020304...0f) * IPv4 uses dot-separated decimal with leading 0's (010.123.045.006) |
0159f24ee
|
973 |
* - '[Ii]4[hnbl]' IPv4 addresses in host, network, big or little endian order |
8a27f7c90
|
974 |
* - 'I6c' for IPv6 addresses printed as specified by |
29cf519ee
|
975 |
* http://tools.ietf.org/html/rfc5952 |
9ac6e44ee
|
976 977 978 979 980 981 982 983 984 985 986 |
* - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form * "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" * Options for %pU are: * b big endian lower case hex (default) * B big endian UPPER case hex * l little endian lower case hex * L little endian UPPER case hex * big endian output byte order is: * [0][1][2][3]-[4][5]-[6][7]-[8][9]-[10][11][12][13][14][15] * little endian output byte order is: * [3][2][1][0]-[5][4]-[7][6]-[8][9]-[10][11][12][13][14][15] |
7db6f5fb6
|
987 988 989 990 991 |
* - 'V' For a struct va_format which contains a format string * and va_list *, * call vsnprintf(->format, *->va_list). * Implements a "recursive vsnprintf". * Do not use this feature without some mechanism to verify the * correctness of the format string and va_list arguments. |
455cd5ab3
|
992 |
* - 'K' For a kernel pointer that should be hidden from unprivileged users |
c8f44affb
|
993 |
* - 'NF' For a netdev_features_t |
31550a16a
|
994 995 996 997 998 999 1000 |
* - 'h[CDN]' For a variable-length buffer, it prints it as a hex string with * a certain separator (' ' by default): * C colon * D dash * N no separator * The maximum supported length is 64 bytes of the input. Consider * to use print_hex_dump() for the larger input. |
9ac6e44ee
|
1001 |
* |
332d2e783
|
1002 1003 1004 |
* Note: The difference between 'S' and 'F' is that on ia64 and ppc64 * function pointers are really function descriptors, which contain a * pointer to the real address. |
4d8a743cd
|
1005 |
*/ |
cf3b429b0
|
1006 1007 1008 |
static noinline_for_stack char *pointer(const char *fmt, char *buf, char *end, void *ptr, struct printf_spec spec) |
78a8bf69b
|
1009 |
{ |
725fe002d
|
1010 |
int default_width = 2 * sizeof(void *) + (spec.flags & SPECIAL ? 2 : 0); |
9f36e2c44
|
1011 |
if (!ptr && *fmt != 'K') { |
5e0579812
|
1012 1013 1014 1015 1016 |
/* * Print (null) with the same width as a pointer so it makes * tabular output look nice. */ if (spec.field_width == -1) |
725fe002d
|
1017 |
spec.field_width = default_width; |
fef20d9c1
|
1018 |
return string(buf, end, "(null)", spec); |
5e0579812
|
1019 |
} |
d97106ab5
|
1020 |
|
0fe1ef24f
|
1021 1022 |
switch (*fmt) { case 'F': |
0c8b946e3
|
1023 |
case 'f': |
0fe1ef24f
|
1024 1025 1026 |
ptr = dereference_function_descriptor(ptr); /* Fallthrough */ case 'S': |
9ac6e44ee
|
1027 |
case 's': |
0f77a8d37
|
1028 |
case 'B': |
0c8b946e3
|
1029 |
return symbol_string(buf, end, ptr, spec, *fmt); |
332d2e783
|
1030 |
case 'R': |
c7dabef8a
|
1031 |
case 'r': |
fd95541e2
|
1032 |
return resource_string(buf, end, ptr, spec, fmt); |
31550a16a
|
1033 1034 |
case 'h': return hex_string(buf, end, ptr, spec, fmt); |
8a27f7c90
|
1035 1036 |
case 'M': /* Colon separated: 00:01:02:03:04:05 */ case 'm': /* Contiguous: 000102030405 */ |
76597ff98
|
1037 1038 |
/* [mM]F (FDDI) */ /* [mM]R (Reverse order; Bluetooth) */ |
8a27f7c90
|
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 |
return mac_address_string(buf, end, ptr, spec, fmt); case 'I': /* Formatted IP supported * 4: 1.2.3.4 * 6: 0001:0203:...:0708 * 6c: 1::708 or 1::1.2.3.4 */ case 'i': /* Contiguous: * 4: 001.002.003.004 * 6: 000102...0f */ switch (fmt[1]) { case '6': return ip6_addr_string(buf, end, ptr, spec, fmt); case '4': return ip4_addr_string(buf, end, ptr, spec, fmt); } |
fef20d9c1
|
1055 |
break; |
9ac6e44ee
|
1056 1057 |
case 'U': return uuid_string(buf, end, ptr, spec, fmt); |
7db6f5fb6
|
1058 |
case 'V': |
5756b76e4
|
1059 1060 1061 1062 1063 1064 1065 1066 1067 |
{ va_list va; va_copy(va, *((struct va_format *)ptr)->va); buf += vsnprintf(buf, end > buf ? end - buf : 0, ((struct va_format *)ptr)->fmt, va); va_end(va); return buf; } |
455cd5ab3
|
1068 1069 1070 1071 1072 |
case 'K': /* * %pK cannot be used in IRQ context because its test * for CAP_SYSLOG would be meaningless. */ |
3715c5309
|
1073 1074 |
if (kptr_restrict && (in_irq() || in_serving_softirq() || in_nmi())) { |
455cd5ab3
|
1075 |
if (spec.field_width == -1) |
725fe002d
|
1076 |
spec.field_width = default_width; |
455cd5ab3
|
1077 |
return string(buf, end, "pK-error", spec); |
455cd5ab3
|
1078 |
} |
26297607e
|
1079 1080 1081 1082 1083 |
if (!((kptr_restrict == 0) || (kptr_restrict == 1 && has_capability_noaudit(current, CAP_SYSLOG)))) ptr = NULL; break; |
c8f44affb
|
1084 1085 1086 1087 1088 1089 |
case 'N': switch (fmt[1]) { case 'F': return netdev_feature_string(buf, end, ptr, spec); } break; |
fef20d9c1
|
1090 1091 1092 |
} spec.flags |= SMALL; if (spec.field_width == -1) { |
725fe002d
|
1093 |
spec.field_width = default_width; |
fef20d9c1
|
1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 |
spec.flags |= ZEROPAD; } spec.base = 16; return number(buf, end, (unsigned long) ptr, spec); } /* * Helper function to decode printf style format. * Each call decode a token from the format and return the * number of characters read (or likely the delta where it wants * to go on the next call). * The decoded token is returned through the parameters * * 'h', 'l', or 'L' for integer fields * 'z' support added 23/7/1999 S.H. * 'z' changed to 'Z' --davidm 1/25/99 * 't' added for ptrdiff_t * * @fmt: the format string * @type of the token returned * @flags: various flags such as +, -, # tokens.. * @field_width: overwritten width * @base: base of the number (octal, hex, ...) * @precision: precision of a number * @qualifier: qualifier of a number (long, size_t, ...) */ |
cf3b429b0
|
1121 1122 |
static noinline_for_stack int format_decode(const char *fmt, struct printf_spec *spec) |
fef20d9c1
|
1123 1124 |
{ const char *start = fmt; |
fef20d9c1
|
1125 1126 |
/* we finished early by reading the field width */ |
ed681a91a
|
1127 |
if (spec->type == FORMAT_TYPE_WIDTH) { |
fef20d9c1
|
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 |
if (spec->field_width < 0) { spec->field_width = -spec->field_width; spec->flags |= LEFT; } spec->type = FORMAT_TYPE_NONE; goto precision; } /* we finished early by reading the precision */ if (spec->type == FORMAT_TYPE_PRECISION) { if (spec->precision < 0) spec->precision = 0; spec->type = FORMAT_TYPE_NONE; goto qualifier; } /* By default */ spec->type = FORMAT_TYPE_NONE; for (; *fmt ; ++fmt) { if (*fmt == '%') break; } /* Return the current non-format string */ if (fmt != start || !*fmt) return fmt - start; /* Process flags */ spec->flags = 0; while (1) { /* this also skips first '%' */ bool found = true; ++fmt; switch (*fmt) { case '-': spec->flags |= LEFT; break; case '+': spec->flags |= PLUS; break; case ' ': spec->flags |= SPACE; break; case '#': spec->flags |= SPECIAL; break; case '0': spec->flags |= ZEROPAD; break; default: found = false; } if (!found) break; } /* get field width */ spec->field_width = -1; if (isdigit(*fmt)) spec->field_width = skip_atoi(&fmt); else if (*fmt == '*') { /* it's the next argument */ |
ed681a91a
|
1185 |
spec->type = FORMAT_TYPE_WIDTH; |
fef20d9c1
|
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 |
return ++fmt - start; } precision: /* get the precision */ spec->precision = -1; if (*fmt == '.') { ++fmt; if (isdigit(*fmt)) { spec->precision = skip_atoi(&fmt); if (spec->precision < 0) spec->precision = 0; } else if (*fmt == '*') { /* it's the next argument */ |
adf26f84a
|
1200 |
spec->type = FORMAT_TYPE_PRECISION; |
fef20d9c1
|
1201 1202 1203 1204 1205 1206 1207 |
return ++fmt - start; } } qualifier: /* get the conversion qualifier */ spec->qualifier = -1; |
75fb8f269
|
1208 1209 |
if (*fmt == 'h' || _tolower(*fmt) == 'l' || _tolower(*fmt) == 'z' || *fmt == 't') { |
a4e94ef0d
|
1210 1211 1212 1213 1214 1215 1216 1217 1218 |
spec->qualifier = *fmt++; if (unlikely(spec->qualifier == *fmt)) { if (spec->qualifier == 'l') { spec->qualifier = 'L'; ++fmt; } else if (spec->qualifier == 'h') { spec->qualifier = 'H'; ++fmt; } |
fef20d9c1
|
1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 |
} } /* default base */ spec->base = 10; switch (*fmt) { case 'c': spec->type = FORMAT_TYPE_CHAR; return ++fmt - start; case 's': spec->type = FORMAT_TYPE_STR; return ++fmt - start; case 'p': spec->type = FORMAT_TYPE_PTR; return fmt - start; /* skip alnum */ case 'n': spec->type = FORMAT_TYPE_NRCHARS; return ++fmt - start; case '%': spec->type = FORMAT_TYPE_PERCENT_CHAR; return ++fmt - start; /* integer number formats - set up the flags and "break" */ case 'o': spec->base = 8; break; case 'x': spec->flags |= SMALL; case 'X': spec->base = 16; break; case 'd': case 'i': |
39e874f8a
|
1260 |
spec->flags |= SIGN; |
fef20d9c1
|
1261 |
case 'u': |
4aa996066
|
1262 |
break; |
fef20d9c1
|
1263 1264 1265 1266 |
default: spec->type = FORMAT_TYPE_INVALID; return fmt - start; |
0fe1ef24f
|
1267 |
} |
fef20d9c1
|
1268 1269 1270 1271 |
if (spec->qualifier == 'L') spec->type = FORMAT_TYPE_LONG_LONG; else if (spec->qualifier == 'l') { |
39e874f8a
|
1272 |
if (spec->flags & SIGN) |
fef20d9c1
|
1273 1274 1275 |
spec->type = FORMAT_TYPE_LONG; else spec->type = FORMAT_TYPE_ULONG; |
75fb8f269
|
1276 |
} else if (_tolower(spec->qualifier) == 'z') { |
fef20d9c1
|
1277 1278 1279 |
spec->type = FORMAT_TYPE_SIZE_T; } else if (spec->qualifier == 't') { spec->type = FORMAT_TYPE_PTRDIFF; |
a4e94ef0d
|
1280 1281 1282 1283 1284 |
} else if (spec->qualifier == 'H') { if (spec->flags & SIGN) spec->type = FORMAT_TYPE_BYTE; else spec->type = FORMAT_TYPE_UBYTE; |
fef20d9c1
|
1285 |
} else if (spec->qualifier == 'h') { |
39e874f8a
|
1286 |
if (spec->flags & SIGN) |
fef20d9c1
|
1287 1288 1289 1290 |
spec->type = FORMAT_TYPE_SHORT; else spec->type = FORMAT_TYPE_USHORT; } else { |
39e874f8a
|
1291 |
if (spec->flags & SIGN) |
fef20d9c1
|
1292 1293 1294 |
spec->type = FORMAT_TYPE_INT; else spec->type = FORMAT_TYPE_UINT; |
78a8bf69b
|
1295 |
} |
fef20d9c1
|
1296 1297 |
return ++fmt - start; |
78a8bf69b
|
1298 |
} |
1da177e4c
|
1299 1300 1301 1302 1303 1304 1305 |
/** * vsnprintf - Format a string and place it in a buffer * @buf: The buffer to place the result into * @size: The size of the buffer, including the trailing null space * @fmt: The format string to use * @args: Arguments for the format string * |
20036fdca
|
1306 |
* This function follows C99 vsnprintf, but has some extensions: |
91adcd2c4
|
1307 1308 |
* %pS output the name of a text symbol with offset * %ps output the name of a text symbol without offset |
0c8b946e3
|
1309 1310 |
* %pF output the name of a function pointer with its offset * %pf output the name of a function pointer without its offset |
0f77a8d37
|
1311 |
* %pB output the name of a backtrace symbol with its offset |
8a79503aa
|
1312 1313 1314 |
* %pR output the address range in a struct resource with decoded flags * %pr output the address range in a struct resource with raw flags * %pM output a 6-byte MAC address with colons |
7c59154e7
|
1315 1316 |
* %pMR output a 6-byte MAC address with colons in reversed order * %pMF output a 6-byte MAC address with dashes |
8a79503aa
|
1317 |
* %pm output a 6-byte MAC address without colons |
7c59154e7
|
1318 |
* %pmR output a 6-byte MAC address without colons in reversed order |
8a79503aa
|
1319 1320 1321 1322 |
* %pI4 print an IPv4 address without leading zeros * %pi4 print an IPv4 address with leading zeros * %pI6 print an IPv6 address with colons * %pi6 print an IPv6 address without colons |
f996f2081
|
1323 |
* %pI6c print an IPv6 address as specified by RFC 5952 |
8a79503aa
|
1324 1325 |
* %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper * case. |
31550a16a
|
1326 1327 |
* %*ph[CDN] a variable-length hex string with a separator (supports up to 64 * bytes of the input) |
0efb4d207
|
1328 |
* %n is ignored |
20036fdca
|
1329 |
* |
80f548e04
|
1330 1331 |
* ** Please update Documentation/printk-formats.txt when making changes ** * |
1da177e4c
|
1332 1333 1334 1335 |
* The return value is the number of characters which would * be generated for the given input, excluding the trailing * '\0', as per ISO C99. If you want to have the exact * number of characters written into @buf as return value |
72fd4a35a
|
1336 |
* (not including the trailing '\0'), use vscnprintf(). If the |
1da177e4c
|
1337 1338 1339 |
* return is greater than or equal to @size, the resulting * string is truncated. * |
ba1835eb3
|
1340 |
* If you're not already dealing with a va_list consider using snprintf(). |
1da177e4c
|
1341 1342 1343 |
*/ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) { |
1da177e4c
|
1344 |
unsigned long long num; |
d4be151b2
|
1345 |
char *str, *end; |
fef20d9c1
|
1346 |
struct printf_spec spec = {0}; |
1da177e4c
|
1347 |
|
f796937a0
|
1348 1349 |
/* Reject out-of-range values early. Large positive sizes are used for unknown buffer sizes. */ |
2f30b1f9e
|
1350 |
if (WARN_ON_ONCE((int) size < 0)) |
1da177e4c
|
1351 |
return 0; |
1da177e4c
|
1352 1353 |
str = buf; |
f796937a0
|
1354 |
end = buf + size; |
1da177e4c
|
1355 |
|
f796937a0
|
1356 1357 1358 1359 |
/* Make sure end is always >= buf */ if (end < buf) { end = ((void *)-1); size = end - buf; |
1da177e4c
|
1360 |
} |
fef20d9c1
|
1361 1362 |
while (*fmt) { const char *old_fmt = fmt; |
d4be151b2
|
1363 |
int read = format_decode(fmt, &spec); |
1da177e4c
|
1364 |
|
fef20d9c1
|
1365 |
fmt += read; |
1da177e4c
|
1366 |
|
fef20d9c1
|
1367 1368 1369 1370 1371 1372 1373 |
switch (spec.type) { case FORMAT_TYPE_NONE: { int copy = read; if (str < end) { if (copy > end - str) copy = end - str; memcpy(str, old_fmt, copy); |
1da177e4c
|
1374 |
} |
fef20d9c1
|
1375 1376 |
str += read; break; |
1da177e4c
|
1377 |
} |
ed681a91a
|
1378 |
case FORMAT_TYPE_WIDTH: |
fef20d9c1
|
1379 1380 |
spec.field_width = va_arg(args, int); break; |
1da177e4c
|
1381 |
|
fef20d9c1
|
1382 1383 1384 |
case FORMAT_TYPE_PRECISION: spec.precision = va_arg(args, int); break; |
1da177e4c
|
1385 |
|
d4be151b2
|
1386 1387 |
case FORMAT_TYPE_CHAR: { char c; |
fef20d9c1
|
1388 1389 |
if (!(spec.flags & LEFT)) { while (--spec.field_width > 0) { |
f796937a0
|
1390 |
if (str < end) |
1da177e4c
|
1391 1392 |
*str = ' '; ++str; |
1da177e4c
|
1393 |
|
fef20d9c1
|
1394 1395 1396 1397 1398 1399 1400 |
} } c = (unsigned char) va_arg(args, int); if (str < end) *str = c; ++str; while (--spec.field_width > 0) { |
f796937a0
|
1401 |
if (str < end) |
fef20d9c1
|
1402 |
*str = ' '; |
1da177e4c
|
1403 |
++str; |
fef20d9c1
|
1404 1405 |
} break; |
d4be151b2
|
1406 |
} |
1da177e4c
|
1407 |
|
fef20d9c1
|
1408 1409 1410 |
case FORMAT_TYPE_STR: str = string(str, end, va_arg(args, char *), spec); break; |
1da177e4c
|
1411 |
|
fef20d9c1
|
1412 1413 1414 1415 1416 1417 |
case FORMAT_TYPE_PTR: str = pointer(fmt+1, str, end, va_arg(args, void *), spec); while (isalnum(*fmt)) fmt++; break; |
1da177e4c
|
1418 |
|
fef20d9c1
|
1419 1420 1421 1422 1423 |
case FORMAT_TYPE_PERCENT_CHAR: if (str < end) *str = '%'; ++str; break; |
1da177e4c
|
1424 |
|
fef20d9c1
|
1425 1426 1427 1428 |
case FORMAT_TYPE_INVALID: if (str < end) *str = '%'; ++str; |
fef20d9c1
|
1429 1430 1431 |
break; case FORMAT_TYPE_NRCHARS: { |
ef0658f3d
|
1432 |
u8 qualifier = spec.qualifier; |
fef20d9c1
|
1433 1434 1435 1436 |
if (qualifier == 'l') { long *ip = va_arg(args, long *); *ip = (str - buf); |
75fb8f269
|
1437 |
} else if (_tolower(qualifier) == 'z') { |
fef20d9c1
|
1438 1439 1440 1441 1442 1443 1444 |
size_t *ip = va_arg(args, size_t *); *ip = (str - buf); } else { int *ip = va_arg(args, int *); *ip = (str - buf); } break; |
1da177e4c
|
1445 |
} |
fef20d9c1
|
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 |
default: switch (spec.type) { case FORMAT_TYPE_LONG_LONG: num = va_arg(args, long long); break; case FORMAT_TYPE_ULONG: num = va_arg(args, unsigned long); break; case FORMAT_TYPE_LONG: num = va_arg(args, long); break; case FORMAT_TYPE_SIZE_T: num = va_arg(args, size_t); break; case FORMAT_TYPE_PTRDIFF: num = va_arg(args, ptrdiff_t); break; |
a4e94ef0d
|
1464 1465 1466 1467 1468 1469 |
case FORMAT_TYPE_UBYTE: num = (unsigned char) va_arg(args, int); break; case FORMAT_TYPE_BYTE: num = (signed char) va_arg(args, int); break; |
fef20d9c1
|
1470 1471 1472 1473 1474 1475 |
case FORMAT_TYPE_USHORT: num = (unsigned short) va_arg(args, int); break; case FORMAT_TYPE_SHORT: num = (short) va_arg(args, int); break; |
39e874f8a
|
1476 1477 |
case FORMAT_TYPE_INT: num = (int) va_arg(args, int); |
fef20d9c1
|
1478 1479 1480 1481 1482 1483 |
break; default: num = va_arg(args, unsigned int); } str = number(str, end, num, spec); |
1da177e4c
|
1484 |
} |
1da177e4c
|
1485 |
} |
fef20d9c1
|
1486 |
|
f796937a0
|
1487 1488 1489 1490 |
if (size > 0) { if (str < end) *str = '\0'; else |
0a6047eef
|
1491 |
end[-1] = '\0'; |
f796937a0
|
1492 |
} |
fef20d9c1
|
1493 |
|
f796937a0
|
1494 |
/* the trailing null byte doesn't count towards the total */ |
1da177e4c
|
1495 |
return str-buf; |
fef20d9c1
|
1496 |
|
1da177e4c
|
1497 |
} |
1da177e4c
|
1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 |
EXPORT_SYMBOL(vsnprintf); /** * vscnprintf - Format a string and place it in a buffer * @buf: The buffer to place the result into * @size: The size of the buffer, including the trailing null space * @fmt: The format string to use * @args: Arguments for the format string * * The return value is the number of characters which have been written into |
b921c69fb
|
1508 |
* the @buf not including the trailing '\0'. If @size is == 0 the function |
1da177e4c
|
1509 1510 |
* returns 0. * |
ba1835eb3
|
1511 |
* If you're not already dealing with a va_list consider using scnprintf(). |
20036fdca
|
1512 1513 |
* * See the vsnprintf() documentation for format string extensions over C99. |
1da177e4c
|
1514 1515 1516 1517 |
*/ int vscnprintf(char *buf, size_t size, const char *fmt, va_list args) { int i; |
7b9186f5e
|
1518 |
i = vsnprintf(buf, size, fmt, args); |
b921c69fb
|
1519 1520 1521 1522 1523 |
if (likely(i < size)) return i; if (size != 0) return size - 1; return 0; |
1da177e4c
|
1524 |
} |
1da177e4c
|
1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 |
EXPORT_SYMBOL(vscnprintf); /** * snprintf - Format a string and place it in a buffer * @buf: The buffer to place the result into * @size: The size of the buffer, including the trailing null space * @fmt: The format string to use * @...: Arguments for the format string * * The return value is the number of characters which would be * generated for the given input, excluding the trailing null, * as per ISO C99. If the return is greater than or equal to * @size, the resulting string is truncated. |
20036fdca
|
1538 1539 |
* * See the vsnprintf() documentation for format string extensions over C99. |
1da177e4c
|
1540 |
*/ |
7b9186f5e
|
1541 |
int snprintf(char *buf, size_t size, const char *fmt, ...) |
1da177e4c
|
1542 1543 1544 1545 1546 |
{ va_list args; int i; va_start(args, fmt); |
7b9186f5e
|
1547 |
i = vsnprintf(buf, size, fmt, args); |
1da177e4c
|
1548 |
va_end(args); |
7b9186f5e
|
1549 |
|
1da177e4c
|
1550 1551 |
return i; } |
1da177e4c
|
1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 |
EXPORT_SYMBOL(snprintf); /** * scnprintf - Format a string and place it in a buffer * @buf: The buffer to place the result into * @size: The size of the buffer, including the trailing null space * @fmt: The format string to use * @...: Arguments for the format string * * The return value is the number of characters written into @buf not including |
b903c0b88
|
1562 |
* the trailing '\0'. If @size is == 0 the function returns 0. |
1da177e4c
|
1563 |
*/ |
7b9186f5e
|
1564 |
int scnprintf(char *buf, size_t size, const char *fmt, ...) |
1da177e4c
|
1565 1566 1567 1568 1569 |
{ va_list args; int i; va_start(args, fmt); |
b921c69fb
|
1570 |
i = vscnprintf(buf, size, fmt, args); |
1da177e4c
|
1571 |
va_end(args); |
7b9186f5e
|
1572 |
|
b921c69fb
|
1573 |
return i; |
1da177e4c
|
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 |
} EXPORT_SYMBOL(scnprintf); /** * vsprintf - Format a string and place it in a buffer * @buf: The buffer to place the result into * @fmt: The format string to use * @args: Arguments for the format string * * The function returns the number of characters written |
72fd4a35a
|
1584 |
* into @buf. Use vsnprintf() or vscnprintf() in order to avoid |
1da177e4c
|
1585 1586 |
* buffer overflows. * |
ba1835eb3
|
1587 |
* If you're not already dealing with a va_list consider using sprintf(). |
20036fdca
|
1588 1589 |
* * See the vsnprintf() documentation for format string extensions over C99. |
1da177e4c
|
1590 1591 1592 1593 1594 |
*/ int vsprintf(char *buf, const char *fmt, va_list args) { return vsnprintf(buf, INT_MAX, fmt, args); } |
1da177e4c
|
1595 1596 1597 1598 1599 1600 1601 1602 1603 |
EXPORT_SYMBOL(vsprintf); /** * sprintf - Format a string and place it in a buffer * @buf: The buffer to place the result into * @fmt: The format string to use * @...: Arguments for the format string * * The function returns the number of characters written |
72fd4a35a
|
1604 |
* into @buf. Use snprintf() or scnprintf() in order to avoid |
1da177e4c
|
1605 |
* buffer overflows. |
20036fdca
|
1606 1607 |
* * See the vsnprintf() documentation for format string extensions over C99. |
1da177e4c
|
1608 |
*/ |
7b9186f5e
|
1609 |
int sprintf(char *buf, const char *fmt, ...) |
1da177e4c
|
1610 1611 1612 1613 1614 |
{ va_list args; int i; va_start(args, fmt); |
7b9186f5e
|
1615 |
i = vsnprintf(buf, INT_MAX, fmt, args); |
1da177e4c
|
1616 |
va_end(args); |
7b9186f5e
|
1617 |
|
1da177e4c
|
1618 1619 |
return i; } |
1da177e4c
|
1620 |
EXPORT_SYMBOL(sprintf); |
4370aa4aa
|
1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 |
#ifdef CONFIG_BINARY_PRINTF /* * bprintf service: * vbin_printf() - VA arguments to binary data * bstr_printf() - Binary data to text string */ /** * vbin_printf - Parse a format string and place args' binary value in a buffer * @bin_buf: The buffer to place args' binary value * @size: The size of the buffer(by words(32bits), not characters) * @fmt: The format string to use * @args: Arguments for the format string * * The format follows C99 vsnprintf, except %n is ignored, and its argument * is skiped. * * The return value is the number of words(32bits) which would be generated for * the given input. * * NOTE: * If the return value is greater than @size, the resulting bin_buf is NOT * valid for bstr_printf(). */ int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args) { |
fef20d9c1
|
1647 |
struct printf_spec spec = {0}; |
4370aa4aa
|
1648 |
char *str, *end; |
4370aa4aa
|
1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 |
str = (char *)bin_buf; end = (char *)(bin_buf + size); #define save_arg(type) \ do { \ if (sizeof(type) == 8) { \ unsigned long long value; \ str = PTR_ALIGN(str, sizeof(u32)); \ value = va_arg(args, unsigned long long); \ if (str + sizeof(type) <= end) { \ *(u32 *)str = *(u32 *)&value; \ *(u32 *)(str + 4) = *((u32 *)&value + 1); \ } \ } else { \ unsigned long value; \ str = PTR_ALIGN(str, sizeof(type)); \ value = va_arg(args, int); \ if (str + sizeof(type) <= end) \ *(typeof(type) *)str = (type)value; \ } \ str += sizeof(type); \ } while (0) |
fef20d9c1
|
1672 |
while (*fmt) { |
d4be151b2
|
1673 |
int read = format_decode(fmt, &spec); |
4370aa4aa
|
1674 |
|
fef20d9c1
|
1675 |
fmt += read; |
4370aa4aa
|
1676 |
|
fef20d9c1
|
1677 1678 |
switch (spec.type) { case FORMAT_TYPE_NONE: |
d4be151b2
|
1679 1680 |
case FORMAT_TYPE_INVALID: case FORMAT_TYPE_PERCENT_CHAR: |
fef20d9c1
|
1681 |
break; |
ed681a91a
|
1682 |
case FORMAT_TYPE_WIDTH: |
fef20d9c1
|
1683 1684 1685 1686 1687 |
case FORMAT_TYPE_PRECISION: save_arg(int); break; case FORMAT_TYPE_CHAR: |
4370aa4aa
|
1688 |
save_arg(char); |
fef20d9c1
|
1689 1690 1691 |
break; case FORMAT_TYPE_STR: { |
4370aa4aa
|
1692 1693 |
const char *save_str = va_arg(args, char *); size_t len; |
6c3566341
|
1694 |
|
4370aa4aa
|
1695 1696 |
if ((unsigned long)save_str > (unsigned long)-PAGE_SIZE || (unsigned long)save_str < PAGE_SIZE) |
0f4f81dce
|
1697 |
save_str = "(null)"; |
6c3566341
|
1698 1699 1700 1701 |
len = strlen(save_str) + 1; if (str + len < end) memcpy(str, save_str, len); str += len; |
fef20d9c1
|
1702 |
break; |
4370aa4aa
|
1703 |
} |
fef20d9c1
|
1704 1705 |
case FORMAT_TYPE_PTR: |
4370aa4aa
|
1706 1707 |
save_arg(void *); /* skip all alphanumeric pointer suffixes */ |
fef20d9c1
|
1708 |
while (isalnum(*fmt)) |
4370aa4aa
|
1709 |
fmt++; |
fef20d9c1
|
1710 |
break; |
fef20d9c1
|
1711 |
case FORMAT_TYPE_NRCHARS: { |
4370aa4aa
|
1712 |
/* skip %n 's argument */ |
ef0658f3d
|
1713 |
u8 qualifier = spec.qualifier; |
4370aa4aa
|
1714 1715 1716 |
void *skip_arg; if (qualifier == 'l') skip_arg = va_arg(args, long *); |
75fb8f269
|
1717 |
else if (_tolower(qualifier) == 'z') |
4370aa4aa
|
1718 1719 1720 |
skip_arg = va_arg(args, size_t *); else skip_arg = va_arg(args, int *); |
fef20d9c1
|
1721 |
break; |
4370aa4aa
|
1722 |
} |
fef20d9c1
|
1723 1724 1725 1726 1727 |
default: switch (spec.type) { case FORMAT_TYPE_LONG_LONG: |
4370aa4aa
|
1728 |
save_arg(long long); |
fef20d9c1
|
1729 1730 1731 |
break; case FORMAT_TYPE_ULONG: case FORMAT_TYPE_LONG: |
4370aa4aa
|
1732 |
save_arg(unsigned long); |
fef20d9c1
|
1733 1734 |
break; case FORMAT_TYPE_SIZE_T: |
4370aa4aa
|
1735 |
save_arg(size_t); |
fef20d9c1
|
1736 1737 |
break; case FORMAT_TYPE_PTRDIFF: |
4370aa4aa
|
1738 |
save_arg(ptrdiff_t); |
fef20d9c1
|
1739 |
break; |
a4e94ef0d
|
1740 1741 1742 1743 |
case FORMAT_TYPE_UBYTE: case FORMAT_TYPE_BYTE: save_arg(char); break; |
fef20d9c1
|
1744 1745 |
case FORMAT_TYPE_USHORT: case FORMAT_TYPE_SHORT: |
4370aa4aa
|
1746 |
save_arg(short); |
fef20d9c1
|
1747 1748 |
break; default: |
4370aa4aa
|
1749 |
save_arg(int); |
fef20d9c1
|
1750 |
} |
4370aa4aa
|
1751 1752 |
} } |
fef20d9c1
|
1753 |
|
7b9186f5e
|
1754 |
return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf; |
fef20d9c1
|
1755 |
#undef save_arg |
4370aa4aa
|
1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 |
} EXPORT_SYMBOL_GPL(vbin_printf); /** * bstr_printf - Format a string from binary arguments and place it in a buffer * @buf: The buffer to place the result into * @size: The size of the buffer, including the trailing null space * @fmt: The format string to use * @bin_buf: Binary arguments for the format string * * This function like C99 vsnprintf, but the difference is that vsnprintf gets * arguments from stack, and bstr_printf gets arguments from @bin_buf which is * a binary buffer that generated by vbin_printf. * * The format follows C99 vsnprintf, but has some extensions: |
0efb4d207
|
1771 |
* see vsnprintf comment for details. |
4370aa4aa
|
1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 |
* * The return value is the number of characters which would * be generated for the given input, excluding the trailing * '\0', as per ISO C99. If you want to have the exact * number of characters written into @buf as return value * (not including the trailing '\0'), use vscnprintf(). If the * return is greater than or equal to @size, the resulting * string is truncated. */ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf) { |
fef20d9c1
|
1783 |
struct printf_spec spec = {0}; |
d4be151b2
|
1784 1785 |
char *str, *end; const char *args = (const char *)bin_buf; |
4370aa4aa
|
1786 |
|
2f30b1f9e
|
1787 |
if (WARN_ON_ONCE((int) size < 0)) |
4370aa4aa
|
1788 |
return 0; |
4370aa4aa
|
1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 |
str = buf; end = buf + size; #define get_arg(type) \ ({ \ typeof(type) value; \ if (sizeof(type) == 8) { \ args = PTR_ALIGN(args, sizeof(u32)); \ *(u32 *)&value = *(u32 *)args; \ *((u32 *)&value + 1) = *(u32 *)(args + 4); \ } else { \ args = PTR_ALIGN(args, sizeof(type)); \ value = *(typeof(type) *)args; \ } \ args += sizeof(type); \ value; \ }) /* Make sure end is always >= buf */ if (end < buf) { end = ((void *)-1); size = end - buf; } |
fef20d9c1
|
1813 |
while (*fmt) { |
fef20d9c1
|
1814 |
const char *old_fmt = fmt; |
d4be151b2
|
1815 |
int read = format_decode(fmt, &spec); |
4370aa4aa
|
1816 |
|
fef20d9c1
|
1817 |
fmt += read; |
4370aa4aa
|
1818 |
|
fef20d9c1
|
1819 1820 1821 1822 1823 1824 1825 |
switch (spec.type) { case FORMAT_TYPE_NONE: { int copy = read; if (str < end) { if (copy > end - str) copy = end - str; memcpy(str, old_fmt, copy); |
4370aa4aa
|
1826 |
} |
fef20d9c1
|
1827 1828 |
str += read; break; |
4370aa4aa
|
1829 |
} |
ed681a91a
|
1830 |
case FORMAT_TYPE_WIDTH: |
fef20d9c1
|
1831 1832 |
spec.field_width = get_arg(int); break; |
4370aa4aa
|
1833 |
|
fef20d9c1
|
1834 1835 1836 |
case FORMAT_TYPE_PRECISION: spec.precision = get_arg(int); break; |
4370aa4aa
|
1837 |
|
d4be151b2
|
1838 1839 |
case FORMAT_TYPE_CHAR: { char c; |
fef20d9c1
|
1840 1841 |
if (!(spec.flags & LEFT)) { while (--spec.field_width > 0) { |
4370aa4aa
|
1842 1843 1844 1845 1846 1847 1848 1849 1850 |
if (str < end) *str = ' '; ++str; } } c = (unsigned char) get_arg(char); if (str < end) *str = c; ++str; |
fef20d9c1
|
1851 |
while (--spec.field_width > 0) { |
4370aa4aa
|
1852 1853 1854 1855 |
if (str < end) *str = ' '; ++str; } |
fef20d9c1
|
1856 |
break; |
d4be151b2
|
1857 |
} |
4370aa4aa
|
1858 |
|
fef20d9c1
|
1859 |
case FORMAT_TYPE_STR: { |
4370aa4aa
|
1860 |
const char *str_arg = args; |
d4be151b2
|
1861 |
args += strlen(str_arg) + 1; |
fef20d9c1
|
1862 1863 |
str = string(str, end, (char *)str_arg, spec); break; |
4370aa4aa
|
1864 |
} |
fef20d9c1
|
1865 1866 1867 |
case FORMAT_TYPE_PTR: str = pointer(fmt+1, str, end, get_arg(void *), spec); while (isalnum(*fmt)) |
4370aa4aa
|
1868 |
fmt++; |
fef20d9c1
|
1869 |
break; |
4370aa4aa
|
1870 |
|
fef20d9c1
|
1871 |
case FORMAT_TYPE_PERCENT_CHAR: |
fef20d9c1
|
1872 |
case FORMAT_TYPE_INVALID: |
4370aa4aa
|
1873 1874 1875 |
if (str < end) *str = '%'; ++str; |
fef20d9c1
|
1876 1877 1878 1879 1880 |
break; case FORMAT_TYPE_NRCHARS: /* skip */ break; |
d4be151b2
|
1881 1882 |
default: { unsigned long long num; |
fef20d9c1
|
1883 1884 1885 1886 1887 1888 |
switch (spec.type) { case FORMAT_TYPE_LONG_LONG: num = get_arg(long long); break; case FORMAT_TYPE_ULONG: |
fef20d9c1
|
1889 1890 1891 1892 1893 1894 1895 1896 1897 |
case FORMAT_TYPE_LONG: num = get_arg(unsigned long); break; case FORMAT_TYPE_SIZE_T: num = get_arg(size_t); break; case FORMAT_TYPE_PTRDIFF: num = get_arg(ptrdiff_t); break; |
a4e94ef0d
|
1898 1899 1900 1901 1902 1903 |
case FORMAT_TYPE_UBYTE: num = get_arg(unsigned char); break; case FORMAT_TYPE_BYTE: num = get_arg(signed char); break; |
fef20d9c1
|
1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 |
case FORMAT_TYPE_USHORT: num = get_arg(unsigned short); break; case FORMAT_TYPE_SHORT: num = get_arg(short); break; case FORMAT_TYPE_UINT: num = get_arg(unsigned int); break; default: num = get_arg(int); } str = number(str, end, num, spec); |
d4be151b2
|
1918 1919 1920 |
} /* default: */ } /* switch(spec.type) */ } /* while(*fmt) */ |
fef20d9c1
|
1921 |
|
4370aa4aa
|
1922 1923 1924 1925 1926 1927 |
if (size > 0) { if (str < end) *str = '\0'; else end[-1] = '\0'; } |
fef20d9c1
|
1928 |
|
4370aa4aa
|
1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 |
#undef get_arg /* the trailing null byte doesn't count towards the total */ return str - buf; } EXPORT_SYMBOL_GPL(bstr_printf); /** * bprintf - Parse a format string and place args' binary value in a buffer * @bin_buf: The buffer to place args' binary value * @size: The size of the buffer(by words(32bits), not characters) * @fmt: The format string to use * @...: Arguments for the format string * * The function returns the number of words(u32) written * into @bin_buf. */ int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) { va_list args; int ret; va_start(args, fmt); ret = vbin_printf(bin_buf, size, fmt, args); va_end(args); |
7b9186f5e
|
1954 |
|
4370aa4aa
|
1955 1956 1957 1958 1959 |
return ret; } EXPORT_SYMBOL_GPL(bprintf); #endif /* CONFIG_BINARY_PRINTF */ |
1da177e4c
|
1960 1961 1962 1963 1964 1965 |
/** * vsscanf - Unformat a buffer into a list of arguments * @buf: input buffer * @fmt: format of buffer * @args: arguments */ |
7b9186f5e
|
1966 |
int vsscanf(const char *buf, const char *fmt, va_list args) |
1da177e4c
|
1967 1968 1969 1970 1971 |
{ const char *str = buf; char *next; char digit; int num = 0; |
ef0658f3d
|
1972 1973 1974 |
u8 qualifier; u8 base; s16 field_width; |
d4be151b2
|
1975 |
bool is_sign; |
1da177e4c
|
1976 |
|
da99075c1
|
1977 |
while (*fmt) { |
1da177e4c
|
1978 1979 1980 1981 1982 |
/* skip any white space in format */ /* white space in format matchs any amount of * white space, including none, in the input. */ if (isspace(*fmt)) { |
e7d2860b6
|
1983 1984 |
fmt = skip_spaces(++fmt); str = skip_spaces(str); |
1da177e4c
|
1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 |
} /* anything that is not a conversion must match exactly */ if (*fmt != '%' && *fmt) { if (*fmt++ != *str++) break; continue; } if (!*fmt) break; ++fmt; |
7b9186f5e
|
1997 |
|
1da177e4c
|
1998 1999 2000 2001 |
/* skip this conversion. * advance both strings to next white space */ if (*fmt == '*') { |
da99075c1
|
2002 2003 |
if (!*str) break; |
8fccae2c9
|
2004 |
while (!isspace(*fmt) && *fmt != '%' && *fmt) |
1da177e4c
|
2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 |
fmt++; while (!isspace(*str) && *str) str++; continue; } /* get field width */ field_width = -1; if (isdigit(*fmt)) field_width = skip_atoi(&fmt); /* get conversion qualifier */ qualifier = -1; |
75fb8f269
|
2018 2019 |
if (*fmt == 'h' || _tolower(*fmt) == 'l' || _tolower(*fmt) == 'z') { |
1da177e4c
|
2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 |
qualifier = *fmt++; if (unlikely(qualifier == *fmt)) { if (qualifier == 'h') { qualifier = 'H'; fmt++; } else if (qualifier == 'l') { qualifier = 'L'; fmt++; } } } |
1da177e4c
|
2031 |
|
da99075c1
|
2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 |
if (!*fmt) break; if (*fmt == 'n') { /* return number of characters read so far */ *va_arg(args, int *) = str - buf; ++fmt; continue; } if (!*str) |
1da177e4c
|
2043 |
break; |
d4be151b2
|
2044 2045 |
base = 10; is_sign = 0; |
7b9186f5e
|
2046 |
switch (*fmt++) { |
1da177e4c
|
2047 2048 |
case 'c': { |
7b9186f5e
|
2049 |
char *s = (char *)va_arg(args, char*); |
1da177e4c
|
2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 |
if (field_width == -1) field_width = 1; do { *s++ = *str++; } while (--field_width > 0 && *str); num++; } continue; case 's': { |
7b9186f5e
|
2060 2061 |
char *s = (char *)va_arg(args, char *); if (field_width == -1) |
4be929be3
|
2062 |
field_width = SHRT_MAX; |
1da177e4c
|
2063 |
/* first, skip leading white space in buffer */ |
e7d2860b6
|
2064 |
str = skip_spaces(str); |
1da177e4c
|
2065 2066 |
/* now copy until next white space */ |
7b9186f5e
|
2067 |
while (*str && !isspace(*str) && field_width--) |
1da177e4c
|
2068 |
*s++ = *str++; |
1da177e4c
|
2069 2070 2071 2072 |
*s = '\0'; num++; } continue; |
1da177e4c
|
2073 2074 2075 2076 2077 2078 2079 2080 |
case 'o': base = 8; break; case 'x': case 'X': base = 16; break; case 'i': |
7b9186f5e
|
2081 |
base = 0; |
1da177e4c
|
2082 2083 2084 2085 2086 2087 |
case 'd': is_sign = 1; case 'u': break; case '%': /* looking for '%' in str */ |
7b9186f5e
|
2088 |
if (*str++ != '%') |
1da177e4c
|
2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 |
return num; continue; default: /* invalid format; stop here */ return num; } /* have some sort of integer conversion. * first, skip white space in buffer. */ |
e7d2860b6
|
2099 |
str = skip_spaces(str); |
1da177e4c
|
2100 2101 2102 2103 2104 2105 |
digit = *str; if (is_sign && digit == '-') digit = *(str + 1); if (!digit |
7b9186f5e
|
2106 2107 2108 2109 2110 |
|| (base == 16 && !isxdigit(digit)) || (base == 10 && !isdigit(digit)) || (base == 8 && (!isdigit(digit) || digit > '7')) || (base == 0 && !isdigit(digit))) break; |
1da177e4c
|
2111 |
|
7b9186f5e
|
2112 |
switch (qualifier) { |
1da177e4c
|
2113 2114 |
case 'H': /* that's 'hh' in format */ if (is_sign) { |
7b9186f5e
|
2115 2116 |
signed char *s = (signed char *)va_arg(args, signed char *); *s = (signed char)simple_strtol(str, &next, base); |
1da177e4c
|
2117 |
} else { |
7b9186f5e
|
2118 2119 |
unsigned char *s = (unsigned char *)va_arg(args, unsigned char *); *s = (unsigned char)simple_strtoul(str, &next, base); |
1da177e4c
|
2120 2121 2122 2123 |
} break; case 'h': if (is_sign) { |
7b9186f5e
|
2124 2125 |
short *s = (short *)va_arg(args, short *); *s = (short)simple_strtol(str, &next, base); |
1da177e4c
|
2126 |
} else { |
7b9186f5e
|
2127 2128 |
unsigned short *s = (unsigned short *)va_arg(args, unsigned short *); *s = (unsigned short)simple_strtoul(str, &next, base); |
1da177e4c
|
2129 2130 2131 2132 |
} break; case 'l': if (is_sign) { |
7b9186f5e
|
2133 2134 |
long *l = (long *)va_arg(args, long *); *l = simple_strtol(str, &next, base); |
1da177e4c
|
2135 |
} else { |
7b9186f5e
|
2136 2137 |
unsigned long *l = (unsigned long *)va_arg(args, unsigned long *); *l = simple_strtoul(str, &next, base); |
1da177e4c
|
2138 2139 2140 2141 |
} break; case 'L': if (is_sign) { |
7b9186f5e
|
2142 2143 |
long long *l = (long long *)va_arg(args, long long *); *l = simple_strtoll(str, &next, base); |
1da177e4c
|
2144 |
} else { |
7b9186f5e
|
2145 2146 |
unsigned long long *l = (unsigned long long *)va_arg(args, unsigned long long *); *l = simple_strtoull(str, &next, base); |
1da177e4c
|
2147 2148 2149 2150 2151 |
} break; case 'Z': case 'z': { |
7b9186f5e
|
2152 2153 |
size_t *s = (size_t *)va_arg(args, size_t *); *s = (size_t)simple_strtoul(str, &next, base); |
1da177e4c
|
2154 2155 2156 2157 |
} break; default: if (is_sign) { |
7b9186f5e
|
2158 2159 |
int *i = (int *)va_arg(args, int *); *i = (int)simple_strtol(str, &next, base); |
1da177e4c
|
2160 |
} else { |
7b9186f5e
|
2161 2162 |
unsigned int *i = (unsigned int *)va_arg(args, unsigned int*); *i = (unsigned int)simple_strtoul(str, &next, base); |
1da177e4c
|
2163 2164 2165 2166 2167 2168 2169 2170 2171 |
} break; } num++; if (!next) break; str = next; } |
c6b40d16d
|
2172 |
|
1da177e4c
|
2173 2174 |
return num; } |
1da177e4c
|
2175 2176 2177 2178 2179 2180 2181 2182 |
EXPORT_SYMBOL(vsscanf); /** * sscanf - Unformat a buffer into a list of arguments * @buf: input buffer * @fmt: formatting of buffer * @...: resulting arguments */ |
7b9186f5e
|
2183 |
int sscanf(const char *buf, const char *fmt, ...) |
1da177e4c
|
2184 2185 2186 |
{ va_list args; int i; |
7b9186f5e
|
2187 2188 |
va_start(args, fmt); i = vsscanf(buf, fmt, args); |
1da177e4c
|
2189 |
va_end(args); |
7b9186f5e
|
2190 |
|
1da177e4c
|
2191 2192 |
return i; } |
1da177e4c
|
2193 |
EXPORT_SYMBOL(sscanf); |