/* 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; return 0;
}
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);
return ptr_to_id(buf, end, ptr, spec);
}
int kptr_restrict __read_mostly;
static noinline_for_stack char *restricted_pointer(char *buf, char *end, constvoid *ptr, struct printf_spec spec)
{ switch (kptr_restrict) { case 0: /* Handle as %p, hash and do _not_ leak addresses. */ return default_pointer(buf, end, ptr, spec); case 1: { conststruct cred *cred;
/* * 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;
} case 2: 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);
for (i = 0; i < 16; i++) { if (uc)
p = hex_byte_pack_upper(p, addr[index[i]]); else
p = hex_byte_pack(p, addr[index[i]]); switch (i) { case 3: case 5: case 7: case 9:
*p++ = '-'; break;
}
}
/* 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
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.