|
@@ -33,6 +33,7 @@
|
|
|
#include <asm/page.h> /* for PAGE_SIZE */
|
|
|
#include <asm/sections.h> /* for dereference_function_descriptor() */
|
|
|
|
|
|
+#include <linux/string_helpers.h>
|
|
|
#include "kstrtox.h"
|
|
|
|
|
|
/**
|
|
@@ -1100,6 +1101,62 @@ char *ip4_addr_string_sa(char *buf, char *end, const struct sockaddr_in *sa,
|
|
|
return string(buf, end, ip4_addr, spec);
|
|
|
}
|
|
|
|
|
|
+static noinline_for_stack
|
|
|
+char *escaped_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
|
|
|
+ const char *fmt)
|
|
|
+{
|
|
|
+ bool found = true;
|
|
|
+ int count = 1;
|
|
|
+ unsigned int flags = 0;
|
|
|
+ int len;
|
|
|
+
|
|
|
+ if (spec.field_width == 0)
|
|
|
+ return buf; /* nothing to print */
|
|
|
+
|
|
|
+ if (ZERO_OR_NULL_PTR(addr))
|
|
|
+ return string(buf, end, NULL, spec); /* NULL pointer */
|
|
|
+
|
|
|
+
|
|
|
+ do {
|
|
|
+ switch (fmt[count++]) {
|
|
|
+ case 'a':
|
|
|
+ flags |= ESCAPE_ANY;
|
|
|
+ break;
|
|
|
+ case 'c':
|
|
|
+ flags |= ESCAPE_SPECIAL;
|
|
|
+ break;
|
|
|
+ case 'h':
|
|
|
+ flags |= ESCAPE_HEX;
|
|
|
+ break;
|
|
|
+ case 'n':
|
|
|
+ flags |= ESCAPE_NULL;
|
|
|
+ break;
|
|
|
+ case 'o':
|
|
|
+ flags |= ESCAPE_OCTAL;
|
|
|
+ break;
|
|
|
+ case 'p':
|
|
|
+ flags |= ESCAPE_NP;
|
|
|
+ break;
|
|
|
+ case 's':
|
|
|
+ flags |= ESCAPE_SPACE;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ found = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } while (found);
|
|
|
+
|
|
|
+ if (!flags)
|
|
|
+ flags = ESCAPE_ANY_NP;
|
|
|
+
|
|
|
+ len = spec.field_width < 0 ? 1 : spec.field_width;
|
|
|
+
|
|
|
+ /* Ignore the error. We print as many characters as we can */
|
|
|
+ string_escape_mem(addr, len, &buf, end - buf, flags, NULL);
|
|
|
+
|
|
|
+ return buf;
|
|
|
+}
|
|
|
+
|
|
|
static noinline_for_stack
|
|
|
char *uuid_string(char *buf, char *end, const u8 *addr,
|
|
|
struct printf_spec spec, const char *fmt)
|
|
@@ -1221,6 +1278,17 @@ int kptr_restrict __read_mostly;
|
|
|
* - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order
|
|
|
* - 'I[6S]c' for IPv6 addresses printed as specified by
|
|
|
* http://tools.ietf.org/html/rfc5952
|
|
|
+ * - 'E[achnops]' For an escaped buffer, where rules are defined by combination
|
|
|
+ * of the following flags (see string_escape_mem() for the
|
|
|
+ * details):
|
|
|
+ * a - ESCAPE_ANY
|
|
|
+ * c - ESCAPE_SPECIAL
|
|
|
+ * h - ESCAPE_HEX
|
|
|
+ * n - ESCAPE_NULL
|
|
|
+ * o - ESCAPE_OCTAL
|
|
|
+ * p - ESCAPE_NP
|
|
|
+ * s - ESCAPE_SPACE
|
|
|
+ * By default ESCAPE_ANY_NP is used.
|
|
|
* - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form
|
|
|
* "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
|
|
* Options for %pU are:
|
|
@@ -1321,6 +1389,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
|
|
}}
|
|
|
}
|
|
|
break;
|
|
|
+ case 'E':
|
|
|
+ return escaped_string(buf, end, ptr, spec, fmt);
|
|
|
case 'U':
|
|
|
return uuid_string(buf, end, ptr, spec, fmt);
|
|
|
case 'V':
|
|
@@ -1633,6 +1703,7 @@ qualifier:
|
|
|
* %piS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address
|
|
|
* %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper
|
|
|
* case.
|
|
|
+ * %*pE[achnops] print an escaped buffer
|
|
|
* %*ph[CDN] a variable-length hex string with a separator (supports up to 64
|
|
|
* bytes of the input)
|
|
|
* %n is ignored
|