Message ID | 20190410031720.11067-3-alastair@au1.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Hexdump enhancements | expand |
On Wed, 2019-04-10 at 13:17 +1000, Alastair D'Silva wrote: > From: Alastair D'Silva <alastair@d-silva.org> > > Some buffers may only be partially filled with useful data, while the > rest > is padded (typically with 0x00 or 0xff). > This patch introduces flags which allow lines of padding bytes to be > suppressed, making the output easier to interpret: > HEXDUMP_SUPPRESS_0X00, > HEXDUMP_SUPPRESS_0XFF > > The first and last lines are not suppressed by default, so the > function > always outputs something. This behaviour can be further controlled > with > the HEXDUMP_SUPPRESS_FIRST & HEXDUMP_SUPPRESS_LAST flags. > > An inline wrapper function is provided for backwards compatibility > with > existing code, which maintains the original behaviour. > > Signed-off-by: Alastair D'Silva <alastair@d-silva.org> > --- > <snip> > diff --git a/lib/hexdump.c b/lib/hexdump.c > index b8a164814744..2f3bafb55a44 100644 > --- a/lib/hexdump.c > +++ b/lib/hexdump.c > @@ -209,8 +209,21 @@ int hex_dump_to_buffer(const void *buf, size_t > len, int rowsize, int groupsize, > EXPORT_SYMBOL(hex_dump_to_buffer); > > #ifdef CONFIG_PRINTK > + > +static bool buf_is_all(const u8 *buf, size_t len, u8 val) > +{ > + size_t i; > + > + for (i = 0; i < len; i++) { > + if (buf[i] != val) > + return false; > + } > + > + return true; > +} > + > /** > - * print_hex_dump - print a text hex dump to syslog for a binary > blob of data > + * print_hex_dump_ext: dump a binary blob of data to syslog in > hexadecimal > * @level: kernel log level (e.g. KERN_DEBUG) > * @prefix_str: string to prefix each line with; > * caller supplies trailing spaces for alignment if desired > @@ -221,42 +234,73 @@ EXPORT_SYMBOL(hex_dump_to_buffer); > * @buf: data blob to dump > * @len: number of bytes in the @buf > * @ascii: include ASCII after the hex output This line should have been removed. I'll address it in V2. > + * @flags: A bitwise OR of the following flags: > + * HEXDUMP_ASCII: include ASCII after the hex output > + * HEXDUMP_SUPPRESS_0X00: suppress lines that are all 0x00 > + * (other than first or last) > + * HEXDUMP_SUPPRESS_0XFF: suppress lines that are all 0xff > + * (other than first or last) > + * HEXDUMP_SUPPRESS_FIRST: allows the first line to be > suppressed > + * HEXDUMP_SUPPRESS_LAST: allows the last line to be suppressed > + * If the first and last line may be > suppressed, > + * an empty buffer will not produce any > output > * > * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII > dump > * to the kernel log at the specified kernel log level, with an > optional > * leading prefix. > * > - * print_hex_dump() works on one "line" of output at a time, i.e., > + * print_hex_dump_ext() works on one "line" of output at a time, > i.e., > * 16, 32 or 64 bytes of input data converted to hex + ASCII output. > - * print_hex_dump() iterates over the entire input @buf, breaking it > into > + * print_hex_dump_ext() iterates over the entire input @buf, > breaking it into > * "line size" chunks to format and print. > * > * E.g.: > - * print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_ADDRESS, > - * 16, 1, frame->data, frame->len, true); > + * print_hex_dump_ext(KERN_DEBUG, "raw data: ", > DUMP_PREFIX_ADDRESS, > + * 16, 1, frame->data, frame->len, HEXDUMP_ASCII); > * > * Example output using %DUMP_PREFIX_OFFSET and 1-byte mode: > * 0009ab42: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e > 4f @ABCDEFGHIJKLMNO > * Example output using %DUMP_PREFIX_ADDRESS and 4-byte mode: > * ffffffff88089af0: 73727170 77767574 7b7a7978 > 7f7e7d7c pqrstuvwxyz{|}~. > */
On Wed 2019-04-10 13:17:18, Alastair D'Silva wrote: > From: Alastair D'Silva <alastair@d-silva.org> > > Some buffers may only be partially filled with useful data, while the rest > is padded (typically with 0x00 or 0xff). > > This patch introduces flags which allow lines of padding bytes to be > suppressed, making the output easier to interpret: HEXDUMP_SUPPRESS_0X00, > HEXDUMP_SUPPRESS_0XFF > > The first and last lines are not suppressed by default, so the function > always outputs something. This behaviour can be further controlled with > the HEXDUMP_SUPPRESS_FIRST & HEXDUMP_SUPPRESS_LAST flags. > > An inline wrapper function is provided for backwards compatibility with > existing code, which maintains the original behaviour. > > diff --git a/lib/hexdump.c b/lib/hexdump.c > index b8a164814744..2f3bafb55a44 100644 > --- a/lib/hexdump.c > +++ b/lib/hexdump.c > +void print_hex_dump_ext(const char *level, const char *prefix_str, > + int prefix_type, int rowsize, int groupsize, > + const void *buf, size_t len, u64 flags) > { > const u8 *ptr = buf; > - int i, linelen, remaining = len; > + int i, remaining = len; > unsigned char linebuf[64 * 3 + 2 + 64 + 1]; > + bool first_line = true; > > if (rowsize != 16 && rowsize != 32 && rowsize != 64) > rowsize = 16; > > for (i = 0; i < len; i += rowsize) { > - linelen = min(remaining, rowsize); > + bool skip = false; > + int linelen = min(remaining, rowsize); > + > remaining -= rowsize; > > + if (flags & HEXDUMP_SUPPRESS_0X00) > + skip = buf_is_all(ptr + i, linelen, 0x00); > + > + if (!skip && (flags & HEXDUMP_SUPPRESS_0XFF)) > + skip = buf_is_all(ptr + i, linelen, 0xff); > + > + if (first_line && !(flags & HEXDUMP_SUPPRESS_FIRST)) > + skip = false; > + > + if (remaining <= 0 && !(flags & HEXDUMP_SUPPRESS_LAST)) > + skip = false; > + > + if (skip) > + continue; IMHO, quietly skipping lines could cause a lot of confusion, espcially when the address is not printed. I wonder how it would look like when we print something like: --- skipped XX lines full of 0x00 --- Then we might even remove the SUPPRESS_FIRST, SUPPRESS_LAST and the ambiguous QUIET flags. > + > + first_line = false; This should be above the if (skip). > + > hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize, > - linebuf, sizeof(linebuf), ascii); > + linebuf, sizeof(linebuf), > + flags & HEXDUMP_ASCII); > > switch (prefix_type) { > case DUMP_PREFIX_ADDRESS: > @@ -272,7 +316,7 @@ void print_hex_dump(const char *level, const char *prefix_str, int prefix_type, > } > } > } > -EXPORT_SYMBOL(print_hex_dump); > +EXPORT_SYMBOL(print_hex_dump_ext); We should still export even the original function that is still used everywhere. Best Regards, Petr
> -----Original Message----- > From: Petr Mladek <pmladek@suse.com> > Sent: Saturday, 13 April 2019 12:04 AM > To: Alastair D'Silva <alastair@au1.ibm.com> > Cc: alastair@d-silva.org; Jani Nikula <jani.nikula@linux.intel.com>; Joonas > Lahtinen <joonas.lahtinen@linux.intel.com>; Rodrigo Vivi > <rodrigo.vivi@intel.com>; David Airlie <airlied@linux.ie>; Daniel Vetter > <daniel@ffwll.ch>; Karsten Keil <isdn@linux-pingi.de>; Jassi Brar > <jassisinghbrar@gmail.com>; Tom Lendacky <thomas.lendacky@amd.com>; > David S. Miller <davem@davemloft.net>; Jose Abreu > <Jose.Abreu@synopsys.com>; Kalle Valo <kvalo@codeaurora.org>; > Stanislaw Gruszka <sgruszka@redhat.com>; Benson Leung > <bleung@chromium.org>; Enric Balletbo i Serra > <enric.balletbo@collabora.com>; James E.J. Bottomley > <jejb@linux.ibm.com>; Martin K. Petersen <martin.petersen@oracle.com>; > Greg Kroah-Hartman <gregkh@linuxfoundation.org>; Alexander Viro > <viro@zeniv.linux.org.uk>; Sergey Senozhatsky > <sergey.senozhatsky@gmail.com>; Steven Rostedt <rostedt@goodmis.org>; > Andrew Morton <akpm@linux-foundation.org>; intel- > gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org; linux- > kernel@vger.kernel.org; netdev@vger.kernel.org; > ath10k@lists.infradead.org; linux-wireless@vger.kernel.org; linux- > scsi@vger.kernel.org; linux-fbdev@vger.kernel.org; > devel@driverdev.osuosl.org; linux-fsdevel@vger.kernel.org > Subject: Re: [PATCH 2/4] lib/hexdump.c: Optionally suppress lines of filler > bytes > > On Wed 2019-04-10 13:17:18, Alastair D'Silva wrote: > > From: Alastair D'Silva <alastair@d-silva.org> > > > > Some buffers may only be partially filled with useful data, while the > > rest is padded (typically with 0x00 or 0xff). > > > > This patch introduces flags which allow lines of padding bytes to be > > suppressed, making the output easier to interpret: > > HEXDUMP_SUPPRESS_0X00, HEXDUMP_SUPPRESS_0XFF > > > > The first and last lines are not suppressed by default, so the > > function always outputs something. This behaviour can be further > > controlled with the HEXDUMP_SUPPRESS_FIRST & > HEXDUMP_SUPPRESS_LAST flags. > > > > An inline wrapper function is provided for backwards compatibility > > with existing code, which maintains the original behaviour. > > > > > diff --git a/lib/hexdump.c b/lib/hexdump.c index > > b8a164814744..2f3bafb55a44 100644 > > --- a/lib/hexdump.c > > +++ b/lib/hexdump.c > > +void print_hex_dump_ext(const char *level, const char *prefix_str, > > + int prefix_type, int rowsize, int groupsize, > > + const void *buf, size_t len, u64 flags) > > { > > const u8 *ptr = buf; > > - int i, linelen, remaining = len; > > + int i, remaining = len; > > unsigned char linebuf[64 * 3 + 2 + 64 + 1]; > > + bool first_line = true; > > > > if (rowsize != 16 && rowsize != 32 && rowsize != 64) > > rowsize = 16; > > > > for (i = 0; i < len; i += rowsize) { > > - linelen = min(remaining, rowsize); > > + bool skip = false; > > + int linelen = min(remaining, rowsize); > > + > > remaining -= rowsize; > > > > + if (flags & HEXDUMP_SUPPRESS_0X00) > > + skip = buf_is_all(ptr + i, linelen, 0x00); > > + > > + if (!skip && (flags & HEXDUMP_SUPPRESS_0XFF)) > > + skip = buf_is_all(ptr + i, linelen, 0xff); > > + > > + if (first_line && !(flags & HEXDUMP_SUPPRESS_FIRST)) > > + skip = false; > > + > > + if (remaining <= 0 && !(flags & HEXDUMP_SUPPRESS_LAST)) > > + skip = false; > > + > > + if (skip) > > + continue; > > IMHO, quietly skipping lines could cause a lot of confusion, espcially when > the address is not printed. > It's up to the caller to decide how they want it displayed. > I wonder how it would look like when we print something like: > > --- skipped XX lines full of 0x00 --- This could be added as a later enhancement, with a new flag (eg. HEXDUMP_SUPPRESS_VERBOSE). > > Then we might even remove the SUPPRESS_FIRST, SUPPRESS_LAST and the > ambiguous QUIET flags. > > > + > > + first_line = false; > > This should be above the if (skip). > > > + > > hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize, > > - linebuf, sizeof(linebuf), ascii); > > + linebuf, sizeof(linebuf), > > + flags & HEXDUMP_ASCII); > > > > switch (prefix_type) { > > case DUMP_PREFIX_ADDRESS: > > @@ -272,7 +316,7 @@ void print_hex_dump(const char *level, const char > *prefix_str, int prefix_type, > > } > > } > > } > > -EXPORT_SYMBOL(print_hex_dump); > > +EXPORT_SYMBOL(print_hex_dump_ext); > > We should still export even the original function that is still used everywhere. It's replaced with an inline wrapper function, there's no need to export it.
On Sat 2019-04-13 09:28:03, Alastair D'Silva wrote: > > -----Original Message----- > > From: Petr Mladek <pmladek@suse.com> > > Sent: Saturday, 13 April 2019 12:04 AM > > To: Alastair D'Silva <alastair@au1.ibm.com> > > Cc: alastair@d-silva.org; Jani Nikula <jani.nikula@linux.intel.com>; > Joonas > > Lahtinen <joonas.lahtinen@linux.intel.com>; Rodrigo Vivi > > <rodrigo.vivi@intel.com>; David Airlie <airlied@linux.ie>; Daniel Vetter > > <daniel@ffwll.ch>; Karsten Keil <isdn@linux-pingi.de>; Jassi Brar > > <jassisinghbrar@gmail.com>; Tom Lendacky <thomas.lendacky@amd.com>; > > David S. Miller <davem@davemloft.net>; Jose Abreu > > <Jose.Abreu@synopsys.com>; Kalle Valo <kvalo@codeaurora.org>; > > Stanislaw Gruszka <sgruszka@redhat.com>; Benson Leung > > <bleung@chromium.org>; Enric Balletbo i Serra > > <enric.balletbo@collabora.com>; James E.J. Bottomley > > <jejb@linux.ibm.com>; Martin K. Petersen <martin.petersen@oracle.com>; > > Greg Kroah-Hartman <gregkh@linuxfoundation.org>; Alexander Viro > > <viro@zeniv.linux.org.uk>; Sergey Senozhatsky > > <sergey.senozhatsky@gmail.com>; Steven Rostedt <rostedt@goodmis.org>; > > Andrew Morton <akpm@linux-foundation.org>; intel- > > gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org; linux- > > kernel@vger.kernel.org; netdev@vger.kernel.org; > > ath10k@lists.infradead.org; linux-wireless@vger.kernel.org; linux- > > scsi@vger.kernel.org; linux-fbdev@vger.kernel.org; > > devel@driverdev.osuosl.org; linux-fsdevel@vger.kernel.org > > Subject: Re: [PATCH 2/4] lib/hexdump.c: Optionally suppress lines of > filler > > bytes > > > > On Wed 2019-04-10 13:17:18, Alastair D'Silva wrote: > > > From: Alastair D'Silva <alastair@d-silva.org> > > > > > > Some buffers may only be partially filled with useful data, while the > > > rest is padded (typically with 0x00 or 0xff). > > > > > > This patch introduces flags which allow lines of padding bytes to be > > > suppressed, making the output easier to interpret: > > > HEXDUMP_SUPPRESS_0X00, HEXDUMP_SUPPRESS_0XFF > > > > > > The first and last lines are not suppressed by default, so the > > > function always outputs something. This behaviour can be further > > > controlled with the HEXDUMP_SUPPRESS_FIRST & > > HEXDUMP_SUPPRESS_LAST flags. > > > > > > An inline wrapper function is provided for backwards compatibility > > > with existing code, which maintains the original behaviour. > > > > > > > > diff --git a/lib/hexdump.c b/lib/hexdump.c index > > > b8a164814744..2f3bafb55a44 100644 > > > --- a/lib/hexdump.c > > > +++ b/lib/hexdump.c > > > +void print_hex_dump_ext(const char *level, const char *prefix_str, > > > + int prefix_type, int rowsize, int groupsize, > > > + const void *buf, size_t len, u64 flags) > > > { > > > const u8 *ptr = buf; > > > - int i, linelen, remaining = len; > > > + int i, remaining = len; > > > unsigned char linebuf[64 * 3 + 2 + 64 + 1]; > > > + bool first_line = true; > > > > > > if (rowsize != 16 && rowsize != 32 && rowsize != 64) > > > rowsize = 16; > > > > > > for (i = 0; i < len; i += rowsize) { > > > - linelen = min(remaining, rowsize); > > > + bool skip = false; > > > + int linelen = min(remaining, rowsize); > > > + > > > remaining -= rowsize; > > > > > > + if (flags & HEXDUMP_SUPPRESS_0X00) > > > + skip = buf_is_all(ptr + i, linelen, 0x00); > > > + > > > + if (!skip && (flags & HEXDUMP_SUPPRESS_0XFF)) > > > + skip = buf_is_all(ptr + i, linelen, 0xff); > > > + > > > + if (first_line && !(flags & HEXDUMP_SUPPRESS_FIRST)) > > > + skip = false; > > > + > > > + if (remaining <= 0 && !(flags & HEXDUMP_SUPPRESS_LAST)) > > > + skip = false; > > > + > > > + if (skip) > > > + continue; > > > > IMHO, quietly skipping lines could cause a lot of confusion, espcially > when the address is not printed. > > > It's up to the caller to decide how they want it displayed. I wonder who would want to quietly skip some data values. Are you using it yourself? Could you please provide an example? I do not see why we would need to complicate the API and code by this. The behavior proposed by Tvrtko Ursulin makes much more sense. I mean https://lkml.kernel.org/r/929244ed-cc7f-b0f3-b5ac-50e798e83188@linux.intel.com > > I wonder how it would look like when we print something like: > > > > --- skipped XX lines full of 0x00 --- > > This could be added as a later enhancement, with a new flag (eg. > HEXDUMP_SUPPRESS_VERBOSE). Who will add this later? Frankly, this looks like a half baked feature that it good enough for you. If you want it upstream, it must behave reasonably and it must be worth it. Best Regards, Petr
> > > On Wed 2019-04-10 13:17:18, Alastair D'Silva wrote: > > > > From: Alastair D'Silva <alastair@d-silva.org> > > > > > > > > Some buffers may only be partially filled with useful data, while > > > > the rest is padded (typically with 0x00 or 0xff). > > > > > > > > This patch introduces flags which allow lines of padding bytes to > > > > be suppressed, making the output easier to interpret: > > > > HEXDUMP_SUPPRESS_0X00, HEXDUMP_SUPPRESS_0XFF > > > > > > > > The first and last lines are not suppressed by default, so the > > > > function always outputs something. This behaviour can be further > > > > controlled with the HEXDUMP_SUPPRESS_FIRST & > > > HEXDUMP_SUPPRESS_LAST flags. > > > > > > > > An inline wrapper function is provided for backwards compatibility > > > > with existing code, which maintains the original behaviour. > > > > > > > > > > > diff --git a/lib/hexdump.c b/lib/hexdump.c index > > > > b8a164814744..2f3bafb55a44 100644 > > > > --- a/lib/hexdump.c > > > > +++ b/lib/hexdump.c > > > > +void print_hex_dump_ext(const char *level, const char *prefix_str, > > > > + int prefix_type, int rowsize, int groupsize, > > > > + const void *buf, size_t len, u64 flags) > > > > { > > > > const u8 *ptr = buf; > > > > - int i, linelen, remaining = len; > > > > + int i, remaining = len; > > > > unsigned char linebuf[64 * 3 + 2 + 64 + 1]; > > > > + bool first_line = true; > > > > > > > > if (rowsize != 16 && rowsize != 32 && rowsize != 64) > > > > rowsize = 16; > > > > > > > > for (i = 0; i < len; i += rowsize) { > > > > - linelen = min(remaining, rowsize); > > > > + bool skip = false; > > > > + int linelen = min(remaining, rowsize); > > > > + > > > > remaining -= rowsize; > > > > > > > > + if (flags & HEXDUMP_SUPPRESS_0X00) > > > > + skip = buf_is_all(ptr + i, linelen, 0x00); > > > > + > > > > + if (!skip && (flags & HEXDUMP_SUPPRESS_0XFF)) > > > > + skip = buf_is_all(ptr + i, linelen, 0xff); > > > > + > > > > + if (first_line && !(flags & HEXDUMP_SUPPRESS_FIRST)) > > > > + skip = false; > > > > + > > > > + if (remaining <= 0 && !(flags & HEXDUMP_SUPPRESS_LAST)) > > > > + skip = false; > > > > + > > > > + if (skip) > > > > + continue; > > > > > > IMHO, quietly skipping lines could cause a lot of confusion, > > > espcially > > when the address is not printed. > > > > > It's up to the caller to decide how they want it displayed. > > I wonder who would want to quietly skip some data values. > Are you using it yourself? Could you please provide an example? Yes, but I don't have the content with me at the moment, so I can't share it. I'm dumping persistent memory labels, which are 64kB long, but only the first few hundred bytes are populated. > I do not see why we would need to complicate the API and code by this. > > The behavior proposed by Tvrtko Ursulin makes much more sense. I mean > https://lkml.kernel.org/r/929244ed-cc7f-b0f3-b5ac- > 50e798e83188@linux.intel.com I agree that is better, I'll add that to V2.
diff --git a/include/linux/printk.h b/include/linux/printk.h index d7c77ed1a4cb..c014e5573665 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -479,13 +479,26 @@ enum { DUMP_PREFIX_ADDRESS, DUMP_PREFIX_OFFSET }; + +#define HEXDUMP_ASCII (1 << 0) +#define HEXDUMP_SUPPRESS_0X00 (1 << 1) +#define HEXDUMP_SUPPRESS_0XFF (1 << 2) +#define HEXDUMP_SUPPRESS_FIRST (1 << 3) +#define HEXDUMP_SUPPRESS_LAST (1 << 4) + +#define HEXDUMP_QUIET (HEXDUMP_SUPPRESS_0X00 | \ + HEXDUMP_SUPPRESS_0XFF | \ + HEXDUMP_SUPPRESS_FIRST | \ + HEXDUMP_SUPPRESS_LAST) + extern int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize, char *linebuf, size_t linebuflen, bool ascii); + #ifdef CONFIG_PRINTK -extern 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); +extern void print_hex_dump_ext(const char *level, const char *prefix_str, + int prefix_type, int rowsize, int groupsize, + const void *buf, size_t len, u64 flags); #if defined(CONFIG_DYNAMIC_DEBUG) #define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ dynamic_hex_dump(prefix_str, prefix_type, 16, 1, buf, len, true) @@ -494,18 +507,29 @@ extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type, const void *buf, size_t len); #endif /* defined(CONFIG_DYNAMIC_DEBUG) */ #else -static inline 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) +static inline void print_hex_dump_ext(const char *level, const char *prefix_str, + int prefix_type, int rowsize, + int groupsize, const void *buf, + size_t len, u64 flags) { } static inline void print_hex_dump_bytes(const char *prefix_str, int prefix_type, const void *buf, size_t len) { } - #endif +static __always_inline 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) +{ + print_hex_dump_ext(level, prefix_str, prefix_type, rowsize, groupsize, + buf, len, ascii ? HEXDUMP_ASCII : 0); +} + + #if defined(CONFIG_DYNAMIC_DEBUG) #define print_hex_dump_debug(prefix_str, prefix_type, rowsize, \ groupsize, buf, len, ascii) \ diff --git a/lib/hexdump.c b/lib/hexdump.c index b8a164814744..2f3bafb55a44 100644 --- a/lib/hexdump.c +++ b/lib/hexdump.c @@ -209,8 +209,21 @@ int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize, EXPORT_SYMBOL(hex_dump_to_buffer); #ifdef CONFIG_PRINTK + +static bool buf_is_all(const u8 *buf, size_t len, u8 val) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (buf[i] != val) + return false; + } + + return true; +} + /** - * print_hex_dump - print a text hex dump to syslog for a binary blob of data + * print_hex_dump_ext: dump a binary blob of data to syslog in hexadecimal * @level: kernel log level (e.g. KERN_DEBUG) * @prefix_str: string to prefix each line with; * caller supplies trailing spaces for alignment if desired @@ -221,42 +234,73 @@ EXPORT_SYMBOL(hex_dump_to_buffer); * @buf: data blob to dump * @len: number of bytes in the @buf * @ascii: include ASCII after the hex output + * @flags: A bitwise OR of the following flags: + * HEXDUMP_ASCII: include ASCII after the hex output + * HEXDUMP_SUPPRESS_0X00: suppress lines that are all 0x00 + * (other than first or last) + * HEXDUMP_SUPPRESS_0XFF: suppress lines that are all 0xff + * (other than first or last) + * HEXDUMP_SUPPRESS_FIRST: allows the first line to be suppressed + * HEXDUMP_SUPPRESS_LAST: allows the last line to be suppressed + * If the first and last line may be suppressed, + * an empty buffer will not produce any output * * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump * to the kernel log at the specified kernel log level, with an optional * leading prefix. * - * print_hex_dump() works on one "line" of output at a time, i.e., + * print_hex_dump_ext() works on one "line" of output at a time, i.e., * 16, 32 or 64 bytes of input data converted to hex + ASCII output. - * print_hex_dump() iterates over the entire input @buf, breaking it into + * print_hex_dump_ext() iterates over the entire input @buf, breaking it into * "line size" chunks to format and print. * * E.g.: - * print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_ADDRESS, - * 16, 1, frame->data, frame->len, true); + * print_hex_dump_ext(KERN_DEBUG, "raw data: ", DUMP_PREFIX_ADDRESS, + * 16, 1, frame->data, frame->len, HEXDUMP_ASCII); * * Example output using %DUMP_PREFIX_OFFSET and 1-byte mode: * 0009ab42: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO * Example output using %DUMP_PREFIX_ADDRESS and 4-byte mode: * ffffffff88089af0: 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~. */ -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) +void print_hex_dump_ext(const char *level, const char *prefix_str, + int prefix_type, int rowsize, int groupsize, + const void *buf, size_t len, u64 flags) { const u8 *ptr = buf; - int i, linelen, remaining = len; + int i, remaining = len; unsigned char linebuf[64 * 3 + 2 + 64 + 1]; + bool first_line = true; if (rowsize != 16 && rowsize != 32 && rowsize != 64) rowsize = 16; for (i = 0; i < len; i += rowsize) { - linelen = min(remaining, rowsize); + bool skip = false; + int linelen = min(remaining, rowsize); + remaining -= rowsize; + if (flags & HEXDUMP_SUPPRESS_0X00) + skip = buf_is_all(ptr + i, linelen, 0x00); + + if (!skip && (flags & HEXDUMP_SUPPRESS_0XFF)) + skip = buf_is_all(ptr + i, linelen, 0xff); + + if (first_line && !(flags & HEXDUMP_SUPPRESS_FIRST)) + skip = false; + + if (remaining <= 0 && !(flags & HEXDUMP_SUPPRESS_LAST)) + skip = false; + + if (skip) + continue; + + first_line = false; + hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize, - linebuf, sizeof(linebuf), ascii); + linebuf, sizeof(linebuf), + flags & HEXDUMP_ASCII); switch (prefix_type) { case DUMP_PREFIX_ADDRESS: @@ -272,7 +316,7 @@ void print_hex_dump(const char *level, const char *prefix_str, int prefix_type, } } } -EXPORT_SYMBOL(print_hex_dump); +EXPORT_SYMBOL(print_hex_dump_ext); #if !defined(CONFIG_DYNAMIC_DEBUG) /** @@ -290,8 +334,8 @@ EXPORT_SYMBOL(print_hex_dump); void print_hex_dump_bytes(const char *prefix_str, int prefix_type, const void *buf, size_t len) { - print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, 16, 1, - buf, len, true); + print_hex_dump_ext(KERN_DEBUG, prefix_str, prefix_type, 16, 1, + buf, len, HEXDUMP_ASCII); } EXPORT_SYMBOL(print_hex_dump_bytes); #endif /* !defined(CONFIG_DYNAMIC_DEBUG) */