/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ /* * Wirzenius wrote this portably, Torvalds fucked it up :-)
*/
/* * 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
*/
cp = _parse_integer_fixup_radix(startp, &base);
prefix_chars = cp - startp; if (prefix_chars < max_chars) {
rv = _parse_integer_limit(cp, base, &result, max_chars - prefix_chars); /* FIXME */
cp += (rv & ~KSTRTOX_OVERFLOW);
} else { /* Field too short for prefix + digit, skip over without converting */
cp = startp + max_chars;
}
if (endp)
*endp = (char *)cp;
return result;
}
/** * simple_strtoull - convert a string to an unsigned 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 * * This function has caveats. Please use kstrtoull instead.
*/
noinline unsignedlonglong simple_strtoull(constchar *cp, char **endp, unsignedint base)
{ return simple_strntoull(cp, endp, base, INT_MAX);
}
EXPORT_SYMBOL(simple_strtoull);
/** * simple_strtoul - convert a string to an unsigned 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 * * This function has caveats. Please use kstrtoul instead.
*/ unsignedlong simple_strtoul(constchar *cp, char **endp, unsignedint base)
{ return simple_strtoull(cp, endp, base);
}
EXPORT_SYMBOL(simple_strtoul);
/** * simple_strtol - convert a string to a signed 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 * * This function has caveats. Please use kstrtol instead.
*/ long simple_strtol(constchar *cp, char **endp, unsignedint base)
{ if (*cp == '-') return -simple_strtoul(cp + 1, endp, base);
noinline staticlonglong simple_strntoll(constchar *cp, char **endp, unsignedint base, size_t max_chars)
{ /* * simple_strntoull() safely handles receiving max_chars==0 in the * case cp[0] == '-' && max_chars == 1. * If max_chars == 0 we can drop through and pass it to simple_strntoull() * and the content of *cp is irrelevant.
*/ if (*cp == '-' && max_chars > 0) return -simple_strntoull(cp + 1, endp, base, max_chars - 1);
/** * 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 * * This function has caveats. Please use kstrtoll instead.
*/ longlong simple_strtoll(constchar *cp, char **endp, unsignedint base)
{ return simple_strntoll(cp, endp, base, INT_MAX);
}
EXPORT_SYMBOL(simple_strtoll);
staticinlineint skip_atoi(constchar **s)
{ int i = 0;
do {
i = i*10 + *((*s)++) - '0';
} while (isdigit(**s));
return i;
}
/* * 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 by emitting * two characters at a time, using a 200 byte lookup table. This * roughly halves the number of multiplications compared to computing * the digits one at a time. Implementation strongly inspired by the * previous version, which in turn used ideas described at * <http://www.cs.uiowa.edu/~jones/bcd/divide.html> (with permission * from the author, Douglas W. Jones). * * It turns out there is precisely one 26 bit fixed-point * approximation a of 64/100 for which x/100 == (x * (u64)a) >> 32 * holds for all x in [0, 10^8-1], namely a = 0x28f5c29. The actual * range happens to be somewhat larger (x <= 1073741898), but that's * irrelevant for our purpose. * * For dividing a number in the range [10^4, 10^6-1] by 100, we still * need a 32x32->64 bit multiply, so we simply use the same constant. * * For dividing a number in the range [100, 10^4-1] by 100, there are * several options. The simplest is (x * 0x147b) >> 19, which is valid * for all x <= 43698.
*/
/* * This will print a single '0' even if r == 0, since we would * immediately jump to out_r where two 0s would be written but only * one of them accounted for in buf. This is needed by ip4_string * below. All other callers pass a non-zero value of r.
*/ static noinline_for_stack char *put_dec_trunc8(char *buf, unsigned r)
{ unsigned q;
/* * 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. * (second call in the put_dec code, assuming n is all-ones).
*/ static noinline_for_stack 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;
}
/* 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, unsignedlonglong n)
{
uint32_t d3, d2, d1, q, h;
if (n < 100*1000*1000) return put_dec_trunc8(buf, n);
/* * 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, unsignedlonglong num, unsignedint width)
{ /* put_dec requires 2-byte alignment of the buffer. */ char tmp[sizeof(num) * 3] __aligned(2); int idx, len;
/* 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;
}
#define SIGN 1/* unsigned/signed */ #define LEFT 2/* left justified */ #define PLUS 4/* show plus */ #define SPACE 8/* space if plus */ #define ZEROPAD 16/* pad with zero, must be 16 == '0' - ' ' */ #define SMALL 32/* use lowercase in hex (must be 32 == 0x20) */ #define SPECIAL 64/* prefix hex with "0x", octal with "0" */
enum format_state {
FORMAT_STATE_NONE, /* Just a string part */
FORMAT_STATE_NUM,
FORMAT_STATE_WIDTH,
FORMAT_STATE_PRECISION,
FORMAT_STATE_CHAR,
FORMAT_STATE_STR,
FORMAT_STATE_PTR,
FORMAT_STATE_PERCENT_CHAR,
FORMAT_STATE_INVALID,
};
struct printf_spec { unsignedchar flags; /* flags to number() */ unsignedchar base; /* number base, 8, 10 or 16 only */ short precision; /* # of digits/chars */ int field_width; /* width of output field */
} __packed;
static_assert(sizeof(struct printf_spec) == 8);
static noinline_for_stack char *number(char *buf, char *end, unsignedlonglong num, struct printf_spec spec)
{ /* put_dec requires 2-byte alignment of the buffer. */ char tmp[3 * sizeof(num)] __aligned(2); char sign; char locase; int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); int i; bool is_zero = num == 0LL; int field_width = spec.field_width; int precision = spec.precision;
/* locase = 0 or 0x20. ORing digits or letters with 'locase'
* produces same digits or (maybe lowercased) letters */
locase = (spec.flags & SMALL); if (spec.flags & LEFT)
spec.flags &= ~ZEROPAD;
sign = 0; if (spec.flags & SIGN) { if ((signedlonglong)num < 0) {
sign = '-';
num = -(signedlonglong)num;
field_width--;
} elseif (spec.flags & PLUS) {
sign = '+';
field_width--;
} elseif (spec.flags & SPACE) {
sign = ' ';
field_width--;
}
} if (need_pfx) { if (spec.base == 16)
field_width -= 2; elseif (!is_zero)
field_width--;
}
/* generate full string in tmp[], in reverse order */
i = 0; if (num < spec.base)
tmp[i++] = hex_asc_upper[num] | locase; elseif (spec.base != 10) { /* 8 or 16 */ int mask = spec.base - 1; int shift = 3;
if (spec.base == 16)
shift = 4; do {
tmp[i++] = (hex_asc_upper[((unsignedchar)num) & mask] | locase);
num >>= shift;
} while (num);
} else { /* base 10 */
i = put_dec(tmp, num) - tmp;
}
/* printing 100 using %2d gives "100", not "00" */ if (i > precision)
precision = i; /* leading space padding */
field_width -= precision; if (!(spec.flags & (ZEROPAD | LEFT))) { while (--field_width >= 0) { if (buf < end)
*buf = ' ';
++buf;
}
} /* sign */ if (sign) { if (buf < end)
*buf = sign;
++buf;
} /* "0x" / "0" prefix */ if (need_pfx) { if (spec.base == 16 || !is_zero) { if (buf < end)
*buf = '0';
++buf;
} if (spec.base == 16) { if (buf < end)
*buf = ('X' | locase);
++buf;
}
} /* zero or space padding */ if (!(spec.flags & LEFT)) { char c = ' ' + (spec.flags & ZEROPAD);
while (--field_width >= 0) { if (buf < end)
*buf = c;
++buf;
}
} /* hmm even more zero padding? */ while (i <= --precision) { if (buf < end)
*buf = '0';
++buf;
} /* actual digits of result */ while (--i >= 0) { if (buf < end)
*buf = tmp[i];
++buf;
} /* trailing space padding */ while (--field_width >= 0) { if (buf < end)
*buf = ' ';
++buf;
}
staticvoid move_right(char *buf, char *end, unsigned len, unsigned spaces)
{
size_t size; if (buf >= end) /* nowhere to put anything */ return;
size = end - buf; if (size <= spaces) {
memset(buf, ' ', size); return;
} if (len) { if (len > size - spaces)
len = size - spaces;
memmove(buf + spaces, buf, len);
}
memset(buf, ' ', spaces);
}
/* * Handle field width padding for a string. * @buf: current buffer position * @n: length of string * @end: end of output buffer * @spec: for field width and flags * Returns: new buffer position after padding.
*/ static noinline_for_stack char *widen_string(char *buf, int n, char *end, struct printf_spec spec)
{ unsigned spaces;
if (likely(n >= spec.field_width)) return buf; /* we want to pad the sucker */
spaces = spec.field_width - n; if (!(spec.flags & LEFT)) {
move_right(buf - n, end, n, spaces); return buf + spaces;
} while (spaces--) { if (buf < end)
*buf = ' ';
++buf;
} return buf;
}
/* Handle string from a well known address. */ staticchar *string_nocheck(char *buf, char *end, constchar *s, struct printf_spec spec)
{ int len = 0; int lim = spec.precision;
while (lim--) { char c = *s++; if (!c) break; if (buf < end)
*buf = c;
++buf;
++len;
} return widen_string(buf, len, end, spec);
}
if (sym) return string_nocheck(buf, end, sym, spec);
/* * Somebody passed ERR_PTR(-1234) or some other non-existing * Efoo - or perhaps CONFIG_SYMBOLIC_ERRNAME=n. Fall back to * printing it as its decimal representation.
*/
spec.flags |= SIGN;
spec.base = 10; return number(buf, end, err, spec);
}
/* Be careful: error messages must fit into the given buffer. */ staticchar *error_string(char *buf, char *end, constchar *s, struct printf_spec spec)
{ /* * Hard limit to avoid a completely insane messages. It actually * works pretty well because most error messages are in * the many pointer format modifiers.
*/ if (spec.precision == -1)
spec.precision = 2 * sizeof(void *);
return string_nocheck(buf, end, s, spec);
}
/* * Do not call any complex external code here. Nested printk()/vsprintf() * might cause infinite loops. Failures might break printk() and would * be hard to debug.
*/ staticconstchar *check_pointer_msg(constvoid *ptr)
{ if (!ptr) return"(null)";
if ((unsignedlong)ptr < PAGE_SIZE || IS_ERR_VALUE(ptr)) return"(efault)";
/* Maps a pointer to a 32 bit unique identifier. */ staticinlineint __ptr_to_hashval(constvoid *ptr, unsignedlong *hashval_out)
{ unsignedlong hashval;
if (!READ_ONCE(filled_random_ptr_key)) return -EBUSY;
/* Pairs with smp_wmb() after writing ptr_key. */
smp_rmb();
#ifdef CONFIG_64BIT
hashval = (unsignedlong)siphash_1u64((u64)ptr, &ptr_key); /* * Mask off the first 32 bits, this makes explicit that we have * modified the address (and 32 bits is plenty for a unique ID).
*/
hashval = hashval & 0xffffffff; #else
hashval = (unsignedlong)siphash_1u32((u32)ptr, &ptr_key); #endif
*hashval_out = hashval; return0;
}
int ptr_to_hashval(constvoid *ptr, unsignedlong *hashval_out)
{ return __ptr_to_hashval(ptr, hashval_out);
}
/* * Print the real pointer value for NULL and error pointers, * as they are not actual addresses.
*/ if (IS_ERR_OR_NULL(ptr)) return pointer_string(buf, end, ptr, spec);
/* When debugging early boot use non-cryptographically secure hash. */ if (unlikely(debug_boot_weak_hash)) {
hashval = hash_long((unsignedlong)ptr, 32); return pointer_string(buf, end, (constvoid *)hashval, spec);
}
ret = __ptr_to_hashval(ptr, &hashval); if (ret) {
spec.field_width = 2 * sizeof(ptr); /* string length must be less than default_width */ return error_string(buf, end, str, spec);
}
staticchar *default_pointer(char *buf, char *end, constvoid *ptr, struct printf_spec spec)
{ /* * default is to _not_ leak addresses, so hash before printing, * unless no_hash_pointers is specified on the command line.
*/ if (unlikely(no_hash_pointers)) return pointer_string(buf, end, ptr, spec);
/* * kptr_restrict==1 cannot be used in IRQ context * because its test for CAP_SYSLOG would be meaningless.
*/ if (in_hardirq() || in_serving_softirq() || in_nmi()) { if (spec.field_width == -1)
spec.field_width = 2 * sizeof(ptr); return error_string(buf, end, "pK-error", spec);
}
/* * Only print the real pointer value if the current * process has CAP_SYSLOG and is running with the * same credentials it started with. This is because * access to files is checked at open() time, but %pK * checks permission at read() time. We don't want to * leak pointer values if a binary opens a file using * %pK and then elevates privileges before reading it.
*/
cred = current_cred(); if (!has_capability_noaudit(current, CAP_SYSLOG) ||
!uid_eq(cred->euid, cred->uid) ||
!gid_eq(cred->egid, cred->gid))
ptr = NULL; break;
} case2: default: /* Always print 0's for %pK */
ptr = NULL; break;
}
return pointer_string(buf, end, ptr, spec);
}
static noinline_for_stack char *dentry_name(char *buf, char *end, conststruct dentry *d, struct printf_spec spec, constchar *fmt)
{ constchar *array[4], *s; conststruct dentry *p; int depth; int i, n;
rcu_read_lock(); for (i = 0; i < depth; i++, d = p) { if (check_pointer(&buf, end, d, spec)) {
rcu_read_unlock(); return buf;
}
p = READ_ONCE(d->d_parent);
array[i] = READ_ONCE(d->d_name.name); if (p == d) { if (i)
array[i] = "";
i++; break;
}
}
s = array[--i]; for (n = 0; n != spec.precision; n++, buf++) { char c = *s++; if (!c) { if (!i) break;
c = '/';
s = array[--i];
} if (buf < end)
*buf = c;
}
rcu_read_unlock(); return widen_string(buf, n, end, spec);
}
if (check_pointer(&buf, end, range, spec)) return buf;
p = string_nocheck(p, pend, "[range ", default_str_spec);
p = hex_range(p, pend, range->start, range->end, range_spec);
*p++ = ']';
*p = '\0';
return string_nocheck(buf, end, sym, spec);
}
static noinline_for_stack char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec, constchar *fmt)
{ int i, len = 1; /* if we pass '%ph[CDN]', field width remains
negative value, fallback to the default */ char separator;
if (spec.field_width == 0) /* nothing to print */ return buf;
if (check_pointer(&buf, end, addr, spec)) return buf;
static noinline_for_stack char *ip4_string(char *p, const u8 *addr, constchar *fmt)
{ int i; 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;
} for (i = 0; i < 4; i++) { char temp[4] __aligned(2); /* hold each IP quad in reverse order */ int digits = put_dec_trunc8(temp, addr[index]) - temp; 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++ = '.';
index += step;
}
*p = '\0';
return p;
}
static noinline_for_stack char *ip6_compressed_string(char *p, constchar *addr)
{ int i, j, range; unsignedchar zerolength[8]; int longest = 1; int colonpos = -1;
u16 word;
u8 hi, lo; bool needcolon = false; bool useIPv4; struct in6_addr in6;
/* find position of longest 0 run */ for (i = 0; i < range; i++) { for (j = i; j < range; j++) { if (in6.s6_addr16[j] != 0) break;
zerolength[i]++;
}
} for (i = 0; i < range; i++) { if (zerolength[i] > longest) {
longest = zerolength[i];
colonpos = i;
}
} if (longest == 1) /* don't compress a single 0 */
colonpos = -1;
/* 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 */
word = ntohs(in6.s6_addr16[i]);
hi = word >> 8;
lo = word & 0xff; if (hi) { if (hi > 0x0f)
p = hex_byte_pack(p, hi); else
*p++ = hex_asc_lo(hi);
p = hex_byte_pack(p, lo);
} elseif (lo > 0x0f)
p = hex_byte_pack(p, lo); else
*p++ = hex_asc_lo(lo);
needcolon = true;
}
if (useIPv4) { if (needcolon)
*p++ = ':';
p = ip4_string(p, &in6.s6_addr[12], "I4");
}
*p = '\0';
len = spec.field_width < 0 ? 1 : spec.field_width;
/* * string_escape_mem() writes as many characters as it can to * the given buffer, and returns the total size of the output * had the buffer been big enough.
*/
buf += string_escape_mem(addr, len, buf, buf < end ? end - buf : 0, flags, NULL);
/* Loop starting from the root node to the current node. */ for (depth = fwnode_count_parents(fwnode); depth >= 0; depth--) { /* * Only get a reference for other nodes (i.e. parent nodes). * fwnode refcount may be 0 here.
*/ struct fwnode_handle *__fwnode = depth ?
fwnode_get_nth_parent(fwnode, depth) : fwnode;
void __init hash_pointers_finalize(bool slub_debug)
{ switch (hash_pointers_mode) { case HASH_PTR_ALWAYS:
no_hash_pointers = false; break; case HASH_PTR_NEVER:
no_hash_pointers = true; break; case HASH_PTR_AUTO: default:
no_hash_pointers = slub_debug; break;
}
if (!no_hash_pointers) return;
pr_warn("**********************************************************\n");
pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n");
pr_warn("** **\n");
pr_warn("** This system shows unhashed kernel memory addresses **\n");
pr_warn("** via the console, logs, and other interfaces. This **\n");
pr_warn("** might reduce the security of your system. **\n");
pr_warn("** **\n");
pr_warn("** If you see this message and you are not debugging **\n");
pr_warn("** the kernel, report this immediately to your system **\n");
pr_warn("** administrator! **\n");
pr_warn("** **\n");
pr_warn("** Use hash_pointers=always to force this mode off **\n");
pr_warn("** **\n");
pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n");
pr_warn("**********************************************************\n");
}
staticint __init hash_pointers_mode_parse(char *str)
{ if (!str) {
pr_warn("Hash pointers mode empty; falling back to auto.\n");
hash_pointers_mode = HASH_PTR_AUTO;
} elseif (strncmp(str, "auto", 4) == 0) {
pr_info("Hash pointers mode set to auto.\n");
hash_pointers_mode = HASH_PTR_AUTO;
} elseif (strncmp(str, "never", 5) == 0) {
pr_info("Hash pointers mode set to never.\n");
hash_pointers_mode = HASH_PTR_NEVER;
} elseif (strncmp(str, "always", 6) == 0) {
pr_info("Hash pointers mode set to always.\n");
hash_pointers_mode = HASH_PTR_ALWAYS;
} else {
pr_warn("Unknown hash_pointers mode '%s' specified; assuming auto.\n", str);
hash_pointers_mode = HASH_PTR_AUTO;
}
/* * 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. * * Please update scripts/checkpatch.pl when adding/removing conversion * characters. (Search for "check for vsprintf extension"). * * Right now we handle: * * - 'S' For symbolic direct pointers (or function descriptors) with offset * - 's' For symbolic direct pointers (or function descriptors) without offset * - '[Ss]R' as above with __builtin_extract_return_addr() translation * - 'S[R]b' as above with module build ID (for use in backtraces) * - '[Ff]' %pf and %pF were obsoleted and later removed in favor of * %ps and %pS. Be careful when re-using these specifiers. * - 'B' For backtraced symbolic direct pointers with offset * - 'Bb' as above with module build ID (for use in backtraces) * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref] * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201] * - 'ra' For struct ranges, e.g., [range 0x0000000000000000 - 0x00000000000000ff] * - 'b[l]' For a bitmap, the number of bits is determined by the field * width which must be explicitly specified either as part of the * format string '%32b[l]' or through '%*b[l]', [l] selects * range-list format instead of hex format * - 'M' For a 6-byte MAC address, it prints the address in the * usual colon-separated hex notation * - 'm' For a 6-byte MAC address, it prints the hex address without colons * - 'MF' For a 6-byte MAC FDDI address, it prints the address * with a dash-separated hex notation * - '[mM]R' For a 6-byte MAC address, Reverse order (Bluetooth) * - '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 * [S][pfs] * Generic IPv4/IPv6 address (struct sockaddr *) that falls back to * [4] or [6] and is able to print port [p], flowinfo [f], scope [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) * [S][pfs] * Generic IPv4/IPv6 address (struct sockaddr *) that falls back to * [4] or [6] and is able to print port [p], flowinfo [f], scope [s] * - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order * - 'I[6S]c' for IPv6 addresses printed as specified by * https://tools.ietf.org/html/rfc5952 * - 'E[achnops]' For an escaped buffer, where rules are defined by combination * of the following flags (see string_escape_mem() for the * details): * a - ESCAPE_ANY * c - ESCAPE_SPECIAL * h - ESCAPE_HEX * n - ESCAPE_NULL * o - ESCAPE_OCTAL * p - ESCAPE_NP * s - ESCAPE_SPACE * By default ESCAPE_ANY_NP is used. * - '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] * - '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. * - 'K' For a kernel pointer that should be hidden from unprivileged users. * Use only for procfs, sysfs and similar files, not printk(); please * read the documentation (path below) first. * - 'NF' For a netdev_features_t * - '4cc' V4L2 or DRM FourCC code, with endianness and raw numerical value. * - '4c[h[R]lb]' For generic FourCC code with raw numerical value. Both are * displayed in the big-endian format. This is the opposite of V4L2 or * DRM FourCCs. * The additional specifiers define what endianness is used to load * the stored bytes. The data might be interpreted using the host, * reversed host byte order, little-endian, or big-endian. * - '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. * - 'a[pd]' For address types [p] phys_addr_t, [d] dma_addr_t and derivatives * (default assumed to be phys_addr_t, passed by reference) * - 'd[234]' For a dentry name (optionally 2-4 last components) * - 'D[234]' Same as 'd' but for a struct file * - 'g' For block_device name (gendisk + partition number) * - 't[RT][dt][r][s]' For time and date as represented by: * R struct rtc_time * T time64_t * - 'C' For a clock, it prints the name (Common Clock Framework) or address * (legacy clock framework) of the clock * - 'G' For flags to be printed as a collection of symbolic strings that would * construct the specific value. Supported flags given by option: * p page flags (see struct page) given as pointer to unsigned long * g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t * v vma flags (VM_*) given as pointer to unsigned long * - 'OF[fnpPcCF]' For a device tree object * Without any optional arguments prints the full_name * f device node full_name * n device node name * p device node phandle * P device node path spec (name + @unit) * F device node flags * c major compatible string * C full compatible string * - 'fw[fP]' For a firmware node (struct fwnode_handle) pointer * Without an option prints the full name of the node * f full name * P node name, including a possible unit address * - 'x' For printing the address unmodified. Equivalent to "%lx". * Please read the documentation (path below) before using! * - '[ku]s' For a BPF/tracing related format specifier, e.g. used out of * bpf_trace_printk() where [ku] prefix specifies either kernel (k) * or user (u) memory to probe, and: * s a string, equivalent to "%s" on direct vsnprintf() use * * ** When making changes please also update: * Documentation/core-api/printk-formats.rst * * Note: The default behaviour (unadorned %p) is to hash the address, * rendering it useful as a unique identifier. * * There is also a '%pA' format specifier, but it is only intended to be used * from Rust code to format core::fmt::Arguments. Do *not* use it from C. * See rust/kernel/print.rs for details.
*/ static noinline_for_stack char *pointer(constchar *fmt, char *buf, char *end, void *ptr, struct printf_spec spec)
{ switch (*fmt) { case'S': case's':
ptr = dereference_symbol_descriptor(ptr);
fallthrough; case'B': return symbol_string(buf, end, ptr, spec, fmt); case'R': case'r': return resource_or_range(fmt, buf, end, ptr, spec); case'h': return hex_string(buf, end, ptr, spec, fmt); case'b': switch (fmt[1]) { case'l': return bitmap_list_string(buf, end, ptr, spec, fmt); default: return bitmap_string(buf, end, ptr, spec, fmt);
} case'M': /* Colon separated: 00:01:02:03:04:05 */ case'm': /* Contiguous: 000102030405 */ /* [mM]F (FDDI) */ /* [mM]R (Reverse order; Bluetooth) */ 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
*/ return ip_addr_string(buf, end, ptr, spec, fmt); case'E': return escaped_string(buf, end, ptr, spec, fmt); case'U': return uuid_string(buf, end, ptr, spec, fmt); case'V': return va_format(buf, end, ptr, spec); case'K': return restricted_pointer(buf, end, ptr, spec); case'N': return netdev_bits(buf, end, ptr, spec, fmt); case'4': return fourcc_string(buf, end, ptr, spec, fmt); case'a': return address_val(buf, end, ptr, spec, fmt); case'd': return dentry_name(buf, end, ptr, spec, fmt); case't': return time_and_date(buf, end, ptr, spec, fmt); case'C': return clock(buf, end, ptr, spec, fmt); case'D': return file_dentry_name(buf, end, ptr, spec, fmt); #ifdef CONFIG_BLOCK case'g': return bdev_name(buf, end, ptr, spec, fmt); #endif
/* * 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 * 'Z' changed to 'z' --adobriyan 2017-01-25 * '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, ...)
*/ static noinline_for_stack struct fmt format_decode(struct fmt fmt, struct printf_spec *spec)
{ constchar *start = fmt.str; char flag;
/* we finished early by reading the field width */ if (unlikely(fmt.state == FORMAT_STATE_WIDTH)) { if (spec->field_width < 0) {
spec->field_width = -spec->field_width;
spec->flags |= LEFT;
}
fmt.state = FORMAT_STATE_NONE; goto precision;
}
/* we finished early by reading the precision */ if (unlikely(fmt.state == FORMAT_STATE_PRECISION)) { if (spec->precision < 0)
spec->precision = 0;
fmt.state = FORMAT_STATE_NONE; goto qualifier;
}
/* By default */
fmt.state = FORMAT_STATE_NONE;
for (; *fmt.str ; fmt.str++) { if (*fmt.str == '%') break;
}
/* Return the current non-format string */ if (fmt.str != start || !*fmt.str) return fmt;
/* Process flags. This also skips the first '%' */
spec->flags = 0; do { /* this also skips first '%' */
flag = spec_flag(*++fmt.str);
spec->flags |= flag;
} while (flag);
/* get field width */
spec->field_width = -1;
if (isdigit(*fmt.str))
spec->field_width = skip_atoi(&fmt.str); elseif (unlikely(*fmt.str == '*')) { /* it's the next argument */
fmt.state = FORMAT_STATE_WIDTH;
fmt.str++; return fmt;
}
precision: /* get the precision */
spec->precision = -1; if (unlikely(*fmt.str == '.')) {
fmt.str++; if (isdigit(*fmt.str)) {
spec->precision = skip_atoi(&fmt.str); if (spec->precision < 0)
spec->precision = 0;
} elseif (*fmt.str == '*') { /* it's the next argument */
fmt.state = FORMAT_STATE_PRECISION;
fmt.str++; return fmt;
}
}
/* * Since %n poses a greater security risk than * utility, treat it as any other invalid or * unsupported format specifier.
*/
};
conststruct format_state *p = lookup_state + (u8)*fmt.str; if (p->size) {
fmt.size = p->size; if (p->flags_or_double_size && fmt.str[0] == fmt.str[1]) {
fmt.size = p->flags_or_double_size;
fmt.str++;
}
fmt.str++;
p = lookup_state + *fmt.str;
} if (p->state) { if (p->base)
spec->base = p->base;
spec->flags |= p->flags_or_double_size;
fmt.state = p->state;
fmt.str++; return fmt;
}
WARN_ONCE(1, "Please remove unsupported %%%c in format string\n", *fmt.str);
fmt.state = FORMAT_STATE_INVALID; return fmt;
}
staticvoid
set_field_width(struct printf_spec *spec, int width)
{
spec->field_width = width; if (WARN_ONCE(spec->field_width != width, "field width %d too large", width)) {
spec->field_width = clamp(width, -FIELD_WIDTH_MAX, FIELD_WIDTH_MAX);
}
}
staticvoid
set_precision(struct printf_spec *spec, int prec)
{
spec->precision = prec; if (WARN_ONCE(spec->precision != prec, "precision %d too large", prec)) {
spec->precision = clamp(prec, 0, PRECISION_MAX);
}
}
/* * Turn a 1/2/4-byte value into a 64-bit one for printing: truncate * as necessary and deal with signedness. * * 'size' is the size of the value in bytes.
*/ staticunsignedlonglong convert_num_spec(unsignedint val, int size, struct printf_spec spec)
{ unsignedint shift = 32 - size*8;
val <<= shift; if (!(spec.flags & SIGN)) return val >> shift; return (int)val >> shift;
}
/** * 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_str: The format string to use * @args: Arguments for the format string * * This function generally follows C99 vsnprintf, but has some * extensions and a few limitations: * * - ``%n`` is unsupported * - ``%p*`` is handled by pointer() * * See pointer() or Documentation/core-api/printk-formats.rst for more * extensive description. * * **Please update the documentation in both places when making changes** * * 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. * * If you're not already dealing with a va_list consider using snprintf().
*/ int vsnprintf(char *buf, size_t size, constchar *fmt_str, va_list args)
{ char *str, *end; struct printf_spec spec = {0}; struct fmt fmt = {
.str = fmt_str,
.state = FORMAT_STATE_NONE,
};
/* Reject out-of-range values early. Large positive sizes are
used for unknown buffer sizes. */ if (WARN_ON_ONCE(size > INT_MAX)) return0;
str = buf;
end = buf + size;
/* Make sure end is always >= buf */ if (end < buf) {
end = ((void *)-1);
size = end - buf;
}
while (*fmt.str) { constchar *old_fmt = fmt.str;
fmt = format_decode(fmt, &spec);
switch (fmt.state) { case FORMAT_STATE_NONE: { int read = fmt.str - old_fmt; if (str < end) { int copy = read; if (copy > end - str)
copy = end - str;
memcpy(str, old_fmt, copy);
}
str += read; continue;
}
case FORMAT_STATE_NUM: { unsignedlonglong num; if (fmt.size <= sizeof(int))
num = convert_num_spec(va_arg(args, int), fmt.size, spec); else
num = va_arg(args, longlong);
str = number(str, end, num, spec); continue;
}
case FORMAT_STATE_WIDTH:
set_field_width(&spec, va_arg(args, int)); continue;
case FORMAT_STATE_PRECISION:
set_precision(&spec, va_arg(args, int)); continue;
case FORMAT_STATE_CHAR: { char c;
if (!(spec.flags & LEFT)) { while (--spec.field_width > 0) { if (str < end)
*str = ' ';
++str;
}
}
c = (unsignedchar) va_arg(args, int); if (str < end)
*str = c;
++str; while (--spec.field_width > 0) { if (str < end)
*str = ' ';
++str;
} continue;
}
case FORMAT_STATE_PTR:
str = pointer(fmt.str, str, end, va_arg(args, void *),
spec); while (isalnum(*fmt.str))
fmt.str++; continue;
case FORMAT_STATE_PERCENT_CHAR: if (str < end)
*str = '%';
++str; continue;
default: /* * Presumably the arguments passed gcc's type * checking, but there is no safe or sane way * for us to continue parsing the format and * fetching from the va_list; the remaining * specifiers and arguments would be out of * sync.
*/ goto out;
}
}
out: if (size > 0) { if (str < end)
*str = '\0'; else
end[-1] = '\0';
}
/* the trailing null byte doesn't count towards the total */ return str-buf;
}
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 * the @buf not including the trailing '\0'. If @size is == 0 the function * returns 0. * * If you're not already dealing with a va_list consider using scnprintf(). * * See the vsnprintf() documentation for format string extensions over C99.
*/ int vscnprintf(char *buf, size_t size, constchar *fmt, va_list args)
{ int i;
if (unlikely(!size)) return0;
i = vsnprintf(buf, size, fmt, args);
if (likely(i < size)) return i;
return size - 1;
}
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. * * See the vsnprintf() documentation for format string extensions over C99.
*/ int snprintf(char *buf, size_t size, constchar *fmt, ...)
{
va_list args; int i;
va_start(args, fmt);
i = vsnprintf(buf, size, fmt, args);
va_end(args);
return i;
}
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 * the trailing '\0'. If @size is == 0 the function returns 0.
*/
int scnprintf(char *buf, size_t size, constchar *fmt, ...)
{
va_list args; int i;
va_start(args, fmt);
i = vscnprintf(buf, size, fmt, args);
va_end(args);
return i;
}
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 * into @buf. Use vsnprintf() or vscnprintf() in order to avoid * buffer overflows. * * If you're not already dealing with a va_list consider using sprintf(). * * See the vsnprintf() documentation for format string extensions over C99.
*/ int vsprintf(char *buf, constchar *fmt, va_list args)
{ return vsnprintf(buf, INT_MAX, fmt, args);
}
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 * into @buf. Use snprintf() or scnprintf() in order to avoid * buffer overflows. * * See the vsnprintf() documentation for format string extensions over C99.
*/ int sprintf(char *buf, constchar *fmt, ...)
{
va_list args; int i;
va_start(args, fmt);
i = vsnprintf(buf, INT_MAX, fmt, args);
va_end(args);
return i;
}
EXPORT_SYMBOL(sprintf);
#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_str: The format string to use * @args: Arguments for the format string * * The format follows C99 vsnprintf, except %n is ignored, and its argument * is skipped. * * 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, constchar *fmt_str, va_list args)
{ struct fmt fmt = {
.str = fmt_str,
.state = FORMAT_STATE_NONE,
}; struct printf_spec spec = {0}; char *str, *end; int width;
str = (char *)bin_buf;
end = (char *)(bin_buf + size);
while (*fmt.str) {
fmt = format_decode(fmt, &spec);
switch (fmt.state) { case FORMAT_STATE_NONE: case FORMAT_STATE_PERCENT_CHAR: break; case FORMAT_STATE_INVALID: goto out;
case FORMAT_STATE_WIDTH: case FORMAT_STATE_PRECISION:
width = (int)save_arg(int); /* Pointers may require the width */ if (*fmt.str == 'p')
set_field_width(&spec, width); break;
/** * 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_str: 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: * see vsnprintf comment for details. * * 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, constchar *fmt_str, const u32 *bin_buf)
{ struct fmt fmt = {
.str = fmt_str,
.state = FORMAT_STATE_NONE,
}; struct printf_spec spec = {0}; char *str, *end; constchar *args = (constchar *)bin_buf;
case FORMAT_STATE_PTR: { bool process = false; int copy, len; /* Non function dereferences were already done */ switch (*fmt.str) { case'S': case's': case'x': case'K': case'e':
process = true; break; default: if (!isalnum(*fmt.str)) {
process = true; break;
} /* Pointer dereference was already processed */ if (str < end) {
len = copy = strlen(args); if (copy > end - str)
copy = end - str;
memcpy(str, args, copy);
str += len;
args += len + 1;
}
} if (process)
str = pointer(fmt.str, str, end, get_arg(void *), spec);
while (isalnum(*fmt.str))
fmt.str++; continue;
}
case FORMAT_STATE_PERCENT_CHAR: if (str < end)
*str = '%';
++str; continue;
case FORMAT_STATE_INVALID: goto out;
case FORMAT_STATE_NUM: if (fmt.size > sizeof(int)) {
num = get_arg(longlong);
} else {
num = convert_num_spec(get_arg(int), fmt.size, spec);
}
str = number(str, end, num, spec); continue;
}
} /* while(*fmt.str) */
out: if (size > 0) { if (str < end)
*str = '\0'; else
end[-1] = '\0';
}
#undef get_arg
/* the trailing null byte doesn't count towards the total */ return str - buf;
}
EXPORT_SYMBOL_GPL(bstr_printf);
#endif/* CONFIG_BINARY_PRINTF */
/** * vsscanf - Unformat a buffer into a list of arguments * @buf: input buffer * @fmt: format of buffer * @args: arguments
*/ int vsscanf(constchar *buf, constchar *fmt, va_list args)
{ constchar *str = buf; char *next; char digit; int num = 0;
u8 qualifier; unsignedint base; union { longlong s; unsignedlonglong u;
} val;
s16 field_width; bool is_sign;
while (*fmt) { /* skip any white space in format */ /* white space in format matches any amount of * white space, including none, in the input.
*/ if (isspace(*fmt)) {
fmt = skip_spaces(++fmt);
str = skip_spaces(str);
}
/* anything that is not a conversion must match exactly */ if (*fmt != '%' && *fmt) { if (*fmt++ != *str++) break; continue;
}
if (!*fmt) break;
++fmt;
/* skip this conversion. * advance both strings to next white space
*/ if (*fmt == '*') { if (!*str) break; while (!isspace(*fmt) && *fmt != '%' && *fmt) { /* '%*[' not yet supported, invalid format */ if (*fmt == '[') return num;
fmt++;
} while (!isspace(*str) && *str)
str++; continue;
}
/* get field width */
field_width = -1; if (isdigit(*fmt)) {
field_width = skip_atoi(&fmt); if (field_width <= 0) break;
}
if (*fmt == 'n') { /* return number of characters read so far */
*va_arg(args, int *) = str - buf;
++fmt; continue;
}
if (!*str) break;
base = 10;
is_sign = false;
switch (*fmt++) { case'c':
{ char *s = (char *)va_arg(args, char*); if (field_width == -1)
field_width = 1; do {
*s++ = *str++;
} while (--field_width > 0 && *str);
num++;
} continue; case's':
{ char *s = (char *)va_arg(args, char *); if (field_width == -1)
field_width = SHRT_MAX; /* first, skip leading white space in buffer */
str = skip_spaces(str);
/* now copy until next white space */ while (*str && !isspace(*str) && field_width--)
*s++ = *str++;
*s = '\0';
num++;
} continue; /* * Warning: This implementation of the '[' conversion specifier * deviates from its glibc counterpart in the following ways: * (1) It does NOT support ranges i.e. '-' is NOT a special * character * (2) It cannot match the closing bracket ']' itself * (3) A field width is required * (4) '%*[' (discard matching input) is currently not supported * * Example usage: * ret = sscanf("00:0a:95","%2[^:]:%2[^:]:%2[^:]", * buf1, buf2, buf3); * if (ret < 3) * // etc..
*/ case'[':
{ char *s = (char *)va_arg(args, char *);
DECLARE_BITMAP(set, 256) = {0}; unsignedint len = 0; bool negate = (*fmt == '^');
/* field width is required */ if (field_width == -1) return num;
switch (qualifier) { case'H': /* that's 'hh' in format */ if (is_sign)
*va_arg(args, signedchar *) = val.s; else
*va_arg(args, unsignedchar *) = val.u; break; case'h': if (is_sign)
*va_arg(args, short *) = val.s; else
*va_arg(args, unsignedshort *) = val.u; break; case'l': if (is_sign)
*va_arg(args, long *) = val.s; else
*va_arg(args, unsignedlong *) = val.u; break; case'L': if (is_sign)
*va_arg(args, longlong *) = val.s; else
*va_arg(args, unsignedlonglong *) = val.u; break; case'z':
*va_arg(args, size_t *) = val.u; break; default: if (is_sign)
*va_arg(args, int *) = val.s; else
*va_arg(args, unsignedint *) = val.u; break;
}
num++;
if (!next) break;
str = next;
}
return num;
}
EXPORT_SYMBOL(vsscanf);
/** * sscanf - Unformat a buffer into a list of arguments * @buf: input buffer * @fmt: formatting of buffer * @...: resulting arguments
*/ int sscanf(constchar *buf, constchar *fmt, ...)
{
va_list args; int i;
va_start(args, fmt);
i = vsscanf(buf, fmt, args);
va_end(args);
return i;
}
EXPORT_SYMBOL(sscanf);
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.84Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-06-05)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.