Received: by 2002:a5d:9c59:0:0:0:0:0 with SMTP id 25csp129766iof; Sun, 5 Jun 2022 23:15:11 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzhEabemMr6BGTA+eEtRlLhC0SENfNOR7JHPrOnvbLmH+4kUhVezQjvm3qixlyB1m33XPdt X-Received: by 2002:a17:902:9a07:b0:161:fdc3:3b9d with SMTP id v7-20020a1709029a0700b00161fdc33b9dmr22534221plp.94.1654496111111; Sun, 05 Jun 2022 23:15:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1654496111; cv=none; d=google.com; s=arc-20160816; b=myslUbRYLrfsr5G3S2UqtYaIFiEX5d4VwaRnvG8UiqmQUsG6774cBw98y4E4+4QWX3 mZT1KvqJGEIpL2myHcsYSJnTaLlgUmJQCIkyqTPMdpWdj85noYK8Mil2R/S1qoEAbHc5 ULdjoi+46p+TMyl+DXqYb1oMQZf2lU/WJz5k0uRnp10VnwF1LeVYjvCUMhhjeAMqLnCJ 0UDf0pyUtN3prMBm8k63BJ8wJpvQZDTsRvH3661oUL3GZFfjhvvdNyfWmaYD4vTtHaDP UYb0G0FBNeTxG6nBhfgKeIm1W9c4ICjOWdUf/se3hzRI6Q3tS5ABXcyj5rKuqeq0BKHT 7EFg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=99r+5/vRUGhJSKZt1j7G05fBKkay2azibBnxMCo4mAc=; b=0Y7oicfdlNYCVMfNUUmnNYpAYdKZubIAsaTYzojh6tdnZe12l2od191OzZPvm6Jue8 u09DwaAw1J6V/Y+qGDKJBLAUHU8jGHK8qUA9zidRUMGGtVKiBd6OvG34Tw2QIBTkwk6F PuHZhH1yTALsmZ9NJTiC+bIS+NuxMh82tVDJasdgJRjPsJ5fSqK6nm2IZtjZy4WHOZ/H WbRVocava1d3XoDK9Qq/NoSxNeRr5oDXJrSaAhWw3nb0TzYjD2bAq4KfFMdqRNqYrzQX L6ZoDoUT3jz8pv+p0Hhm2EUORtgncptHlGEdniXEGNhaExqbii86GQWtSI+DEdJePM6U I/3A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=ne35BTBc; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [2620:137:e000::1:18]) by mx.google.com with ESMTPS id l21-20020a056a0016d500b004fa7e2947fdsi21853303pfc.147.2022.06.05.23.15.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 05 Jun 2022 23:15:11 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) client-ip=2620:137:e000::1:18; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=ne35BTBc; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 751F579367; Sun, 5 Jun 2022 21:54:17 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240065AbiFDTbI (ORCPT + 99 others); Sat, 4 Jun 2022 15:31:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46900 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240001AbiFDTa7 (ORCPT ); Sat, 4 Jun 2022 15:30:59 -0400 Received: from mail-qk1-x72c.google.com (mail-qk1-x72c.google.com [IPv6:2607:f8b0:4864:20::72c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 70A45340EF for ; Sat, 4 Jun 2022 12:30:57 -0700 (PDT) Received: by mail-qk1-x72c.google.com with SMTP id br33so6651041qkb.0 for ; Sat, 04 Jun 2022 12:30:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=99r+5/vRUGhJSKZt1j7G05fBKkay2azibBnxMCo4mAc=; b=ne35BTBcp5szdMiUZlgM/9j3ghl+LXRZhI9QyFMXLphEAjd2KC+bxv+Gu9y8R7LmTS /ytc8gPBleqDWxlLtouiLkM0a5yrN9rTgbTyhZLd8NL7mFarpK8Cp3WP4u+becmhLbYH 6ZKpOnKKXKFSpE5kOBYJY7Q8+sU38lckM9C8BMM+335xNLIwZ12dIwi47yLj3lhegyIA w520P5fzvspe5TQQfMA2NVvn7gDU6lsUUC44ivWjKpHonm/35XdcUISTngLb8i07BOPp sLjpnpcAYe1ua40niKk/ytB0ODaPptNOadeIgUSqT3jCog2ZsIWo1Eo+DclxrDpwz0Ix 93sQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=99r+5/vRUGhJSKZt1j7G05fBKkay2azibBnxMCo4mAc=; b=XiqifSnAgyN05oE/7DsJHCMvmN92FrHuD7TFxF8INHnY6IuYu3pXvmoy6WBS+oHvl1 HyoI3eTPSuKxPVQn77fp5SqolfUTh0lhspMGl8nuManbqfWD14ZwgpT6nPxNCJ0O3QZi 5JBOZBDH8I0ikHS3aKI/3NnyyIxJou51NWJnchuWasj6uOEwUJ0/E0+tUg4/sXbxJFLK CG6fSOnS2/bZ9/mbFzV1JWvmRG9GXcPyoIKirUyl20eNbqCrPTNXvcxoJ/98zFrauKZf v5txbf7X8qOePXjWsRyKbGsJkcW3tjQdQMQq1cAYA5gFvZckjCkJb5LvnQciJiVLuWk+ Wchw== X-Gm-Message-State: AOAM530ogDgvW44ajVO6MzMCv1taTRDr1oCXesg6oNlTG9cqGFfTlVqL Tw2p6cY3HT47Xd0s+ui/BCAKhvPONYJS X-Received: by 2002:a05:620a:d4f:b0:67e:9cbf:a969 with SMTP id o15-20020a05620a0d4f00b0067e9cbfa969mr10970820qkl.509.1654371055580; Sat, 04 Jun 2022 12:30:55 -0700 (PDT) Received: from moria.home.lan (c-73-219-103-14.hsd1.vt.comcast.net. [73.219.103.14]) by smtp.gmail.com with ESMTPSA id o17-20020ac84291000000b00304defdb1b3sm3537426qtl.85.2022.06.04.12.30.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 04 Jun 2022 12:30:54 -0700 (PDT) From: Kent Overstreet To: linux-kernel@vger.kernel.org Cc: Kent Overstreet , pmladek@suse.com, rostedt@goodmis.org Subject: [PATCH v3 04/33] lib/hexdump: Convert to printbuf Date: Sat, 4 Jun 2022 15:30:13 -0400 Message-Id: <20220604193042.1674951-5-kent.overstreet@gmail.com> X-Mailer: git-send-email 2.36.0 In-Reply-To: <20220604193042.1674951-1-kent.overstreet@gmail.com> References: <20220604193042.1674951-1-kent.overstreet@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RDNS_NONE, SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This converts most of the hexdump code to printbufs, along with some significant cleanups and a bit of reorganization. The old non-printbuf functions are mostly left as wrappers around the new printbuf versions. Big note: byte swabbing behaviour Previously, hex_dump_to_buffer() would byteswab the groups of bytes being printed on little endian machines. This behaviour is... not standard or typical for a hex dumper, and this behaviour was silently added/changed without documentation (in 2007). Given that the hex dumpers are just used for debugging output, nothing is likely to break, and hopefully by reverting to more standard behaviour the end result will be _less_ confusion, modulo a few kernel developers who will certainly be annoyed by their tools changing. Signed-off-by: Kent Overstreet --- include/linux/kernel.h | 6 + lib/hexdump.c | 246 ++++++++++++++++++++++++----------------- lib/test_hexdump.c | 30 +---- 3 files changed, 159 insertions(+), 123 deletions(-) diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 5c4f4b6d36..1906861ece 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -293,6 +293,12 @@ extern int hex_to_bin(unsigned char ch); extern int __must_check hex2bin(u8 *dst, const char *src, size_t count); extern char *bin2hex(char *dst, const void *src, size_t count); +struct printbuf; +void prt_hex_bytes(struct printbuf *, const void *, unsigned, unsigned, unsigned); +void prt_hex_line(struct printbuf *, const void *, size_t, int, int, bool); +void prt_hex_dump(struct printbuf *, const void *, size_t, + const char *, int, unsigned, unsigned, bool); + bool mac_pton(const char *s, u8 *mac); /* diff --git a/lib/hexdump.c b/lib/hexdump.c index 06833d4043..9556f15ad2 100644 --- a/lib/hexdump.c +++ b/lib/hexdump.c @@ -9,6 +9,7 @@ #include #include #include +#include #include const char hex_asc[] = "0123456789abcdef"; @@ -79,32 +80,40 @@ int hex2bin(u8 *dst, const char *src, size_t count) EXPORT_SYMBOL(hex2bin); /** - * bin2hex - convert binary data to an ascii hexadecimal string - * @dst: ascii hexadecimal result - * @src: binary data - * @count: binary data length + * prt_hex_bytes - Print a string of hex bytes, with optional separator + * + * @out: The printbuf to output to + * @addr: Buffer to print + * @nr: Number of bytes to print + * @separator: Optional separator character between each byte */ -char *bin2hex(char *dst, const void *src, size_t count) +void prt_hex_bytes(struct printbuf *out, const void *buf, unsigned len, + unsigned groupsize, unsigned separator) { - const unsigned char *_src = src; + const u8 *ptr = buf; + unsigned i; - while (count--) - dst = hex_byte_pack(dst, *_src++); - return dst; + if (!groupsize) + groupsize = 1; + + for (i = 0; i < len ; ++i) { + if (i && separator && !(i % groupsize)) + __prt_char(out, separator); + prt_hex_byte(out, ptr[i]); + } } -EXPORT_SYMBOL(bin2hex); +EXPORT_SYMBOL(prt_hex_bytes); /** - * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory + * prt_hex_line - convert a blob of data to "hex ASCII" in memory + * @out: printbuf to output to * @buf: data blob to dump * @len: number of bytes in the @buf * @rowsize: number of bytes to print per line; must be 16 or 32 * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) - * @linebuf: where to put the converted data - * @linebuflen: total size of @linebuf, including space for terminating NUL * @ascii: include ASCII after the hex output * - * hex_dump_to_buffer() works on one "line" of output at a time, i.e., + * prt_hex_line() works on one "line" of output at a time, i.e., * 16 or 32 bytes of input data converted to hex + ASCII output. * * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data @@ -117,22 +126,13 @@ EXPORT_SYMBOL(bin2hex); * * example output buffer: * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO - * - * Return: - * The amount of bytes placed in the buffer without terminating NUL. If the - * output was truncated, then the return value is the number of bytes - * (excluding the terminating NUL) which would have been written to the final - * string if enough space had been available. */ -int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize, - char *linebuf, size_t linebuflen, bool ascii) +void prt_hex_line(struct printbuf *out, const void *buf, size_t len, + int rowsize, int groupsize, bool ascii) { + unsigned saved_pos = out->pos; const u8 *ptr = buf; - int ngroups; - u8 ch; - int j, lx = 0; - int ascii_column; - int ret; + int i, ngroups; if (rowsize != 16 && rowsize != 32) rowsize = 16; @@ -145,84 +145,127 @@ int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize, groupsize = 1; ngroups = len / groupsize; - ascii_column = rowsize * 2 + rowsize / groupsize + 1; - - if (!linebuflen) - goto overflow1; if (!len) - goto nil; - - if (groupsize == 8) { - const u64 *ptr8 = buf; - - for (j = 0; j < ngroups; j++) { - ret = snprintf(linebuf + lx, linebuflen - lx, - "%s%16.16llx", j ? " " : "", - get_unaligned(ptr8 + j)); - if (ret >= linebuflen - lx) - goto overflow1; - lx += ret; - } - } else if (groupsize == 4) { - const u32 *ptr4 = buf; - - for (j = 0; j < ngroups; j++) { - ret = snprintf(linebuf + lx, linebuflen - lx, - "%s%8.8x", j ? " " : "", - get_unaligned(ptr4 + j)); - if (ret >= linebuflen - lx) - goto overflow1; - lx += ret; - } - } else if (groupsize == 2) { - const u16 *ptr2 = buf; - - for (j = 0; j < ngroups; j++) { - ret = snprintf(linebuf + lx, linebuflen - lx, - "%s%4.4x", j ? " " : "", - get_unaligned(ptr2 + j)); - if (ret >= linebuflen - lx) - goto overflow1; - lx += ret; - } - } else { - for (j = 0; j < len; j++) { - if (linebuflen < lx + 2) - goto overflow2; - ch = ptr[j]; - linebuf[lx++] = hex_asc_hi(ch); - if (linebuflen < lx + 2) - goto overflow2; - linebuf[lx++] = hex_asc_lo(ch); - if (linebuflen < lx + 2) - goto overflow2; - linebuf[lx++] = ' '; + return; + + prt_hex_bytes(out, ptr, len, groupsize, ' '); + + if (ascii) { + unsigned ascii_column = rowsize * 2 + rowsize / groupsize + 1; + + prt_chars(out, ' ', max_t(int, 0, ascii_column - (out->pos - saved_pos))); + + for (i = 0; i < len; i++) { + u8 ch = ptr[i]; + prt_char(out, isascii(ch) && isprint(ch) ? ch : '.'); } - if (j) - lx--; } - if (!ascii) - goto nil; +} +EXPORT_SYMBOL(prt_hex_line); - while (lx < ascii_column) { - if (linebuflen < lx + 2) - goto overflow2; - linebuf[lx++] = ' '; - } - for (j = 0; j < len; j++) { - if (linebuflen < lx + 2) - goto overflow2; - ch = ptr[j]; - linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.'; +/** + * prt_hex_dump - print multiline formatted hex dump + * @out: printbuf to output to + * @buf: data blob to dump + * @len: number of bytes in the @buf + * @prefix_str: string to prefix each line with; + * caller supplies trailing spaces for alignment if desired + * @prefix_type: controls whether prefix of an offset, address, or none + * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) + * @rowsize: number of bytes to print per line; must be 16 or 32 + * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) + * @ascii: include ASCII after the hex output + * + * Function is an analogue of print_hex_dump() and thus has similar interface. + * + * linebuf size is maximal length for one line. + * 32 * 3 - maximum bytes per line, each printed into 2 chars + 1 for + * separating space + * 2 - spaces separating hex dump and ascii representation + * 32 - ascii representation + * 1 - terminating '\0' + */ +void prt_hex_dump(struct printbuf *out, const void *buf, size_t len, + const char *prefix_str, int prefix_type, + unsigned rowsize, unsigned groupsize, bool ascii) +{ + const u8 *ptr = buf; + size_t i; + + if (rowsize != 16 && rowsize != 32) + rowsize = 16; + + for (i = 0; i < len; i += rowsize) { + prt_str(out, prefix_str); + + switch (prefix_type) { + case DUMP_PREFIX_ADDRESS: + prt_printf(out, "%p: ", ptr + i); + break; + case DUMP_PREFIX_OFFSET: + prt_printf(out, "%.8zx: ", i); + break; + } + + prt_hex_line(out, ptr + i, min_t(size_t, len - i, rowsize), + rowsize, groupsize, ascii); + prt_char(out, '\n'); } -nil: - linebuf[lx] = '\0'; - return lx; -overflow2: - linebuf[lx++] = '\0'; -overflow1: - return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1; +} + +/** + * bin2hex - convert binary data to an ascii hexadecimal string + * @dst: ascii hexadecimal result + * @src: binary data + * @count: binary data length + */ +char *bin2hex(char *dst, const void *src, size_t count) +{ + struct printbuf out = PRINTBUF_EXTERN(dst, count * 4); + + prt_hex_bytes(&out, src, count, 0, 0); + return dst + out.pos; +} +EXPORT_SYMBOL(bin2hex); + +/** + * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory + * @buf: data blob to dump + * @len: number of bytes in the @buf + * @rowsize: number of bytes to print per line; must be 16 or 32 + * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) + * @linebuf: where to put the converted data + * @linebuflen: total size of @linebuf, including space for terminating NUL + * @ascii: include ASCII after the hex output + * + * hex_dump_to_buffer() works on one "line" of output at a time, i.e., + * 16 or 32 bytes of input data converted to hex + ASCII output. + * + * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data + * to a hex + ASCII dump at the supplied memory location. + * The converted output is always NUL-terminated. + * + * E.g.: + * hex_dump_to_buffer(frame->data, frame->len, 16, 1, + * linebuf, sizeof(linebuf), true); + * + * example output buffer: + * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO + * + * Return: + * The amount of bytes placed in the buffer without terminating NUL. If the + * output was truncated, then the return value is the number of bytes + * (excluding the terminating NUL) which would have been written to the final + * string if enough space had been available. + */ +int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize, + char *linebuf, size_t linebuflen, bool ascii) +{ + struct printbuf out = PRINTBUF_EXTERN(linebuf, linebuflen); + + prt_hex_line(&out, buf, len, rowsize, groupsize, ascii); + return out.pos; } EXPORT_SYMBOL(hex_dump_to_buffer); @@ -262,6 +305,11 @@ void print_hex_dump(const char *level, const char *prefix_str, int prefix_type, int rowsize, int groupsize, const void *buf, size_t len, bool ascii) { + /* + * XXX: this code does the exact same thing as prt_hex_dump(): we should + * be able to call that and printk() the result, except printk is + * restricted to 1024 bytes of output per call + */ const u8 *ptr = buf; int i, linelen, remaining = len; unsigned char linebuf[32 * 3 + 2 + 32 + 1]; diff --git a/lib/test_hexdump.c b/lib/test_hexdump.c index 5144899d3c..f9e97879dc 100644 --- a/lib/test_hexdump.c +++ b/lib/test_hexdump.c @@ -25,36 +25,19 @@ static const char * const test_data_1[] __initconst = { "4c", "d1", "19", "99", "43", "b1", "af", "0c", }; -static const char * const test_data_2_le[] __initconst = { - "32be", "7bdb", "180a", "b293", - "ba70", "24c4", "837d", "9b34", - "9ca6", "ad31", "0f9c", "e9ac", - "d14c", "9919", "b143", "0caf", -}; - -static const char * const test_data_2_be[] __initconst = { +static const char * const test_data_2[] __initconst = { "be32", "db7b", "0a18", "93b2", "70ba", "c424", "7d83", "349b", "a69c", "31ad", "9c0f", "ace9", "4cd1", "1999", "43b1", "af0c", }; -static const char * const test_data_4_le[] __initconst = { - "7bdb32be", "b293180a", "24c4ba70", "9b34837d", - "ad319ca6", "e9ac0f9c", "9919d14c", "0cafb143", -}; - -static const char * const test_data_4_be[] __initconst = { +static const char * const test_data_4[] __initconst = { "be32db7b", "0a1893b2", "70bac424", "7d83349b", "a69c31ad", "9c0face9", "4cd11999", "43b1af0c", }; -static const char * const test_data_8_le[] __initconst = { - "b293180a7bdb32be", "9b34837d24c4ba70", - "e9ac0f9cad319ca6", "0cafb1439919d14c", -}; - -static const char * const test_data_8_be[] __initconst = { +static const char * const test_data_8[] __initconst = { "be32db7b0a1893b2", "70bac4247d83349b", "a69c31ad9c0face9", "4cd1199943b1af0c", }; @@ -73,7 +56,6 @@ static void __init test_hexdump_prepare_test(size_t len, int rowsize, size_t l = len; int gs = groupsize, rs = rowsize; unsigned int i; - const bool is_be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN); if (rs != 16 && rs != 32) rs = 16; @@ -85,11 +67,11 @@ static void __init test_hexdump_prepare_test(size_t len, int rowsize, gs = 1; if (gs == 8) - result = is_be ? test_data_8_be : test_data_8_le; + result = test_data_8; else if (gs == 4) - result = is_be ? test_data_4_be : test_data_4_le; + result = test_data_4; else if (gs == 2) - result = is_be ? test_data_2_be : test_data_2_le; + result = test_data_2; else result = test_data_1; -- 2.36.0