2007-05-11 09:22:39 +04:00
/*
* lib / hexdump . c
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation . See README and COPYING for
* more details .
*/
# include <linux/types.h>
# include <linux/ctype.h>
# include <linux/kernel.h>
# include <linux/module.h>
2008-05-15 03:05:49 +04:00
const char hex_asc [ ] = " 0123456789abcdef " ;
EXPORT_SYMBOL ( hex_asc ) ;
2010-05-25 01:33:23 +04:00
/**
* hex_to_bin - convert a hex digit to its real value
* @ ch : ascii character represents hex digit
*
* hex_to_bin ( ) converts one hex digit to its actual value or - 1 in case of bad
* input .
*/
int hex_to_bin ( char ch )
{
if ( ( ch > = ' 0 ' ) & & ( ch < = ' 9 ' ) )
return ch - ' 0 ' ;
ch = tolower ( ch ) ;
if ( ( ch > = ' a ' ) & & ( ch < = ' f ' ) )
return ch - ' a ' + 10 ;
return - 1 ;
}
EXPORT_SYMBOL ( hex_to_bin ) ;
2010-11-24 01:50:31 +03:00
/**
* hex2bin - convert an ascii hexadecimal string to its binary representation
* @ dst : binary result
* @ src : ascii hexadecimal string
* @ count : result length
*/
void hex2bin ( u8 * dst , const char * src , size_t count )
{
while ( count - - ) {
* dst = hex_to_bin ( * src + + ) < < 4 ;
* dst + = hex_to_bin ( * src + + ) ;
dst + + ;
}
}
EXPORT_SYMBOL ( hex2bin ) ;
2007-05-11 09:22:39 +04:00
/**
* 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
2007-06-09 00:47:04 +04:00
* @ 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 )
2007-05-11 09:22:39 +04:00
* @ linebuf : where to put the converted data
* @ linebuflen : total size of @ linebuf , including space for terminating NUL
2007-06-09 00:47:04 +04:00
* @ ascii : include ASCII after the hex output
2007-05-11 09:22:39 +04:00
*
* hex_dump_to_buffer ( ) works on one " line " of output at a time , i . e . ,
2007-06-09 00:47:04 +04:00
* 16 or 32 bytes of input data converted to hex + ASCII output .
2007-05-11 09:22:39 +04:00
*
* 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 . :
2007-06-09 00:47:04 +04:00
* hex_dump_to_buffer ( frame - > data , frame - > len , 16 , 1 ,
2010-05-25 01:33:22 +04:00
* linebuf , sizeof ( linebuf ) , true ) ;
2007-05-11 09:22:39 +04:00
*
* example output buffer :
2007-06-09 00:47:04 +04:00
* 40 41 42 43 44 45 46 47 48 49 4 a 4 b 4 c 4 d 4 e 4f @ ABCDEFGHIJKLMNO
2007-05-11 09:22:39 +04:00
*/
2007-06-09 00:47:04 +04:00
void hex_dump_to_buffer ( const void * buf , size_t len , int rowsize ,
int groupsize , char * linebuf , size_t linebuflen ,
bool ascii )
2007-05-11 09:22:39 +04:00
{
const u8 * ptr = buf ;
u8 ch ;
int j , lx = 0 ;
2007-06-09 00:47:04 +04:00
int ascii_column ;
2007-05-11 09:22:39 +04:00
2007-06-09 00:47:04 +04:00
if ( rowsize ! = 16 & & rowsize ! = 32 )
rowsize = 16 ;
if ( ! len )
goto nil ;
if ( len > rowsize ) /* limit to one line at a time */
len = rowsize ;
if ( ( len % groupsize ) ! = 0 ) /* no mixed size output */
groupsize = 1 ;
switch ( groupsize ) {
case 8 : {
const u64 * ptr8 = buf ;
int ngroups = len / groupsize ;
for ( j = 0 ; j < ngroups ; j + + )
lx + = scnprintf ( linebuf + lx , linebuflen - lx ,
2010-05-25 01:33:22 +04:00
" %s%16.16llx " , j ? " " : " " ,
( unsigned long long ) * ( ptr8 + j ) ) ;
2007-06-09 00:47:04 +04:00
ascii_column = 17 * ngroups + 2 ;
break ;
}
case 4 : {
const u32 * ptr4 = buf ;
int ngroups = len / groupsize ;
for ( j = 0 ; j < ngroups ; j + + )
lx + = scnprintf ( linebuf + lx , linebuflen - lx ,
2010-05-25 01:33:22 +04:00
" %s%8.8x " , j ? " " : " " , * ( ptr4 + j ) ) ;
2007-06-09 00:47:04 +04:00
ascii_column = 9 * ngroups + 2 ;
break ;
}
case 2 : {
const u16 * ptr2 = buf ;
int ngroups = len / groupsize ;
for ( j = 0 ; j < ngroups ; j + + )
lx + = scnprintf ( linebuf + lx , linebuflen - lx ,
2010-05-25 01:33:22 +04:00
" %s%4.4x " , j ? " " : " " , * ( ptr2 + j ) ) ;
2007-06-09 00:47:04 +04:00
ascii_column = 5 * ngroups + 2 ;
break ;
}
default :
hexdump: remove the trailing space
For example:
hex_dump_to_buffer("AB", 2, 16, 1, buf, 100, 0);
pr_info("[%s]\n", buf);
I'd expect the output to be "[41 42]", but actually it's "[41 42 ]"
This patch also makes the required buf to be minimum. To print the hex
format of "AB", a buf with size 6 should be sufficient, but
hex_dump_to_buffer() required at least 8.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Acked-by: Randy Dunlap <randy.dunlap@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-06-17 02:33:45 +04:00
for ( j = 0 ; ( j < len ) & & ( lx + 3 ) < = linebuflen ; j + + ) {
2007-06-09 00:47:04 +04:00
ch = ptr [ j ] ;
2008-05-15 03:05:49 +04:00
linebuf [ lx + + ] = hex_asc_hi ( ch ) ;
linebuf [ lx + + ] = hex_asc_lo ( ch ) ;
2007-05-11 09:22:39 +04:00
linebuf [ lx + + ] = ' ' ;
2007-06-09 00:47:04 +04:00
}
hexdump: remove the trailing space
For example:
hex_dump_to_buffer("AB", 2, 16, 1, buf, 100, 0);
pr_info("[%s]\n", buf);
I'd expect the output to be "[41 42]", but actually it's "[41 42 ]"
This patch also makes the required buf to be minimum. To print the hex
format of "AB", a buf with size 6 should be sufficient, but
hex_dump_to_buffer() required at least 8.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Acked-by: Randy Dunlap <randy.dunlap@oracle.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-06-17 02:33:45 +04:00
if ( j )
lx - - ;
2007-06-09 00:47:04 +04:00
ascii_column = 3 * rowsize + 2 ;
break ;
2007-05-11 09:22:39 +04:00
}
2007-06-09 00:47:04 +04:00
if ( ! ascii )
goto nil ;
while ( lx < ( linebuflen - 1 ) & & lx < ( ascii_column - 1 ) )
2007-05-11 09:22:39 +04:00
linebuf [ lx + + ] = ' ' ;
2010-05-25 01:33:22 +04:00
for ( j = 0 ; ( j < len ) & & ( lx + 2 ) < linebuflen ; j + + ) {
ch = ptr [ j ] ;
linebuf [ lx + + ] = ( isascii ( ch ) & & isprint ( ch ) ) ? ch : ' . ' ;
}
2007-06-09 00:47:04 +04:00
nil :
2007-05-11 09:22:39 +04:00
linebuf [ lx + + ] = ' \0 ' ;
}
EXPORT_SYMBOL ( hex_dump_to_buffer ) ;
2011-01-13 03:59:47 +03:00
# ifdef CONFIG_PRINTK
2007-05-11 09:22:39 +04:00
/**
* print_hex_dump - print a text hex dump to syslog for a binary blob of data
* @ level : kernel log level ( e . g . KERN_DEBUG )
2007-06-09 00:47:04 +04:00
* @ prefix_str : string to prefix each line with ;
* caller supplies trailing spaces for alignment if desired
2007-05-11 09:22:39 +04:00
* @ prefix_type : controls whether prefix of an offset , address , or none
* is printed ( % DUMP_PREFIX_OFFSET , % DUMP_PREFIX_ADDRESS , % DUMP_PREFIX_NONE )
2007-06-09 00:47:04 +04:00
* @ 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 )
2007-05-11 09:22:39 +04:00
* @ buf : data blob to dump
* @ len : number of bytes in the @ buf
2007-06-09 00:47:04 +04:00
* @ ascii : include ASCII after the hex output
2007-05-11 09:22:39 +04:00
*
* 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 .
*
2007-06-09 00:47:04 +04:00
* print_hex_dump ( ) works on one " line " of output at a time , i . e . ,
* 16 or 32 bytes of input data converted to hex + ASCII output .
* print_hex_dump ( ) iterates over the entire input @ buf , breaking it into
* " line size " chunks to format and print .
*
2007-05-11 09:22:39 +04:00
* E . g . :
2007-06-09 00:47:04 +04:00
* print_hex_dump ( KERN_DEBUG , " raw data: " , DUMP_PREFIX_ADDRESS ,
2010-05-25 01:33:22 +04:00
* 16 , 1 , frame - > data , frame - > len , true ) ;
2007-05-11 09:22:39 +04:00
*
2007-06-09 00:47:04 +04:00
* Example output using % DUMP_PREFIX_OFFSET and 1 - byte mode :
* 000 9 ab42 : 40 41 42 43 44 45 46 47 48 49 4 a 4 b 4 c 4 d 4 e 4f @ ABCDEFGHIJKLMNO
* Example output using % DUMP_PREFIX_ADDRESS and 4 - byte mode :
* ffffffff88089af0 : 73727170 77767574 7 b7a7978 7f 7e7 d7c pqrstuvwxyz { | } ~ .
2007-05-11 09:22:39 +04:00
*/
2007-06-09 00:47:04 +04:00
void print_hex_dump ( const char * level , const char * prefix_str , int prefix_type ,
2010-05-25 01:33:22 +04:00
int rowsize , int groupsize ,
const void * buf , size_t len , bool ascii )
2007-05-11 09:22:39 +04:00
{
2007-08-08 00:43:14 +04:00
const u8 * ptr = buf ;
2007-05-11 09:22:39 +04:00
int i , linelen , remaining = len ;
2010-05-25 01:33:22 +04:00
unsigned char linebuf [ 32 * 3 + 2 + 32 + 1 ] ;
2007-05-11 09:22:39 +04:00
2007-06-09 00:47:04 +04:00
if ( rowsize ! = 16 & & rowsize ! = 32 )
rowsize = 16 ;
for ( i = 0 ; i < len ; i + = rowsize ) {
linelen = min ( remaining , rowsize ) ;
remaining - = rowsize ;
2010-05-25 01:33:22 +04:00
2007-06-09 00:47:04 +04:00
hex_dump_to_buffer ( ptr + i , linelen , rowsize , groupsize ,
2010-05-25 01:33:22 +04:00
linebuf , sizeof ( linebuf ) , ascii ) ;
2007-05-11 09:22:39 +04:00
switch ( prefix_type ) {
case DUMP_PREFIX_ADDRESS :
2010-05-25 01:33:22 +04:00
printk ( " %s%s%p: %s \n " ,
level , prefix_str , ptr + i , linebuf ) ;
2007-05-11 09:22:39 +04:00
break ;
case DUMP_PREFIX_OFFSET :
2007-06-09 00:47:04 +04:00
printk ( " %s%s%.8x: %s \n " , level , prefix_str , i , linebuf ) ;
2007-05-11 09:22:39 +04:00
break ;
default :
2007-06-09 00:47:04 +04:00
printk ( " %s%s%s \n " , level , prefix_str , linebuf ) ;
2007-05-11 09:22:39 +04:00
break ;
}
}
}
EXPORT_SYMBOL ( print_hex_dump ) ;
2007-06-09 00:47:04 +04:00
/**
* print_hex_dump_bytes - shorthand form of print_hex_dump ( ) with default params
* @ 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 )
* @ buf : data blob to dump
* @ len : number of bytes in the @ buf
*
* Calls print_hex_dump ( ) , with log level of KERN_DEBUG ,
* rowsize of 16 , groupsize of 1 , and ASCII output included .
*/
void print_hex_dump_bytes ( const char * prefix_str , int prefix_type ,
2010-05-25 01:33:22 +04:00
const void * buf , size_t len )
2007-06-09 00:47:04 +04:00
{
print_hex_dump ( KERN_DEBUG , prefix_str , prefix_type , 16 , 1 ,
2010-05-25 01:33:22 +04:00
buf , len , true ) ;
2007-06-09 00:47:04 +04:00
}
EXPORT_SYMBOL ( print_hex_dump_bytes ) ;
2011-01-13 03:59:47 +03:00
# endif