2015-02-13 02:02:21 +03:00
/*
* Test cases for lib / hexdump . c module .
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/random.h>
# include <linux/string.h>
static const unsigned char data_b [ ] = {
' \xbe ' , ' \x32 ' , ' \xdb ' , ' \x7b ' , ' \x0a ' , ' \x18 ' , ' \x93 ' , ' \xb2 ' , /* 00 - 07 */
' \x70 ' , ' \xba ' , ' \xc4 ' , ' \x24 ' , ' \x7d ' , ' \x83 ' , ' \x34 ' , ' \x9b ' , /* 08 - 0f */
' \xa6 ' , ' \x9c ' , ' \x31 ' , ' \xad ' , ' \x9c ' , ' \x0f ' , ' \xac ' , ' \xe9 ' , /* 10 - 17 */
' \x4c ' , ' \xd1 ' , ' \x19 ' , ' \x99 ' , ' \x43 ' , ' \xb1 ' , ' \xaf ' , ' \x0c ' , /* 18 - 1f */
} ;
static const unsigned char data_a [ ] = " .2.{....p..$}.4...1.....L...C... " ;
2018-08-22 07:57:22 +03:00
static const char * const test_data_1 [ ] __initconst = {
2015-02-13 02:02:21 +03:00
" be " , " 32 " , " db " , " 7b " , " 0a " , " 18 " , " 93 " , " b2 " ,
" 70 " , " ba " , " c4 " , " 24 " , " 7d " , " 83 " , " 34 " , " 9b " ,
" a6 " , " 9c " , " 31 " , " ad " , " 9c " , " 0f " , " ac " , " e9 " ,
" 4c " , " d1 " , " 19 " , " 99 " , " 43 " , " b1 " , " af " , " 0c " ,
} ;
2015-06-26 01:02:11 +03:00
static const char * const test_data_2_le [ ] __initconst = {
2015-02-13 02:02:21 +03:00
" 32be " , " 7bdb " , " 180a " , " b293 " ,
" ba70 " , " 24c4 " , " 837d " , " 9b34 " ,
" 9ca6 " , " ad31 " , " 0f9c " , " e9ac " ,
" d14c " , " 9919 " , " b143 " , " 0caf " ,
} ;
2018-08-22 07:57:22 +03:00
static const char * const test_data_2_be [ ] __initconst = {
" be32 " , " db7b " , " 0a18 " , " 93b2 " ,
" 70ba " , " c424 " , " 7d83 " , " 349b " ,
" a69c " , " 31ad " , " 9c0f " , " ace9 " ,
" 4cd1 " , " 1999 " , " 43b1 " , " af0c " ,
} ;
2015-06-26 01:02:11 +03:00
static const char * const test_data_4_le [ ] __initconst = {
2015-02-13 02:02:21 +03:00
" 7bdb32be " , " b293180a " , " 24c4ba70 " , " 9b34837d " ,
" ad319ca6 " , " e9ac0f9c " , " 9919d14c " , " 0cafb143 " ,
} ;
2018-08-22 07:57:22 +03:00
static const char * const test_data_4_be [ ] __initconst = {
" be32db7b " , " 0a1893b2 " , " 70bac424 " , " 7d83349b " ,
" a69c31ad " , " 9c0face9 " , " 4cd11999 " , " 43b1af0c " ,
} ;
2015-06-26 01:02:11 +03:00
static const char * const test_data_8_le [ ] __initconst = {
2015-02-13 02:02:21 +03:00
" b293180a7bdb32be " , " 9b34837d24c4ba70 " ,
" e9ac0f9cad319ca6 " , " 0cafb1439919d14c " ,
} ;
2018-08-22 07:57:22 +03:00
static const char * const test_data_8_be [ ] __initconst = {
" be32db7b0a1893b2 " , " 70bac4247d83349b " ,
" a69c31ad9c0face9 " , " 4cd1199943b1af0c " ,
} ;
2016-01-21 01:58:50 +03:00
# define FILL_CHAR '#'
2016-01-21 01:59:07 +03:00
static unsigned total_tests __initdata ;
static unsigned failed_tests __initdata ;
2016-01-21 01:58:47 +03:00
static void __init test_hexdump_prepare_test ( size_t len , int rowsize ,
int groupsize , char * test ,
size_t testlen , bool ascii )
2015-02-13 02:02:21 +03:00
{
char * p ;
2015-04-19 23:48:40 +03:00
const char * const * result ;
2015-02-13 02:02:21 +03:00
size_t l = len ;
int gs = groupsize , rs = rowsize ;
unsigned int i ;
2018-08-22 07:57:22 +03:00
const bool is_be = IS_ENABLED ( CONFIG_CPU_BIG_ENDIAN ) ;
2015-02-13 02:02:21 +03:00
if ( rs ! = 16 & & rs ! = 32 )
rs = 16 ;
if ( l > rs )
l = rs ;
if ( ! is_power_of_2 ( gs ) | | gs > 8 | | ( len % gs ! = 0 ) )
gs = 1 ;
if ( gs = = 8 )
2018-08-22 07:57:22 +03:00
result = is_be ? test_data_8_be : test_data_8_le ;
2015-02-13 02:02:21 +03:00
else if ( gs = = 4 )
2018-08-22 07:57:22 +03:00
result = is_be ? test_data_4_be : test_data_4_le ;
2015-02-13 02:02:21 +03:00
else if ( gs = = 2 )
2018-08-22 07:57:22 +03:00
result = is_be ? test_data_2_be : test_data_2_le ;
2015-02-13 02:02:21 +03:00
else
2018-08-22 07:57:22 +03:00
result = test_data_1 ;
2015-02-13 02:02:21 +03:00
/* hex dump */
p = test ;
for ( i = 0 ; i < l / gs ; i + + ) {
const char * q = * result + + ;
size_t amount = strlen ( q ) ;
2018-11-30 23:13:15 +03:00
memcpy ( p , q , amount ) ;
2016-01-21 01:58:50 +03:00
p + = amount ;
* p + + = ' ' ;
2015-02-13 02:02:21 +03:00
}
if ( i )
p - - ;
/* ASCII part */
if ( ascii ) {
2016-01-21 01:58:50 +03:00
do {
* p + + = ' ' ;
} while ( p < test + rs * 2 + rs / gs + 1 ) ;
2015-02-13 02:02:21 +03:00
strncpy ( p , data_a , l ) ;
p + = l ;
}
* p = ' \0 ' ;
2016-01-21 01:58:47 +03:00
}
# define TEST_HEXDUMP_BUF_SIZE (32 * 3 + 2 + 32 + 1)
static void __init test_hexdump ( size_t len , int rowsize , int groupsize ,
bool ascii )
{
char test [ TEST_HEXDUMP_BUF_SIZE ] ;
char real [ TEST_HEXDUMP_BUF_SIZE ] ;
2016-01-21 01:59:07 +03:00
total_tests + + ;
2016-01-21 01:58:58 +03:00
memset ( real , FILL_CHAR , sizeof ( real ) ) ;
2016-01-21 01:58:47 +03:00
hex_dump_to_buffer ( data_b , len , rowsize , groupsize , real , sizeof ( real ) ,
ascii ) ;
2016-01-21 01:58:58 +03:00
memset ( test , FILL_CHAR , sizeof ( test ) ) ;
2016-01-21 01:58:47 +03:00
test_hexdump_prepare_test ( len , rowsize , groupsize , test , sizeof ( test ) ,
ascii ) ;
2015-02-13 02:02:21 +03:00
2016-01-21 01:58:58 +03:00
if ( memcmp ( test , real , TEST_HEXDUMP_BUF_SIZE ) ) {
2015-02-13 02:02:21 +03:00
pr_err ( " Len: %zu row: %d group: %d \n " , len , rowsize , groupsize ) ;
pr_err ( " Result: '%s' \n " , real ) ;
pr_err ( " Expect: '%s' \n " , test ) ;
2016-01-21 01:59:07 +03:00
failed_tests + + ;
2015-02-13 02:02:21 +03:00
}
}
static void __init test_hexdump_set ( int rowsize , bool ascii )
{
size_t d = min_t ( size_t , sizeof ( data_b ) , rowsize ) ;
2022-10-10 05:44:02 +03:00
size_t len = get_random_u32_inclusive ( 1 , d ) ;
2015-02-13 02:02:21 +03:00
test_hexdump ( len , rowsize , 4 , ascii ) ;
test_hexdump ( len , rowsize , 2 , ascii ) ;
test_hexdump ( len , rowsize , 8 , ascii ) ;
test_hexdump ( len , rowsize , 1 , ascii ) ;
}
2016-01-21 01:59:04 +03:00
static void __init test_hexdump_overflow ( size_t buflen , size_t len ,
int rowsize , int groupsize ,
bool ascii )
2015-02-13 02:02:29 +03:00
{
2016-01-21 01:59:01 +03:00
char test [ TEST_HEXDUMP_BUF_SIZE ] ;
2016-01-21 01:58:53 +03:00
char buf [ TEST_HEXDUMP_BUF_SIZE ] ;
2016-01-21 01:59:01 +03:00
int rs = rowsize , gs = groupsize ;
int ae , he , e , f , r ;
2015-02-13 02:02:29 +03:00
bool a ;
2016-01-21 01:59:07 +03:00
total_tests + + ;
2016-01-21 01:58:50 +03:00
memset ( buf , FILL_CHAR , sizeof ( buf ) ) ;
2015-02-13 02:02:29 +03:00
2016-01-21 01:58:56 +03:00
r = hex_dump_to_buffer ( data_b , len , rs , gs , buf , buflen , ascii ) ;
/*
* Caller must provide the data length multiple of groupsize . The
* calculations below are made with that assumption in mind .
*/
ae = rs * 2 /* hex */ + rs / gs /* spaces */ + 1 /* space */ + len /* ascii */ ;
he = ( gs * 2 /* hex */ + 1 /* space */ ) * len / gs - 1 /* no trailing space */ ;
2015-02-13 02:02:29 +03:00
if ( ascii )
2016-01-21 01:58:56 +03:00
e = ae ;
2015-02-13 02:02:29 +03:00
else
2016-01-21 01:58:56 +03:00
e = he ;
2016-01-21 01:59:01 +03:00
f = min_t ( int , e + 1 , buflen ) ;
if ( buflen ) {
test_hexdump_prepare_test ( len , rs , gs , test , sizeof ( test ) , ascii ) ;
test [ f - 1 ] = ' \0 ' ;
2015-02-13 02:02:29 +03:00
}
2016-01-21 01:59:01 +03:00
memset ( test + f , FILL_CHAR , sizeof ( test ) - f ) ;
a = r = = e & & ! memcmp ( test , buf , TEST_HEXDUMP_BUF_SIZE ) ;
buf [ sizeof ( buf ) - 1 ] = ' \0 ' ;
2015-02-13 02:02:29 +03:00
if ( ! a ) {
2016-01-21 01:59:01 +03:00
pr_err ( " Len: %zu buflen: %zu strlen: %zu \n " ,
len , buflen , strnlen ( buf , sizeof ( buf ) ) ) ;
pr_err ( " Result: %d '%s' \n " , r , buf ) ;
pr_err ( " Expect: %d '%s' \n " , e , test ) ;
2016-01-21 01:59:07 +03:00
failed_tests + + ;
2015-02-13 02:02:29 +03:00
}
}
2016-01-21 01:59:04 +03:00
static void __init test_hexdump_overflow_set ( size_t buflen , bool ascii )
{
unsigned int i = 0 ;
2022-10-10 05:44:02 +03:00
int rs = get_random_u32_inclusive ( 1 , 2 ) * 16 ;
2016-01-21 01:59:04 +03:00
do {
int gs = 1 < < i ;
2022-10-10 05:44:02 +03:00
size_t len = get_random_u32_below ( rs ) + gs ;
2016-01-21 01:59:04 +03:00
test_hexdump_overflow ( buflen , rounddown ( len , gs ) , rs , gs , ascii ) ;
} while ( i + + < 3 ) ;
}
2015-02-13 02:02:21 +03:00
static int __init test_hexdump_init ( void )
{
unsigned int i ;
int rowsize ;
2022-10-10 05:44:02 +03:00
rowsize = get_random_u32_inclusive ( 1 , 2 ) * 16 ;
2015-02-13 02:02:21 +03:00
for ( i = 0 ; i < 16 ; i + + )
test_hexdump_set ( rowsize , false ) ;
2022-10-10 05:44:02 +03:00
rowsize = get_random_u32_inclusive ( 1 , 2 ) * 16 ;
2015-02-13 02:02:21 +03:00
for ( i = 0 ; i < 16 ; i + + )
test_hexdump_set ( rowsize , true ) ;
2016-01-21 01:58:53 +03:00
for ( i = 0 ; i < = TEST_HEXDUMP_BUF_SIZE ; i + + )
2016-01-21 01:59:04 +03:00
test_hexdump_overflow_set ( i , false ) ;
2015-02-13 02:02:29 +03:00
2016-01-21 01:58:53 +03:00
for ( i = 0 ; i < = TEST_HEXDUMP_BUF_SIZE ; i + + )
2016-01-21 01:59:04 +03:00
test_hexdump_overflow_set ( i , true ) ;
2015-02-13 02:02:29 +03:00
2016-01-21 01:59:07 +03:00
if ( failed_tests = = 0 )
pr_info ( " all %u tests passed \n " , total_tests ) ;
else
pr_err ( " failed %u out of %u tests \n " , failed_tests , total_tests ) ;
return failed_tests ? - EINVAL : 0 ;
2015-02-13 02:02:21 +03:00
}
module_init ( test_hexdump_init ) ;
2016-01-21 01:59:07 +03:00
static void __exit test_hexdump_exit ( void )
{
/* do nothing */
}
module_exit ( test_hexdump_exit ) ;
MODULE_AUTHOR ( " Andy Shevchenko <andriy.shevchenko@linux.intel.com> " ) ;
2015-02-13 02:02:21 +03:00
MODULE_LICENSE ( " Dual BSD/GPL " ) ;