1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * linux/lib/vsprintf.c 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds 61da177e4SLinus Torvalds */ 71da177e4SLinus Torvalds 81da177e4SLinus Torvalds /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ 91da177e4SLinus Torvalds /* 101da177e4SLinus Torvalds * Wirzenius wrote this portably, Torvalds fucked it up :-) 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds 131da177e4SLinus Torvalds /* 141da177e4SLinus Torvalds * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com> 151da177e4SLinus Torvalds * - changed to provide snprintf and vsnprintf functions 161da177e4SLinus Torvalds * So Feb 1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de> 171da177e4SLinus Torvalds * - scnprintf and vscnprintf 181da177e4SLinus Torvalds */ 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds #include <stdarg.h> 21ef27ac18SRasmus Villemoes #include <linux/build_bug.h> 220d1d7a55SStephen Boyd #include <linux/clk.h> 23900cca29SGeert Uytterhoeven #include <linux/clk-provider.h> 24*57f5677eSRasmus Villemoes #include <linux/errname.h> 258bc3bcc9SPaul Gortmaker #include <linux/module.h> /* for KSYM_SYMBOL_LEN */ 261da177e4SLinus Torvalds #include <linux/types.h> 271da177e4SLinus Torvalds #include <linux/string.h> 281da177e4SLinus Torvalds #include <linux/ctype.h> 291da177e4SLinus Torvalds #include <linux/kernel.h> 300fe1ef24SLinus Torvalds #include <linux/kallsyms.h> 3153809751SJan Beulich #include <linux/math64.h> 320fe1ef24SLinus Torvalds #include <linux/uaccess.h> 33332d2e78SLinus Torvalds #include <linux/ioport.h> 344b6ccca7SAl Viro #include <linux/dcache.h> 35312b4e22SRyan Mallon #include <linux/cred.h> 364d42c447SAndy Shevchenko #include <linux/rtc.h> 372b1b0d66SAndy Shevchenko #include <linux/uuid.h> 38ce4fecf1SPantelis Antoniou #include <linux/of.h> 398a27f7c9SJoe Perches #include <net/addrconf.h> 40ad67b74dSTobin C. Harding #include <linux/siphash.h> 41ad67b74dSTobin C. Harding #include <linux/compiler.h> 421031bc58SDmitry Monakhov #ifdef CONFIG_BLOCK 431031bc58SDmitry Monakhov #include <linux/blkdev.h> 441031bc58SDmitry Monakhov #endif 451da177e4SLinus Torvalds 46edf14cdbSVlastimil Babka #include "../mm/internal.h" /* For the trace_print_flags arrays */ 47edf14cdbSVlastimil Babka 484e57b681STim Schmielau #include <asm/page.h> /* for PAGE_SIZE */ 497c43d9a3SRasmus Villemoes #include <asm/byteorder.h> /* cpu_to_le16 */ 501da177e4SLinus Torvalds 5171dca95dSAndy Shevchenko #include <linux/string_helpers.h> 521dff46d6SAlexey Dobriyan #include "kstrtox.h" 53aa46a63eSHarvey Harrison 541da177e4SLinus Torvalds /** 551da177e4SLinus Torvalds * simple_strtoull - convert a string to an unsigned long long 561da177e4SLinus Torvalds * @cp: The start of the string 571da177e4SLinus Torvalds * @endp: A pointer to the end of the parsed string will be placed here 581da177e4SLinus Torvalds * @base: The number base to use 59462e4711SEldad Zack * 60462e4711SEldad Zack * This function is obsolete. Please use kstrtoull instead. 611da177e4SLinus Torvalds */ 621da177e4SLinus Torvalds unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base) 631da177e4SLinus Torvalds { 641dff46d6SAlexey Dobriyan unsigned long long result; 651dff46d6SAlexey Dobriyan unsigned int rv; 661da177e4SLinus Torvalds 671dff46d6SAlexey Dobriyan cp = _parse_integer_fixup_radix(cp, &base); 681dff46d6SAlexey Dobriyan rv = _parse_integer(cp, base, &result); 691dff46d6SAlexey Dobriyan /* FIXME */ 701dff46d6SAlexey Dobriyan cp += (rv & ~KSTRTOX_OVERFLOW); 71aa46a63eSHarvey Harrison 721da177e4SLinus Torvalds if (endp) 731da177e4SLinus Torvalds *endp = (char *)cp; 747b9186f5SAndré Goddard Rosa 751da177e4SLinus Torvalds return result; 761da177e4SLinus Torvalds } 771da177e4SLinus Torvalds EXPORT_SYMBOL(simple_strtoull); 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds /** 80922ac25cSAndré Goddard Rosa * simple_strtoul - convert a string to an unsigned long 81922ac25cSAndré Goddard Rosa * @cp: The start of the string 82922ac25cSAndré Goddard Rosa * @endp: A pointer to the end of the parsed string will be placed here 83922ac25cSAndré Goddard Rosa * @base: The number base to use 84462e4711SEldad Zack * 85462e4711SEldad Zack * This function is obsolete. Please use kstrtoul instead. 86922ac25cSAndré Goddard Rosa */ 87922ac25cSAndré Goddard Rosa unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) 88922ac25cSAndré Goddard Rosa { 89922ac25cSAndré Goddard Rosa return simple_strtoull(cp, endp, base); 90922ac25cSAndré Goddard Rosa } 91922ac25cSAndré Goddard Rosa EXPORT_SYMBOL(simple_strtoul); 92922ac25cSAndré Goddard Rosa 93922ac25cSAndré Goddard Rosa /** 94922ac25cSAndré Goddard Rosa * simple_strtol - convert a string to a signed long 95922ac25cSAndré Goddard Rosa * @cp: The start of the string 96922ac25cSAndré Goddard Rosa * @endp: A pointer to the end of the parsed string will be placed here 97922ac25cSAndré Goddard Rosa * @base: The number base to use 98462e4711SEldad Zack * 99462e4711SEldad Zack * This function is obsolete. Please use kstrtol instead. 100922ac25cSAndré Goddard Rosa */ 101922ac25cSAndré Goddard Rosa long simple_strtol(const char *cp, char **endp, unsigned int base) 102922ac25cSAndré Goddard Rosa { 103922ac25cSAndré Goddard Rosa if (*cp == '-') 104922ac25cSAndré Goddard Rosa return -simple_strtoul(cp + 1, endp, base); 105922ac25cSAndré Goddard Rosa 106922ac25cSAndré Goddard Rosa return simple_strtoul(cp, endp, base); 107922ac25cSAndré Goddard Rosa } 108922ac25cSAndré Goddard Rosa EXPORT_SYMBOL(simple_strtol); 109922ac25cSAndré Goddard Rosa 110922ac25cSAndré Goddard Rosa /** 1111da177e4SLinus Torvalds * simple_strtoll - convert a string to a signed long long 1121da177e4SLinus Torvalds * @cp: The start of the string 1131da177e4SLinus Torvalds * @endp: A pointer to the end of the parsed string will be placed here 1141da177e4SLinus Torvalds * @base: The number base to use 115462e4711SEldad Zack * 116462e4711SEldad Zack * This function is obsolete. Please use kstrtoll instead. 1171da177e4SLinus Torvalds */ 1181da177e4SLinus Torvalds long long simple_strtoll(const char *cp, char **endp, unsigned int base) 1191da177e4SLinus Torvalds { 1201da177e4SLinus Torvalds if (*cp == '-') 1211da177e4SLinus Torvalds return -simple_strtoull(cp + 1, endp, base); 1227b9186f5SAndré Goddard Rosa 1231da177e4SLinus Torvalds return simple_strtoull(cp, endp, base); 1241da177e4SLinus Torvalds } 12598d5ce0dSHans Verkuil EXPORT_SYMBOL(simple_strtoll); 1261da177e4SLinus Torvalds 127cf3b429bSJoe Perches static noinline_for_stack 128cf3b429bSJoe Perches int skip_atoi(const char **s) 1291da177e4SLinus Torvalds { 1301da177e4SLinus Torvalds int i = 0; 1311da177e4SLinus Torvalds 13243e5b666SRasmus Villemoes do { 1331da177e4SLinus Torvalds i = i*10 + *((*s)++) - '0'; 13443e5b666SRasmus Villemoes } while (isdigit(**s)); 1357b9186f5SAndré Goddard Rosa 1361da177e4SLinus Torvalds return i; 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds 1397c43d9a3SRasmus Villemoes /* 1407c43d9a3SRasmus Villemoes * Decimal conversion is by far the most typical, and is used for 1417c43d9a3SRasmus Villemoes * /proc and /sys data. This directly impacts e.g. top performance 1427c43d9a3SRasmus Villemoes * with many processes running. We optimize it for speed by emitting 1437c43d9a3SRasmus Villemoes * two characters at a time, using a 200 byte lookup table. This 1447c43d9a3SRasmus Villemoes * roughly halves the number of multiplications compared to computing 1457c43d9a3SRasmus Villemoes * the digits one at a time. Implementation strongly inspired by the 1467c43d9a3SRasmus Villemoes * previous version, which in turn used ideas described at 1477c43d9a3SRasmus Villemoes * <http://www.cs.uiowa.edu/~jones/bcd/divide.html> (with permission 1487c43d9a3SRasmus Villemoes * from the author, Douglas W. Jones). 1497c43d9a3SRasmus Villemoes * 1507c43d9a3SRasmus Villemoes * It turns out there is precisely one 26 bit fixed-point 1517c43d9a3SRasmus Villemoes * approximation a of 64/100 for which x/100 == (x * (u64)a) >> 32 1527c43d9a3SRasmus Villemoes * holds for all x in [0, 10^8-1], namely a = 0x28f5c29. The actual 1537c43d9a3SRasmus Villemoes * range happens to be somewhat larger (x <= 1073741898), but that's 1547c43d9a3SRasmus Villemoes * irrelevant for our purpose. 1557c43d9a3SRasmus Villemoes * 1567c43d9a3SRasmus Villemoes * For dividing a number in the range [10^4, 10^6-1] by 100, we still 1577c43d9a3SRasmus Villemoes * need a 32x32->64 bit multiply, so we simply use the same constant. 1587c43d9a3SRasmus Villemoes * 1597c43d9a3SRasmus Villemoes * For dividing a number in the range [100, 10^4-1] by 100, there are 1607c43d9a3SRasmus Villemoes * several options. The simplest is (x * 0x147b) >> 19, which is valid 1617c43d9a3SRasmus Villemoes * for all x <= 43698. 162133fd9f5SDenys Vlasenko */ 1634277eeddSDenis Vlasenko 1647c43d9a3SRasmus Villemoes static const u16 decpair[100] = { 1657c43d9a3SRasmus Villemoes #define _(x) (__force u16) cpu_to_le16(((x % 10) | ((x / 10) << 8)) + 0x3030) 1667c43d9a3SRasmus Villemoes _( 0), _( 1), _( 2), _( 3), _( 4), _( 5), _( 6), _( 7), _( 8), _( 9), 1677c43d9a3SRasmus Villemoes _(10), _(11), _(12), _(13), _(14), _(15), _(16), _(17), _(18), _(19), 1687c43d9a3SRasmus Villemoes _(20), _(21), _(22), _(23), _(24), _(25), _(26), _(27), _(28), _(29), 1697c43d9a3SRasmus Villemoes _(30), _(31), _(32), _(33), _(34), _(35), _(36), _(37), _(38), _(39), 1707c43d9a3SRasmus Villemoes _(40), _(41), _(42), _(43), _(44), _(45), _(46), _(47), _(48), _(49), 1717c43d9a3SRasmus Villemoes _(50), _(51), _(52), _(53), _(54), _(55), _(56), _(57), _(58), _(59), 1727c43d9a3SRasmus Villemoes _(60), _(61), _(62), _(63), _(64), _(65), _(66), _(67), _(68), _(69), 1737c43d9a3SRasmus Villemoes _(70), _(71), _(72), _(73), _(74), _(75), _(76), _(77), _(78), _(79), 1747c43d9a3SRasmus Villemoes _(80), _(81), _(82), _(83), _(84), _(85), _(86), _(87), _(88), _(89), 1757c43d9a3SRasmus Villemoes _(90), _(91), _(92), _(93), _(94), _(95), _(96), _(97), _(98), _(99), 1767c43d9a3SRasmus Villemoes #undef _ 1777c43d9a3SRasmus Villemoes }; 1784277eeddSDenis Vlasenko 1797b9186f5SAndré Goddard Rosa /* 1807c43d9a3SRasmus Villemoes * This will print a single '0' even if r == 0, since we would 181675cf53cSRasmus Villemoes * immediately jump to out_r where two 0s would be written but only 182675cf53cSRasmus Villemoes * one of them accounted for in buf. This is needed by ip4_string 183675cf53cSRasmus Villemoes * below. All other callers pass a non-zero value of r. 184133fd9f5SDenys Vlasenko */ 185133fd9f5SDenys Vlasenko static noinline_for_stack 186133fd9f5SDenys Vlasenko char *put_dec_trunc8(char *buf, unsigned r) 187133fd9f5SDenys Vlasenko { 188133fd9f5SDenys Vlasenko unsigned q; 1894277eeddSDenis Vlasenko 1907c43d9a3SRasmus Villemoes /* 1 <= r < 10^8 */ 1917c43d9a3SRasmus Villemoes if (r < 100) 1927c43d9a3SRasmus Villemoes goto out_r; 193cb239d0aSGeorge Spelvin 1947c43d9a3SRasmus Villemoes /* 100 <= r < 10^8 */ 1957c43d9a3SRasmus Villemoes q = (r * (u64)0x28f5c29) >> 32; 1967c43d9a3SRasmus Villemoes *((u16 *)buf) = decpair[r - 100*q]; 1977c43d9a3SRasmus Villemoes buf += 2; 1987c43d9a3SRasmus Villemoes 1997c43d9a3SRasmus Villemoes /* 1 <= q < 10^6 */ 2007c43d9a3SRasmus Villemoes if (q < 100) 2017c43d9a3SRasmus Villemoes goto out_q; 2027c43d9a3SRasmus Villemoes 2037c43d9a3SRasmus Villemoes /* 100 <= q < 10^6 */ 2047c43d9a3SRasmus Villemoes r = (q * (u64)0x28f5c29) >> 32; 2057c43d9a3SRasmus Villemoes *((u16 *)buf) = decpair[q - 100*r]; 2067c43d9a3SRasmus Villemoes buf += 2; 2077c43d9a3SRasmus Villemoes 2087c43d9a3SRasmus Villemoes /* 1 <= r < 10^4 */ 2097c43d9a3SRasmus Villemoes if (r < 100) 2107c43d9a3SRasmus Villemoes goto out_r; 2117c43d9a3SRasmus Villemoes 2127c43d9a3SRasmus Villemoes /* 100 <= r < 10^4 */ 2137c43d9a3SRasmus Villemoes q = (r * 0x147b) >> 19; 2147c43d9a3SRasmus Villemoes *((u16 *)buf) = decpair[r - 100*q]; 2157c43d9a3SRasmus Villemoes buf += 2; 2167c43d9a3SRasmus Villemoes out_q: 2177c43d9a3SRasmus Villemoes /* 1 <= q < 100 */ 2187c43d9a3SRasmus Villemoes r = q; 2197c43d9a3SRasmus Villemoes out_r: 2207c43d9a3SRasmus Villemoes /* 1 <= r < 100 */ 2217c43d9a3SRasmus Villemoes *((u16 *)buf) = decpair[r]; 222675cf53cSRasmus Villemoes buf += r < 10 ? 1 : 2; 223133fd9f5SDenys Vlasenko return buf; 224133fd9f5SDenys Vlasenko } 225133fd9f5SDenys Vlasenko 2267c43d9a3SRasmus Villemoes #if BITS_PER_LONG == 64 && BITS_PER_LONG_LONG == 64 2277c43d9a3SRasmus Villemoes static noinline_for_stack 2287c43d9a3SRasmus Villemoes char *put_dec_full8(char *buf, unsigned r) 2297c43d9a3SRasmus Villemoes { 2307c43d9a3SRasmus Villemoes unsigned q; 231133fd9f5SDenys Vlasenko 2327c43d9a3SRasmus Villemoes /* 0 <= r < 10^8 */ 2337c43d9a3SRasmus Villemoes q = (r * (u64)0x28f5c29) >> 32; 2347c43d9a3SRasmus Villemoes *((u16 *)buf) = decpair[r - 100*q]; 2357c43d9a3SRasmus Villemoes buf += 2; 236133fd9f5SDenys Vlasenko 2377c43d9a3SRasmus Villemoes /* 0 <= q < 10^6 */ 2387c43d9a3SRasmus Villemoes r = (q * (u64)0x28f5c29) >> 32; 2397c43d9a3SRasmus Villemoes *((u16 *)buf) = decpair[q - 100*r]; 2407c43d9a3SRasmus Villemoes buf += 2; 241133fd9f5SDenys Vlasenko 2427c43d9a3SRasmus Villemoes /* 0 <= r < 10^4 */ 2437c43d9a3SRasmus Villemoes q = (r * 0x147b) >> 19; 2447c43d9a3SRasmus Villemoes *((u16 *)buf) = decpair[r - 100*q]; 2457c43d9a3SRasmus Villemoes buf += 2; 2467c43d9a3SRasmus Villemoes 2477c43d9a3SRasmus Villemoes /* 0 <= q < 100 */ 2487c43d9a3SRasmus Villemoes *((u16 *)buf) = decpair[q]; 2497c43d9a3SRasmus Villemoes buf += 2; 2507c43d9a3SRasmus Villemoes return buf; 2517c43d9a3SRasmus Villemoes } 2527c43d9a3SRasmus Villemoes 2537c43d9a3SRasmus Villemoes static noinline_for_stack 254133fd9f5SDenys Vlasenko char *put_dec(char *buf, unsigned long long n) 255133fd9f5SDenys Vlasenko { 256133fd9f5SDenys Vlasenko if (n >= 100*1000*1000) 2577c43d9a3SRasmus Villemoes buf = put_dec_full8(buf, do_div(n, 100*1000*1000)); 2587c43d9a3SRasmus Villemoes /* 1 <= n <= 1.6e11 */ 2597c43d9a3SRasmus Villemoes if (n >= 100*1000*1000) 2607c43d9a3SRasmus Villemoes buf = put_dec_full8(buf, do_div(n, 100*1000*1000)); 2617c43d9a3SRasmus Villemoes /* 1 <= n < 1e8 */ 262133fd9f5SDenys Vlasenko return put_dec_trunc8(buf, n); 263133fd9f5SDenys Vlasenko } 264133fd9f5SDenys Vlasenko 2657c43d9a3SRasmus Villemoes #elif BITS_PER_LONG == 32 && BITS_PER_LONG_LONG == 64 266133fd9f5SDenys Vlasenko 2677c43d9a3SRasmus Villemoes static void 2687c43d9a3SRasmus Villemoes put_dec_full4(char *buf, unsigned r) 269133fd9f5SDenys Vlasenko { 2707c43d9a3SRasmus Villemoes unsigned q; 2717c43d9a3SRasmus Villemoes 2727c43d9a3SRasmus Villemoes /* 0 <= r < 10^4 */ 2737c43d9a3SRasmus Villemoes q = (r * 0x147b) >> 19; 2747c43d9a3SRasmus Villemoes *((u16 *)buf) = decpair[r - 100*q]; 2757c43d9a3SRasmus Villemoes buf += 2; 2767c43d9a3SRasmus Villemoes /* 0 <= q < 100 */ 2777c43d9a3SRasmus Villemoes *((u16 *)buf) = decpair[q]; 2782359172aSGeorge Spelvin } 2792359172aSGeorge Spelvin 2802359172aSGeorge Spelvin /* 2812359172aSGeorge Spelvin * Call put_dec_full4 on x % 10000, return x / 10000. 2822359172aSGeorge Spelvin * The approximation x/10000 == (x * 0x346DC5D7) >> 43 2832359172aSGeorge Spelvin * holds for all x < 1,128,869,999. The largest value this 2842359172aSGeorge Spelvin * helper will ever be asked to convert is 1,125,520,955. 2857c43d9a3SRasmus Villemoes * (second call in the put_dec code, assuming n is all-ones). 2862359172aSGeorge Spelvin */ 2877c43d9a3SRasmus Villemoes static noinline_for_stack 2882359172aSGeorge Spelvin unsigned put_dec_helper4(char *buf, unsigned x) 2892359172aSGeorge Spelvin { 2902359172aSGeorge Spelvin uint32_t q = (x * (uint64_t)0x346DC5D7) >> 43; 2912359172aSGeorge Spelvin 2922359172aSGeorge Spelvin put_dec_full4(buf, x - q * 10000); 2932359172aSGeorge Spelvin return q; 294133fd9f5SDenys Vlasenko } 295133fd9f5SDenys Vlasenko 296133fd9f5SDenys Vlasenko /* Based on code by Douglas W. Jones found at 297133fd9f5SDenys Vlasenko * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour> 298133fd9f5SDenys Vlasenko * (with permission from the author). 299133fd9f5SDenys Vlasenko * Performs no 64-bit division and hence should be fast on 32-bit machines. 300133fd9f5SDenys Vlasenko */ 301133fd9f5SDenys Vlasenko static 302133fd9f5SDenys Vlasenko char *put_dec(char *buf, unsigned long long n) 303133fd9f5SDenys Vlasenko { 304133fd9f5SDenys Vlasenko uint32_t d3, d2, d1, q, h; 305133fd9f5SDenys Vlasenko 306133fd9f5SDenys Vlasenko if (n < 100*1000*1000) 307133fd9f5SDenys Vlasenko return put_dec_trunc8(buf, n); 308133fd9f5SDenys Vlasenko 309133fd9f5SDenys Vlasenko d1 = ((uint32_t)n >> 16); /* implicit "& 0xffff" */ 310133fd9f5SDenys Vlasenko h = (n >> 32); 311133fd9f5SDenys Vlasenko d2 = (h ) & 0xffff; 312133fd9f5SDenys Vlasenko d3 = (h >> 16); /* implicit "& 0xffff" */ 313133fd9f5SDenys Vlasenko 3147c43d9a3SRasmus Villemoes /* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0 3157c43d9a3SRasmus Villemoes = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */ 316133fd9f5SDenys Vlasenko q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff); 3172359172aSGeorge Spelvin q = put_dec_helper4(buf, q); 318133fd9f5SDenys Vlasenko 3192359172aSGeorge Spelvin q += 7671 * d3 + 9496 * d2 + 6 * d1; 3202359172aSGeorge Spelvin q = put_dec_helper4(buf+4, q); 321133fd9f5SDenys Vlasenko 3222359172aSGeorge Spelvin q += 4749 * d3 + 42 * d2; 3232359172aSGeorge Spelvin q = put_dec_helper4(buf+8, q); 324133fd9f5SDenys Vlasenko 3252359172aSGeorge Spelvin q += 281 * d3; 3262359172aSGeorge Spelvin buf += 12; 3272359172aSGeorge Spelvin if (q) 3282359172aSGeorge Spelvin buf = put_dec_trunc8(buf, q); 3292359172aSGeorge Spelvin else while (buf[-1] == '0') 330133fd9f5SDenys Vlasenko --buf; 3317b9186f5SAndré Goddard Rosa 3324277eeddSDenis Vlasenko return buf; 3334277eeddSDenis Vlasenko } 334133fd9f5SDenys Vlasenko 335133fd9f5SDenys Vlasenko #endif 3364277eeddSDenis Vlasenko 3371ac101a5SKAMEZAWA Hiroyuki /* 3381ac101a5SKAMEZAWA Hiroyuki * Convert passed number to decimal string. 3391ac101a5SKAMEZAWA Hiroyuki * Returns the length of string. On buffer overflow, returns 0. 3401ac101a5SKAMEZAWA Hiroyuki * 3411ac101a5SKAMEZAWA Hiroyuki * If speed is not important, use snprintf(). It's easy to read the code. 3421ac101a5SKAMEZAWA Hiroyuki */ 343d1be35cbSAndrei Vagin int num_to_str(char *buf, int size, unsigned long long num, unsigned int width) 3441ac101a5SKAMEZAWA Hiroyuki { 3457c43d9a3SRasmus Villemoes /* put_dec requires 2-byte alignment of the buffer. */ 3467c43d9a3SRasmus Villemoes char tmp[sizeof(num) * 3] __aligned(2); 3471ac101a5SKAMEZAWA Hiroyuki int idx, len; 3481ac101a5SKAMEZAWA Hiroyuki 349133fd9f5SDenys Vlasenko /* put_dec() may work incorrectly for num = 0 (generate "", not "0") */ 350133fd9f5SDenys Vlasenko if (num <= 9) { 351133fd9f5SDenys Vlasenko tmp[0] = '0' + num; 352133fd9f5SDenys Vlasenko len = 1; 353133fd9f5SDenys Vlasenko } else { 3541ac101a5SKAMEZAWA Hiroyuki len = put_dec(tmp, num) - tmp; 355133fd9f5SDenys Vlasenko } 3561ac101a5SKAMEZAWA Hiroyuki 357d1be35cbSAndrei Vagin if (len > size || width > size) 3581ac101a5SKAMEZAWA Hiroyuki return 0; 359d1be35cbSAndrei Vagin 360d1be35cbSAndrei Vagin if (width > len) { 361d1be35cbSAndrei Vagin width = width - len; 362d1be35cbSAndrei Vagin for (idx = 0; idx < width; idx++) 363d1be35cbSAndrei Vagin buf[idx] = ' '; 364d1be35cbSAndrei Vagin } else { 365d1be35cbSAndrei Vagin width = 0; 366d1be35cbSAndrei Vagin } 367d1be35cbSAndrei Vagin 3681ac101a5SKAMEZAWA Hiroyuki for (idx = 0; idx < len; ++idx) 369d1be35cbSAndrei Vagin buf[idx + width] = tmp[len - idx - 1]; 370d1be35cbSAndrei Vagin 371d1be35cbSAndrei Vagin return len + width; 3721ac101a5SKAMEZAWA Hiroyuki } 3731ac101a5SKAMEZAWA Hiroyuki 37451be17dfSRasmus Villemoes #define SIGN 1 /* unsigned/signed, must be 1 */ 375d1c1b121SRasmus Villemoes #define LEFT 2 /* left justified */ 3761da177e4SLinus Torvalds #define PLUS 4 /* show plus */ 3771da177e4SLinus Torvalds #define SPACE 8 /* space if plus */ 378d1c1b121SRasmus Villemoes #define ZEROPAD 16 /* pad with zero, must be 16 == '0' - ' ' */ 379b89dc5d6SBjorn Helgaas #define SMALL 32 /* use lowercase in hex (must be 32 == 0x20) */ 380b89dc5d6SBjorn Helgaas #define SPECIAL 64 /* prefix hex with "0x", octal with "0" */ 3811da177e4SLinus Torvalds 382fef20d9cSFrederic Weisbecker enum format_type { 383fef20d9cSFrederic Weisbecker FORMAT_TYPE_NONE, /* Just a string part */ 384ed681a91SVegard Nossum FORMAT_TYPE_WIDTH, 385fef20d9cSFrederic Weisbecker FORMAT_TYPE_PRECISION, 386fef20d9cSFrederic Weisbecker FORMAT_TYPE_CHAR, 387fef20d9cSFrederic Weisbecker FORMAT_TYPE_STR, 388fef20d9cSFrederic Weisbecker FORMAT_TYPE_PTR, 389fef20d9cSFrederic Weisbecker FORMAT_TYPE_PERCENT_CHAR, 390fef20d9cSFrederic Weisbecker FORMAT_TYPE_INVALID, 391fef20d9cSFrederic Weisbecker FORMAT_TYPE_LONG_LONG, 392fef20d9cSFrederic Weisbecker FORMAT_TYPE_ULONG, 393fef20d9cSFrederic Weisbecker FORMAT_TYPE_LONG, 394a4e94ef0SZhaolei FORMAT_TYPE_UBYTE, 395a4e94ef0SZhaolei FORMAT_TYPE_BYTE, 396fef20d9cSFrederic Weisbecker FORMAT_TYPE_USHORT, 397fef20d9cSFrederic Weisbecker FORMAT_TYPE_SHORT, 398fef20d9cSFrederic Weisbecker FORMAT_TYPE_UINT, 399fef20d9cSFrederic Weisbecker FORMAT_TYPE_INT, 400fef20d9cSFrederic Weisbecker FORMAT_TYPE_SIZE_T, 401fef20d9cSFrederic Weisbecker FORMAT_TYPE_PTRDIFF 402fef20d9cSFrederic Weisbecker }; 403fef20d9cSFrederic Weisbecker 404fef20d9cSFrederic Weisbecker struct printf_spec { 405d0484193SRasmus Villemoes unsigned int type:8; /* format_type enum */ 406d0484193SRasmus Villemoes signed int field_width:24; /* width of output field */ 407d0484193SRasmus Villemoes unsigned int flags:8; /* flags to number() */ 408d0484193SRasmus Villemoes unsigned int base:8; /* number base, 8, 10 or 16 only */ 409d0484193SRasmus Villemoes signed int precision:16; /* # of digits/chars */ 410d0484193SRasmus Villemoes } __packed; 411ef27ac18SRasmus Villemoes static_assert(sizeof(struct printf_spec) == 8); 412ef27ac18SRasmus Villemoes 4134d72ba01SRasmus Villemoes #define FIELD_WIDTH_MAX ((1 << 23) - 1) 4144d72ba01SRasmus Villemoes #define PRECISION_MAX ((1 << 15) - 1) 415fef20d9cSFrederic Weisbecker 416cf3b429bSJoe Perches static noinline_for_stack 417cf3b429bSJoe Perches char *number(char *buf, char *end, unsigned long long num, 418fef20d9cSFrederic Weisbecker struct printf_spec spec) 4191da177e4SLinus Torvalds { 4207c43d9a3SRasmus Villemoes /* put_dec requires 2-byte alignment of the buffer. */ 4217c43d9a3SRasmus Villemoes char tmp[3 * sizeof(num)] __aligned(2); 4229b706aeeSDenys Vlasenko char sign; 4239b706aeeSDenys Vlasenko char locase; 424fef20d9cSFrederic Weisbecker int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); 4251da177e4SLinus Torvalds int i; 4267c203422SPierre Carrier bool is_zero = num == 0LL; 4271c7a8e62SRasmus Villemoes int field_width = spec.field_width; 4281c7a8e62SRasmus Villemoes int precision = spec.precision; 4291da177e4SLinus Torvalds 4309b706aeeSDenys Vlasenko /* locase = 0 or 0x20. ORing digits or letters with 'locase' 4319b706aeeSDenys Vlasenko * produces same digits or (maybe lowercased) letters */ 432fef20d9cSFrederic Weisbecker locase = (spec.flags & SMALL); 433fef20d9cSFrederic Weisbecker if (spec.flags & LEFT) 434fef20d9cSFrederic Weisbecker spec.flags &= ~ZEROPAD; 4351da177e4SLinus Torvalds sign = 0; 436fef20d9cSFrederic Weisbecker if (spec.flags & SIGN) { 4371da177e4SLinus Torvalds if ((signed long long)num < 0) { 4381da177e4SLinus Torvalds sign = '-'; 4391da177e4SLinus Torvalds num = -(signed long long)num; 4401c7a8e62SRasmus Villemoes field_width--; 441fef20d9cSFrederic Weisbecker } else if (spec.flags & PLUS) { 4421da177e4SLinus Torvalds sign = '+'; 4431c7a8e62SRasmus Villemoes field_width--; 444fef20d9cSFrederic Weisbecker } else if (spec.flags & SPACE) { 4451da177e4SLinus Torvalds sign = ' '; 4461c7a8e62SRasmus Villemoes field_width--; 4471da177e4SLinus Torvalds } 4481da177e4SLinus Torvalds } 449b39a7340SDenis Vlasenko if (need_pfx) { 450fef20d9cSFrederic Weisbecker if (spec.base == 16) 4511c7a8e62SRasmus Villemoes field_width -= 2; 4527c203422SPierre Carrier else if (!is_zero) 4531c7a8e62SRasmus Villemoes field_width--; 4541da177e4SLinus Torvalds } 455b39a7340SDenis Vlasenko 456b39a7340SDenis Vlasenko /* generate full string in tmp[], in reverse order */ 4571da177e4SLinus Torvalds i = 0; 458133fd9f5SDenys Vlasenko if (num < spec.base) 4593ea8d440SRasmus Villemoes tmp[i++] = hex_asc_upper[num] | locase; 460fef20d9cSFrederic Weisbecker else if (spec.base != 10) { /* 8 or 16 */ 461fef20d9cSFrederic Weisbecker int mask = spec.base - 1; 462b39a7340SDenis Vlasenko int shift = 3; 4637b9186f5SAndré Goddard Rosa 4647b9186f5SAndré Goddard Rosa if (spec.base == 16) 4657b9186f5SAndré Goddard Rosa shift = 4; 466b39a7340SDenis Vlasenko do { 4673ea8d440SRasmus Villemoes tmp[i++] = (hex_asc_upper[((unsigned char)num) & mask] | locase); 468b39a7340SDenis Vlasenko num >>= shift; 469b39a7340SDenis Vlasenko } while (num); 4704277eeddSDenis Vlasenko } else { /* base 10 */ 4714277eeddSDenis Vlasenko i = put_dec(tmp, num) - tmp; 4724277eeddSDenis Vlasenko } 473b39a7340SDenis Vlasenko 474b39a7340SDenis Vlasenko /* printing 100 using %2d gives "100", not "00" */ 4751c7a8e62SRasmus Villemoes if (i > precision) 4761c7a8e62SRasmus Villemoes precision = i; 477b39a7340SDenis Vlasenko /* leading space padding */ 4781c7a8e62SRasmus Villemoes field_width -= precision; 47951be17dfSRasmus Villemoes if (!(spec.flags & (ZEROPAD | LEFT))) { 4801c7a8e62SRasmus Villemoes while (--field_width >= 0) { 481f796937aSJeremy Fitzhardinge if (buf < end) 4821da177e4SLinus Torvalds *buf = ' '; 4831da177e4SLinus Torvalds ++buf; 4841da177e4SLinus Torvalds } 4851da177e4SLinus Torvalds } 486b39a7340SDenis Vlasenko /* sign */ 4871da177e4SLinus Torvalds if (sign) { 488f796937aSJeremy Fitzhardinge if (buf < end) 4891da177e4SLinus Torvalds *buf = sign; 4901da177e4SLinus Torvalds ++buf; 4911da177e4SLinus Torvalds } 492b39a7340SDenis Vlasenko /* "0x" / "0" prefix */ 493b39a7340SDenis Vlasenko if (need_pfx) { 4947c203422SPierre Carrier if (spec.base == 16 || !is_zero) { 495f796937aSJeremy Fitzhardinge if (buf < end) 4961da177e4SLinus Torvalds *buf = '0'; 4971da177e4SLinus Torvalds ++buf; 4987c203422SPierre Carrier } 499fef20d9cSFrederic Weisbecker if (spec.base == 16) { 500f796937aSJeremy Fitzhardinge if (buf < end) 5019b706aeeSDenys Vlasenko *buf = ('X' | locase); 5021da177e4SLinus Torvalds ++buf; 5031da177e4SLinus Torvalds } 5041da177e4SLinus Torvalds } 505b39a7340SDenis Vlasenko /* zero or space padding */ 506fef20d9cSFrederic Weisbecker if (!(spec.flags & LEFT)) { 507d1c1b121SRasmus Villemoes char c = ' ' + (spec.flags & ZEROPAD); 508d1c1b121SRasmus Villemoes BUILD_BUG_ON(' ' + ZEROPAD != '0'); 5091c7a8e62SRasmus Villemoes while (--field_width >= 0) { 510f796937aSJeremy Fitzhardinge if (buf < end) 5111da177e4SLinus Torvalds *buf = c; 5121da177e4SLinus Torvalds ++buf; 5131da177e4SLinus Torvalds } 5141da177e4SLinus Torvalds } 515b39a7340SDenis Vlasenko /* hmm even more zero padding? */ 5161c7a8e62SRasmus Villemoes while (i <= --precision) { 517f796937aSJeremy Fitzhardinge if (buf < end) 5181da177e4SLinus Torvalds *buf = '0'; 5191da177e4SLinus Torvalds ++buf; 5201da177e4SLinus Torvalds } 521b39a7340SDenis Vlasenko /* actual digits of result */ 522b39a7340SDenis Vlasenko while (--i >= 0) { 523f796937aSJeremy Fitzhardinge if (buf < end) 5241da177e4SLinus Torvalds *buf = tmp[i]; 5251da177e4SLinus Torvalds ++buf; 5261da177e4SLinus Torvalds } 527b39a7340SDenis Vlasenko /* trailing space padding */ 5281c7a8e62SRasmus Villemoes while (--field_width >= 0) { 529f796937aSJeremy Fitzhardinge if (buf < end) 5301da177e4SLinus Torvalds *buf = ' '; 5311da177e4SLinus Torvalds ++buf; 5321da177e4SLinus Torvalds } 5337b9186f5SAndré Goddard Rosa 5341da177e4SLinus Torvalds return buf; 5351da177e4SLinus Torvalds } 5361da177e4SLinus Torvalds 5373cab1e71SAndy Shevchenko static noinline_for_stack 5383cab1e71SAndy Shevchenko char *special_hex_number(char *buf, char *end, unsigned long long num, int size) 5393cab1e71SAndy Shevchenko { 5403cab1e71SAndy Shevchenko struct printf_spec spec; 5413cab1e71SAndy Shevchenko 5423cab1e71SAndy Shevchenko spec.type = FORMAT_TYPE_PTR; 5433cab1e71SAndy Shevchenko spec.field_width = 2 + 2 * size; /* 0x + hex */ 5443cab1e71SAndy Shevchenko spec.flags = SPECIAL | SMALL | ZEROPAD; 5453cab1e71SAndy Shevchenko spec.base = 16; 5463cab1e71SAndy Shevchenko spec.precision = -1; 5473cab1e71SAndy Shevchenko 5483cab1e71SAndy Shevchenko return number(buf, end, num, spec); 5493cab1e71SAndy Shevchenko } 5503cab1e71SAndy Shevchenko 551cfccde04SRasmus Villemoes static void move_right(char *buf, char *end, unsigned len, unsigned spaces) 5524b6ccca7SAl Viro { 5534b6ccca7SAl Viro size_t size; 5544b6ccca7SAl Viro if (buf >= end) /* nowhere to put anything */ 5554b6ccca7SAl Viro return; 5564b6ccca7SAl Viro size = end - buf; 5574b6ccca7SAl Viro if (size <= spaces) { 5584b6ccca7SAl Viro memset(buf, ' ', size); 5594b6ccca7SAl Viro return; 5604b6ccca7SAl Viro } 5614b6ccca7SAl Viro if (len) { 5624b6ccca7SAl Viro if (len > size - spaces) 5634b6ccca7SAl Viro len = size - spaces; 5644b6ccca7SAl Viro memmove(buf + spaces, buf, len); 5654b6ccca7SAl Viro } 5664b6ccca7SAl Viro memset(buf, ' ', spaces); 5674b6ccca7SAl Viro } 5684b6ccca7SAl Viro 569cfccde04SRasmus Villemoes /* 570cfccde04SRasmus Villemoes * Handle field width padding for a string. 571cfccde04SRasmus Villemoes * @buf: current buffer position 572cfccde04SRasmus Villemoes * @n: length of string 573cfccde04SRasmus Villemoes * @end: end of output buffer 574cfccde04SRasmus Villemoes * @spec: for field width and flags 575cfccde04SRasmus Villemoes * Returns: new buffer position after padding. 576cfccde04SRasmus Villemoes */ 577cfccde04SRasmus Villemoes static noinline_for_stack 578cfccde04SRasmus Villemoes char *widen_string(char *buf, int n, char *end, struct printf_spec spec) 579cfccde04SRasmus Villemoes { 580cfccde04SRasmus Villemoes unsigned spaces; 581cfccde04SRasmus Villemoes 582cfccde04SRasmus Villemoes if (likely(n >= spec.field_width)) 583cfccde04SRasmus Villemoes return buf; 584cfccde04SRasmus Villemoes /* we want to pad the sucker */ 585cfccde04SRasmus Villemoes spaces = spec.field_width - n; 586cfccde04SRasmus Villemoes if (!(spec.flags & LEFT)) { 587cfccde04SRasmus Villemoes move_right(buf - n, end, n, spaces); 588cfccde04SRasmus Villemoes return buf + spaces; 589cfccde04SRasmus Villemoes } 590cfccde04SRasmus Villemoes while (spaces--) { 591cfccde04SRasmus Villemoes if (buf < end) 592cfccde04SRasmus Villemoes *buf = ' '; 593cfccde04SRasmus Villemoes ++buf; 594cfccde04SRasmus Villemoes } 595cfccde04SRasmus Villemoes return buf; 596cfccde04SRasmus Villemoes } 597cfccde04SRasmus Villemoes 598d529ac41SPetr Mladek /* Handle string from a well known address. */ 599d529ac41SPetr Mladek static char *string_nocheck(char *buf, char *end, const char *s, 600d529ac41SPetr Mladek struct printf_spec spec) 60195508cfaSRasmus Villemoes { 60234fc8b90SRasmus Villemoes int len = 0; 603b314dd49SYoungmin Nam int lim = spec.precision; 60495508cfaSRasmus Villemoes 60534fc8b90SRasmus Villemoes while (lim--) { 60634fc8b90SRasmus Villemoes char c = *s++; 60734fc8b90SRasmus Villemoes if (!c) 60834fc8b90SRasmus Villemoes break; 60995508cfaSRasmus Villemoes if (buf < end) 61034fc8b90SRasmus Villemoes *buf = c; 61195508cfaSRasmus Villemoes ++buf; 61234fc8b90SRasmus Villemoes ++len; 61395508cfaSRasmus Villemoes } 61434fc8b90SRasmus Villemoes return widen_string(buf, len, end, spec); 61595508cfaSRasmus Villemoes } 61695508cfaSRasmus Villemoes 617*57f5677eSRasmus Villemoes static char *err_ptr(char *buf, char *end, void *ptr, 618*57f5677eSRasmus Villemoes struct printf_spec spec) 619*57f5677eSRasmus Villemoes { 620*57f5677eSRasmus Villemoes int err = PTR_ERR(ptr); 621*57f5677eSRasmus Villemoes const char *sym = errname(err); 622*57f5677eSRasmus Villemoes 623*57f5677eSRasmus Villemoes if (sym) 624*57f5677eSRasmus Villemoes return string_nocheck(buf, end, sym, spec); 625*57f5677eSRasmus Villemoes 626*57f5677eSRasmus Villemoes /* 627*57f5677eSRasmus Villemoes * Somebody passed ERR_PTR(-1234) or some other non-existing 628*57f5677eSRasmus Villemoes * Efoo - or perhaps CONFIG_SYMBOLIC_ERRNAME=n. Fall back to 629*57f5677eSRasmus Villemoes * printing it as its decimal representation. 630*57f5677eSRasmus Villemoes */ 631*57f5677eSRasmus Villemoes spec.flags |= SIGN; 632*57f5677eSRasmus Villemoes spec.base = 10; 633*57f5677eSRasmus Villemoes return number(buf, end, err, spec); 634*57f5677eSRasmus Villemoes } 635*57f5677eSRasmus Villemoes 636c8c3b584SPetr Mladek /* Be careful: error messages must fit into the given buffer. */ 637c8c3b584SPetr Mladek static char *error_string(char *buf, char *end, const char *s, 638c8c3b584SPetr Mladek struct printf_spec spec) 639c8c3b584SPetr Mladek { 640c8c3b584SPetr Mladek /* 641c8c3b584SPetr Mladek * Hard limit to avoid a completely insane messages. It actually 642c8c3b584SPetr Mladek * works pretty well because most error messages are in 643c8c3b584SPetr Mladek * the many pointer format modifiers. 644c8c3b584SPetr Mladek */ 645c8c3b584SPetr Mladek if (spec.precision == -1) 646c8c3b584SPetr Mladek spec.precision = 2 * sizeof(void *); 647c8c3b584SPetr Mladek 648c8c3b584SPetr Mladek return string_nocheck(buf, end, s, spec); 649c8c3b584SPetr Mladek } 650c8c3b584SPetr Mladek 6513e5903ebSPetr Mladek /* 6522ac5a3bfSPetr Mladek * Do not call any complex external code here. Nested printk()/vsprintf() 6532ac5a3bfSPetr Mladek * might cause infinite loops. Failures might break printk() and would 6542ac5a3bfSPetr Mladek * be hard to debug. 6553e5903ebSPetr Mladek */ 6563e5903ebSPetr Mladek static const char *check_pointer_msg(const void *ptr) 6573e5903ebSPetr Mladek { 6583e5903ebSPetr Mladek if (!ptr) 6593e5903ebSPetr Mladek return "(null)"; 6603e5903ebSPetr Mladek 6612ac5a3bfSPetr Mladek if ((unsigned long)ptr < PAGE_SIZE || IS_ERR_VALUE(ptr)) 6623e5903ebSPetr Mladek return "(efault)"; 6633e5903ebSPetr Mladek 6643e5903ebSPetr Mladek return NULL; 6653e5903ebSPetr Mladek } 6663e5903ebSPetr Mladek 6673e5903ebSPetr Mladek static int check_pointer(char **buf, char *end, const void *ptr, 6683e5903ebSPetr Mladek struct printf_spec spec) 6693e5903ebSPetr Mladek { 6703e5903ebSPetr Mladek const char *err_msg; 6713e5903ebSPetr Mladek 6723e5903ebSPetr Mladek err_msg = check_pointer_msg(ptr); 6733e5903ebSPetr Mladek if (err_msg) { 674c8c3b584SPetr Mladek *buf = error_string(*buf, end, err_msg, spec); 6753e5903ebSPetr Mladek return -EFAULT; 6763e5903ebSPetr Mladek } 6773e5903ebSPetr Mladek 6783e5903ebSPetr Mladek return 0; 6793e5903ebSPetr Mladek } 6803e5903ebSPetr Mladek 68195508cfaSRasmus Villemoes static noinline_for_stack 682d529ac41SPetr Mladek char *string(char *buf, char *end, const char *s, 683d529ac41SPetr Mladek struct printf_spec spec) 684d529ac41SPetr Mladek { 6853e5903ebSPetr Mladek if (check_pointer(&buf, end, s, spec)) 6863e5903ebSPetr Mladek return buf; 687d529ac41SPetr Mladek 688d529ac41SPetr Mladek return string_nocheck(buf, end, s, spec); 689d529ac41SPetr Mladek } 690d529ac41SPetr Mladek 691ce9d3eceSYueHaibing static char *pointer_string(char *buf, char *end, 692ce9d3eceSYueHaibing const void *ptr, 6939073dac1SGeert Uytterhoeven struct printf_spec spec) 6949073dac1SGeert Uytterhoeven { 6959073dac1SGeert Uytterhoeven spec.base = 16; 6969073dac1SGeert Uytterhoeven spec.flags |= SMALL; 6979073dac1SGeert Uytterhoeven if (spec.field_width == -1) { 6989073dac1SGeert Uytterhoeven spec.field_width = 2 * sizeof(ptr); 6999073dac1SGeert Uytterhoeven spec.flags |= ZEROPAD; 7009073dac1SGeert Uytterhoeven } 7019073dac1SGeert Uytterhoeven 7029073dac1SGeert Uytterhoeven return number(buf, end, (unsigned long int)ptr, spec); 7039073dac1SGeert Uytterhoeven } 7049073dac1SGeert Uytterhoeven 7059073dac1SGeert Uytterhoeven /* Make pointers available for printing early in the boot sequence. */ 7069073dac1SGeert Uytterhoeven static int debug_boot_weak_hash __ro_after_init; 7079073dac1SGeert Uytterhoeven 7089073dac1SGeert Uytterhoeven static int __init debug_boot_weak_hash_enable(char *str) 7099073dac1SGeert Uytterhoeven { 7109073dac1SGeert Uytterhoeven debug_boot_weak_hash = 1; 7119073dac1SGeert Uytterhoeven pr_info("debug_boot_weak_hash enabled\n"); 7129073dac1SGeert Uytterhoeven return 0; 7139073dac1SGeert Uytterhoeven } 7149073dac1SGeert Uytterhoeven early_param("debug_boot_weak_hash", debug_boot_weak_hash_enable); 7159073dac1SGeert Uytterhoeven 7169073dac1SGeert Uytterhoeven static DEFINE_STATIC_KEY_TRUE(not_filled_random_ptr_key); 7179073dac1SGeert Uytterhoeven static siphash_key_t ptr_key __read_mostly; 7189073dac1SGeert Uytterhoeven 7199073dac1SGeert Uytterhoeven static void enable_ptr_key_workfn(struct work_struct *work) 7209073dac1SGeert Uytterhoeven { 7219073dac1SGeert Uytterhoeven get_random_bytes(&ptr_key, sizeof(ptr_key)); 7229073dac1SGeert Uytterhoeven /* Needs to run from preemptible context */ 7239073dac1SGeert Uytterhoeven static_branch_disable(¬_filled_random_ptr_key); 7249073dac1SGeert Uytterhoeven } 7259073dac1SGeert Uytterhoeven 7269073dac1SGeert Uytterhoeven static DECLARE_WORK(enable_ptr_key_work, enable_ptr_key_workfn); 7279073dac1SGeert Uytterhoeven 7289073dac1SGeert Uytterhoeven static void fill_random_ptr_key(struct random_ready_callback *unused) 7299073dac1SGeert Uytterhoeven { 7309073dac1SGeert Uytterhoeven /* This may be in an interrupt handler. */ 7319073dac1SGeert Uytterhoeven queue_work(system_unbound_wq, &enable_ptr_key_work); 7329073dac1SGeert Uytterhoeven } 7339073dac1SGeert Uytterhoeven 7349073dac1SGeert Uytterhoeven static struct random_ready_callback random_ready = { 7359073dac1SGeert Uytterhoeven .func = fill_random_ptr_key 7369073dac1SGeert Uytterhoeven }; 7379073dac1SGeert Uytterhoeven 7389073dac1SGeert Uytterhoeven static int __init initialize_ptr_random(void) 7399073dac1SGeert Uytterhoeven { 7409073dac1SGeert Uytterhoeven int key_size = sizeof(ptr_key); 7419073dac1SGeert Uytterhoeven int ret; 7429073dac1SGeert Uytterhoeven 7439073dac1SGeert Uytterhoeven /* Use hw RNG if available. */ 7449073dac1SGeert Uytterhoeven if (get_random_bytes_arch(&ptr_key, key_size) == key_size) { 7459073dac1SGeert Uytterhoeven static_branch_disable(¬_filled_random_ptr_key); 7469073dac1SGeert Uytterhoeven return 0; 7479073dac1SGeert Uytterhoeven } 7489073dac1SGeert Uytterhoeven 7499073dac1SGeert Uytterhoeven ret = add_random_ready_callback(&random_ready); 7509073dac1SGeert Uytterhoeven if (!ret) { 7519073dac1SGeert Uytterhoeven return 0; 7529073dac1SGeert Uytterhoeven } else if (ret == -EALREADY) { 7539073dac1SGeert Uytterhoeven /* This is in preemptible context */ 7549073dac1SGeert Uytterhoeven enable_ptr_key_workfn(&enable_ptr_key_work); 7559073dac1SGeert Uytterhoeven return 0; 7569073dac1SGeert Uytterhoeven } 7579073dac1SGeert Uytterhoeven 7589073dac1SGeert Uytterhoeven return ret; 7599073dac1SGeert Uytterhoeven } 7609073dac1SGeert Uytterhoeven early_initcall(initialize_ptr_random); 7619073dac1SGeert Uytterhoeven 7629073dac1SGeert Uytterhoeven /* Maps a pointer to a 32 bit unique identifier. */ 7639073dac1SGeert Uytterhoeven static char *ptr_to_id(char *buf, char *end, const void *ptr, 7649073dac1SGeert Uytterhoeven struct printf_spec spec) 7659073dac1SGeert Uytterhoeven { 7669073dac1SGeert Uytterhoeven const char *str = sizeof(ptr) == 8 ? "(____ptrval____)" : "(ptrval)"; 7679073dac1SGeert Uytterhoeven unsigned long hashval; 7689073dac1SGeert Uytterhoeven 7699073dac1SGeert Uytterhoeven /* When debugging early boot use non-cryptographically secure hash. */ 7709073dac1SGeert Uytterhoeven if (unlikely(debug_boot_weak_hash)) { 7719073dac1SGeert Uytterhoeven hashval = hash_long((unsigned long)ptr, 32); 7729073dac1SGeert Uytterhoeven return pointer_string(buf, end, (const void *)hashval, spec); 7739073dac1SGeert Uytterhoeven } 7749073dac1SGeert Uytterhoeven 7759073dac1SGeert Uytterhoeven if (static_branch_unlikely(¬_filled_random_ptr_key)) { 7769073dac1SGeert Uytterhoeven spec.field_width = 2 * sizeof(ptr); 7779073dac1SGeert Uytterhoeven /* string length must be less than default_width */ 778c8c3b584SPetr Mladek return error_string(buf, end, str, spec); 7799073dac1SGeert Uytterhoeven } 7809073dac1SGeert Uytterhoeven 7819073dac1SGeert Uytterhoeven #ifdef CONFIG_64BIT 7829073dac1SGeert Uytterhoeven hashval = (unsigned long)siphash_1u64((u64)ptr, &ptr_key); 7839073dac1SGeert Uytterhoeven /* 7849073dac1SGeert Uytterhoeven * Mask off the first 32 bits, this makes explicit that we have 7859073dac1SGeert Uytterhoeven * modified the address (and 32 bits is plenty for a unique ID). 7869073dac1SGeert Uytterhoeven */ 7879073dac1SGeert Uytterhoeven hashval = hashval & 0xffffffff; 7889073dac1SGeert Uytterhoeven #else 7899073dac1SGeert Uytterhoeven hashval = (unsigned long)siphash_1u32((u32)ptr, &ptr_key); 7909073dac1SGeert Uytterhoeven #endif 7919073dac1SGeert Uytterhoeven return pointer_string(buf, end, (const void *)hashval, spec); 7929073dac1SGeert Uytterhoeven } 7939073dac1SGeert Uytterhoeven 7946eea242fSPetr Mladek int kptr_restrict __read_mostly; 7956eea242fSPetr Mladek 7966eea242fSPetr Mladek static noinline_for_stack 7976eea242fSPetr Mladek char *restricted_pointer(char *buf, char *end, const void *ptr, 7986eea242fSPetr Mladek struct printf_spec spec) 7996eea242fSPetr Mladek { 8006eea242fSPetr Mladek switch (kptr_restrict) { 8016eea242fSPetr Mladek case 0: 8021ac2f978SPetr Mladek /* Handle as %p, hash and do _not_ leak addresses. */ 8031ac2f978SPetr Mladek return ptr_to_id(buf, end, ptr, spec); 8046eea242fSPetr Mladek case 1: { 8056eea242fSPetr Mladek const struct cred *cred; 8066eea242fSPetr Mladek 8076eea242fSPetr Mladek /* 8086eea242fSPetr Mladek * kptr_restrict==1 cannot be used in IRQ context 8096eea242fSPetr Mladek * because its test for CAP_SYSLOG would be meaningless. 8106eea242fSPetr Mladek */ 8116eea242fSPetr Mladek if (in_irq() || in_serving_softirq() || in_nmi()) { 8126eea242fSPetr Mladek if (spec.field_width == -1) 8136eea242fSPetr Mladek spec.field_width = 2 * sizeof(ptr); 814c8c3b584SPetr Mladek return error_string(buf, end, "pK-error", spec); 8156eea242fSPetr Mladek } 8166eea242fSPetr Mladek 8176eea242fSPetr Mladek /* 8186eea242fSPetr Mladek * Only print the real pointer value if the current 8196eea242fSPetr Mladek * process has CAP_SYSLOG and is running with the 8206eea242fSPetr Mladek * same credentials it started with. This is because 8216eea242fSPetr Mladek * access to files is checked at open() time, but %pK 8226eea242fSPetr Mladek * checks permission at read() time. We don't want to 8236eea242fSPetr Mladek * leak pointer values if a binary opens a file using 8246eea242fSPetr Mladek * %pK and then elevates privileges before reading it. 8256eea242fSPetr Mladek */ 8266eea242fSPetr Mladek cred = current_cred(); 8276eea242fSPetr Mladek if (!has_capability_noaudit(current, CAP_SYSLOG) || 8286eea242fSPetr Mladek !uid_eq(cred->euid, cred->uid) || 8296eea242fSPetr Mladek !gid_eq(cred->egid, cred->gid)) 8306eea242fSPetr Mladek ptr = NULL; 8316eea242fSPetr Mladek break; 8326eea242fSPetr Mladek } 8336eea242fSPetr Mladek case 2: 8346eea242fSPetr Mladek default: 8356eea242fSPetr Mladek /* Always print 0's for %pK */ 8366eea242fSPetr Mladek ptr = NULL; 8376eea242fSPetr Mladek break; 8386eea242fSPetr Mladek } 8396eea242fSPetr Mladek 8406eea242fSPetr Mladek return pointer_string(buf, end, ptr, spec); 8416eea242fSPetr Mladek } 8426eea242fSPetr Mladek 8439073dac1SGeert Uytterhoeven static noinline_for_stack 8444b6ccca7SAl Viro char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_spec spec, 8454b6ccca7SAl Viro const char *fmt) 8464b6ccca7SAl Viro { 8474b6ccca7SAl Viro const char *array[4], *s; 8484b6ccca7SAl Viro const struct dentry *p; 8494b6ccca7SAl Viro int depth; 8504b6ccca7SAl Viro int i, n; 8514b6ccca7SAl Viro 8524b6ccca7SAl Viro switch (fmt[1]) { 8534b6ccca7SAl Viro case '2': case '3': case '4': 8544b6ccca7SAl Viro depth = fmt[1] - '0'; 8554b6ccca7SAl Viro break; 8564b6ccca7SAl Viro default: 8574b6ccca7SAl Viro depth = 1; 8584b6ccca7SAl Viro } 8594b6ccca7SAl Viro 8604b6ccca7SAl Viro rcu_read_lock(); 8614b6ccca7SAl Viro for (i = 0; i < depth; i++, d = p) { 8623e5903ebSPetr Mladek if (check_pointer(&buf, end, d, spec)) { 8633e5903ebSPetr Mladek rcu_read_unlock(); 8643e5903ebSPetr Mladek return buf; 8653e5903ebSPetr Mladek } 8663e5903ebSPetr Mladek 8676aa7de05SMark Rutland p = READ_ONCE(d->d_parent); 8686aa7de05SMark Rutland array[i] = READ_ONCE(d->d_name.name); 8694b6ccca7SAl Viro if (p == d) { 8704b6ccca7SAl Viro if (i) 8714b6ccca7SAl Viro array[i] = ""; 8724b6ccca7SAl Viro i++; 8734b6ccca7SAl Viro break; 8744b6ccca7SAl Viro } 8754b6ccca7SAl Viro } 8764b6ccca7SAl Viro s = array[--i]; 8774b6ccca7SAl Viro for (n = 0; n != spec.precision; n++, buf++) { 8784b6ccca7SAl Viro char c = *s++; 8794b6ccca7SAl Viro if (!c) { 8804b6ccca7SAl Viro if (!i) 8814b6ccca7SAl Viro break; 8824b6ccca7SAl Viro c = '/'; 8834b6ccca7SAl Viro s = array[--i]; 8844b6ccca7SAl Viro } 8854b6ccca7SAl Viro if (buf < end) 8864b6ccca7SAl Viro *buf = c; 8874b6ccca7SAl Viro } 8884b6ccca7SAl Viro rcu_read_unlock(); 889cfccde04SRasmus Villemoes return widen_string(buf, n, end, spec); 8904b6ccca7SAl Viro } 8914b6ccca7SAl Viro 89236594b31SJia He static noinline_for_stack 89336594b31SJia He char *file_dentry_name(char *buf, char *end, const struct file *f, 89436594b31SJia He struct printf_spec spec, const char *fmt) 89536594b31SJia He { 89636594b31SJia He if (check_pointer(&buf, end, f, spec)) 89736594b31SJia He return buf; 89836594b31SJia He 89936594b31SJia He return dentry_name(buf, end, f->f_path.dentry, spec, fmt); 90036594b31SJia He } 9011031bc58SDmitry Monakhov #ifdef CONFIG_BLOCK 9021031bc58SDmitry Monakhov static noinline_for_stack 9031031bc58SDmitry Monakhov char *bdev_name(char *buf, char *end, struct block_device *bdev, 9041031bc58SDmitry Monakhov struct printf_spec spec, const char *fmt) 9051031bc58SDmitry Monakhov { 9063e5903ebSPetr Mladek struct gendisk *hd; 9071031bc58SDmitry Monakhov 9083e5903ebSPetr Mladek if (check_pointer(&buf, end, bdev, spec)) 9093e5903ebSPetr Mladek return buf; 9103e5903ebSPetr Mladek 9113e5903ebSPetr Mladek hd = bdev->bd_disk; 9121031bc58SDmitry Monakhov buf = string(buf, end, hd->disk_name, spec); 9131031bc58SDmitry Monakhov if (bdev->bd_part->partno) { 9141031bc58SDmitry Monakhov if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) { 9151031bc58SDmitry Monakhov if (buf < end) 9161031bc58SDmitry Monakhov *buf = 'p'; 9171031bc58SDmitry Monakhov buf++; 9181031bc58SDmitry Monakhov } 9191031bc58SDmitry Monakhov buf = number(buf, end, bdev->bd_part->partno, spec); 9201031bc58SDmitry Monakhov } 9211031bc58SDmitry Monakhov return buf; 9221031bc58SDmitry Monakhov } 9231031bc58SDmitry Monakhov #endif 9241031bc58SDmitry Monakhov 925cf3b429bSJoe Perches static noinline_for_stack 926cf3b429bSJoe Perches char *symbol_string(char *buf, char *end, void *ptr, 927b0d33c2bSJoe Perches struct printf_spec spec, const char *fmt) 9280fe1ef24SLinus Torvalds { 929b0d33c2bSJoe Perches unsigned long value; 9300fe1ef24SLinus Torvalds #ifdef CONFIG_KALLSYMS 9310fe1ef24SLinus Torvalds char sym[KSYM_SYMBOL_LEN]; 932b0d33c2bSJoe Perches #endif 933b0d33c2bSJoe Perches 934b0d33c2bSJoe Perches if (fmt[1] == 'R') 935b0d33c2bSJoe Perches ptr = __builtin_extract_return_addr(ptr); 936b0d33c2bSJoe Perches value = (unsigned long)ptr; 937b0d33c2bSJoe Perches 938b0d33c2bSJoe Perches #ifdef CONFIG_KALLSYMS 939b0d33c2bSJoe Perches if (*fmt == 'B') 9400f77a8d3SNamhyung Kim sprint_backtrace(sym, value); 941b0d33c2bSJoe Perches else if (*fmt != 'f' && *fmt != 's') 9420fe1ef24SLinus Torvalds sprint_symbol(sym, value); 9430c8b946eSFrederic Weisbecker else 9444796dd20SStephen Boyd sprint_symbol_no_offset(sym, value); 9457b9186f5SAndré Goddard Rosa 946d529ac41SPetr Mladek return string_nocheck(buf, end, sym, spec); 9470fe1ef24SLinus Torvalds #else 9483cab1e71SAndy Shevchenko return special_hex_number(buf, end, value, sizeof(void *)); 9490fe1ef24SLinus Torvalds #endif 9500fe1ef24SLinus Torvalds } 9510fe1ef24SLinus Torvalds 952abd4fe62SAndy Shevchenko static const struct printf_spec default_str_spec = { 953abd4fe62SAndy Shevchenko .field_width = -1, 954abd4fe62SAndy Shevchenko .precision = -1, 955abd4fe62SAndy Shevchenko }; 956abd4fe62SAndy Shevchenko 95754433973SAndy Shevchenko static const struct printf_spec default_flag_spec = { 95854433973SAndy Shevchenko .base = 16, 95954433973SAndy Shevchenko .precision = -1, 96054433973SAndy Shevchenko .flags = SPECIAL | SMALL, 96154433973SAndy Shevchenko }; 96254433973SAndy Shevchenko 963ce0b4910SAndy Shevchenko static const struct printf_spec default_dec_spec = { 964ce0b4910SAndy Shevchenko .base = 10, 965ce0b4910SAndy Shevchenko .precision = -1, 966ce0b4910SAndy Shevchenko }; 967ce0b4910SAndy Shevchenko 9684d42c447SAndy Shevchenko static const struct printf_spec default_dec02_spec = { 9694d42c447SAndy Shevchenko .base = 10, 9704d42c447SAndy Shevchenko .field_width = 2, 9714d42c447SAndy Shevchenko .precision = -1, 9724d42c447SAndy Shevchenko .flags = ZEROPAD, 9734d42c447SAndy Shevchenko }; 9744d42c447SAndy Shevchenko 9754d42c447SAndy Shevchenko static const struct printf_spec default_dec04_spec = { 9764d42c447SAndy Shevchenko .base = 10, 9774d42c447SAndy Shevchenko .field_width = 4, 9784d42c447SAndy Shevchenko .precision = -1, 9794d42c447SAndy Shevchenko .flags = ZEROPAD, 9804d42c447SAndy Shevchenko }; 9814d42c447SAndy Shevchenko 982cf3b429bSJoe Perches static noinline_for_stack 983cf3b429bSJoe Perches char *resource_string(char *buf, char *end, struct resource *res, 984fd95541eSBjorn Helgaas struct printf_spec spec, const char *fmt) 985332d2e78SLinus Torvalds { 986332d2e78SLinus Torvalds #ifndef IO_RSRC_PRINTK_SIZE 98728405372SBjorn Helgaas #define IO_RSRC_PRINTK_SIZE 6 988332d2e78SLinus Torvalds #endif 989332d2e78SLinus Torvalds 990332d2e78SLinus Torvalds #ifndef MEM_RSRC_PRINTK_SIZE 99128405372SBjorn Helgaas #define MEM_RSRC_PRINTK_SIZE 10 992332d2e78SLinus Torvalds #endif 9934da0b66cSBjorn Helgaas static const struct printf_spec io_spec = { 994fef20d9cSFrederic Weisbecker .base = 16, 9954da0b66cSBjorn Helgaas .field_width = IO_RSRC_PRINTK_SIZE, 996fef20d9cSFrederic Weisbecker .precision = -1, 997fef20d9cSFrederic Weisbecker .flags = SPECIAL | SMALL | ZEROPAD, 998fef20d9cSFrederic Weisbecker }; 9994da0b66cSBjorn Helgaas static const struct printf_spec mem_spec = { 10004da0b66cSBjorn Helgaas .base = 16, 10014da0b66cSBjorn Helgaas .field_width = MEM_RSRC_PRINTK_SIZE, 10024da0b66cSBjorn Helgaas .precision = -1, 10034da0b66cSBjorn Helgaas .flags = SPECIAL | SMALL | ZEROPAD, 10044da0b66cSBjorn Helgaas }; 10050f4050c7SBjorn Helgaas static const struct printf_spec bus_spec = { 10060f4050c7SBjorn Helgaas .base = 16, 10070f4050c7SBjorn Helgaas .field_width = 2, 10080f4050c7SBjorn Helgaas .precision = -1, 10090f4050c7SBjorn Helgaas .flags = SMALL | ZEROPAD, 10100f4050c7SBjorn Helgaas }; 10114da0b66cSBjorn Helgaas static const struct printf_spec str_spec = { 1012fd95541eSBjorn Helgaas .field_width = -1, 1013fd95541eSBjorn Helgaas .precision = 10, 1014fd95541eSBjorn Helgaas .flags = LEFT, 1015fd95541eSBjorn Helgaas }; 1016c7dabef8SBjorn Helgaas 1017c7dabef8SBjorn Helgaas /* 32-bit res (sizeof==4): 10 chars in dec, 10 in hex ("0x" + 8) 1018c7dabef8SBjorn Helgaas * 64-bit res (sizeof==8): 20 chars in dec, 18 in hex ("0x" + 16) */ 1019c7dabef8SBjorn Helgaas #define RSRC_BUF_SIZE ((2 * sizeof(resource_size_t)) + 4) 1020c7dabef8SBjorn Helgaas #define FLAG_BUF_SIZE (2 * sizeof(res->flags)) 10219d7cca04SBjorn Helgaas #define DECODED_BUF_SIZE sizeof("[mem - 64bit pref window disabled]") 1022c7dabef8SBjorn Helgaas #define RAW_BUF_SIZE sizeof("[mem - flags 0x]") 1023c7dabef8SBjorn Helgaas char sym[max(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE, 1024c7dabef8SBjorn Helgaas 2*RSRC_BUF_SIZE + FLAG_BUF_SIZE + RAW_BUF_SIZE)]; 1025c7dabef8SBjorn Helgaas 1026332d2e78SLinus Torvalds char *p = sym, *pend = sym + sizeof(sym); 1027c7dabef8SBjorn Helgaas int decode = (fmt[0] == 'R') ? 1 : 0; 10284da0b66cSBjorn Helgaas const struct printf_spec *specp; 1029332d2e78SLinus Torvalds 10303e5903ebSPetr Mladek if (check_pointer(&buf, end, res, spec)) 10313e5903ebSPetr Mladek return buf; 10323e5903ebSPetr Mladek 1033332d2e78SLinus Torvalds *p++ = '['; 10344da0b66cSBjorn Helgaas if (res->flags & IORESOURCE_IO) { 1035d529ac41SPetr Mladek p = string_nocheck(p, pend, "io ", str_spec); 10364da0b66cSBjorn Helgaas specp = &io_spec; 10374da0b66cSBjorn Helgaas } else if (res->flags & IORESOURCE_MEM) { 1038d529ac41SPetr Mladek p = string_nocheck(p, pend, "mem ", str_spec); 10394da0b66cSBjorn Helgaas specp = &mem_spec; 10404da0b66cSBjorn Helgaas } else if (res->flags & IORESOURCE_IRQ) { 1041d529ac41SPetr Mladek p = string_nocheck(p, pend, "irq ", str_spec); 1042ce0b4910SAndy Shevchenko specp = &default_dec_spec; 10434da0b66cSBjorn Helgaas } else if (res->flags & IORESOURCE_DMA) { 1044d529ac41SPetr Mladek p = string_nocheck(p, pend, "dma ", str_spec); 1045ce0b4910SAndy Shevchenko specp = &default_dec_spec; 10460f4050c7SBjorn Helgaas } else if (res->flags & IORESOURCE_BUS) { 1047d529ac41SPetr Mladek p = string_nocheck(p, pend, "bus ", str_spec); 10480f4050c7SBjorn Helgaas specp = &bus_spec; 10494da0b66cSBjorn Helgaas } else { 1050d529ac41SPetr Mladek p = string_nocheck(p, pend, "??? ", str_spec); 10514da0b66cSBjorn Helgaas specp = &mem_spec; 1052c7dabef8SBjorn Helgaas decode = 0; 1053fd95541eSBjorn Helgaas } 1054d19cb803SBjorn Helgaas if (decode && res->flags & IORESOURCE_UNSET) { 1055d529ac41SPetr Mladek p = string_nocheck(p, pend, "size ", str_spec); 1056d19cb803SBjorn Helgaas p = number(p, pend, resource_size(res), *specp); 1057d19cb803SBjorn Helgaas } else { 10584da0b66cSBjorn Helgaas p = number(p, pend, res->start, *specp); 1059c91d3376SBjorn Helgaas if (res->start != res->end) { 1060332d2e78SLinus Torvalds *p++ = '-'; 10614da0b66cSBjorn Helgaas p = number(p, pend, res->end, *specp); 1062c91d3376SBjorn Helgaas } 1063d19cb803SBjorn Helgaas } 1064c7dabef8SBjorn Helgaas if (decode) { 1065fd95541eSBjorn Helgaas if (res->flags & IORESOURCE_MEM_64) 1066d529ac41SPetr Mladek p = string_nocheck(p, pend, " 64bit", str_spec); 1067fd95541eSBjorn Helgaas if (res->flags & IORESOURCE_PREFETCH) 1068d529ac41SPetr Mladek p = string_nocheck(p, pend, " pref", str_spec); 10699d7cca04SBjorn Helgaas if (res->flags & IORESOURCE_WINDOW) 1070d529ac41SPetr Mladek p = string_nocheck(p, pend, " window", str_spec); 1071fd95541eSBjorn Helgaas if (res->flags & IORESOURCE_DISABLED) 1072d529ac41SPetr Mladek p = string_nocheck(p, pend, " disabled", str_spec); 1073c7dabef8SBjorn Helgaas } else { 1074d529ac41SPetr Mladek p = string_nocheck(p, pend, " flags ", str_spec); 107554433973SAndy Shevchenko p = number(p, pend, res->flags, default_flag_spec); 1076fd95541eSBjorn Helgaas } 1077332d2e78SLinus Torvalds *p++ = ']'; 1078c7dabef8SBjorn Helgaas *p = '\0'; 1079332d2e78SLinus Torvalds 1080d529ac41SPetr Mladek return string_nocheck(buf, end, sym, spec); 1081332d2e78SLinus Torvalds } 1082332d2e78SLinus Torvalds 1083cf3b429bSJoe Perches static noinline_for_stack 108431550a16SAndy Shevchenko char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec, 108531550a16SAndy Shevchenko const char *fmt) 108631550a16SAndy Shevchenko { 1087360603a1SSteven Rostedt int i, len = 1; /* if we pass '%ph[CDN]', field width remains 108831550a16SAndy Shevchenko negative value, fallback to the default */ 108931550a16SAndy Shevchenko char separator; 109031550a16SAndy Shevchenko 109131550a16SAndy Shevchenko if (spec.field_width == 0) 109231550a16SAndy Shevchenko /* nothing to print */ 109331550a16SAndy Shevchenko return buf; 109431550a16SAndy Shevchenko 10953e5903ebSPetr Mladek if (check_pointer(&buf, end, addr, spec)) 10963e5903ebSPetr Mladek return buf; 109731550a16SAndy Shevchenko 109831550a16SAndy Shevchenko switch (fmt[1]) { 109931550a16SAndy Shevchenko case 'C': 110031550a16SAndy Shevchenko separator = ':'; 110131550a16SAndy Shevchenko break; 110231550a16SAndy Shevchenko case 'D': 110331550a16SAndy Shevchenko separator = '-'; 110431550a16SAndy Shevchenko break; 110531550a16SAndy Shevchenko case 'N': 110631550a16SAndy Shevchenko separator = 0; 110731550a16SAndy Shevchenko break; 110831550a16SAndy Shevchenko default: 110931550a16SAndy Shevchenko separator = ' '; 111031550a16SAndy Shevchenko break; 111131550a16SAndy Shevchenko } 111231550a16SAndy Shevchenko 111331550a16SAndy Shevchenko if (spec.field_width > 0) 111431550a16SAndy Shevchenko len = min_t(int, spec.field_width, 64); 111531550a16SAndy Shevchenko 11169c98f235SRasmus Villemoes for (i = 0; i < len; ++i) { 11179c98f235SRasmus Villemoes if (buf < end) 11189c98f235SRasmus Villemoes *buf = hex_asc_hi(addr[i]); 11199c98f235SRasmus Villemoes ++buf; 11209c98f235SRasmus Villemoes if (buf < end) 11219c98f235SRasmus Villemoes *buf = hex_asc_lo(addr[i]); 11229c98f235SRasmus Villemoes ++buf; 112331550a16SAndy Shevchenko 11249c98f235SRasmus Villemoes if (separator && i != len - 1) { 11259c98f235SRasmus Villemoes if (buf < end) 11269c98f235SRasmus Villemoes *buf = separator; 11279c98f235SRasmus Villemoes ++buf; 11289c98f235SRasmus Villemoes } 112931550a16SAndy Shevchenko } 113031550a16SAndy Shevchenko 113131550a16SAndy Shevchenko return buf; 113231550a16SAndy Shevchenko } 113331550a16SAndy Shevchenko 113431550a16SAndy Shevchenko static noinline_for_stack 1135dbc760bcSTejun Heo char *bitmap_string(char *buf, char *end, unsigned long *bitmap, 1136dbc760bcSTejun Heo struct printf_spec spec, const char *fmt) 1137dbc760bcSTejun Heo { 1138dbc760bcSTejun Heo const int CHUNKSZ = 32; 1139dbc760bcSTejun Heo int nr_bits = max_t(int, spec.field_width, 0); 1140dbc760bcSTejun Heo int i, chunksz; 1141dbc760bcSTejun Heo bool first = true; 1142dbc760bcSTejun Heo 11433e5903ebSPetr Mladek if (check_pointer(&buf, end, bitmap, spec)) 11443e5903ebSPetr Mladek return buf; 11453e5903ebSPetr Mladek 1146dbc760bcSTejun Heo /* reused to print numbers */ 1147dbc760bcSTejun Heo spec = (struct printf_spec){ .flags = SMALL | ZEROPAD, .base = 16 }; 1148dbc760bcSTejun Heo 1149dbc760bcSTejun Heo chunksz = nr_bits & (CHUNKSZ - 1); 1150dbc760bcSTejun Heo if (chunksz == 0) 1151dbc760bcSTejun Heo chunksz = CHUNKSZ; 1152dbc760bcSTejun Heo 1153dbc760bcSTejun Heo i = ALIGN(nr_bits, CHUNKSZ) - CHUNKSZ; 1154dbc760bcSTejun Heo for (; i >= 0; i -= CHUNKSZ) { 1155dbc760bcSTejun Heo u32 chunkmask, val; 1156dbc760bcSTejun Heo int word, bit; 1157dbc760bcSTejun Heo 1158dbc760bcSTejun Heo chunkmask = ((1ULL << chunksz) - 1); 1159dbc760bcSTejun Heo word = i / BITS_PER_LONG; 1160dbc760bcSTejun Heo bit = i % BITS_PER_LONG; 1161dbc760bcSTejun Heo val = (bitmap[word] >> bit) & chunkmask; 1162dbc760bcSTejun Heo 1163dbc760bcSTejun Heo if (!first) { 1164dbc760bcSTejun Heo if (buf < end) 1165dbc760bcSTejun Heo *buf = ','; 1166dbc760bcSTejun Heo buf++; 1167dbc760bcSTejun Heo } 1168dbc760bcSTejun Heo first = false; 1169dbc760bcSTejun Heo 1170dbc760bcSTejun Heo spec.field_width = DIV_ROUND_UP(chunksz, 4); 1171dbc760bcSTejun Heo buf = number(buf, end, val, spec); 1172dbc760bcSTejun Heo 1173dbc760bcSTejun Heo chunksz = CHUNKSZ; 1174dbc760bcSTejun Heo } 1175dbc760bcSTejun Heo return buf; 1176dbc760bcSTejun Heo } 1177dbc760bcSTejun Heo 1178dbc760bcSTejun Heo static noinline_for_stack 1179dbc760bcSTejun Heo char *bitmap_list_string(char *buf, char *end, unsigned long *bitmap, 1180dbc760bcSTejun Heo struct printf_spec spec, const char *fmt) 1181dbc760bcSTejun Heo { 1182dbc760bcSTejun Heo int nr_bits = max_t(int, spec.field_width, 0); 1183dbc760bcSTejun Heo /* current bit is 'cur', most recently seen range is [rbot, rtop] */ 1184dbc760bcSTejun Heo int cur, rbot, rtop; 1185dbc760bcSTejun Heo bool first = true; 1186dbc760bcSTejun Heo 11873e5903ebSPetr Mladek if (check_pointer(&buf, end, bitmap, spec)) 11883e5903ebSPetr Mladek return buf; 11893e5903ebSPetr Mladek 1190dbc760bcSTejun Heo rbot = cur = find_first_bit(bitmap, nr_bits); 1191dbc760bcSTejun Heo while (cur < nr_bits) { 1192dbc760bcSTejun Heo rtop = cur; 1193dbc760bcSTejun Heo cur = find_next_bit(bitmap, nr_bits, cur + 1); 1194dbc760bcSTejun Heo if (cur < nr_bits && cur <= rtop + 1) 1195dbc760bcSTejun Heo continue; 1196dbc760bcSTejun Heo 1197dbc760bcSTejun Heo if (!first) { 1198dbc760bcSTejun Heo if (buf < end) 1199dbc760bcSTejun Heo *buf = ','; 1200dbc760bcSTejun Heo buf++; 1201dbc760bcSTejun Heo } 1202dbc760bcSTejun Heo first = false; 1203dbc760bcSTejun Heo 1204ce0b4910SAndy Shevchenko buf = number(buf, end, rbot, default_dec_spec); 1205dbc760bcSTejun Heo if (rbot < rtop) { 1206dbc760bcSTejun Heo if (buf < end) 1207dbc760bcSTejun Heo *buf = '-'; 1208dbc760bcSTejun Heo buf++; 1209dbc760bcSTejun Heo 1210ce0b4910SAndy Shevchenko buf = number(buf, end, rtop, default_dec_spec); 1211dbc760bcSTejun Heo } 1212dbc760bcSTejun Heo 1213dbc760bcSTejun Heo rbot = cur; 1214dbc760bcSTejun Heo } 1215dbc760bcSTejun Heo return buf; 1216dbc760bcSTejun Heo } 1217dbc760bcSTejun Heo 1218dbc760bcSTejun Heo static noinline_for_stack 1219cf3b429bSJoe Perches char *mac_address_string(char *buf, char *end, u8 *addr, 12208a27f7c9SJoe Perches struct printf_spec spec, const char *fmt) 1221dd45c9cfSHarvey Harrison { 12228a27f7c9SJoe Perches char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")]; 1223dd45c9cfSHarvey Harrison char *p = mac_addr; 1224dd45c9cfSHarvey Harrison int i; 1225bc7259a2SJoe Perches char separator; 122676597ff9SAndrei Emeltchenko bool reversed = false; 1227bc7259a2SJoe Perches 12283e5903ebSPetr Mladek if (check_pointer(&buf, end, addr, spec)) 12293e5903ebSPetr Mladek return buf; 12303e5903ebSPetr Mladek 123176597ff9SAndrei Emeltchenko switch (fmt[1]) { 123276597ff9SAndrei Emeltchenko case 'F': 1233bc7259a2SJoe Perches separator = '-'; 123476597ff9SAndrei Emeltchenko break; 123576597ff9SAndrei Emeltchenko 123676597ff9SAndrei Emeltchenko case 'R': 123776597ff9SAndrei Emeltchenko reversed = true; 123876597ff9SAndrei Emeltchenko /* fall through */ 123976597ff9SAndrei Emeltchenko 124076597ff9SAndrei Emeltchenko default: 1241bc7259a2SJoe Perches separator = ':'; 124276597ff9SAndrei Emeltchenko break; 1243bc7259a2SJoe Perches } 1244dd45c9cfSHarvey Harrison 1245dd45c9cfSHarvey Harrison for (i = 0; i < 6; i++) { 124676597ff9SAndrei Emeltchenko if (reversed) 124776597ff9SAndrei Emeltchenko p = hex_byte_pack(p, addr[5 - i]); 124876597ff9SAndrei Emeltchenko else 124955036ba7SAndy Shevchenko p = hex_byte_pack(p, addr[i]); 125076597ff9SAndrei Emeltchenko 12518a27f7c9SJoe Perches if (fmt[0] == 'M' && i != 5) 1252bc7259a2SJoe Perches *p++ = separator; 1253dd45c9cfSHarvey Harrison } 1254dd45c9cfSHarvey Harrison *p = '\0'; 1255dd45c9cfSHarvey Harrison 1256d529ac41SPetr Mladek return string_nocheck(buf, end, mac_addr, spec); 1257dd45c9cfSHarvey Harrison } 1258dd45c9cfSHarvey Harrison 1259cf3b429bSJoe Perches static noinline_for_stack 1260cf3b429bSJoe Perches char *ip4_string(char *p, const u8 *addr, const char *fmt) 1261689afa7dSHarvey Harrison { 1262689afa7dSHarvey Harrison int i; 12630159f24eSJoe Perches bool leading_zeros = (fmt[0] == 'i'); 12640159f24eSJoe Perches int index; 12650159f24eSJoe Perches int step; 1266689afa7dSHarvey Harrison 12670159f24eSJoe Perches switch (fmt[2]) { 12680159f24eSJoe Perches case 'h': 12690159f24eSJoe Perches #ifdef __BIG_ENDIAN 12700159f24eSJoe Perches index = 0; 12710159f24eSJoe Perches step = 1; 12720159f24eSJoe Perches #else 12730159f24eSJoe Perches index = 3; 12740159f24eSJoe Perches step = -1; 12750159f24eSJoe Perches #endif 12760159f24eSJoe Perches break; 12770159f24eSJoe Perches case 'l': 12780159f24eSJoe Perches index = 3; 12790159f24eSJoe Perches step = -1; 12800159f24eSJoe Perches break; 12810159f24eSJoe Perches case 'n': 12820159f24eSJoe Perches case 'b': 12830159f24eSJoe Perches default: 12840159f24eSJoe Perches index = 0; 12850159f24eSJoe Perches step = 1; 12860159f24eSJoe Perches break; 12870159f24eSJoe Perches } 12888a27f7c9SJoe Perches for (i = 0; i < 4; i++) { 12897c43d9a3SRasmus Villemoes char temp[4] __aligned(2); /* hold each IP quad in reverse order */ 1290133fd9f5SDenys Vlasenko int digits = put_dec_trunc8(temp, addr[index]) - temp; 12918a27f7c9SJoe Perches if (leading_zeros) { 12928a27f7c9SJoe Perches if (digits < 3) 12938a27f7c9SJoe Perches *p++ = '0'; 12948a27f7c9SJoe Perches if (digits < 2) 12958a27f7c9SJoe Perches *p++ = '0'; 12968a27f7c9SJoe Perches } 12978a27f7c9SJoe Perches /* reverse the digits in the quad */ 12988a27f7c9SJoe Perches while (digits--) 12998a27f7c9SJoe Perches *p++ = temp[digits]; 13008a27f7c9SJoe Perches if (i < 3) 13018a27f7c9SJoe Perches *p++ = '.'; 13020159f24eSJoe Perches index += step; 13038a27f7c9SJoe Perches } 13048a27f7c9SJoe Perches *p = '\0'; 13057b9186f5SAndré Goddard Rosa 13068a27f7c9SJoe Perches return p; 13078a27f7c9SJoe Perches } 13088a27f7c9SJoe Perches 1309cf3b429bSJoe Perches static noinline_for_stack 1310cf3b429bSJoe Perches char *ip6_compressed_string(char *p, const char *addr) 13118a27f7c9SJoe Perches { 13127b9186f5SAndré Goddard Rosa int i, j, range; 13138a27f7c9SJoe Perches unsigned char zerolength[8]; 13148a27f7c9SJoe Perches int longest = 1; 13158a27f7c9SJoe Perches int colonpos = -1; 13168a27f7c9SJoe Perches u16 word; 13177b9186f5SAndré Goddard Rosa u8 hi, lo; 13188a27f7c9SJoe Perches bool needcolon = false; 1319eb78cd26SJoe Perches bool useIPv4; 1320eb78cd26SJoe Perches struct in6_addr in6; 1321eb78cd26SJoe Perches 1322eb78cd26SJoe Perches memcpy(&in6, addr, sizeof(struct in6_addr)); 1323eb78cd26SJoe Perches 1324eb78cd26SJoe Perches useIPv4 = ipv6_addr_v4mapped(&in6) || ipv6_addr_is_isatap(&in6); 13258a27f7c9SJoe Perches 13268a27f7c9SJoe Perches memset(zerolength, 0, sizeof(zerolength)); 13278a27f7c9SJoe Perches 13288a27f7c9SJoe Perches if (useIPv4) 13298a27f7c9SJoe Perches range = 6; 13308a27f7c9SJoe Perches else 13318a27f7c9SJoe Perches range = 8; 13328a27f7c9SJoe Perches 13338a27f7c9SJoe Perches /* find position of longest 0 run */ 13348a27f7c9SJoe Perches for (i = 0; i < range; i++) { 13358a27f7c9SJoe Perches for (j = i; j < range; j++) { 1336eb78cd26SJoe Perches if (in6.s6_addr16[j] != 0) 13378a27f7c9SJoe Perches break; 13388a27f7c9SJoe Perches zerolength[i]++; 13398a27f7c9SJoe Perches } 13408a27f7c9SJoe Perches } 13418a27f7c9SJoe Perches for (i = 0; i < range; i++) { 13428a27f7c9SJoe Perches if (zerolength[i] > longest) { 13438a27f7c9SJoe Perches longest = zerolength[i]; 13448a27f7c9SJoe Perches colonpos = i; 13458a27f7c9SJoe Perches } 13468a27f7c9SJoe Perches } 134729cf519eSJoe Perches if (longest == 1) /* don't compress a single 0 */ 134829cf519eSJoe Perches colonpos = -1; 13498a27f7c9SJoe Perches 13508a27f7c9SJoe Perches /* emit address */ 13518a27f7c9SJoe Perches for (i = 0; i < range; i++) { 13528a27f7c9SJoe Perches if (i == colonpos) { 13538a27f7c9SJoe Perches if (needcolon || i == 0) 13548a27f7c9SJoe Perches *p++ = ':'; 13558a27f7c9SJoe Perches *p++ = ':'; 13568a27f7c9SJoe Perches needcolon = false; 13578a27f7c9SJoe Perches i += longest - 1; 13588a27f7c9SJoe Perches continue; 13598a27f7c9SJoe Perches } 13608a27f7c9SJoe Perches if (needcolon) { 13618a27f7c9SJoe Perches *p++ = ':'; 13628a27f7c9SJoe Perches needcolon = false; 13638a27f7c9SJoe Perches } 13648a27f7c9SJoe Perches /* hex u16 without leading 0s */ 1365eb78cd26SJoe Perches word = ntohs(in6.s6_addr16[i]); 13668a27f7c9SJoe Perches hi = word >> 8; 13678a27f7c9SJoe Perches lo = word & 0xff; 13688a27f7c9SJoe Perches if (hi) { 13698a27f7c9SJoe Perches if (hi > 0x0f) 137055036ba7SAndy Shevchenko p = hex_byte_pack(p, hi); 13718a27f7c9SJoe Perches else 13728a27f7c9SJoe Perches *p++ = hex_asc_lo(hi); 137355036ba7SAndy Shevchenko p = hex_byte_pack(p, lo); 13748a27f7c9SJoe Perches } 1375b5ff992bSAndré Goddard Rosa else if (lo > 0x0f) 137655036ba7SAndy Shevchenko p = hex_byte_pack(p, lo); 13778a27f7c9SJoe Perches else 13788a27f7c9SJoe Perches *p++ = hex_asc_lo(lo); 13798a27f7c9SJoe Perches needcolon = true; 13808a27f7c9SJoe Perches } 13818a27f7c9SJoe Perches 13828a27f7c9SJoe Perches if (useIPv4) { 13838a27f7c9SJoe Perches if (needcolon) 13848a27f7c9SJoe Perches *p++ = ':'; 13850159f24eSJoe Perches p = ip4_string(p, &in6.s6_addr[12], "I4"); 13868a27f7c9SJoe Perches } 13878a27f7c9SJoe Perches *p = '\0'; 13887b9186f5SAndré Goddard Rosa 13898a27f7c9SJoe Perches return p; 13908a27f7c9SJoe Perches } 13918a27f7c9SJoe Perches 1392cf3b429bSJoe Perches static noinline_for_stack 1393cf3b429bSJoe Perches char *ip6_string(char *p, const char *addr, const char *fmt) 13948a27f7c9SJoe Perches { 13958a27f7c9SJoe Perches int i; 13967b9186f5SAndré Goddard Rosa 1397689afa7dSHarvey Harrison for (i = 0; i < 8; i++) { 139855036ba7SAndy Shevchenko p = hex_byte_pack(p, *addr++); 139955036ba7SAndy Shevchenko p = hex_byte_pack(p, *addr++); 14008a27f7c9SJoe Perches if (fmt[0] == 'I' && i != 7) 1401689afa7dSHarvey Harrison *p++ = ':'; 1402689afa7dSHarvey Harrison } 1403689afa7dSHarvey Harrison *p = '\0'; 14047b9186f5SAndré Goddard Rosa 14058a27f7c9SJoe Perches return p; 14068a27f7c9SJoe Perches } 14078a27f7c9SJoe Perches 1408cf3b429bSJoe Perches static noinline_for_stack 1409cf3b429bSJoe Perches char *ip6_addr_string(char *buf, char *end, const u8 *addr, 14108a27f7c9SJoe Perches struct printf_spec spec, const char *fmt) 14118a27f7c9SJoe Perches { 14128a27f7c9SJoe Perches char ip6_addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")]; 14138a27f7c9SJoe Perches 14148a27f7c9SJoe Perches if (fmt[0] == 'I' && fmt[2] == 'c') 1415eb78cd26SJoe Perches ip6_compressed_string(ip6_addr, addr); 14168a27f7c9SJoe Perches else 1417eb78cd26SJoe Perches ip6_string(ip6_addr, addr, fmt); 1418689afa7dSHarvey Harrison 1419d529ac41SPetr Mladek return string_nocheck(buf, end, ip6_addr, spec); 1420689afa7dSHarvey Harrison } 1421689afa7dSHarvey Harrison 1422cf3b429bSJoe Perches static noinline_for_stack 1423cf3b429bSJoe Perches char *ip4_addr_string(char *buf, char *end, const u8 *addr, 14248a27f7c9SJoe Perches struct printf_spec spec, const char *fmt) 14254aa99606SHarvey Harrison { 14268a27f7c9SJoe Perches char ip4_addr[sizeof("255.255.255.255")]; 14274aa99606SHarvey Harrison 14280159f24eSJoe Perches ip4_string(ip4_addr, addr, fmt); 14294aa99606SHarvey Harrison 1430d529ac41SPetr Mladek return string_nocheck(buf, end, ip4_addr, spec); 14314aa99606SHarvey Harrison } 14324aa99606SHarvey Harrison 1433cf3b429bSJoe Perches static noinline_for_stack 143410679643SDaniel Borkmann char *ip6_addr_string_sa(char *buf, char *end, const struct sockaddr_in6 *sa, 143510679643SDaniel Borkmann struct printf_spec spec, const char *fmt) 143610679643SDaniel Borkmann { 143710679643SDaniel Borkmann bool have_p = false, have_s = false, have_f = false, have_c = false; 143810679643SDaniel Borkmann char ip6_addr[sizeof("[xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255]") + 143910679643SDaniel Borkmann sizeof(":12345") + sizeof("/123456789") + 144010679643SDaniel Borkmann sizeof("%1234567890")]; 144110679643SDaniel Borkmann char *p = ip6_addr, *pend = ip6_addr + sizeof(ip6_addr); 144210679643SDaniel Borkmann const u8 *addr = (const u8 *) &sa->sin6_addr; 144310679643SDaniel Borkmann char fmt6[2] = { fmt[0], '6' }; 144410679643SDaniel Borkmann u8 off = 0; 144510679643SDaniel Borkmann 144610679643SDaniel Borkmann fmt++; 144710679643SDaniel Borkmann while (isalpha(*++fmt)) { 144810679643SDaniel Borkmann switch (*fmt) { 144910679643SDaniel Borkmann case 'p': 145010679643SDaniel Borkmann have_p = true; 145110679643SDaniel Borkmann break; 145210679643SDaniel Borkmann case 'f': 145310679643SDaniel Borkmann have_f = true; 145410679643SDaniel Borkmann break; 145510679643SDaniel Borkmann case 's': 145610679643SDaniel Borkmann have_s = true; 145710679643SDaniel Borkmann break; 145810679643SDaniel Borkmann case 'c': 145910679643SDaniel Borkmann have_c = true; 146010679643SDaniel Borkmann break; 146110679643SDaniel Borkmann } 146210679643SDaniel Borkmann } 146310679643SDaniel Borkmann 146410679643SDaniel Borkmann if (have_p || have_s || have_f) { 146510679643SDaniel Borkmann *p = '['; 146610679643SDaniel Borkmann off = 1; 146710679643SDaniel Borkmann } 146810679643SDaniel Borkmann 146910679643SDaniel Borkmann if (fmt6[0] == 'I' && have_c) 147010679643SDaniel Borkmann p = ip6_compressed_string(ip6_addr + off, addr); 147110679643SDaniel Borkmann else 147210679643SDaniel Borkmann p = ip6_string(ip6_addr + off, addr, fmt6); 147310679643SDaniel Borkmann 147410679643SDaniel Borkmann if (have_p || have_s || have_f) 147510679643SDaniel Borkmann *p++ = ']'; 147610679643SDaniel Borkmann 147710679643SDaniel Borkmann if (have_p) { 147810679643SDaniel Borkmann *p++ = ':'; 147910679643SDaniel Borkmann p = number(p, pend, ntohs(sa->sin6_port), spec); 148010679643SDaniel Borkmann } 148110679643SDaniel Borkmann if (have_f) { 148210679643SDaniel Borkmann *p++ = '/'; 148310679643SDaniel Borkmann p = number(p, pend, ntohl(sa->sin6_flowinfo & 148410679643SDaniel Borkmann IPV6_FLOWINFO_MASK), spec); 148510679643SDaniel Borkmann } 148610679643SDaniel Borkmann if (have_s) { 148710679643SDaniel Borkmann *p++ = '%'; 148810679643SDaniel Borkmann p = number(p, pend, sa->sin6_scope_id, spec); 148910679643SDaniel Borkmann } 149010679643SDaniel Borkmann *p = '\0'; 149110679643SDaniel Borkmann 1492d529ac41SPetr Mladek return string_nocheck(buf, end, ip6_addr, spec); 149310679643SDaniel Borkmann } 149410679643SDaniel Borkmann 149510679643SDaniel Borkmann static noinline_for_stack 149610679643SDaniel Borkmann char *ip4_addr_string_sa(char *buf, char *end, const struct sockaddr_in *sa, 149710679643SDaniel Borkmann struct printf_spec spec, const char *fmt) 149810679643SDaniel Borkmann { 149910679643SDaniel Borkmann bool have_p = false; 150010679643SDaniel Borkmann char *p, ip4_addr[sizeof("255.255.255.255") + sizeof(":12345")]; 150110679643SDaniel Borkmann char *pend = ip4_addr + sizeof(ip4_addr); 150210679643SDaniel Borkmann const u8 *addr = (const u8 *) &sa->sin_addr.s_addr; 150310679643SDaniel Borkmann char fmt4[3] = { fmt[0], '4', 0 }; 150410679643SDaniel Borkmann 150510679643SDaniel Borkmann fmt++; 150610679643SDaniel Borkmann while (isalpha(*++fmt)) { 150710679643SDaniel Borkmann switch (*fmt) { 150810679643SDaniel Borkmann case 'p': 150910679643SDaniel Borkmann have_p = true; 151010679643SDaniel Borkmann break; 151110679643SDaniel Borkmann case 'h': 151210679643SDaniel Borkmann case 'l': 151310679643SDaniel Borkmann case 'n': 151410679643SDaniel Borkmann case 'b': 151510679643SDaniel Borkmann fmt4[2] = *fmt; 151610679643SDaniel Borkmann break; 151710679643SDaniel Borkmann } 151810679643SDaniel Borkmann } 151910679643SDaniel Borkmann 152010679643SDaniel Borkmann p = ip4_string(ip4_addr, addr, fmt4); 152110679643SDaniel Borkmann if (have_p) { 152210679643SDaniel Borkmann *p++ = ':'; 152310679643SDaniel Borkmann p = number(p, pend, ntohs(sa->sin_port), spec); 152410679643SDaniel Borkmann } 152510679643SDaniel Borkmann *p = '\0'; 152610679643SDaniel Borkmann 1527d529ac41SPetr Mladek return string_nocheck(buf, end, ip4_addr, spec); 152810679643SDaniel Borkmann } 152910679643SDaniel Borkmann 153010679643SDaniel Borkmann static noinline_for_stack 1531f00cc102SPetr Mladek char *ip_addr_string(char *buf, char *end, const void *ptr, 1532f00cc102SPetr Mladek struct printf_spec spec, const char *fmt) 1533f00cc102SPetr Mladek { 15340b74d4d7SPetr Mladek char *err_fmt_msg; 15350b74d4d7SPetr Mladek 15363e5903ebSPetr Mladek if (check_pointer(&buf, end, ptr, spec)) 15373e5903ebSPetr Mladek return buf; 15383e5903ebSPetr Mladek 1539f00cc102SPetr Mladek switch (fmt[1]) { 1540f00cc102SPetr Mladek case '6': 1541f00cc102SPetr Mladek return ip6_addr_string(buf, end, ptr, spec, fmt); 1542f00cc102SPetr Mladek case '4': 1543f00cc102SPetr Mladek return ip4_addr_string(buf, end, ptr, spec, fmt); 1544f00cc102SPetr Mladek case 'S': { 1545f00cc102SPetr Mladek const union { 1546f00cc102SPetr Mladek struct sockaddr raw; 1547f00cc102SPetr Mladek struct sockaddr_in v4; 1548f00cc102SPetr Mladek struct sockaddr_in6 v6; 1549f00cc102SPetr Mladek } *sa = ptr; 1550f00cc102SPetr Mladek 1551f00cc102SPetr Mladek switch (sa->raw.sa_family) { 1552f00cc102SPetr Mladek case AF_INET: 1553f00cc102SPetr Mladek return ip4_addr_string_sa(buf, end, &sa->v4, spec, fmt); 1554f00cc102SPetr Mladek case AF_INET6: 1555f00cc102SPetr Mladek return ip6_addr_string_sa(buf, end, &sa->v6, spec, fmt); 1556f00cc102SPetr Mladek default: 1557c8c3b584SPetr Mladek return error_string(buf, end, "(einval)", spec); 1558f00cc102SPetr Mladek }} 1559f00cc102SPetr Mladek } 1560f00cc102SPetr Mladek 15610b74d4d7SPetr Mladek err_fmt_msg = fmt[0] == 'i' ? "(%pi?)" : "(%pI?)"; 1562c8c3b584SPetr Mladek return error_string(buf, end, err_fmt_msg, spec); 1563f00cc102SPetr Mladek } 1564f00cc102SPetr Mladek 1565f00cc102SPetr Mladek static noinline_for_stack 156671dca95dSAndy Shevchenko char *escaped_string(char *buf, char *end, u8 *addr, struct printf_spec spec, 156771dca95dSAndy Shevchenko const char *fmt) 156871dca95dSAndy Shevchenko { 156971dca95dSAndy Shevchenko bool found = true; 157071dca95dSAndy Shevchenko int count = 1; 157171dca95dSAndy Shevchenko unsigned int flags = 0; 157271dca95dSAndy Shevchenko int len; 157371dca95dSAndy Shevchenko 157471dca95dSAndy Shevchenko if (spec.field_width == 0) 157571dca95dSAndy Shevchenko return buf; /* nothing to print */ 157671dca95dSAndy Shevchenko 15773e5903ebSPetr Mladek if (check_pointer(&buf, end, addr, spec)) 15783e5903ebSPetr Mladek return buf; 157971dca95dSAndy Shevchenko 158071dca95dSAndy Shevchenko do { 158171dca95dSAndy Shevchenko switch (fmt[count++]) { 158271dca95dSAndy Shevchenko case 'a': 158371dca95dSAndy Shevchenko flags |= ESCAPE_ANY; 158471dca95dSAndy Shevchenko break; 158571dca95dSAndy Shevchenko case 'c': 158671dca95dSAndy Shevchenko flags |= ESCAPE_SPECIAL; 158771dca95dSAndy Shevchenko break; 158871dca95dSAndy Shevchenko case 'h': 158971dca95dSAndy Shevchenko flags |= ESCAPE_HEX; 159071dca95dSAndy Shevchenko break; 159171dca95dSAndy Shevchenko case 'n': 159271dca95dSAndy Shevchenko flags |= ESCAPE_NULL; 159371dca95dSAndy Shevchenko break; 159471dca95dSAndy Shevchenko case 'o': 159571dca95dSAndy Shevchenko flags |= ESCAPE_OCTAL; 159671dca95dSAndy Shevchenko break; 159771dca95dSAndy Shevchenko case 'p': 159871dca95dSAndy Shevchenko flags |= ESCAPE_NP; 159971dca95dSAndy Shevchenko break; 160071dca95dSAndy Shevchenko case 's': 160171dca95dSAndy Shevchenko flags |= ESCAPE_SPACE; 160271dca95dSAndy Shevchenko break; 160371dca95dSAndy Shevchenko default: 160471dca95dSAndy Shevchenko found = false; 160571dca95dSAndy Shevchenko break; 160671dca95dSAndy Shevchenko } 160771dca95dSAndy Shevchenko } while (found); 160871dca95dSAndy Shevchenko 160971dca95dSAndy Shevchenko if (!flags) 161071dca95dSAndy Shevchenko flags = ESCAPE_ANY_NP; 161171dca95dSAndy Shevchenko 161271dca95dSAndy Shevchenko len = spec.field_width < 0 ? 1 : spec.field_width; 161371dca95dSAndy Shevchenko 161441416f23SRasmus Villemoes /* 161541416f23SRasmus Villemoes * string_escape_mem() writes as many characters as it can to 161641416f23SRasmus Villemoes * the given buffer, and returns the total size of the output 161741416f23SRasmus Villemoes * had the buffer been big enough. 161841416f23SRasmus Villemoes */ 161941416f23SRasmus Villemoes buf += string_escape_mem(addr, len, buf, buf < end ? end - buf : 0, flags, NULL); 162071dca95dSAndy Shevchenko 162171dca95dSAndy Shevchenko return buf; 162271dca95dSAndy Shevchenko } 162371dca95dSAndy Shevchenko 16243e5903ebSPetr Mladek static char *va_format(char *buf, char *end, struct va_format *va_fmt, 16253e5903ebSPetr Mladek struct printf_spec spec, const char *fmt) 162645c3e93dSPetr Mladek { 162745c3e93dSPetr Mladek va_list va; 162845c3e93dSPetr Mladek 16293e5903ebSPetr Mladek if (check_pointer(&buf, end, va_fmt, spec)) 16303e5903ebSPetr Mladek return buf; 16313e5903ebSPetr Mladek 163245c3e93dSPetr Mladek va_copy(va, *va_fmt->va); 163345c3e93dSPetr Mladek buf += vsnprintf(buf, end > buf ? end - buf : 0, va_fmt->fmt, va); 163445c3e93dSPetr Mladek va_end(va); 163545c3e93dSPetr Mladek 163645c3e93dSPetr Mladek return buf; 163745c3e93dSPetr Mladek } 163845c3e93dSPetr Mladek 163971dca95dSAndy Shevchenko static noinline_for_stack 1640cf3b429bSJoe Perches char *uuid_string(char *buf, char *end, const u8 *addr, 16419ac6e44eSJoe Perches struct printf_spec spec, const char *fmt) 16429ac6e44eSJoe Perches { 16432b1b0d66SAndy Shevchenko char uuid[UUID_STRING_LEN + 1]; 16449ac6e44eSJoe Perches char *p = uuid; 16459ac6e44eSJoe Perches int i; 1646f9727a17SChristoph Hellwig const u8 *index = uuid_index; 16479ac6e44eSJoe Perches bool uc = false; 16489ac6e44eSJoe Perches 16493e5903ebSPetr Mladek if (check_pointer(&buf, end, addr, spec)) 16503e5903ebSPetr Mladek return buf; 16513e5903ebSPetr Mladek 16529ac6e44eSJoe Perches switch (*(++fmt)) { 16539ac6e44eSJoe Perches case 'L': 16549ac6e44eSJoe Perches uc = true; /* fall-through */ 16559ac6e44eSJoe Perches case 'l': 1656f9727a17SChristoph Hellwig index = guid_index; 16579ac6e44eSJoe Perches break; 16589ac6e44eSJoe Perches case 'B': 16599ac6e44eSJoe Perches uc = true; 16609ac6e44eSJoe Perches break; 16619ac6e44eSJoe Perches } 16629ac6e44eSJoe Perches 16639ac6e44eSJoe Perches for (i = 0; i < 16; i++) { 1664aa4ea1c3SAndy Shevchenko if (uc) 1665aa4ea1c3SAndy Shevchenko p = hex_byte_pack_upper(p, addr[index[i]]); 1666aa4ea1c3SAndy Shevchenko else 166755036ba7SAndy Shevchenko p = hex_byte_pack(p, addr[index[i]]); 16689ac6e44eSJoe Perches switch (i) { 16699ac6e44eSJoe Perches case 3: 16709ac6e44eSJoe Perches case 5: 16719ac6e44eSJoe Perches case 7: 16729ac6e44eSJoe Perches case 9: 16739ac6e44eSJoe Perches *p++ = '-'; 16749ac6e44eSJoe Perches break; 16759ac6e44eSJoe Perches } 16769ac6e44eSJoe Perches } 16779ac6e44eSJoe Perches 16789ac6e44eSJoe Perches *p = 0; 16799ac6e44eSJoe Perches 1680d529ac41SPetr Mladek return string_nocheck(buf, end, uuid, spec); 16819ac6e44eSJoe Perches } 16829ac6e44eSJoe Perches 16835b17aecfSAndy Shevchenko static noinline_for_stack 1684431bca24SGeert Uytterhoeven char *netdev_bits(char *buf, char *end, const void *addr, 1685431bca24SGeert Uytterhoeven struct printf_spec spec, const char *fmt) 1686c8f44affSMichał Mirosław { 16875b17aecfSAndy Shevchenko unsigned long long num; 16885b17aecfSAndy Shevchenko int size; 16895b17aecfSAndy Shevchenko 16903e5903ebSPetr Mladek if (check_pointer(&buf, end, addr, spec)) 16913e5903ebSPetr Mladek return buf; 16923e5903ebSPetr Mladek 16935b17aecfSAndy Shevchenko switch (fmt[1]) { 16945b17aecfSAndy Shevchenko case 'F': 16955b17aecfSAndy Shevchenko num = *(const netdev_features_t *)addr; 16965b17aecfSAndy Shevchenko size = sizeof(netdev_features_t); 16975b17aecfSAndy Shevchenko break; 16985b17aecfSAndy Shevchenko default: 1699c8c3b584SPetr Mladek return error_string(buf, end, "(%pN?)", spec); 17005b17aecfSAndy Shevchenko } 1701c8f44affSMichał Mirosław 17023cab1e71SAndy Shevchenko return special_hex_number(buf, end, num, size); 1703c8f44affSMichał Mirosław } 1704c8f44affSMichał Mirosław 1705aaf07621SJoe Perches static noinline_for_stack 17063e5903ebSPetr Mladek char *address_val(char *buf, char *end, const void *addr, 17073e5903ebSPetr Mladek struct printf_spec spec, const char *fmt) 1708aaf07621SJoe Perches { 1709aaf07621SJoe Perches unsigned long long num; 17103cab1e71SAndy Shevchenko int size; 1711aaf07621SJoe Perches 17123e5903ebSPetr Mladek if (check_pointer(&buf, end, addr, spec)) 17133e5903ebSPetr Mladek return buf; 17143e5903ebSPetr Mladek 1715aaf07621SJoe Perches switch (fmt[1]) { 1716aaf07621SJoe Perches case 'd': 1717aaf07621SJoe Perches num = *(const dma_addr_t *)addr; 17183cab1e71SAndy Shevchenko size = sizeof(dma_addr_t); 1719aaf07621SJoe Perches break; 1720aaf07621SJoe Perches case 'p': 1721aaf07621SJoe Perches default: 1722aaf07621SJoe Perches num = *(const phys_addr_t *)addr; 17233cab1e71SAndy Shevchenko size = sizeof(phys_addr_t); 1724aaf07621SJoe Perches break; 1725aaf07621SJoe Perches } 1726aaf07621SJoe Perches 17273cab1e71SAndy Shevchenko return special_hex_number(buf, end, num, size); 1728aaf07621SJoe Perches } 1729aaf07621SJoe Perches 1730900cca29SGeert Uytterhoeven static noinline_for_stack 17314d42c447SAndy Shevchenko char *date_str(char *buf, char *end, const struct rtc_time *tm, bool r) 17324d42c447SAndy Shevchenko { 17334d42c447SAndy Shevchenko int year = tm->tm_year + (r ? 0 : 1900); 17344d42c447SAndy Shevchenko int mon = tm->tm_mon + (r ? 0 : 1); 17354d42c447SAndy Shevchenko 17364d42c447SAndy Shevchenko buf = number(buf, end, year, default_dec04_spec); 17374d42c447SAndy Shevchenko if (buf < end) 17384d42c447SAndy Shevchenko *buf = '-'; 17394d42c447SAndy Shevchenko buf++; 17404d42c447SAndy Shevchenko 17414d42c447SAndy Shevchenko buf = number(buf, end, mon, default_dec02_spec); 17424d42c447SAndy Shevchenko if (buf < end) 17434d42c447SAndy Shevchenko *buf = '-'; 17444d42c447SAndy Shevchenko buf++; 17454d42c447SAndy Shevchenko 17464d42c447SAndy Shevchenko return number(buf, end, tm->tm_mday, default_dec02_spec); 17474d42c447SAndy Shevchenko } 17484d42c447SAndy Shevchenko 17494d42c447SAndy Shevchenko static noinline_for_stack 17504d42c447SAndy Shevchenko char *time_str(char *buf, char *end, const struct rtc_time *tm, bool r) 17514d42c447SAndy Shevchenko { 17524d42c447SAndy Shevchenko buf = number(buf, end, tm->tm_hour, default_dec02_spec); 17534d42c447SAndy Shevchenko if (buf < end) 17544d42c447SAndy Shevchenko *buf = ':'; 17554d42c447SAndy Shevchenko buf++; 17564d42c447SAndy Shevchenko 17574d42c447SAndy Shevchenko buf = number(buf, end, tm->tm_min, default_dec02_spec); 17584d42c447SAndy Shevchenko if (buf < end) 17594d42c447SAndy Shevchenko *buf = ':'; 17604d42c447SAndy Shevchenko buf++; 17614d42c447SAndy Shevchenko 17624d42c447SAndy Shevchenko return number(buf, end, tm->tm_sec, default_dec02_spec); 17634d42c447SAndy Shevchenko } 17644d42c447SAndy Shevchenko 17654d42c447SAndy Shevchenko static noinline_for_stack 17663e5903ebSPetr Mladek char *rtc_str(char *buf, char *end, const struct rtc_time *tm, 17673e5903ebSPetr Mladek struct printf_spec spec, const char *fmt) 17684d42c447SAndy Shevchenko { 17694d42c447SAndy Shevchenko bool have_t = true, have_d = true; 17704d42c447SAndy Shevchenko bool raw = false; 17714d42c447SAndy Shevchenko int count = 2; 17724d42c447SAndy Shevchenko 17733e5903ebSPetr Mladek if (check_pointer(&buf, end, tm, spec)) 17743e5903ebSPetr Mladek return buf; 17753e5903ebSPetr Mladek 17764d42c447SAndy Shevchenko switch (fmt[count]) { 17774d42c447SAndy Shevchenko case 'd': 17784d42c447SAndy Shevchenko have_t = false; 17794d42c447SAndy Shevchenko count++; 17804d42c447SAndy Shevchenko break; 17814d42c447SAndy Shevchenko case 't': 17824d42c447SAndy Shevchenko have_d = false; 17834d42c447SAndy Shevchenko count++; 17844d42c447SAndy Shevchenko break; 17854d42c447SAndy Shevchenko } 17864d42c447SAndy Shevchenko 17874d42c447SAndy Shevchenko raw = fmt[count] == 'r'; 17884d42c447SAndy Shevchenko 17894d42c447SAndy Shevchenko if (have_d) 17904d42c447SAndy Shevchenko buf = date_str(buf, end, tm, raw); 17914d42c447SAndy Shevchenko if (have_d && have_t) { 17924d42c447SAndy Shevchenko /* Respect ISO 8601 */ 17934d42c447SAndy Shevchenko if (buf < end) 17944d42c447SAndy Shevchenko *buf = 'T'; 17954d42c447SAndy Shevchenko buf++; 17964d42c447SAndy Shevchenko } 17974d42c447SAndy Shevchenko if (have_t) 17984d42c447SAndy Shevchenko buf = time_str(buf, end, tm, raw); 17994d42c447SAndy Shevchenko 18004d42c447SAndy Shevchenko return buf; 18014d42c447SAndy Shevchenko } 18024d42c447SAndy Shevchenko 18034d42c447SAndy Shevchenko static noinline_for_stack 18044d42c447SAndy Shevchenko char *time_and_date(char *buf, char *end, void *ptr, struct printf_spec spec, 18054d42c447SAndy Shevchenko const char *fmt) 18064d42c447SAndy Shevchenko { 18074d42c447SAndy Shevchenko switch (fmt[1]) { 18084d42c447SAndy Shevchenko case 'R': 18093e5903ebSPetr Mladek return rtc_str(buf, end, (const struct rtc_time *)ptr, spec, fmt); 18104d42c447SAndy Shevchenko default: 1811c8c3b584SPetr Mladek return error_string(buf, end, "(%ptR?)", spec); 18124d42c447SAndy Shevchenko } 18134d42c447SAndy Shevchenko } 18144d42c447SAndy Shevchenko 18154d42c447SAndy Shevchenko static noinline_for_stack 1816900cca29SGeert Uytterhoeven char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec, 1817900cca29SGeert Uytterhoeven const char *fmt) 1818900cca29SGeert Uytterhoeven { 18190b74d4d7SPetr Mladek if (!IS_ENABLED(CONFIG_HAVE_CLK)) 1820c8c3b584SPetr Mladek return error_string(buf, end, "(%pC?)", spec); 18210b74d4d7SPetr Mladek 18223e5903ebSPetr Mladek if (check_pointer(&buf, end, clk, spec)) 18233e5903ebSPetr Mladek return buf; 1824900cca29SGeert Uytterhoeven 1825900cca29SGeert Uytterhoeven switch (fmt[1]) { 1826900cca29SGeert Uytterhoeven case 'n': 1827900cca29SGeert Uytterhoeven default: 1828900cca29SGeert Uytterhoeven #ifdef CONFIG_COMMON_CLK 1829900cca29SGeert Uytterhoeven return string(buf, end, __clk_get_name(clk), spec); 1830900cca29SGeert Uytterhoeven #else 18314ca96aa9SGeert Uytterhoeven return ptr_to_id(buf, end, clk, spec); 1832900cca29SGeert Uytterhoeven #endif 1833900cca29SGeert Uytterhoeven } 1834900cca29SGeert Uytterhoeven } 1835900cca29SGeert Uytterhoeven 1836edf14cdbSVlastimil Babka static 1837edf14cdbSVlastimil Babka char *format_flags(char *buf, char *end, unsigned long flags, 1838edf14cdbSVlastimil Babka const struct trace_print_flags *names) 1839edf14cdbSVlastimil Babka { 1840edf14cdbSVlastimil Babka unsigned long mask; 1841edf14cdbSVlastimil Babka 1842edf14cdbSVlastimil Babka for ( ; flags && names->name; names++) { 1843edf14cdbSVlastimil Babka mask = names->mask; 1844edf14cdbSVlastimil Babka if ((flags & mask) != mask) 1845edf14cdbSVlastimil Babka continue; 1846edf14cdbSVlastimil Babka 1847abd4fe62SAndy Shevchenko buf = string(buf, end, names->name, default_str_spec); 1848edf14cdbSVlastimil Babka 1849edf14cdbSVlastimil Babka flags &= ~mask; 1850edf14cdbSVlastimil Babka if (flags) { 1851edf14cdbSVlastimil Babka if (buf < end) 1852edf14cdbSVlastimil Babka *buf = '|'; 1853edf14cdbSVlastimil Babka buf++; 1854edf14cdbSVlastimil Babka } 1855edf14cdbSVlastimil Babka } 1856edf14cdbSVlastimil Babka 1857edf14cdbSVlastimil Babka if (flags) 185854433973SAndy Shevchenko buf = number(buf, end, flags, default_flag_spec); 1859edf14cdbSVlastimil Babka 1860edf14cdbSVlastimil Babka return buf; 1861edf14cdbSVlastimil Babka } 1862edf14cdbSVlastimil Babka 1863edf14cdbSVlastimil Babka static noinline_for_stack 18640b74d4d7SPetr Mladek char *flags_string(char *buf, char *end, void *flags_ptr, 18650b74d4d7SPetr Mladek struct printf_spec spec, const char *fmt) 1866edf14cdbSVlastimil Babka { 1867edf14cdbSVlastimil Babka unsigned long flags; 1868edf14cdbSVlastimil Babka const struct trace_print_flags *names; 1869edf14cdbSVlastimil Babka 18703e5903ebSPetr Mladek if (check_pointer(&buf, end, flags_ptr, spec)) 18713e5903ebSPetr Mladek return buf; 18723e5903ebSPetr Mladek 1873edf14cdbSVlastimil Babka switch (fmt[1]) { 1874edf14cdbSVlastimil Babka case 'p': 1875edf14cdbSVlastimil Babka flags = *(unsigned long *)flags_ptr; 1876edf14cdbSVlastimil Babka /* Remove zone id */ 1877edf14cdbSVlastimil Babka flags &= (1UL << NR_PAGEFLAGS) - 1; 1878edf14cdbSVlastimil Babka names = pageflag_names; 1879edf14cdbSVlastimil Babka break; 1880edf14cdbSVlastimil Babka case 'v': 1881edf14cdbSVlastimil Babka flags = *(unsigned long *)flags_ptr; 1882edf14cdbSVlastimil Babka names = vmaflag_names; 1883edf14cdbSVlastimil Babka break; 1884edf14cdbSVlastimil Babka case 'g': 1885edf14cdbSVlastimil Babka flags = *(gfp_t *)flags_ptr; 1886edf14cdbSVlastimil Babka names = gfpflag_names; 1887edf14cdbSVlastimil Babka break; 1888edf14cdbSVlastimil Babka default: 1889c8c3b584SPetr Mladek return error_string(buf, end, "(%pG?)", spec); 1890edf14cdbSVlastimil Babka } 1891edf14cdbSVlastimil Babka 1892edf14cdbSVlastimil Babka return format_flags(buf, end, flags, names); 1893edf14cdbSVlastimil Babka } 1894edf14cdbSVlastimil Babka 1895ce4fecf1SPantelis Antoniou static const char *device_node_name_for_depth(const struct device_node *np, int depth) 1896ce4fecf1SPantelis Antoniou { 1897ce4fecf1SPantelis Antoniou for ( ; np && depth; depth--) 1898ce4fecf1SPantelis Antoniou np = np->parent; 1899ce4fecf1SPantelis Antoniou 1900ce4fecf1SPantelis Antoniou return kbasename(np->full_name); 1901ce4fecf1SPantelis Antoniou } 1902ce4fecf1SPantelis Antoniou 1903ce4fecf1SPantelis Antoniou static noinline_for_stack 1904ce4fecf1SPantelis Antoniou char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end) 1905ce4fecf1SPantelis Antoniou { 1906ce4fecf1SPantelis Antoniou int depth; 1907ce4fecf1SPantelis Antoniou const struct device_node *parent = np->parent; 1908ce4fecf1SPantelis Antoniou 1909ce4fecf1SPantelis Antoniou /* special case for root node */ 1910ce4fecf1SPantelis Antoniou if (!parent) 1911d529ac41SPetr Mladek return string_nocheck(buf, end, "/", default_str_spec); 1912ce4fecf1SPantelis Antoniou 1913ce4fecf1SPantelis Antoniou for (depth = 0; parent->parent; depth++) 1914ce4fecf1SPantelis Antoniou parent = parent->parent; 1915ce4fecf1SPantelis Antoniou 1916ce4fecf1SPantelis Antoniou for ( ; depth >= 0; depth--) { 1917d529ac41SPetr Mladek buf = string_nocheck(buf, end, "/", default_str_spec); 1918ce4fecf1SPantelis Antoniou buf = string(buf, end, device_node_name_for_depth(np, depth), 1919abd4fe62SAndy Shevchenko default_str_spec); 1920ce4fecf1SPantelis Antoniou } 1921ce4fecf1SPantelis Antoniou return buf; 1922ce4fecf1SPantelis Antoniou } 1923ce4fecf1SPantelis Antoniou 1924ce4fecf1SPantelis Antoniou static noinline_for_stack 1925ce4fecf1SPantelis Antoniou char *device_node_string(char *buf, char *end, struct device_node *dn, 1926ce4fecf1SPantelis Antoniou struct printf_spec spec, const char *fmt) 1927ce4fecf1SPantelis Antoniou { 1928ce4fecf1SPantelis Antoniou char tbuf[sizeof("xxxx") + 1]; 1929ce4fecf1SPantelis Antoniou const char *p; 1930ce4fecf1SPantelis Antoniou int ret; 1931ce4fecf1SPantelis Antoniou char *buf_start = buf; 1932ce4fecf1SPantelis Antoniou struct property *prop; 1933ce4fecf1SPantelis Antoniou bool has_mult, pass; 1934ce4fecf1SPantelis Antoniou static const struct printf_spec num_spec = { 1935ce4fecf1SPantelis Antoniou .flags = SMALL, 1936ce4fecf1SPantelis Antoniou .field_width = -1, 1937ce4fecf1SPantelis Antoniou .precision = -1, 1938ce4fecf1SPantelis Antoniou .base = 10, 1939ce4fecf1SPantelis Antoniou }; 1940ce4fecf1SPantelis Antoniou 1941ce4fecf1SPantelis Antoniou struct printf_spec str_spec = spec; 1942ce4fecf1SPantelis Antoniou str_spec.field_width = -1; 1943ce4fecf1SPantelis Antoniou 1944ce4fecf1SPantelis Antoniou if (!IS_ENABLED(CONFIG_OF)) 1945c8c3b584SPetr Mladek return error_string(buf, end, "(%pOF?)", spec); 1946ce4fecf1SPantelis Antoniou 19473e5903ebSPetr Mladek if (check_pointer(&buf, end, dn, spec)) 19483e5903ebSPetr Mladek return buf; 1949ce4fecf1SPantelis Antoniou 1950ce4fecf1SPantelis Antoniou /* simple case without anything any more format specifiers */ 1951ce4fecf1SPantelis Antoniou fmt++; 1952ce4fecf1SPantelis Antoniou if (fmt[0] == '\0' || strcspn(fmt,"fnpPFcC") > 0) 1953ce4fecf1SPantelis Antoniou fmt = "f"; 1954ce4fecf1SPantelis Antoniou 1955ce4fecf1SPantelis Antoniou for (pass = false; strspn(fmt,"fnpPFcC"); fmt++, pass = true) { 19566d0a70a2SRob Herring int precision; 1957ce4fecf1SPantelis Antoniou if (pass) { 1958ce4fecf1SPantelis Antoniou if (buf < end) 1959ce4fecf1SPantelis Antoniou *buf = ':'; 1960ce4fecf1SPantelis Antoniou buf++; 1961ce4fecf1SPantelis Antoniou } 1962ce4fecf1SPantelis Antoniou 1963ce4fecf1SPantelis Antoniou switch (*fmt) { 1964ce4fecf1SPantelis Antoniou case 'f': /* full_name */ 1965ce4fecf1SPantelis Antoniou buf = device_node_gen_full_name(dn, buf, end); 1966ce4fecf1SPantelis Antoniou break; 1967ce4fecf1SPantelis Antoniou case 'n': /* name */ 19686d0a70a2SRob Herring p = kbasename(of_node_full_name(dn)); 19696d0a70a2SRob Herring precision = str_spec.precision; 19706d0a70a2SRob Herring str_spec.precision = strchrnul(p, '@') - p; 19716d0a70a2SRob Herring buf = string(buf, end, p, str_spec); 19726d0a70a2SRob Herring str_spec.precision = precision; 1973ce4fecf1SPantelis Antoniou break; 1974ce4fecf1SPantelis Antoniou case 'p': /* phandle */ 1975ce4fecf1SPantelis Antoniou buf = number(buf, end, (unsigned int)dn->phandle, num_spec); 1976ce4fecf1SPantelis Antoniou break; 1977ce4fecf1SPantelis Antoniou case 'P': /* path-spec */ 1978ce4fecf1SPantelis Antoniou p = kbasename(of_node_full_name(dn)); 1979ce4fecf1SPantelis Antoniou if (!p[1]) 1980ce4fecf1SPantelis Antoniou p = "/"; 1981ce4fecf1SPantelis Antoniou buf = string(buf, end, p, str_spec); 1982ce4fecf1SPantelis Antoniou break; 1983ce4fecf1SPantelis Antoniou case 'F': /* flags */ 1984ce4fecf1SPantelis Antoniou tbuf[0] = of_node_check_flag(dn, OF_DYNAMIC) ? 'D' : '-'; 1985ce4fecf1SPantelis Antoniou tbuf[1] = of_node_check_flag(dn, OF_DETACHED) ? 'd' : '-'; 1986ce4fecf1SPantelis Antoniou tbuf[2] = of_node_check_flag(dn, OF_POPULATED) ? 'P' : '-'; 1987ce4fecf1SPantelis Antoniou tbuf[3] = of_node_check_flag(dn, OF_POPULATED_BUS) ? 'B' : '-'; 1988ce4fecf1SPantelis Antoniou tbuf[4] = 0; 1989d529ac41SPetr Mladek buf = string_nocheck(buf, end, tbuf, str_spec); 1990ce4fecf1SPantelis Antoniou break; 1991ce4fecf1SPantelis Antoniou case 'c': /* major compatible string */ 1992ce4fecf1SPantelis Antoniou ret = of_property_read_string(dn, "compatible", &p); 1993ce4fecf1SPantelis Antoniou if (!ret) 1994ce4fecf1SPantelis Antoniou buf = string(buf, end, p, str_spec); 1995ce4fecf1SPantelis Antoniou break; 1996ce4fecf1SPantelis Antoniou case 'C': /* full compatible string */ 1997ce4fecf1SPantelis Antoniou has_mult = false; 1998ce4fecf1SPantelis Antoniou of_property_for_each_string(dn, "compatible", prop, p) { 1999ce4fecf1SPantelis Antoniou if (has_mult) 2000d529ac41SPetr Mladek buf = string_nocheck(buf, end, ",", str_spec); 2001d529ac41SPetr Mladek buf = string_nocheck(buf, end, "\"", str_spec); 2002ce4fecf1SPantelis Antoniou buf = string(buf, end, p, str_spec); 2003d529ac41SPetr Mladek buf = string_nocheck(buf, end, "\"", str_spec); 2004ce4fecf1SPantelis Antoniou 2005ce4fecf1SPantelis Antoniou has_mult = true; 2006ce4fecf1SPantelis Antoniou } 2007ce4fecf1SPantelis Antoniou break; 2008ce4fecf1SPantelis Antoniou default: 2009ce4fecf1SPantelis Antoniou break; 2010ce4fecf1SPantelis Antoniou } 2011ce4fecf1SPantelis Antoniou } 2012ce4fecf1SPantelis Antoniou 2013ce4fecf1SPantelis Antoniou return widen_string(buf, buf - buf_start, end, spec); 2014ce4fecf1SPantelis Antoniou } 2015ce4fecf1SPantelis Antoniou 2016798cc27aSPetr Mladek static char *kobject_string(char *buf, char *end, void *ptr, 2017798cc27aSPetr Mladek struct printf_spec spec, const char *fmt) 2018798cc27aSPetr Mladek { 2019798cc27aSPetr Mladek switch (fmt[1]) { 2020798cc27aSPetr Mladek case 'F': 2021798cc27aSPetr Mladek return device_node_string(buf, end, ptr, spec, fmt + 1); 2022798cc27aSPetr Mladek } 2023798cc27aSPetr Mladek 2024c8c3b584SPetr Mladek return error_string(buf, end, "(%pO?)", spec); 2025798cc27aSPetr Mladek } 2026798cc27aSPetr Mladek 20274d8a743cSLinus Torvalds /* 20284d8a743cSLinus Torvalds * Show a '%p' thing. A kernel extension is that the '%p' is followed 20294d8a743cSLinus Torvalds * by an extra set of alphanumeric characters that are extended format 20304d8a743cSLinus Torvalds * specifiers. 20314d8a743cSLinus Torvalds * 20320b523769SJoe Perches * Please update scripts/checkpatch.pl when adding/removing conversion 20330b523769SJoe Perches * characters. (Search for "check for vsprintf extension"). 20340b523769SJoe Perches * 2035332d2e78SLinus Torvalds * Right now we handle: 20360fe1ef24SLinus Torvalds * 2037cdb7e52dSSergey Senozhatsky * - 'S' For symbolic direct pointers (or function descriptors) with offset 2038cdb7e52dSSergey Senozhatsky * - 's' For symbolic direct pointers (or function descriptors) without offset 2039cdb7e52dSSergey Senozhatsky * - 'F' Same as 'S' 2040cdb7e52dSSergey Senozhatsky * - 'f' Same as 's' 2041b0d33c2bSJoe Perches * - '[FfSs]R' as above with __builtin_extract_return_addr() translation 20420f77a8d3SNamhyung Kim * - 'B' For backtraced symbolic direct pointers with offset 2043c7dabef8SBjorn Helgaas * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref] 2044c7dabef8SBjorn Helgaas * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201] 2045dbc760bcSTejun Heo * - 'b[l]' For a bitmap, the number of bits is determined by the field 2046dbc760bcSTejun Heo * width which must be explicitly specified either as part of the 2047dbc760bcSTejun Heo * format string '%32b[l]' or through '%*b[l]', [l] selects 2048dbc760bcSTejun Heo * range-list format instead of hex format 2049dd45c9cfSHarvey Harrison * - 'M' For a 6-byte MAC address, it prints the address in the 2050dd45c9cfSHarvey Harrison * usual colon-separated hex notation 20518a27f7c9SJoe Perches * - 'm' For a 6-byte MAC address, it prints the hex address without colons 2052bc7259a2SJoe Perches * - 'MF' For a 6-byte MAC FDDI address, it prints the address 2053c8e00060SJoe Perches * with a dash-separated hex notation 20547c59154eSAndy Shevchenko * - '[mM]R' For a 6-byte MAC address, Reverse order (Bluetooth) 20558a27f7c9SJoe Perches * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way 20568a27f7c9SJoe Perches * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4) 20578a27f7c9SJoe Perches * IPv6 uses colon separated network-order 16 bit hex with leading 0's 205810679643SDaniel Borkmann * [S][pfs] 205910679643SDaniel Borkmann * Generic IPv4/IPv6 address (struct sockaddr *) that falls back to 206010679643SDaniel Borkmann * [4] or [6] and is able to print port [p], flowinfo [f], scope [s] 20618a27f7c9SJoe Perches * - 'i' [46] for 'raw' IPv4/IPv6 addresses 20628a27f7c9SJoe Perches * IPv6 omits the colons (01020304...0f) 20638a27f7c9SJoe Perches * IPv4 uses dot-separated decimal with leading 0's (010.123.045.006) 206410679643SDaniel Borkmann * [S][pfs] 206510679643SDaniel Borkmann * Generic IPv4/IPv6 address (struct sockaddr *) that falls back to 206610679643SDaniel Borkmann * [4] or [6] and is able to print port [p], flowinfo [f], scope [s] 206710679643SDaniel Borkmann * - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order 206810679643SDaniel Borkmann * - 'I[6S]c' for IPv6 addresses printed as specified by 206929cf519eSJoe Perches * http://tools.ietf.org/html/rfc5952 207071dca95dSAndy Shevchenko * - 'E[achnops]' For an escaped buffer, where rules are defined by combination 207171dca95dSAndy Shevchenko * of the following flags (see string_escape_mem() for the 207271dca95dSAndy Shevchenko * details): 207371dca95dSAndy Shevchenko * a - ESCAPE_ANY 207471dca95dSAndy Shevchenko * c - ESCAPE_SPECIAL 207571dca95dSAndy Shevchenko * h - ESCAPE_HEX 207671dca95dSAndy Shevchenko * n - ESCAPE_NULL 207771dca95dSAndy Shevchenko * o - ESCAPE_OCTAL 207871dca95dSAndy Shevchenko * p - ESCAPE_NP 207971dca95dSAndy Shevchenko * s - ESCAPE_SPACE 208071dca95dSAndy Shevchenko * By default ESCAPE_ANY_NP is used. 20819ac6e44eSJoe Perches * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form 20829ac6e44eSJoe Perches * "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" 20839ac6e44eSJoe Perches * Options for %pU are: 20849ac6e44eSJoe Perches * b big endian lower case hex (default) 20859ac6e44eSJoe Perches * B big endian UPPER case hex 20869ac6e44eSJoe Perches * l little endian lower case hex 20879ac6e44eSJoe Perches * L little endian UPPER case hex 20889ac6e44eSJoe Perches * big endian output byte order is: 20899ac6e44eSJoe Perches * [0][1][2][3]-[4][5]-[6][7]-[8][9]-[10][11][12][13][14][15] 20909ac6e44eSJoe Perches * little endian output byte order is: 20919ac6e44eSJoe Perches * [3][2][1][0]-[5][4]-[7][6]-[8][9]-[10][11][12][13][14][15] 20927db6f5fbSJoe Perches * - 'V' For a struct va_format which contains a format string * and va_list *, 20937db6f5fbSJoe Perches * call vsnprintf(->format, *->va_list). 20947db6f5fbSJoe Perches * Implements a "recursive vsnprintf". 20957db6f5fbSJoe Perches * Do not use this feature without some mechanism to verify the 20967db6f5fbSJoe Perches * correctness of the format string and va_list arguments. 2097455cd5abSDan Rosenberg * - 'K' For a kernel pointer that should be hidden from unprivileged users 2098c8f44affSMichał Mirosław * - 'NF' For a netdev_features_t 209931550a16SAndy Shevchenko * - 'h[CDN]' For a variable-length buffer, it prints it as a hex string with 210031550a16SAndy Shevchenko * a certain separator (' ' by default): 210131550a16SAndy Shevchenko * C colon 210231550a16SAndy Shevchenko * D dash 210331550a16SAndy Shevchenko * N no separator 210431550a16SAndy Shevchenko * The maximum supported length is 64 bytes of the input. Consider 210531550a16SAndy Shevchenko * to use print_hex_dump() for the larger input. 2106aaf07621SJoe Perches * - 'a[pd]' For address types [p] phys_addr_t, [d] dma_addr_t and derivatives 2107aaf07621SJoe Perches * (default assumed to be phys_addr_t, passed by reference) 2108c0d92a57SOlof Johansson * - 'd[234]' For a dentry name (optionally 2-4 last components) 2109c0d92a57SOlof Johansson * - 'D[234]' Same as 'd' but for a struct file 21101031bc58SDmitry Monakhov * - 'g' For block_device name (gendisk + partition number) 21114d42c447SAndy Shevchenko * - 't[R][dt][r]' For time and date as represented: 21124d42c447SAndy Shevchenko * R struct rtc_time 2113900cca29SGeert Uytterhoeven * - 'C' For a clock, it prints the name (Common Clock Framework) or address 2114900cca29SGeert Uytterhoeven * (legacy clock framework) of the clock 2115900cca29SGeert Uytterhoeven * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address 2116900cca29SGeert Uytterhoeven * (legacy clock framework) of the clock 2117edf14cdbSVlastimil Babka * - 'G' For flags to be printed as a collection of symbolic strings that would 2118edf14cdbSVlastimil Babka * construct the specific value. Supported flags given by option: 2119edf14cdbSVlastimil Babka * p page flags (see struct page) given as pointer to unsigned long 2120edf14cdbSVlastimil Babka * g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t 2121edf14cdbSVlastimil Babka * v vma flags (VM_*) given as pointer to unsigned long 2122ce4fecf1SPantelis Antoniou * - 'OF[fnpPcCF]' For a device tree object 2123ce4fecf1SPantelis Antoniou * Without any optional arguments prints the full_name 2124ce4fecf1SPantelis Antoniou * f device node full_name 2125ce4fecf1SPantelis Antoniou * n device node name 2126ce4fecf1SPantelis Antoniou * p device node phandle 2127ce4fecf1SPantelis Antoniou * P device node path spec (name + @unit) 2128ce4fecf1SPantelis Antoniou * F device node flags 2129ce4fecf1SPantelis Antoniou * c major compatible string 2130ce4fecf1SPantelis Antoniou * C full compatible string 21317b1924a1STobin C. Harding * - 'x' For printing the address. Equivalent to "%lx". 21327b1924a1STobin C. Harding * 2133b3ed2321STobin C. Harding * ** When making changes please also update: 2134b3ed2321STobin C. Harding * Documentation/core-api/printk-formats.rst 21359ac6e44eSJoe Perches * 2136ad67b74dSTobin C. Harding * Note: The default behaviour (unadorned %p) is to hash the address, 2137ad67b74dSTobin C. Harding * rendering it useful as a unique identifier. 21384d8a743cSLinus Torvalds */ 2139cf3b429bSJoe Perches static noinline_for_stack 2140cf3b429bSJoe Perches char *pointer(const char *fmt, char *buf, char *end, void *ptr, 2141fef20d9cSFrederic Weisbecker struct printf_spec spec) 214278a8bf69SLinus Torvalds { 21430fe1ef24SLinus Torvalds switch (*fmt) { 21440fe1ef24SLinus Torvalds case 'F': 21450c8b946eSFrederic Weisbecker case 'f': 21460fe1ef24SLinus Torvalds case 'S': 21479ac6e44eSJoe Perches case 's': 214804b8eb7aSSergey Senozhatsky ptr = dereference_symbol_descriptor(ptr); 214904b8eb7aSSergey Senozhatsky /* Fallthrough */ 21500f77a8d3SNamhyung Kim case 'B': 2151b0d33c2bSJoe Perches return symbol_string(buf, end, ptr, spec, fmt); 2152332d2e78SLinus Torvalds case 'R': 2153c7dabef8SBjorn Helgaas case 'r': 2154fd95541eSBjorn Helgaas return resource_string(buf, end, ptr, spec, fmt); 215531550a16SAndy Shevchenko case 'h': 215631550a16SAndy Shevchenko return hex_string(buf, end, ptr, spec, fmt); 2157dbc760bcSTejun Heo case 'b': 2158dbc760bcSTejun Heo switch (fmt[1]) { 2159dbc760bcSTejun Heo case 'l': 2160dbc760bcSTejun Heo return bitmap_list_string(buf, end, ptr, spec, fmt); 2161dbc760bcSTejun Heo default: 2162dbc760bcSTejun Heo return bitmap_string(buf, end, ptr, spec, fmt); 2163dbc760bcSTejun Heo } 21648a27f7c9SJoe Perches case 'M': /* Colon separated: 00:01:02:03:04:05 */ 21658a27f7c9SJoe Perches case 'm': /* Contiguous: 000102030405 */ 216676597ff9SAndrei Emeltchenko /* [mM]F (FDDI) */ 216776597ff9SAndrei Emeltchenko /* [mM]R (Reverse order; Bluetooth) */ 21688a27f7c9SJoe Perches return mac_address_string(buf, end, ptr, spec, fmt); 21698a27f7c9SJoe Perches case 'I': /* Formatted IP supported 21708a27f7c9SJoe Perches * 4: 1.2.3.4 21718a27f7c9SJoe Perches * 6: 0001:0203:...:0708 21728a27f7c9SJoe Perches * 6c: 1::708 or 1::1.2.3.4 21738a27f7c9SJoe Perches */ 21748a27f7c9SJoe Perches case 'i': /* Contiguous: 21758a27f7c9SJoe Perches * 4: 001.002.003.004 21768a27f7c9SJoe Perches * 6: 000102...0f 21778a27f7c9SJoe Perches */ 2178f00cc102SPetr Mladek return ip_addr_string(buf, end, ptr, spec, fmt); 217971dca95dSAndy Shevchenko case 'E': 218071dca95dSAndy Shevchenko return escaped_string(buf, end, ptr, spec, fmt); 21819ac6e44eSJoe Perches case 'U': 21829ac6e44eSJoe Perches return uuid_string(buf, end, ptr, spec, fmt); 21837db6f5fbSJoe Perches case 'V': 21843e5903ebSPetr Mladek return va_format(buf, end, ptr, spec, fmt); 2185455cd5abSDan Rosenberg case 'K': 218657e73442STobin C. Harding return restricted_pointer(buf, end, ptr, spec); 2187c8f44affSMichał Mirosław case 'N': 2188431bca24SGeert Uytterhoeven return netdev_bits(buf, end, ptr, spec, fmt); 21897d799210SStepan Moskovchenko case 'a': 21903e5903ebSPetr Mladek return address_val(buf, end, ptr, spec, fmt); 21914b6ccca7SAl Viro case 'd': 21924b6ccca7SAl Viro return dentry_name(buf, end, ptr, spec, fmt); 21934d42c447SAndy Shevchenko case 't': 21944d42c447SAndy Shevchenko return time_and_date(buf, end, ptr, spec, fmt); 2195900cca29SGeert Uytterhoeven case 'C': 2196900cca29SGeert Uytterhoeven return clock(buf, end, ptr, spec, fmt); 21974b6ccca7SAl Viro case 'D': 219836594b31SJia He return file_dentry_name(buf, end, ptr, spec, fmt); 21991031bc58SDmitry Monakhov #ifdef CONFIG_BLOCK 22001031bc58SDmitry Monakhov case 'g': 22011031bc58SDmitry Monakhov return bdev_name(buf, end, ptr, spec, fmt); 22021031bc58SDmitry Monakhov #endif 22031031bc58SDmitry Monakhov 2204edf14cdbSVlastimil Babka case 'G': 22050b74d4d7SPetr Mladek return flags_string(buf, end, ptr, spec, fmt); 2206ce4fecf1SPantelis Antoniou case 'O': 2207798cc27aSPetr Mladek return kobject_string(buf, end, ptr, spec, fmt); 22087b1924a1STobin C. Harding case 'x': 22097b1924a1STobin C. Harding return pointer_string(buf, end, ptr, spec); 2210*57f5677eSRasmus Villemoes case 'e': 2211*57f5677eSRasmus Villemoes /* %pe with a non-ERR_PTR gets treated as plain %p */ 2212*57f5677eSRasmus Villemoes if (!IS_ERR(ptr)) 2213*57f5677eSRasmus Villemoes break; 2214*57f5677eSRasmus Villemoes return err_ptr(buf, end, ptr, spec); 22150fe1ef24SLinus Torvalds } 2216fef20d9cSFrederic Weisbecker 2217ad67b74dSTobin C. Harding /* default is to _not_ leak addresses, hash before printing */ 2218ad67b74dSTobin C. Harding return ptr_to_id(buf, end, ptr, spec); 2219fef20d9cSFrederic Weisbecker } 2220fef20d9cSFrederic Weisbecker 2221fef20d9cSFrederic Weisbecker /* 2222fef20d9cSFrederic Weisbecker * Helper function to decode printf style format. 2223fef20d9cSFrederic Weisbecker * Each call decode a token from the format and return the 2224fef20d9cSFrederic Weisbecker * number of characters read (or likely the delta where it wants 2225fef20d9cSFrederic Weisbecker * to go on the next call). 2226fef20d9cSFrederic Weisbecker * The decoded token is returned through the parameters 2227fef20d9cSFrederic Weisbecker * 2228fef20d9cSFrederic Weisbecker * 'h', 'l', or 'L' for integer fields 2229fef20d9cSFrederic Weisbecker * 'z' support added 23/7/1999 S.H. 2230fef20d9cSFrederic Weisbecker * 'z' changed to 'Z' --davidm 1/25/99 22315b5e0928SAlexey Dobriyan * 'Z' changed to 'z' --adobriyan 2017-01-25 2232fef20d9cSFrederic Weisbecker * 't' added for ptrdiff_t 2233fef20d9cSFrederic Weisbecker * 2234fef20d9cSFrederic Weisbecker * @fmt: the format string 2235fef20d9cSFrederic Weisbecker * @type of the token returned 2236fef20d9cSFrederic Weisbecker * @flags: various flags such as +, -, # tokens.. 2237fef20d9cSFrederic Weisbecker * @field_width: overwritten width 2238fef20d9cSFrederic Weisbecker * @base: base of the number (octal, hex, ...) 2239fef20d9cSFrederic Weisbecker * @precision: precision of a number 2240fef20d9cSFrederic Weisbecker * @qualifier: qualifier of a number (long, size_t, ...) 2241fef20d9cSFrederic Weisbecker */ 2242cf3b429bSJoe Perches static noinline_for_stack 2243cf3b429bSJoe Perches int format_decode(const char *fmt, struct printf_spec *spec) 2244fef20d9cSFrederic Weisbecker { 2245fef20d9cSFrederic Weisbecker const char *start = fmt; 2246d0484193SRasmus Villemoes char qualifier; 2247fef20d9cSFrederic Weisbecker 2248fef20d9cSFrederic Weisbecker /* we finished early by reading the field width */ 2249ed681a91SVegard Nossum if (spec->type == FORMAT_TYPE_WIDTH) { 2250fef20d9cSFrederic Weisbecker if (spec->field_width < 0) { 2251fef20d9cSFrederic Weisbecker spec->field_width = -spec->field_width; 2252fef20d9cSFrederic Weisbecker spec->flags |= LEFT; 2253fef20d9cSFrederic Weisbecker } 2254fef20d9cSFrederic Weisbecker spec->type = FORMAT_TYPE_NONE; 2255fef20d9cSFrederic Weisbecker goto precision; 2256fef20d9cSFrederic Weisbecker } 2257fef20d9cSFrederic Weisbecker 2258fef20d9cSFrederic Weisbecker /* we finished early by reading the precision */ 2259fef20d9cSFrederic Weisbecker if (spec->type == FORMAT_TYPE_PRECISION) { 2260fef20d9cSFrederic Weisbecker if (spec->precision < 0) 2261fef20d9cSFrederic Weisbecker spec->precision = 0; 2262fef20d9cSFrederic Weisbecker 2263fef20d9cSFrederic Weisbecker spec->type = FORMAT_TYPE_NONE; 2264fef20d9cSFrederic Weisbecker goto qualifier; 2265fef20d9cSFrederic Weisbecker } 2266fef20d9cSFrederic Weisbecker 2267fef20d9cSFrederic Weisbecker /* By default */ 2268fef20d9cSFrederic Weisbecker spec->type = FORMAT_TYPE_NONE; 2269fef20d9cSFrederic Weisbecker 2270fef20d9cSFrederic Weisbecker for (; *fmt ; ++fmt) { 2271fef20d9cSFrederic Weisbecker if (*fmt == '%') 2272fef20d9cSFrederic Weisbecker break; 2273fef20d9cSFrederic Weisbecker } 2274fef20d9cSFrederic Weisbecker 2275fef20d9cSFrederic Weisbecker /* Return the current non-format string */ 2276fef20d9cSFrederic Weisbecker if (fmt != start || !*fmt) 2277fef20d9cSFrederic Weisbecker return fmt - start; 2278fef20d9cSFrederic Weisbecker 2279fef20d9cSFrederic Weisbecker /* Process flags */ 2280fef20d9cSFrederic Weisbecker spec->flags = 0; 2281fef20d9cSFrederic Weisbecker 2282fef20d9cSFrederic Weisbecker while (1) { /* this also skips first '%' */ 2283fef20d9cSFrederic Weisbecker bool found = true; 2284fef20d9cSFrederic Weisbecker 2285fef20d9cSFrederic Weisbecker ++fmt; 2286fef20d9cSFrederic Weisbecker 2287fef20d9cSFrederic Weisbecker switch (*fmt) { 2288fef20d9cSFrederic Weisbecker case '-': spec->flags |= LEFT; break; 2289fef20d9cSFrederic Weisbecker case '+': spec->flags |= PLUS; break; 2290fef20d9cSFrederic Weisbecker case ' ': spec->flags |= SPACE; break; 2291fef20d9cSFrederic Weisbecker case '#': spec->flags |= SPECIAL; break; 2292fef20d9cSFrederic Weisbecker case '0': spec->flags |= ZEROPAD; break; 2293fef20d9cSFrederic Weisbecker default: found = false; 2294fef20d9cSFrederic Weisbecker } 2295fef20d9cSFrederic Weisbecker 2296fef20d9cSFrederic Weisbecker if (!found) 2297fef20d9cSFrederic Weisbecker break; 2298fef20d9cSFrederic Weisbecker } 2299fef20d9cSFrederic Weisbecker 2300fef20d9cSFrederic Weisbecker /* get field width */ 2301fef20d9cSFrederic Weisbecker spec->field_width = -1; 2302fef20d9cSFrederic Weisbecker 2303fef20d9cSFrederic Weisbecker if (isdigit(*fmt)) 2304fef20d9cSFrederic Weisbecker spec->field_width = skip_atoi(&fmt); 2305fef20d9cSFrederic Weisbecker else if (*fmt == '*') { 2306fef20d9cSFrederic Weisbecker /* it's the next argument */ 2307ed681a91SVegard Nossum spec->type = FORMAT_TYPE_WIDTH; 2308fef20d9cSFrederic Weisbecker return ++fmt - start; 2309fef20d9cSFrederic Weisbecker } 2310fef20d9cSFrederic Weisbecker 2311fef20d9cSFrederic Weisbecker precision: 2312fef20d9cSFrederic Weisbecker /* get the precision */ 2313fef20d9cSFrederic Weisbecker spec->precision = -1; 2314fef20d9cSFrederic Weisbecker if (*fmt == '.') { 2315fef20d9cSFrederic Weisbecker ++fmt; 2316fef20d9cSFrederic Weisbecker if (isdigit(*fmt)) { 2317fef20d9cSFrederic Weisbecker spec->precision = skip_atoi(&fmt); 2318fef20d9cSFrederic Weisbecker if (spec->precision < 0) 2319fef20d9cSFrederic Weisbecker spec->precision = 0; 2320fef20d9cSFrederic Weisbecker } else if (*fmt == '*') { 2321fef20d9cSFrederic Weisbecker /* it's the next argument */ 2322adf26f84SVegard Nossum spec->type = FORMAT_TYPE_PRECISION; 2323fef20d9cSFrederic Weisbecker return ++fmt - start; 2324fef20d9cSFrederic Weisbecker } 2325fef20d9cSFrederic Weisbecker } 2326fef20d9cSFrederic Weisbecker 2327fef20d9cSFrederic Weisbecker qualifier: 2328fef20d9cSFrederic Weisbecker /* get the conversion qualifier */ 2329d0484193SRasmus Villemoes qualifier = 0; 233075fb8f26SAndy Shevchenko if (*fmt == 'h' || _tolower(*fmt) == 'l' || 23315b5e0928SAlexey Dobriyan *fmt == 'z' || *fmt == 't') { 2332d0484193SRasmus Villemoes qualifier = *fmt++; 2333d0484193SRasmus Villemoes if (unlikely(qualifier == *fmt)) { 2334d0484193SRasmus Villemoes if (qualifier == 'l') { 2335d0484193SRasmus Villemoes qualifier = 'L'; 2336fef20d9cSFrederic Weisbecker ++fmt; 2337d0484193SRasmus Villemoes } else if (qualifier == 'h') { 2338d0484193SRasmus Villemoes qualifier = 'H'; 2339a4e94ef0SZhaolei ++fmt; 2340a4e94ef0SZhaolei } 2341fef20d9cSFrederic Weisbecker } 2342fef20d9cSFrederic Weisbecker } 2343fef20d9cSFrederic Weisbecker 2344fef20d9cSFrederic Weisbecker /* default base */ 2345fef20d9cSFrederic Weisbecker spec->base = 10; 2346fef20d9cSFrederic Weisbecker switch (*fmt) { 2347fef20d9cSFrederic Weisbecker case 'c': 2348fef20d9cSFrederic Weisbecker spec->type = FORMAT_TYPE_CHAR; 2349fef20d9cSFrederic Weisbecker return ++fmt - start; 2350fef20d9cSFrederic Weisbecker 2351fef20d9cSFrederic Weisbecker case 's': 2352fef20d9cSFrederic Weisbecker spec->type = FORMAT_TYPE_STR; 2353fef20d9cSFrederic Weisbecker return ++fmt - start; 2354fef20d9cSFrederic Weisbecker 2355fef20d9cSFrederic Weisbecker case 'p': 2356fef20d9cSFrederic Weisbecker spec->type = FORMAT_TYPE_PTR; 2357ffbfed03SRasmus Villemoes return ++fmt - start; 2358fef20d9cSFrederic Weisbecker 2359fef20d9cSFrederic Weisbecker case '%': 2360fef20d9cSFrederic Weisbecker spec->type = FORMAT_TYPE_PERCENT_CHAR; 2361fef20d9cSFrederic Weisbecker return ++fmt - start; 2362fef20d9cSFrederic Weisbecker 2363fef20d9cSFrederic Weisbecker /* integer number formats - set up the flags and "break" */ 2364fef20d9cSFrederic Weisbecker case 'o': 2365fef20d9cSFrederic Weisbecker spec->base = 8; 2366fef20d9cSFrederic Weisbecker break; 2367fef20d9cSFrederic Weisbecker 2368fef20d9cSFrederic Weisbecker case 'x': 2369fef20d9cSFrederic Weisbecker spec->flags |= SMALL; 23707e6bd6f3SAndy Shevchenko /* fall through */ 2371fef20d9cSFrederic Weisbecker 2372fef20d9cSFrederic Weisbecker case 'X': 2373fef20d9cSFrederic Weisbecker spec->base = 16; 2374fef20d9cSFrederic Weisbecker break; 2375fef20d9cSFrederic Weisbecker 2376fef20d9cSFrederic Weisbecker case 'd': 2377fef20d9cSFrederic Weisbecker case 'i': 237839e874f8SFrederic Weisbecker spec->flags |= SIGN; 2379fef20d9cSFrederic Weisbecker case 'u': 2380fef20d9cSFrederic Weisbecker break; 2381fef20d9cSFrederic Weisbecker 2382708d96fdSRyan Mallon case 'n': 2383708d96fdSRyan Mallon /* 2384b006f19bSRasmus Villemoes * Since %n poses a greater security risk than 2385b006f19bSRasmus Villemoes * utility, treat it as any other invalid or 2386b006f19bSRasmus Villemoes * unsupported format specifier. 2387708d96fdSRyan Mallon */ 2388708d96fdSRyan Mallon /* Fall-through */ 2389708d96fdSRyan Mallon 2390fef20d9cSFrederic Weisbecker default: 2391b006f19bSRasmus Villemoes WARN_ONCE(1, "Please remove unsupported %%%c in format string\n", *fmt); 2392fef20d9cSFrederic Weisbecker spec->type = FORMAT_TYPE_INVALID; 2393fef20d9cSFrederic Weisbecker return fmt - start; 2394fef20d9cSFrederic Weisbecker } 2395fef20d9cSFrederic Weisbecker 2396d0484193SRasmus Villemoes if (qualifier == 'L') 2397fef20d9cSFrederic Weisbecker spec->type = FORMAT_TYPE_LONG_LONG; 2398d0484193SRasmus Villemoes else if (qualifier == 'l') { 239951be17dfSRasmus Villemoes BUILD_BUG_ON(FORMAT_TYPE_ULONG + SIGN != FORMAT_TYPE_LONG); 240051be17dfSRasmus Villemoes spec->type = FORMAT_TYPE_ULONG + (spec->flags & SIGN); 24015b5e0928SAlexey Dobriyan } else if (qualifier == 'z') { 2402fef20d9cSFrederic Weisbecker spec->type = FORMAT_TYPE_SIZE_T; 2403d0484193SRasmus Villemoes } else if (qualifier == 't') { 2404fef20d9cSFrederic Weisbecker spec->type = FORMAT_TYPE_PTRDIFF; 2405d0484193SRasmus Villemoes } else if (qualifier == 'H') { 240651be17dfSRasmus Villemoes BUILD_BUG_ON(FORMAT_TYPE_UBYTE + SIGN != FORMAT_TYPE_BYTE); 240751be17dfSRasmus Villemoes spec->type = FORMAT_TYPE_UBYTE + (spec->flags & SIGN); 2408d0484193SRasmus Villemoes } else if (qualifier == 'h') { 240951be17dfSRasmus Villemoes BUILD_BUG_ON(FORMAT_TYPE_USHORT + SIGN != FORMAT_TYPE_SHORT); 241051be17dfSRasmus Villemoes spec->type = FORMAT_TYPE_USHORT + (spec->flags & SIGN); 2411fef20d9cSFrederic Weisbecker } else { 241251be17dfSRasmus Villemoes BUILD_BUG_ON(FORMAT_TYPE_UINT + SIGN != FORMAT_TYPE_INT); 241351be17dfSRasmus Villemoes spec->type = FORMAT_TYPE_UINT + (spec->flags & SIGN); 2414fef20d9cSFrederic Weisbecker } 2415fef20d9cSFrederic Weisbecker 2416fef20d9cSFrederic Weisbecker return ++fmt - start; 241778a8bf69SLinus Torvalds } 241878a8bf69SLinus Torvalds 24194d72ba01SRasmus Villemoes static void 24204d72ba01SRasmus Villemoes set_field_width(struct printf_spec *spec, int width) 24214d72ba01SRasmus Villemoes { 24224d72ba01SRasmus Villemoes spec->field_width = width; 24234d72ba01SRasmus Villemoes if (WARN_ONCE(spec->field_width != width, "field width %d too large", width)) { 24244d72ba01SRasmus Villemoes spec->field_width = clamp(width, -FIELD_WIDTH_MAX, FIELD_WIDTH_MAX); 24254d72ba01SRasmus Villemoes } 24264d72ba01SRasmus Villemoes } 24274d72ba01SRasmus Villemoes 24284d72ba01SRasmus Villemoes static void 24294d72ba01SRasmus Villemoes set_precision(struct printf_spec *spec, int prec) 24304d72ba01SRasmus Villemoes { 24314d72ba01SRasmus Villemoes spec->precision = prec; 24324d72ba01SRasmus Villemoes if (WARN_ONCE(spec->precision != prec, "precision %d too large", prec)) { 24334d72ba01SRasmus Villemoes spec->precision = clamp(prec, 0, PRECISION_MAX); 24344d72ba01SRasmus Villemoes } 24354d72ba01SRasmus Villemoes } 24364d72ba01SRasmus Villemoes 24371da177e4SLinus Torvalds /** 24381da177e4SLinus Torvalds * vsnprintf - Format a string and place it in a buffer 24391da177e4SLinus Torvalds * @buf: The buffer to place the result into 24401da177e4SLinus Torvalds * @size: The size of the buffer, including the trailing null space 24411da177e4SLinus Torvalds * @fmt: The format string to use 24421da177e4SLinus Torvalds * @args: Arguments for the format string 24431da177e4SLinus Torvalds * 2444d7ec9a05SRasmus Villemoes * This function generally follows C99 vsnprintf, but has some 2445d7ec9a05SRasmus Villemoes * extensions and a few limitations: 2446d7ec9a05SRasmus Villemoes * 24476cc89134Smchehab@s-opensource.com * - ``%n`` is unsupported 24486cc89134Smchehab@s-opensource.com * - ``%p*`` is handled by pointer() 244920036fdcSAndi Kleen * 245027e7c0e8SJonathan Corbet * See pointer() or Documentation/core-api/printk-formats.rst for more 24515e4ee7b1SMartin Kletzander * extensive description. 24525e4ee7b1SMartin Kletzander * 24535e4ee7b1SMartin Kletzander * **Please update the documentation in both places when making changes** 245480f548e0SAndrew Morton * 24551da177e4SLinus Torvalds * The return value is the number of characters which would 24561da177e4SLinus Torvalds * be generated for the given input, excluding the trailing 24571da177e4SLinus Torvalds * '\0', as per ISO C99. If you want to have the exact 24581da177e4SLinus Torvalds * number of characters written into @buf as return value 245972fd4a35SRobert P. J. Day * (not including the trailing '\0'), use vscnprintf(). If the 24601da177e4SLinus Torvalds * return is greater than or equal to @size, the resulting 24611da177e4SLinus Torvalds * string is truncated. 24621da177e4SLinus Torvalds * 2463ba1835ebSUwe Kleine-König * If you're not already dealing with a va_list consider using snprintf(). 24641da177e4SLinus Torvalds */ 24651da177e4SLinus Torvalds int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) 24661da177e4SLinus Torvalds { 24671da177e4SLinus Torvalds unsigned long long num; 2468d4be151bSAndré Goddard Rosa char *str, *end; 2469fef20d9cSFrederic Weisbecker struct printf_spec spec = {0}; 24701da177e4SLinus Torvalds 2471f796937aSJeremy Fitzhardinge /* Reject out-of-range values early. Large positive sizes are 2472f796937aSJeremy Fitzhardinge used for unknown buffer sizes. */ 24732aa2f9e2SRasmus Villemoes if (WARN_ON_ONCE(size > INT_MAX)) 24741da177e4SLinus Torvalds return 0; 24751da177e4SLinus Torvalds 24761da177e4SLinus Torvalds str = buf; 2477f796937aSJeremy Fitzhardinge end = buf + size; 24781da177e4SLinus Torvalds 2479f796937aSJeremy Fitzhardinge /* Make sure end is always >= buf */ 2480f796937aSJeremy Fitzhardinge if (end < buf) { 24811da177e4SLinus Torvalds end = ((void *)-1); 2482f796937aSJeremy Fitzhardinge size = end - buf; 24831da177e4SLinus Torvalds } 24841da177e4SLinus Torvalds 2485fef20d9cSFrederic Weisbecker while (*fmt) { 2486fef20d9cSFrederic Weisbecker const char *old_fmt = fmt; 2487d4be151bSAndré Goddard Rosa int read = format_decode(fmt, &spec); 2488fef20d9cSFrederic Weisbecker 2489fef20d9cSFrederic Weisbecker fmt += read; 2490fef20d9cSFrederic Weisbecker 2491fef20d9cSFrederic Weisbecker switch (spec.type) { 2492fef20d9cSFrederic Weisbecker case FORMAT_TYPE_NONE: { 2493fef20d9cSFrederic Weisbecker int copy = read; 2494fef20d9cSFrederic Weisbecker if (str < end) { 2495fef20d9cSFrederic Weisbecker if (copy > end - str) 2496fef20d9cSFrederic Weisbecker copy = end - str; 2497fef20d9cSFrederic Weisbecker memcpy(str, old_fmt, copy); 2498fef20d9cSFrederic Weisbecker } 2499fef20d9cSFrederic Weisbecker str += read; 2500fef20d9cSFrederic Weisbecker break; 25011da177e4SLinus Torvalds } 25021da177e4SLinus Torvalds 2503ed681a91SVegard Nossum case FORMAT_TYPE_WIDTH: 25044d72ba01SRasmus Villemoes set_field_width(&spec, va_arg(args, int)); 2505fef20d9cSFrederic Weisbecker break; 25061da177e4SLinus Torvalds 2507fef20d9cSFrederic Weisbecker case FORMAT_TYPE_PRECISION: 25084d72ba01SRasmus Villemoes set_precision(&spec, va_arg(args, int)); 2509fef20d9cSFrederic Weisbecker break; 25101da177e4SLinus Torvalds 2511d4be151bSAndré Goddard Rosa case FORMAT_TYPE_CHAR: { 2512d4be151bSAndré Goddard Rosa char c; 2513d4be151bSAndré Goddard Rosa 2514fef20d9cSFrederic Weisbecker if (!(spec.flags & LEFT)) { 2515fef20d9cSFrederic Weisbecker while (--spec.field_width > 0) { 2516f796937aSJeremy Fitzhardinge if (str < end) 25171da177e4SLinus Torvalds *str = ' '; 25181da177e4SLinus Torvalds ++str; 2519fef20d9cSFrederic Weisbecker 25201da177e4SLinus Torvalds } 25211da177e4SLinus Torvalds } 25221da177e4SLinus Torvalds c = (unsigned char) va_arg(args, int); 2523f796937aSJeremy Fitzhardinge if (str < end) 25241da177e4SLinus Torvalds *str = c; 25251da177e4SLinus Torvalds ++str; 2526fef20d9cSFrederic Weisbecker while (--spec.field_width > 0) { 2527f796937aSJeremy Fitzhardinge if (str < end) 25281da177e4SLinus Torvalds *str = ' '; 25291da177e4SLinus Torvalds ++str; 25301da177e4SLinus Torvalds } 2531fef20d9cSFrederic Weisbecker break; 2532d4be151bSAndré Goddard Rosa } 25331da177e4SLinus Torvalds 2534fef20d9cSFrederic Weisbecker case FORMAT_TYPE_STR: 2535fef20d9cSFrederic Weisbecker str = string(str, end, va_arg(args, char *), spec); 2536fef20d9cSFrederic Weisbecker break; 25371da177e4SLinus Torvalds 2538fef20d9cSFrederic Weisbecker case FORMAT_TYPE_PTR: 2539ffbfed03SRasmus Villemoes str = pointer(fmt, str, end, va_arg(args, void *), 2540fef20d9cSFrederic Weisbecker spec); 2541fef20d9cSFrederic Weisbecker while (isalnum(*fmt)) 25424d8a743cSLinus Torvalds fmt++; 2543fef20d9cSFrederic Weisbecker break; 25441da177e4SLinus Torvalds 2545fef20d9cSFrederic Weisbecker case FORMAT_TYPE_PERCENT_CHAR: 2546f796937aSJeremy Fitzhardinge if (str < end) 25471da177e4SLinus Torvalds *str = '%'; 25481da177e4SLinus Torvalds ++str; 25491da177e4SLinus Torvalds break; 25501da177e4SLinus Torvalds 2551fef20d9cSFrederic Weisbecker case FORMAT_TYPE_INVALID: 2552b006f19bSRasmus Villemoes /* 2553b006f19bSRasmus Villemoes * Presumably the arguments passed gcc's type 2554b006f19bSRasmus Villemoes * checking, but there is no safe or sane way 2555b006f19bSRasmus Villemoes * for us to continue parsing the format and 2556b006f19bSRasmus Villemoes * fetching from the va_list; the remaining 2557b006f19bSRasmus Villemoes * specifiers and arguments would be out of 2558b006f19bSRasmus Villemoes * sync. 2559b006f19bSRasmus Villemoes */ 2560b006f19bSRasmus Villemoes goto out; 2561fef20d9cSFrederic Weisbecker 2562fef20d9cSFrederic Weisbecker default: 2563fef20d9cSFrederic Weisbecker switch (spec.type) { 2564fef20d9cSFrederic Weisbecker case FORMAT_TYPE_LONG_LONG: 2565fef20d9cSFrederic Weisbecker num = va_arg(args, long long); 2566fef20d9cSFrederic Weisbecker break; 2567fef20d9cSFrederic Weisbecker case FORMAT_TYPE_ULONG: 2568fef20d9cSFrederic Weisbecker num = va_arg(args, unsigned long); 2569fef20d9cSFrederic Weisbecker break; 2570fef20d9cSFrederic Weisbecker case FORMAT_TYPE_LONG: 2571fef20d9cSFrederic Weisbecker num = va_arg(args, long); 2572fef20d9cSFrederic Weisbecker break; 2573fef20d9cSFrederic Weisbecker case FORMAT_TYPE_SIZE_T: 2574ef124960SJason Gunthorpe if (spec.flags & SIGN) 2575ef124960SJason Gunthorpe num = va_arg(args, ssize_t); 2576ef124960SJason Gunthorpe else 2577fef20d9cSFrederic Weisbecker num = va_arg(args, size_t); 2578fef20d9cSFrederic Weisbecker break; 2579fef20d9cSFrederic Weisbecker case FORMAT_TYPE_PTRDIFF: 2580fef20d9cSFrederic Weisbecker num = va_arg(args, ptrdiff_t); 2581fef20d9cSFrederic Weisbecker break; 2582a4e94ef0SZhaolei case FORMAT_TYPE_UBYTE: 2583a4e94ef0SZhaolei num = (unsigned char) va_arg(args, int); 2584a4e94ef0SZhaolei break; 2585a4e94ef0SZhaolei case FORMAT_TYPE_BYTE: 2586a4e94ef0SZhaolei num = (signed char) va_arg(args, int); 2587a4e94ef0SZhaolei break; 2588fef20d9cSFrederic Weisbecker case FORMAT_TYPE_USHORT: 2589fef20d9cSFrederic Weisbecker num = (unsigned short) va_arg(args, int); 2590fef20d9cSFrederic Weisbecker break; 2591fef20d9cSFrederic Weisbecker case FORMAT_TYPE_SHORT: 2592fef20d9cSFrederic Weisbecker num = (short) va_arg(args, int); 2593fef20d9cSFrederic Weisbecker break; 259439e874f8SFrederic Weisbecker case FORMAT_TYPE_INT: 259539e874f8SFrederic Weisbecker num = (int) va_arg(args, int); 2596fef20d9cSFrederic Weisbecker break; 2597fef20d9cSFrederic Weisbecker default: 2598fef20d9cSFrederic Weisbecker num = va_arg(args, unsigned int); 25991da177e4SLinus Torvalds } 2600fef20d9cSFrederic Weisbecker 2601fef20d9cSFrederic Weisbecker str = number(str, end, num, spec); 26021da177e4SLinus Torvalds } 2603fef20d9cSFrederic Weisbecker } 2604fef20d9cSFrederic Weisbecker 2605b006f19bSRasmus Villemoes out: 2606f796937aSJeremy Fitzhardinge if (size > 0) { 2607f796937aSJeremy Fitzhardinge if (str < end) 26081da177e4SLinus Torvalds *str = '\0'; 2609f796937aSJeremy Fitzhardinge else 26100a6047eeSLinus Torvalds end[-1] = '\0'; 2611f796937aSJeremy Fitzhardinge } 2612fef20d9cSFrederic Weisbecker 2613f796937aSJeremy Fitzhardinge /* the trailing null byte doesn't count towards the total */ 26141da177e4SLinus Torvalds return str-buf; 2615fef20d9cSFrederic Weisbecker 26161da177e4SLinus Torvalds } 26171da177e4SLinus Torvalds EXPORT_SYMBOL(vsnprintf); 26181da177e4SLinus Torvalds 26191da177e4SLinus Torvalds /** 26201da177e4SLinus Torvalds * vscnprintf - Format a string and place it in a buffer 26211da177e4SLinus Torvalds * @buf: The buffer to place the result into 26221da177e4SLinus Torvalds * @size: The size of the buffer, including the trailing null space 26231da177e4SLinus Torvalds * @fmt: The format string to use 26241da177e4SLinus Torvalds * @args: Arguments for the format string 26251da177e4SLinus Torvalds * 26261da177e4SLinus Torvalds * The return value is the number of characters which have been written into 2627b921c69fSAnton Arapov * the @buf not including the trailing '\0'. If @size is == 0 the function 26281da177e4SLinus Torvalds * returns 0. 26291da177e4SLinus Torvalds * 2630ba1835ebSUwe Kleine-König * If you're not already dealing with a va_list consider using scnprintf(). 263120036fdcSAndi Kleen * 263220036fdcSAndi Kleen * See the vsnprintf() documentation for format string extensions over C99. 26331da177e4SLinus Torvalds */ 26341da177e4SLinus Torvalds int vscnprintf(char *buf, size_t size, const char *fmt, va_list args) 26351da177e4SLinus Torvalds { 26361da177e4SLinus Torvalds int i; 26371da177e4SLinus Torvalds 26381da177e4SLinus Torvalds i = vsnprintf(buf, size, fmt, args); 26397b9186f5SAndré Goddard Rosa 2640b921c69fSAnton Arapov if (likely(i < size)) 2641b921c69fSAnton Arapov return i; 2642b921c69fSAnton Arapov if (size != 0) 2643b921c69fSAnton Arapov return size - 1; 2644b921c69fSAnton Arapov return 0; 26451da177e4SLinus Torvalds } 26461da177e4SLinus Torvalds EXPORT_SYMBOL(vscnprintf); 26471da177e4SLinus Torvalds 26481da177e4SLinus Torvalds /** 26491da177e4SLinus Torvalds * snprintf - Format a string and place it in a buffer 26501da177e4SLinus Torvalds * @buf: The buffer to place the result into 26511da177e4SLinus Torvalds * @size: The size of the buffer, including the trailing null space 26521da177e4SLinus Torvalds * @fmt: The format string to use 26531da177e4SLinus Torvalds * @...: Arguments for the format string 26541da177e4SLinus Torvalds * 26551da177e4SLinus Torvalds * The return value is the number of characters which would be 26561da177e4SLinus Torvalds * generated for the given input, excluding the trailing null, 26571da177e4SLinus Torvalds * as per ISO C99. If the return is greater than or equal to 26581da177e4SLinus Torvalds * @size, the resulting string is truncated. 265920036fdcSAndi Kleen * 266020036fdcSAndi Kleen * See the vsnprintf() documentation for format string extensions over C99. 26611da177e4SLinus Torvalds */ 26621da177e4SLinus Torvalds int snprintf(char *buf, size_t size, const char *fmt, ...) 26631da177e4SLinus Torvalds { 26641da177e4SLinus Torvalds va_list args; 26651da177e4SLinus Torvalds int i; 26661da177e4SLinus Torvalds 26671da177e4SLinus Torvalds va_start(args, fmt); 26681da177e4SLinus Torvalds i = vsnprintf(buf, size, fmt, args); 26691da177e4SLinus Torvalds va_end(args); 26707b9186f5SAndré Goddard Rosa 26711da177e4SLinus Torvalds return i; 26721da177e4SLinus Torvalds } 26731da177e4SLinus Torvalds EXPORT_SYMBOL(snprintf); 26741da177e4SLinus Torvalds 26751da177e4SLinus Torvalds /** 26761da177e4SLinus Torvalds * scnprintf - Format a string and place it in a buffer 26771da177e4SLinus Torvalds * @buf: The buffer to place the result into 26781da177e4SLinus Torvalds * @size: The size of the buffer, including the trailing null space 26791da177e4SLinus Torvalds * @fmt: The format string to use 26801da177e4SLinus Torvalds * @...: Arguments for the format string 26811da177e4SLinus Torvalds * 26821da177e4SLinus Torvalds * The return value is the number of characters written into @buf not including 2683b903c0b8SChangli Gao * the trailing '\0'. If @size is == 0 the function returns 0. 26841da177e4SLinus Torvalds */ 26851da177e4SLinus Torvalds 26861da177e4SLinus Torvalds int scnprintf(char *buf, size_t size, const char *fmt, ...) 26871da177e4SLinus Torvalds { 26881da177e4SLinus Torvalds va_list args; 26891da177e4SLinus Torvalds int i; 26901da177e4SLinus Torvalds 26911da177e4SLinus Torvalds va_start(args, fmt); 2692b921c69fSAnton Arapov i = vscnprintf(buf, size, fmt, args); 26931da177e4SLinus Torvalds va_end(args); 26947b9186f5SAndré Goddard Rosa 2695b903c0b8SChangli Gao return i; 26961da177e4SLinus Torvalds } 26971da177e4SLinus Torvalds EXPORT_SYMBOL(scnprintf); 26981da177e4SLinus Torvalds 26991da177e4SLinus Torvalds /** 27001da177e4SLinus Torvalds * vsprintf - Format a string and place it in a buffer 27011da177e4SLinus Torvalds * @buf: The buffer to place the result into 27021da177e4SLinus Torvalds * @fmt: The format string to use 27031da177e4SLinus Torvalds * @args: Arguments for the format string 27041da177e4SLinus Torvalds * 27051da177e4SLinus Torvalds * The function returns the number of characters written 270672fd4a35SRobert P. J. Day * into @buf. Use vsnprintf() or vscnprintf() in order to avoid 27071da177e4SLinus Torvalds * buffer overflows. 27081da177e4SLinus Torvalds * 2709ba1835ebSUwe Kleine-König * If you're not already dealing with a va_list consider using sprintf(). 271020036fdcSAndi Kleen * 271120036fdcSAndi Kleen * See the vsnprintf() documentation for format string extensions over C99. 27121da177e4SLinus Torvalds */ 27131da177e4SLinus Torvalds int vsprintf(char *buf, const char *fmt, va_list args) 27141da177e4SLinus Torvalds { 27151da177e4SLinus Torvalds return vsnprintf(buf, INT_MAX, fmt, args); 27161da177e4SLinus Torvalds } 27171da177e4SLinus Torvalds EXPORT_SYMBOL(vsprintf); 27181da177e4SLinus Torvalds 27191da177e4SLinus Torvalds /** 27201da177e4SLinus Torvalds * sprintf - Format a string and place it in a buffer 27211da177e4SLinus Torvalds * @buf: The buffer to place the result into 27221da177e4SLinus Torvalds * @fmt: The format string to use 27231da177e4SLinus Torvalds * @...: Arguments for the format string 27241da177e4SLinus Torvalds * 27251da177e4SLinus Torvalds * The function returns the number of characters written 272672fd4a35SRobert P. J. Day * into @buf. Use snprintf() or scnprintf() in order to avoid 27271da177e4SLinus Torvalds * buffer overflows. 272820036fdcSAndi Kleen * 272920036fdcSAndi Kleen * See the vsnprintf() documentation for format string extensions over C99. 27301da177e4SLinus Torvalds */ 27311da177e4SLinus Torvalds int sprintf(char *buf, const char *fmt, ...) 27321da177e4SLinus Torvalds { 27331da177e4SLinus Torvalds va_list args; 27341da177e4SLinus Torvalds int i; 27351da177e4SLinus Torvalds 27361da177e4SLinus Torvalds va_start(args, fmt); 27371da177e4SLinus Torvalds i = vsnprintf(buf, INT_MAX, fmt, args); 27381da177e4SLinus Torvalds va_end(args); 27397b9186f5SAndré Goddard Rosa 27401da177e4SLinus Torvalds return i; 27411da177e4SLinus Torvalds } 27421da177e4SLinus Torvalds EXPORT_SYMBOL(sprintf); 27431da177e4SLinus Torvalds 27444370aa4aSLai Jiangshan #ifdef CONFIG_BINARY_PRINTF 27454370aa4aSLai Jiangshan /* 27464370aa4aSLai Jiangshan * bprintf service: 27474370aa4aSLai Jiangshan * vbin_printf() - VA arguments to binary data 27484370aa4aSLai Jiangshan * bstr_printf() - Binary data to text string 27494370aa4aSLai Jiangshan */ 27504370aa4aSLai Jiangshan 27514370aa4aSLai Jiangshan /** 27524370aa4aSLai Jiangshan * vbin_printf - Parse a format string and place args' binary value in a buffer 27534370aa4aSLai Jiangshan * @bin_buf: The buffer to place args' binary value 27544370aa4aSLai Jiangshan * @size: The size of the buffer(by words(32bits), not characters) 27554370aa4aSLai Jiangshan * @fmt: The format string to use 27564370aa4aSLai Jiangshan * @args: Arguments for the format string 27574370aa4aSLai Jiangshan * 27584370aa4aSLai Jiangshan * The format follows C99 vsnprintf, except %n is ignored, and its argument 2759da3dae54SMasanari Iida * is skipped. 27604370aa4aSLai Jiangshan * 27614370aa4aSLai Jiangshan * The return value is the number of words(32bits) which would be generated for 27624370aa4aSLai Jiangshan * the given input. 27634370aa4aSLai Jiangshan * 27644370aa4aSLai Jiangshan * NOTE: 27654370aa4aSLai Jiangshan * If the return value is greater than @size, the resulting bin_buf is NOT 27664370aa4aSLai Jiangshan * valid for bstr_printf(). 27674370aa4aSLai Jiangshan */ 27684370aa4aSLai Jiangshan int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args) 27694370aa4aSLai Jiangshan { 2770fef20d9cSFrederic Weisbecker struct printf_spec spec = {0}; 27714370aa4aSLai Jiangshan char *str, *end; 2772841a915dSSteven Rostedt (VMware) int width; 27734370aa4aSLai Jiangshan 27744370aa4aSLai Jiangshan str = (char *)bin_buf; 27754370aa4aSLai Jiangshan end = (char *)(bin_buf + size); 27764370aa4aSLai Jiangshan 27774370aa4aSLai Jiangshan #define save_arg(type) \ 2778841a915dSSteven Rostedt (VMware) ({ \ 27794370aa4aSLai Jiangshan unsigned long long value; \ 2780841a915dSSteven Rostedt (VMware) if (sizeof(type) == 8) { \ 2781841a915dSSteven Rostedt (VMware) unsigned long long val8; \ 27824370aa4aSLai Jiangshan str = PTR_ALIGN(str, sizeof(u32)); \ 2783841a915dSSteven Rostedt (VMware) val8 = va_arg(args, unsigned long long); \ 27844370aa4aSLai Jiangshan if (str + sizeof(type) <= end) { \ 2785841a915dSSteven Rostedt (VMware) *(u32 *)str = *(u32 *)&val8; \ 2786841a915dSSteven Rostedt (VMware) *(u32 *)(str + 4) = *((u32 *)&val8 + 1); \ 27874370aa4aSLai Jiangshan } \ 2788841a915dSSteven Rostedt (VMware) value = val8; \ 27894370aa4aSLai Jiangshan } else { \ 2790841a915dSSteven Rostedt (VMware) unsigned int val4; \ 27914370aa4aSLai Jiangshan str = PTR_ALIGN(str, sizeof(type)); \ 2792841a915dSSteven Rostedt (VMware) val4 = va_arg(args, int); \ 27934370aa4aSLai Jiangshan if (str + sizeof(type) <= end) \ 2794841a915dSSteven Rostedt (VMware) *(typeof(type) *)str = (type)(long)val4; \ 2795841a915dSSteven Rostedt (VMware) value = (unsigned long long)val4; \ 27964370aa4aSLai Jiangshan } \ 27974370aa4aSLai Jiangshan str += sizeof(type); \ 2798841a915dSSteven Rostedt (VMware) value; \ 2799841a915dSSteven Rostedt (VMware) }) 28004370aa4aSLai Jiangshan 2801fef20d9cSFrederic Weisbecker while (*fmt) { 2802d4be151bSAndré Goddard Rosa int read = format_decode(fmt, &spec); 28034370aa4aSLai Jiangshan 2804fef20d9cSFrederic Weisbecker fmt += read; 2805fef20d9cSFrederic Weisbecker 2806fef20d9cSFrederic Weisbecker switch (spec.type) { 2807fef20d9cSFrederic Weisbecker case FORMAT_TYPE_NONE: 2808d4be151bSAndré Goddard Rosa case FORMAT_TYPE_PERCENT_CHAR: 2809fef20d9cSFrederic Weisbecker break; 2810b006f19bSRasmus Villemoes case FORMAT_TYPE_INVALID: 2811b006f19bSRasmus Villemoes goto out; 2812fef20d9cSFrederic Weisbecker 2813ed681a91SVegard Nossum case FORMAT_TYPE_WIDTH: 2814fef20d9cSFrederic Weisbecker case FORMAT_TYPE_PRECISION: 2815841a915dSSteven Rostedt (VMware) width = (int)save_arg(int); 2816841a915dSSteven Rostedt (VMware) /* Pointers may require the width */ 2817841a915dSSteven Rostedt (VMware) if (*fmt == 'p') 2818841a915dSSteven Rostedt (VMware) set_field_width(&spec, width); 2819fef20d9cSFrederic Weisbecker break; 28204370aa4aSLai Jiangshan 2821fef20d9cSFrederic Weisbecker case FORMAT_TYPE_CHAR: 28224370aa4aSLai Jiangshan save_arg(char); 2823fef20d9cSFrederic Weisbecker break; 2824fef20d9cSFrederic Weisbecker 2825fef20d9cSFrederic Weisbecker case FORMAT_TYPE_STR: { 28264370aa4aSLai Jiangshan const char *save_str = va_arg(args, char *); 28273e5903ebSPetr Mladek const char *err_msg; 28284370aa4aSLai Jiangshan size_t len; 28296c356634SAndré Goddard Rosa 28303e5903ebSPetr Mladek err_msg = check_pointer_msg(save_str); 28313e5903ebSPetr Mladek if (err_msg) 28323e5903ebSPetr Mladek save_str = err_msg; 28333e5903ebSPetr Mladek 28346c356634SAndré Goddard Rosa len = strlen(save_str) + 1; 28356c356634SAndré Goddard Rosa if (str + len < end) 28366c356634SAndré Goddard Rosa memcpy(str, save_str, len); 28376c356634SAndré Goddard Rosa str += len; 2838fef20d9cSFrederic Weisbecker break; 28394370aa4aSLai Jiangshan } 2840fef20d9cSFrederic Weisbecker 2841fef20d9cSFrederic Weisbecker case FORMAT_TYPE_PTR: 2842841a915dSSteven Rostedt (VMware) /* Dereferenced pointers must be done now */ 2843841a915dSSteven Rostedt (VMware) switch (*fmt) { 2844841a915dSSteven Rostedt (VMware) /* Dereference of functions is still OK */ 2845841a915dSSteven Rostedt (VMware) case 'S': 2846841a915dSSteven Rostedt (VMware) case 's': 2847841a915dSSteven Rostedt (VMware) case 'F': 2848841a915dSSteven Rostedt (VMware) case 'f': 28491e6338cfSSteven Rostedt (VMware) case 'x': 28501e6338cfSSteven Rostedt (VMware) case 'K': 2851*57f5677eSRasmus Villemoes case 'e': 28524370aa4aSLai Jiangshan save_arg(void *); 2853841a915dSSteven Rostedt (VMware) break; 2854841a915dSSteven Rostedt (VMware) default: 2855841a915dSSteven Rostedt (VMware) if (!isalnum(*fmt)) { 2856841a915dSSteven Rostedt (VMware) save_arg(void *); 2857841a915dSSteven Rostedt (VMware) break; 2858841a915dSSteven Rostedt (VMware) } 2859841a915dSSteven Rostedt (VMware) str = pointer(fmt, str, end, va_arg(args, void *), 2860841a915dSSteven Rostedt (VMware) spec); 2861841a915dSSteven Rostedt (VMware) if (str + 1 < end) 2862841a915dSSteven Rostedt (VMware) *str++ = '\0'; 2863841a915dSSteven Rostedt (VMware) else 2864841a915dSSteven Rostedt (VMware) end[-1] = '\0'; /* Must be nul terminated */ 2865841a915dSSteven Rostedt (VMware) } 28664370aa4aSLai Jiangshan /* skip all alphanumeric pointer suffixes */ 2867fef20d9cSFrederic Weisbecker while (isalnum(*fmt)) 28684370aa4aSLai Jiangshan fmt++; 2869fef20d9cSFrederic Weisbecker break; 2870fef20d9cSFrederic Weisbecker 2871fef20d9cSFrederic Weisbecker default: 2872fef20d9cSFrederic Weisbecker switch (spec.type) { 2873fef20d9cSFrederic Weisbecker 2874fef20d9cSFrederic Weisbecker case FORMAT_TYPE_LONG_LONG: 2875fef20d9cSFrederic Weisbecker save_arg(long long); 2876fef20d9cSFrederic Weisbecker break; 2877fef20d9cSFrederic Weisbecker case FORMAT_TYPE_ULONG: 2878fef20d9cSFrederic Weisbecker case FORMAT_TYPE_LONG: 2879fef20d9cSFrederic Weisbecker save_arg(unsigned long); 2880fef20d9cSFrederic Weisbecker break; 2881fef20d9cSFrederic Weisbecker case FORMAT_TYPE_SIZE_T: 2882fef20d9cSFrederic Weisbecker save_arg(size_t); 2883fef20d9cSFrederic Weisbecker break; 2884fef20d9cSFrederic Weisbecker case FORMAT_TYPE_PTRDIFF: 2885fef20d9cSFrederic Weisbecker save_arg(ptrdiff_t); 2886fef20d9cSFrederic Weisbecker break; 2887a4e94ef0SZhaolei case FORMAT_TYPE_UBYTE: 2888a4e94ef0SZhaolei case FORMAT_TYPE_BYTE: 2889a4e94ef0SZhaolei save_arg(char); 2890a4e94ef0SZhaolei break; 2891fef20d9cSFrederic Weisbecker case FORMAT_TYPE_USHORT: 2892fef20d9cSFrederic Weisbecker case FORMAT_TYPE_SHORT: 2893fef20d9cSFrederic Weisbecker save_arg(short); 2894fef20d9cSFrederic Weisbecker break; 2895fef20d9cSFrederic Weisbecker default: 2896fef20d9cSFrederic Weisbecker save_arg(int); 2897fef20d9cSFrederic Weisbecker } 2898fef20d9cSFrederic Weisbecker } 2899fef20d9cSFrederic Weisbecker } 2900fef20d9cSFrederic Weisbecker 2901b006f19bSRasmus Villemoes out: 29027b9186f5SAndré Goddard Rosa return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf; 2903fef20d9cSFrederic Weisbecker #undef save_arg 29044370aa4aSLai Jiangshan } 29054370aa4aSLai Jiangshan EXPORT_SYMBOL_GPL(vbin_printf); 29064370aa4aSLai Jiangshan 29074370aa4aSLai Jiangshan /** 29084370aa4aSLai Jiangshan * bstr_printf - Format a string from binary arguments and place it in a buffer 29094370aa4aSLai Jiangshan * @buf: The buffer to place the result into 29104370aa4aSLai Jiangshan * @size: The size of the buffer, including the trailing null space 29114370aa4aSLai Jiangshan * @fmt: The format string to use 29124370aa4aSLai Jiangshan * @bin_buf: Binary arguments for the format string 29134370aa4aSLai Jiangshan * 29144370aa4aSLai Jiangshan * This function like C99 vsnprintf, but the difference is that vsnprintf gets 29154370aa4aSLai Jiangshan * arguments from stack, and bstr_printf gets arguments from @bin_buf which is 29164370aa4aSLai Jiangshan * a binary buffer that generated by vbin_printf. 29174370aa4aSLai Jiangshan * 29184370aa4aSLai Jiangshan * The format follows C99 vsnprintf, but has some extensions: 29190efb4d20SSteven Rostedt * see vsnprintf comment for details. 29204370aa4aSLai Jiangshan * 29214370aa4aSLai Jiangshan * The return value is the number of characters which would 29224370aa4aSLai Jiangshan * be generated for the given input, excluding the trailing 29234370aa4aSLai Jiangshan * '\0', as per ISO C99. If you want to have the exact 29244370aa4aSLai Jiangshan * number of characters written into @buf as return value 29254370aa4aSLai Jiangshan * (not including the trailing '\0'), use vscnprintf(). If the 29264370aa4aSLai Jiangshan * return is greater than or equal to @size, the resulting 29274370aa4aSLai Jiangshan * string is truncated. 29284370aa4aSLai Jiangshan */ 29294370aa4aSLai Jiangshan int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf) 29304370aa4aSLai Jiangshan { 2931fef20d9cSFrederic Weisbecker struct printf_spec spec = {0}; 2932d4be151bSAndré Goddard Rosa char *str, *end; 2933d4be151bSAndré Goddard Rosa const char *args = (const char *)bin_buf; 29344370aa4aSLai Jiangshan 2935762abb51SRasmus Villemoes if (WARN_ON_ONCE(size > INT_MAX)) 29364370aa4aSLai Jiangshan return 0; 29374370aa4aSLai Jiangshan 29384370aa4aSLai Jiangshan str = buf; 29394370aa4aSLai Jiangshan end = buf + size; 29404370aa4aSLai Jiangshan 29414370aa4aSLai Jiangshan #define get_arg(type) \ 29424370aa4aSLai Jiangshan ({ \ 29434370aa4aSLai Jiangshan typeof(type) value; \ 29444370aa4aSLai Jiangshan if (sizeof(type) == 8) { \ 29454370aa4aSLai Jiangshan args = PTR_ALIGN(args, sizeof(u32)); \ 29464370aa4aSLai Jiangshan *(u32 *)&value = *(u32 *)args; \ 29474370aa4aSLai Jiangshan *((u32 *)&value + 1) = *(u32 *)(args + 4); \ 29484370aa4aSLai Jiangshan } else { \ 29494370aa4aSLai Jiangshan args = PTR_ALIGN(args, sizeof(type)); \ 29504370aa4aSLai Jiangshan value = *(typeof(type) *)args; \ 29514370aa4aSLai Jiangshan } \ 29524370aa4aSLai Jiangshan args += sizeof(type); \ 29534370aa4aSLai Jiangshan value; \ 29544370aa4aSLai Jiangshan }) 29554370aa4aSLai Jiangshan 29564370aa4aSLai Jiangshan /* Make sure end is always >= buf */ 29574370aa4aSLai Jiangshan if (end < buf) { 29584370aa4aSLai Jiangshan end = ((void *)-1); 29594370aa4aSLai Jiangshan size = end - buf; 29604370aa4aSLai Jiangshan } 29614370aa4aSLai Jiangshan 2962fef20d9cSFrederic Weisbecker while (*fmt) { 2963fef20d9cSFrederic Weisbecker const char *old_fmt = fmt; 2964d4be151bSAndré Goddard Rosa int read = format_decode(fmt, &spec); 2965fef20d9cSFrederic Weisbecker 2966fef20d9cSFrederic Weisbecker fmt += read; 2967fef20d9cSFrederic Weisbecker 2968fef20d9cSFrederic Weisbecker switch (spec.type) { 2969fef20d9cSFrederic Weisbecker case FORMAT_TYPE_NONE: { 2970fef20d9cSFrederic Weisbecker int copy = read; 2971fef20d9cSFrederic Weisbecker if (str < end) { 2972fef20d9cSFrederic Weisbecker if (copy > end - str) 2973fef20d9cSFrederic Weisbecker copy = end - str; 2974fef20d9cSFrederic Weisbecker memcpy(str, old_fmt, copy); 2975fef20d9cSFrederic Weisbecker } 2976fef20d9cSFrederic Weisbecker str += read; 2977fef20d9cSFrederic Weisbecker break; 29784370aa4aSLai Jiangshan } 29794370aa4aSLai Jiangshan 2980ed681a91SVegard Nossum case FORMAT_TYPE_WIDTH: 29814d72ba01SRasmus Villemoes set_field_width(&spec, get_arg(int)); 2982fef20d9cSFrederic Weisbecker break; 29834370aa4aSLai Jiangshan 2984fef20d9cSFrederic Weisbecker case FORMAT_TYPE_PRECISION: 29854d72ba01SRasmus Villemoes set_precision(&spec, get_arg(int)); 2986fef20d9cSFrederic Weisbecker break; 29874370aa4aSLai Jiangshan 2988d4be151bSAndré Goddard Rosa case FORMAT_TYPE_CHAR: { 2989d4be151bSAndré Goddard Rosa char c; 2990d4be151bSAndré Goddard Rosa 2991fef20d9cSFrederic Weisbecker if (!(spec.flags & LEFT)) { 2992fef20d9cSFrederic Weisbecker while (--spec.field_width > 0) { 29934370aa4aSLai Jiangshan if (str < end) 29944370aa4aSLai Jiangshan *str = ' '; 29954370aa4aSLai Jiangshan ++str; 29964370aa4aSLai Jiangshan } 29974370aa4aSLai Jiangshan } 29984370aa4aSLai Jiangshan c = (unsigned char) get_arg(char); 29994370aa4aSLai Jiangshan if (str < end) 30004370aa4aSLai Jiangshan *str = c; 30014370aa4aSLai Jiangshan ++str; 3002fef20d9cSFrederic Weisbecker while (--spec.field_width > 0) { 30034370aa4aSLai Jiangshan if (str < end) 30044370aa4aSLai Jiangshan *str = ' '; 30054370aa4aSLai Jiangshan ++str; 30064370aa4aSLai Jiangshan } 3007fef20d9cSFrederic Weisbecker break; 3008d4be151bSAndré Goddard Rosa } 30094370aa4aSLai Jiangshan 3010fef20d9cSFrederic Weisbecker case FORMAT_TYPE_STR: { 30114370aa4aSLai Jiangshan const char *str_arg = args; 3012d4be151bSAndré Goddard Rosa args += strlen(str_arg) + 1; 3013fef20d9cSFrederic Weisbecker str = string(str, end, (char *)str_arg, spec); 3014fef20d9cSFrederic Weisbecker break; 30154370aa4aSLai Jiangshan } 30164370aa4aSLai Jiangshan 3017841a915dSSteven Rostedt (VMware) case FORMAT_TYPE_PTR: { 3018841a915dSSteven Rostedt (VMware) bool process = false; 3019841a915dSSteven Rostedt (VMware) int copy, len; 3020841a915dSSteven Rostedt (VMware) /* Non function dereferences were already done */ 3021841a915dSSteven Rostedt (VMware) switch (*fmt) { 3022841a915dSSteven Rostedt (VMware) case 'S': 3023841a915dSSteven Rostedt (VMware) case 's': 3024841a915dSSteven Rostedt (VMware) case 'F': 3025841a915dSSteven Rostedt (VMware) case 'f': 30261e6338cfSSteven Rostedt (VMware) case 'x': 30271e6338cfSSteven Rostedt (VMware) case 'K': 3028*57f5677eSRasmus Villemoes case 'e': 3029841a915dSSteven Rostedt (VMware) process = true; 3030841a915dSSteven Rostedt (VMware) break; 3031841a915dSSteven Rostedt (VMware) default: 3032841a915dSSteven Rostedt (VMware) if (!isalnum(*fmt)) { 3033841a915dSSteven Rostedt (VMware) process = true; 3034841a915dSSteven Rostedt (VMware) break; 3035841a915dSSteven Rostedt (VMware) } 3036841a915dSSteven Rostedt (VMware) /* Pointer dereference was already processed */ 3037841a915dSSteven Rostedt (VMware) if (str < end) { 3038841a915dSSteven Rostedt (VMware) len = copy = strlen(args); 3039841a915dSSteven Rostedt (VMware) if (copy > end - str) 3040841a915dSSteven Rostedt (VMware) copy = end - str; 3041841a915dSSteven Rostedt (VMware) memcpy(str, args, copy); 3042841a915dSSteven Rostedt (VMware) str += len; 304362165600SSteven Rostedt (VMware) args += len + 1; 3044841a915dSSteven Rostedt (VMware) } 3045841a915dSSteven Rostedt (VMware) } 3046841a915dSSteven Rostedt (VMware) if (process) 3047ffbfed03SRasmus Villemoes str = pointer(fmt, str, end, get_arg(void *), spec); 3048841a915dSSteven Rostedt (VMware) 3049fef20d9cSFrederic Weisbecker while (isalnum(*fmt)) 30504370aa4aSLai Jiangshan fmt++; 3051fef20d9cSFrederic Weisbecker break; 3052841a915dSSteven Rostedt (VMware) } 30534370aa4aSLai Jiangshan 3054fef20d9cSFrederic Weisbecker case FORMAT_TYPE_PERCENT_CHAR: 30554370aa4aSLai Jiangshan if (str < end) 30564370aa4aSLai Jiangshan *str = '%'; 30574370aa4aSLai Jiangshan ++str; 3058fef20d9cSFrederic Weisbecker break; 3059fef20d9cSFrederic Weisbecker 3060b006f19bSRasmus Villemoes case FORMAT_TYPE_INVALID: 3061b006f19bSRasmus Villemoes goto out; 3062b006f19bSRasmus Villemoes 3063d4be151bSAndré Goddard Rosa default: { 3064d4be151bSAndré Goddard Rosa unsigned long long num; 3065d4be151bSAndré Goddard Rosa 3066fef20d9cSFrederic Weisbecker switch (spec.type) { 3067fef20d9cSFrederic Weisbecker 3068fef20d9cSFrederic Weisbecker case FORMAT_TYPE_LONG_LONG: 30694370aa4aSLai Jiangshan num = get_arg(long long); 3070fef20d9cSFrederic Weisbecker break; 3071fef20d9cSFrederic Weisbecker case FORMAT_TYPE_ULONG: 3072fef20d9cSFrederic Weisbecker case FORMAT_TYPE_LONG: 3073fef20d9cSFrederic Weisbecker num = get_arg(unsigned long); 3074fef20d9cSFrederic Weisbecker break; 3075fef20d9cSFrederic Weisbecker case FORMAT_TYPE_SIZE_T: 30764370aa4aSLai Jiangshan num = get_arg(size_t); 3077fef20d9cSFrederic Weisbecker break; 3078fef20d9cSFrederic Weisbecker case FORMAT_TYPE_PTRDIFF: 30794370aa4aSLai Jiangshan num = get_arg(ptrdiff_t); 3080fef20d9cSFrederic Weisbecker break; 3081a4e94ef0SZhaolei case FORMAT_TYPE_UBYTE: 3082a4e94ef0SZhaolei num = get_arg(unsigned char); 3083a4e94ef0SZhaolei break; 3084a4e94ef0SZhaolei case FORMAT_TYPE_BYTE: 3085a4e94ef0SZhaolei num = get_arg(signed char); 3086a4e94ef0SZhaolei break; 3087fef20d9cSFrederic Weisbecker case FORMAT_TYPE_USHORT: 3088fef20d9cSFrederic Weisbecker num = get_arg(unsigned short); 3089fef20d9cSFrederic Weisbecker break; 3090fef20d9cSFrederic Weisbecker case FORMAT_TYPE_SHORT: 3091fef20d9cSFrederic Weisbecker num = get_arg(short); 3092fef20d9cSFrederic Weisbecker break; 3093fef20d9cSFrederic Weisbecker case FORMAT_TYPE_UINT: 30944370aa4aSLai Jiangshan num = get_arg(unsigned int); 3095fef20d9cSFrederic Weisbecker break; 3096fef20d9cSFrederic Weisbecker default: 3097fef20d9cSFrederic Weisbecker num = get_arg(int); 30984370aa4aSLai Jiangshan } 3099fef20d9cSFrederic Weisbecker 3100fef20d9cSFrederic Weisbecker str = number(str, end, num, spec); 3101d4be151bSAndré Goddard Rosa } /* default: */ 3102d4be151bSAndré Goddard Rosa } /* switch(spec.type) */ 3103d4be151bSAndré Goddard Rosa } /* while(*fmt) */ 3104fef20d9cSFrederic Weisbecker 3105b006f19bSRasmus Villemoes out: 31064370aa4aSLai Jiangshan if (size > 0) { 31074370aa4aSLai Jiangshan if (str < end) 31084370aa4aSLai Jiangshan *str = '\0'; 31094370aa4aSLai Jiangshan else 31104370aa4aSLai Jiangshan end[-1] = '\0'; 31114370aa4aSLai Jiangshan } 3112fef20d9cSFrederic Weisbecker 31134370aa4aSLai Jiangshan #undef get_arg 31144370aa4aSLai Jiangshan 31154370aa4aSLai Jiangshan /* the trailing null byte doesn't count towards the total */ 31164370aa4aSLai Jiangshan return str - buf; 31174370aa4aSLai Jiangshan } 31184370aa4aSLai Jiangshan EXPORT_SYMBOL_GPL(bstr_printf); 31194370aa4aSLai Jiangshan 31204370aa4aSLai Jiangshan /** 31214370aa4aSLai Jiangshan * bprintf - Parse a format string and place args' binary value in a buffer 31224370aa4aSLai Jiangshan * @bin_buf: The buffer to place args' binary value 31234370aa4aSLai Jiangshan * @size: The size of the buffer(by words(32bits), not characters) 31244370aa4aSLai Jiangshan * @fmt: The format string to use 31254370aa4aSLai Jiangshan * @...: Arguments for the format string 31264370aa4aSLai Jiangshan * 31274370aa4aSLai Jiangshan * The function returns the number of words(u32) written 31284370aa4aSLai Jiangshan * into @bin_buf. 31294370aa4aSLai Jiangshan */ 31304370aa4aSLai Jiangshan int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) 31314370aa4aSLai Jiangshan { 31324370aa4aSLai Jiangshan va_list args; 31334370aa4aSLai Jiangshan int ret; 31344370aa4aSLai Jiangshan 31354370aa4aSLai Jiangshan va_start(args, fmt); 31364370aa4aSLai Jiangshan ret = vbin_printf(bin_buf, size, fmt, args); 31374370aa4aSLai Jiangshan va_end(args); 31387b9186f5SAndré Goddard Rosa 31394370aa4aSLai Jiangshan return ret; 31404370aa4aSLai Jiangshan } 31414370aa4aSLai Jiangshan EXPORT_SYMBOL_GPL(bprintf); 31424370aa4aSLai Jiangshan 31434370aa4aSLai Jiangshan #endif /* CONFIG_BINARY_PRINTF */ 31444370aa4aSLai Jiangshan 31451da177e4SLinus Torvalds /** 31461da177e4SLinus Torvalds * vsscanf - Unformat a buffer into a list of arguments 31471da177e4SLinus Torvalds * @buf: input buffer 31481da177e4SLinus Torvalds * @fmt: format of buffer 31491da177e4SLinus Torvalds * @args: arguments 31501da177e4SLinus Torvalds */ 31511da177e4SLinus Torvalds int vsscanf(const char *buf, const char *fmt, va_list args) 31521da177e4SLinus Torvalds { 31531da177e4SLinus Torvalds const char *str = buf; 31541da177e4SLinus Torvalds char *next; 31551da177e4SLinus Torvalds char digit; 31561da177e4SLinus Torvalds int num = 0; 3157ef0658f3SJoe Perches u8 qualifier; 315853809751SJan Beulich unsigned int base; 315953809751SJan Beulich union { 316053809751SJan Beulich long long s; 316153809751SJan Beulich unsigned long long u; 316253809751SJan Beulich } val; 3163ef0658f3SJoe Perches s16 field_width; 3164d4be151bSAndré Goddard Rosa bool is_sign; 31651da177e4SLinus Torvalds 3166da99075cSJan Beulich while (*fmt) { 31671da177e4SLinus Torvalds /* skip any white space in format */ 31681da177e4SLinus Torvalds /* white space in format matchs any amount of 31691da177e4SLinus Torvalds * white space, including none, in the input. 31701da177e4SLinus Torvalds */ 31711da177e4SLinus Torvalds if (isspace(*fmt)) { 3172e7d2860bSAndré Goddard Rosa fmt = skip_spaces(++fmt); 3173e7d2860bSAndré Goddard Rosa str = skip_spaces(str); 31741da177e4SLinus Torvalds } 31751da177e4SLinus Torvalds 31761da177e4SLinus Torvalds /* anything that is not a conversion must match exactly */ 31771da177e4SLinus Torvalds if (*fmt != '%' && *fmt) { 31781da177e4SLinus Torvalds if (*fmt++ != *str++) 31791da177e4SLinus Torvalds break; 31801da177e4SLinus Torvalds continue; 31811da177e4SLinus Torvalds } 31821da177e4SLinus Torvalds 31831da177e4SLinus Torvalds if (!*fmt) 31841da177e4SLinus Torvalds break; 31851da177e4SLinus Torvalds ++fmt; 31861da177e4SLinus Torvalds 31871da177e4SLinus Torvalds /* skip this conversion. 31881da177e4SLinus Torvalds * advance both strings to next white space 31891da177e4SLinus Torvalds */ 31901da177e4SLinus Torvalds if (*fmt == '*') { 3191da99075cSJan Beulich if (!*str) 3192da99075cSJan Beulich break; 3193f9310b2fSJessica Yu while (!isspace(*fmt) && *fmt != '%' && *fmt) { 3194f9310b2fSJessica Yu /* '%*[' not yet supported, invalid format */ 3195f9310b2fSJessica Yu if (*fmt == '[') 3196f9310b2fSJessica Yu return num; 31971da177e4SLinus Torvalds fmt++; 3198f9310b2fSJessica Yu } 31991da177e4SLinus Torvalds while (!isspace(*str) && *str) 32001da177e4SLinus Torvalds str++; 32011da177e4SLinus Torvalds continue; 32021da177e4SLinus Torvalds } 32031da177e4SLinus Torvalds 32041da177e4SLinus Torvalds /* get field width */ 32051da177e4SLinus Torvalds field_width = -1; 320653809751SJan Beulich if (isdigit(*fmt)) { 32071da177e4SLinus Torvalds field_width = skip_atoi(&fmt); 320853809751SJan Beulich if (field_width <= 0) 320953809751SJan Beulich break; 321053809751SJan Beulich } 32111da177e4SLinus Torvalds 32121da177e4SLinus Torvalds /* get conversion qualifier */ 32131da177e4SLinus Torvalds qualifier = -1; 321475fb8f26SAndy Shevchenko if (*fmt == 'h' || _tolower(*fmt) == 'l' || 32155b5e0928SAlexey Dobriyan *fmt == 'z') { 32161da177e4SLinus Torvalds qualifier = *fmt++; 32171da177e4SLinus Torvalds if (unlikely(qualifier == *fmt)) { 32181da177e4SLinus Torvalds if (qualifier == 'h') { 32191da177e4SLinus Torvalds qualifier = 'H'; 32201da177e4SLinus Torvalds fmt++; 32211da177e4SLinus Torvalds } else if (qualifier == 'l') { 32221da177e4SLinus Torvalds qualifier = 'L'; 32231da177e4SLinus Torvalds fmt++; 32241da177e4SLinus Torvalds } 32251da177e4SLinus Torvalds } 32261da177e4SLinus Torvalds } 32271da177e4SLinus Torvalds 3228da99075cSJan Beulich if (!*fmt) 3229da99075cSJan Beulich break; 3230da99075cSJan Beulich 3231da99075cSJan Beulich if (*fmt == 'n') { 3232da99075cSJan Beulich /* return number of characters read so far */ 3233da99075cSJan Beulich *va_arg(args, int *) = str - buf; 3234da99075cSJan Beulich ++fmt; 3235da99075cSJan Beulich continue; 3236da99075cSJan Beulich } 3237da99075cSJan Beulich 3238da99075cSJan Beulich if (!*str) 32391da177e4SLinus Torvalds break; 32401da177e4SLinus Torvalds 3241d4be151bSAndré Goddard Rosa base = 10; 32423f623ebaSFabian Frederick is_sign = false; 3243d4be151bSAndré Goddard Rosa 32441da177e4SLinus Torvalds switch (*fmt++) { 32451da177e4SLinus Torvalds case 'c': 32461da177e4SLinus Torvalds { 32471da177e4SLinus Torvalds char *s = (char *)va_arg(args, char*); 32481da177e4SLinus Torvalds if (field_width == -1) 32491da177e4SLinus Torvalds field_width = 1; 32501da177e4SLinus Torvalds do { 32511da177e4SLinus Torvalds *s++ = *str++; 32521da177e4SLinus Torvalds } while (--field_width > 0 && *str); 32531da177e4SLinus Torvalds num++; 32541da177e4SLinus Torvalds } 32551da177e4SLinus Torvalds continue; 32561da177e4SLinus Torvalds case 's': 32571da177e4SLinus Torvalds { 32581da177e4SLinus Torvalds char *s = (char *)va_arg(args, char *); 32591da177e4SLinus Torvalds if (field_width == -1) 32604be929beSAlexey Dobriyan field_width = SHRT_MAX; 32611da177e4SLinus Torvalds /* first, skip leading white space in buffer */ 3262e7d2860bSAndré Goddard Rosa str = skip_spaces(str); 32631da177e4SLinus Torvalds 32641da177e4SLinus Torvalds /* now copy until next white space */ 32657b9186f5SAndré Goddard Rosa while (*str && !isspace(*str) && field_width--) 32661da177e4SLinus Torvalds *s++ = *str++; 32671da177e4SLinus Torvalds *s = '\0'; 32681da177e4SLinus Torvalds num++; 32691da177e4SLinus Torvalds } 32701da177e4SLinus Torvalds continue; 3271f9310b2fSJessica Yu /* 3272f9310b2fSJessica Yu * Warning: This implementation of the '[' conversion specifier 3273f9310b2fSJessica Yu * deviates from its glibc counterpart in the following ways: 3274f9310b2fSJessica Yu * (1) It does NOT support ranges i.e. '-' is NOT a special 3275f9310b2fSJessica Yu * character 3276f9310b2fSJessica Yu * (2) It cannot match the closing bracket ']' itself 3277f9310b2fSJessica Yu * (3) A field width is required 3278f9310b2fSJessica Yu * (4) '%*[' (discard matching input) is currently not supported 3279f9310b2fSJessica Yu * 3280f9310b2fSJessica Yu * Example usage: 3281f9310b2fSJessica Yu * ret = sscanf("00:0a:95","%2[^:]:%2[^:]:%2[^:]", 3282f9310b2fSJessica Yu * buf1, buf2, buf3); 3283f9310b2fSJessica Yu * if (ret < 3) 3284f9310b2fSJessica Yu * // etc.. 3285f9310b2fSJessica Yu */ 3286f9310b2fSJessica Yu case '[': 3287f9310b2fSJessica Yu { 3288f9310b2fSJessica Yu char *s = (char *)va_arg(args, char *); 3289f9310b2fSJessica Yu DECLARE_BITMAP(set, 256) = {0}; 3290f9310b2fSJessica Yu unsigned int len = 0; 3291f9310b2fSJessica Yu bool negate = (*fmt == '^'); 3292f9310b2fSJessica Yu 3293f9310b2fSJessica Yu /* field width is required */ 3294f9310b2fSJessica Yu if (field_width == -1) 3295f9310b2fSJessica Yu return num; 3296f9310b2fSJessica Yu 3297f9310b2fSJessica Yu if (negate) 3298f9310b2fSJessica Yu ++fmt; 3299f9310b2fSJessica Yu 3300f9310b2fSJessica Yu for ( ; *fmt && *fmt != ']'; ++fmt, ++len) 3301f9310b2fSJessica Yu set_bit((u8)*fmt, set); 3302f9310b2fSJessica Yu 3303f9310b2fSJessica Yu /* no ']' or no character set found */ 3304f9310b2fSJessica Yu if (!*fmt || !len) 3305f9310b2fSJessica Yu return num; 3306f9310b2fSJessica Yu ++fmt; 3307f9310b2fSJessica Yu 3308f9310b2fSJessica Yu if (negate) { 3309f9310b2fSJessica Yu bitmap_complement(set, set, 256); 3310f9310b2fSJessica Yu /* exclude null '\0' byte */ 3311f9310b2fSJessica Yu clear_bit(0, set); 3312f9310b2fSJessica Yu } 3313f9310b2fSJessica Yu 3314f9310b2fSJessica Yu /* match must be non-empty */ 3315f9310b2fSJessica Yu if (!test_bit((u8)*str, set)) 3316f9310b2fSJessica Yu return num; 3317f9310b2fSJessica Yu 3318f9310b2fSJessica Yu while (test_bit((u8)*str, set) && field_width--) 3319f9310b2fSJessica Yu *s++ = *str++; 3320f9310b2fSJessica Yu *s = '\0'; 3321f9310b2fSJessica Yu ++num; 3322f9310b2fSJessica Yu } 3323f9310b2fSJessica Yu continue; 33241da177e4SLinus Torvalds case 'o': 33251da177e4SLinus Torvalds base = 8; 33261da177e4SLinus Torvalds break; 33271da177e4SLinus Torvalds case 'x': 33281da177e4SLinus Torvalds case 'X': 33291da177e4SLinus Torvalds base = 16; 33301da177e4SLinus Torvalds break; 33311da177e4SLinus Torvalds case 'i': 33321da177e4SLinus Torvalds base = 0; 33337e6bd6f3SAndy Shevchenko /* fall through */ 33341da177e4SLinus Torvalds case 'd': 33353f623ebaSFabian Frederick is_sign = true; 33367e6bd6f3SAndy Shevchenko /* fall through */ 33371da177e4SLinus Torvalds case 'u': 33381da177e4SLinus Torvalds break; 33391da177e4SLinus Torvalds case '%': 33401da177e4SLinus Torvalds /* looking for '%' in str */ 33411da177e4SLinus Torvalds if (*str++ != '%') 33421da177e4SLinus Torvalds return num; 33431da177e4SLinus Torvalds continue; 33441da177e4SLinus Torvalds default: 33451da177e4SLinus Torvalds /* invalid format; stop here */ 33461da177e4SLinus Torvalds return num; 33471da177e4SLinus Torvalds } 33481da177e4SLinus Torvalds 33491da177e4SLinus Torvalds /* have some sort of integer conversion. 33501da177e4SLinus Torvalds * first, skip white space in buffer. 33511da177e4SLinus Torvalds */ 3352e7d2860bSAndré Goddard Rosa str = skip_spaces(str); 33531da177e4SLinus Torvalds 33541da177e4SLinus Torvalds digit = *str; 33551da177e4SLinus Torvalds if (is_sign && digit == '-') 33561da177e4SLinus Torvalds digit = *(str + 1); 33571da177e4SLinus Torvalds 33581da177e4SLinus Torvalds if (!digit 33591da177e4SLinus Torvalds || (base == 16 && !isxdigit(digit)) 33601da177e4SLinus Torvalds || (base == 10 && !isdigit(digit)) 33611da177e4SLinus Torvalds || (base == 8 && (!isdigit(digit) || digit > '7')) 33621da177e4SLinus Torvalds || (base == 0 && !isdigit(digit))) 33631da177e4SLinus Torvalds break; 33641da177e4SLinus Torvalds 336553809751SJan Beulich if (is_sign) 336653809751SJan Beulich val.s = qualifier != 'L' ? 336753809751SJan Beulich simple_strtol(str, &next, base) : 336853809751SJan Beulich simple_strtoll(str, &next, base); 336953809751SJan Beulich else 337053809751SJan Beulich val.u = qualifier != 'L' ? 337153809751SJan Beulich simple_strtoul(str, &next, base) : 337253809751SJan Beulich simple_strtoull(str, &next, base); 337353809751SJan Beulich 337453809751SJan Beulich if (field_width > 0 && next - str > field_width) { 337553809751SJan Beulich if (base == 0) 337653809751SJan Beulich _parse_integer_fixup_radix(str, &base); 337753809751SJan Beulich while (next - str > field_width) { 337853809751SJan Beulich if (is_sign) 337953809751SJan Beulich val.s = div_s64(val.s, base); 338053809751SJan Beulich else 338153809751SJan Beulich val.u = div_u64(val.u, base); 338253809751SJan Beulich --next; 338353809751SJan Beulich } 338453809751SJan Beulich } 338553809751SJan Beulich 33861da177e4SLinus Torvalds switch (qualifier) { 33871da177e4SLinus Torvalds case 'H': /* that's 'hh' in format */ 338853809751SJan Beulich if (is_sign) 338953809751SJan Beulich *va_arg(args, signed char *) = val.s; 339053809751SJan Beulich else 339153809751SJan Beulich *va_arg(args, unsigned char *) = val.u; 33921da177e4SLinus Torvalds break; 33931da177e4SLinus Torvalds case 'h': 339453809751SJan Beulich if (is_sign) 339553809751SJan Beulich *va_arg(args, short *) = val.s; 339653809751SJan Beulich else 339753809751SJan Beulich *va_arg(args, unsigned short *) = val.u; 33981da177e4SLinus Torvalds break; 33991da177e4SLinus Torvalds case 'l': 340053809751SJan Beulich if (is_sign) 340153809751SJan Beulich *va_arg(args, long *) = val.s; 340253809751SJan Beulich else 340353809751SJan Beulich *va_arg(args, unsigned long *) = val.u; 34041da177e4SLinus Torvalds break; 34051da177e4SLinus Torvalds case 'L': 340653809751SJan Beulich if (is_sign) 340753809751SJan Beulich *va_arg(args, long long *) = val.s; 340853809751SJan Beulich else 340953809751SJan Beulich *va_arg(args, unsigned long long *) = val.u; 34101da177e4SLinus Torvalds break; 34111da177e4SLinus Torvalds case 'z': 341253809751SJan Beulich *va_arg(args, size_t *) = val.u; 34131da177e4SLinus Torvalds break; 34141da177e4SLinus Torvalds default: 341553809751SJan Beulich if (is_sign) 341653809751SJan Beulich *va_arg(args, int *) = val.s; 341753809751SJan Beulich else 341853809751SJan Beulich *va_arg(args, unsigned int *) = val.u; 34191da177e4SLinus Torvalds break; 34201da177e4SLinus Torvalds } 34211da177e4SLinus Torvalds num++; 34221da177e4SLinus Torvalds 34231da177e4SLinus Torvalds if (!next) 34241da177e4SLinus Torvalds break; 34251da177e4SLinus Torvalds str = next; 34261da177e4SLinus Torvalds } 3427c6b40d16SJohannes Berg 34281da177e4SLinus Torvalds return num; 34291da177e4SLinus Torvalds } 34301da177e4SLinus Torvalds EXPORT_SYMBOL(vsscanf); 34311da177e4SLinus Torvalds 34321da177e4SLinus Torvalds /** 34331da177e4SLinus Torvalds * sscanf - Unformat a buffer into a list of arguments 34341da177e4SLinus Torvalds * @buf: input buffer 34351da177e4SLinus Torvalds * @fmt: formatting of buffer 34361da177e4SLinus Torvalds * @...: resulting arguments 34371da177e4SLinus Torvalds */ 34381da177e4SLinus Torvalds int sscanf(const char *buf, const char *fmt, ...) 34391da177e4SLinus Torvalds { 34401da177e4SLinus Torvalds va_list args; 34411da177e4SLinus Torvalds int i; 34421da177e4SLinus Torvalds 34431da177e4SLinus Torvalds va_start(args, fmt); 34441da177e4SLinus Torvalds i = vsscanf(buf, fmt, args); 34451da177e4SLinus Torvalds va_end(args); 34467b9186f5SAndré Goddard Rosa 34471da177e4SLinus Torvalds return i; 34481da177e4SLinus Torvalds } 34491da177e4SLinus Torvalds EXPORT_SYMBOL(sscanf); 3450