|
@@ -654,6 +654,50 @@ char *resource_string(char *buf, char *end, struct resource *res,
|
|
|
return string(buf, end, sym, spec);
|
|
|
}
|
|
|
|
|
|
+static noinline_for_stack
|
|
|
+char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
|
|
|
+ const char *fmt)
|
|
|
+{
|
|
|
+ int i, len = 1; /* if we pass '%ph[CDN]', field witdh remains
|
|
|
+ negative value, fallback to the default */
|
|
|
+ char separator;
|
|
|
+
|
|
|
+ if (spec.field_width == 0)
|
|
|
+ /* nothing to print */
|
|
|
+ return buf;
|
|
|
+
|
|
|
+ if (ZERO_OR_NULL_PTR(addr))
|
|
|
+ /* NULL pointer */
|
|
|
+ return string(buf, end, NULL, spec);
|
|
|
+
|
|
|
+ switch (fmt[1]) {
|
|
|
+ case 'C':
|
|
|
+ separator = ':';
|
|
|
+ break;
|
|
|
+ case 'D':
|
|
|
+ separator = '-';
|
|
|
+ break;
|
|
|
+ case 'N':
|
|
|
+ separator = 0;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ separator = ' ';
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (spec.field_width > 0)
|
|
|
+ len = min_t(int, spec.field_width, 64);
|
|
|
+
|
|
|
+ for (i = 0; i < len && buf < end - 1; i++) {
|
|
|
+ buf = hex_byte_pack(buf, addr[i]);
|
|
|
+
|
|
|
+ if (buf < end && separator && i != len - 1)
|
|
|
+ *buf++ = separator;
|
|
|
+ }
|
|
|
+
|
|
|
+ return buf;
|
|
|
+}
|
|
|
+
|
|
|
static noinline_for_stack
|
|
|
char *mac_address_string(char *buf, char *end, u8 *addr,
|
|
|
struct printf_spec spec, const char *fmt)
|
|
@@ -974,6 +1018,13 @@ int kptr_restrict __read_mostly;
|
|
|
* correctness of the format string and va_list arguments.
|
|
|
* - 'K' For a kernel pointer that should be hidden from unprivileged users
|
|
|
* - 'NF' For a netdev_features_t
|
|
|
+ * - 'h[CDN]' For a variable-length buffer, it prints it as a hex string with
|
|
|
+ * a certain separator (' ' by default):
|
|
|
+ * C colon
|
|
|
+ * D dash
|
|
|
+ * N no separator
|
|
|
+ * The maximum supported length is 64 bytes of the input. Consider
|
|
|
+ * to use print_hex_dump() for the larger input.
|
|
|
*
|
|
|
* Note: The difference between 'S' and 'F' is that on ia64 and ppc64
|
|
|
* function pointers are really function descriptors, which contain a
|
|
@@ -1007,6 +1058,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
|
|
case 'R':
|
|
|
case 'r':
|
|
|
return resource_string(buf, end, ptr, spec, fmt);
|
|
|
+ case 'h':
|
|
|
+ return hex_string(buf, end, ptr, spec, fmt);
|
|
|
case 'M': /* Colon separated: 00:01:02:03:04:05 */
|
|
|
case 'm': /* Contiguous: 000102030405 */
|
|
|
/* [mM]F (FDDI) */
|
|
@@ -1296,6 +1349,8 @@ qualifier:
|
|
|
* %pI6c print an IPv6 address as specified by RFC 5952
|
|
|
* %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper
|
|
|
* case.
|
|
|
+ * %*ph[CDN] a variable-length hex string with a separator (supports up to 64
|
|
|
+ * bytes of the input)
|
|
|
* %n is ignored
|
|
|
*
|
|
|
* ** Please update Documentation/printk-formats.txt when making changes **
|