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 ) ;
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 ,
* linebuf , sizeof ( linebuf ) , 1 ) ;
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 ,
" %16.16llx " , ( unsigned long long ) * ( ptr8 + j ) ) ;
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 ,
" %8.8x " , * ( ptr4 + j ) ) ;
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 ,
" %4.4x " , * ( ptr2 + j ) ) ;
ascii_column = 5 * ngroups + 2 ;
break ;
}
default :
for ( j = 0 ; ( j < rowsize ) & & ( j < len ) & & ( lx + 4 ) < linebuflen ;
j + + ) {
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
}
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 + + ] = ' ' ;
2007-06-09 00:47:04 +04:00
for ( j = 0 ; ( j < rowsize ) & & ( j < len ) & & ( lx + 2 ) < linebuflen ; j + + )
2007-11-29 03:21:46 +03:00
linebuf [ lx + + ] = ( isascii ( ptr [ j ] ) & & isprint ( ptr [ j ] ) ) ? ptr [ j ]
: ' . ' ;
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 ) ;
/**
* 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 ,
* 16 , 1 , frame - > data , frame - > len , 1 ) ;
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 ,
int rowsize , int groupsize ,
2007-08-08 00:43:14 +04:00
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 ;
2007-06-09 00:47:04 +04:00
unsigned char linebuf [ 200 ] ;
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 ;
hex_dump_to_buffer ( ptr + i , linelen , rowsize , groupsize ,
linebuf , sizeof ( linebuf ) , ascii ) ;
2007-05-11 09:22:39 +04:00
switch ( prefix_type ) {
case DUMP_PREFIX_ADDRESS :
2007-06-09 00:47:04 +04:00
printk ( " %s%s%*p: %s \n " , level , prefix_str ,
2007-05-11 09:22:39 +04:00
( int ) ( 2 * sizeof ( void * ) ) , ptr + i , linebuf ) ;
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 ,
2007-08-11 00:01:07 +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 ,
buf , len , 1 ) ;
}
EXPORT_SYMBOL ( print_hex_dump_bytes ) ;