2019-05-27 09:55:05 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-10-20 18:01:09 +04:00
/*
* x86 decoder sanity test - based on test_get_insn . c
*
* Copyright ( C ) IBM Corporation , 2009
* Copyright ( C ) Hitachi , Ltd . , 2011
*/
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <assert.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <asm/insn.h>
# include <inat.c>
# include <insn.c>
/*
* Test of instruction analysis against tampering .
* Feed random binary to instruction decoder and ensure not to
* access out - of - instruction - buffer .
*/
# define DEFAULT_MAX_ITER 10000
# define INSN_NOP 0x90
static const char * prog ; /* Program name */
static int verbose ; /* Verbosity */
static int x86_64 ; /* x86-64 bit mode flag */
static unsigned int seed ; /* Random seed */
static unsigned long iter_start ; /* Start of iteration number */
static unsigned long iter_end = DEFAULT_MAX_ITER ; /* End of iteration number */
static FILE * input_file ; /* Input file name */
static void usage ( const char * err )
{
if ( err )
2012-12-19 00:22:12 +04:00
fprintf ( stderr , " %s: Error: %s \n \n " , prog , err ) ;
2011-10-20 18:01:09 +04:00
fprintf ( stderr , " Usage: %s [-y|-n|-v] [-s seed[,no]] [-m max] [-i input] \n " , prog ) ;
fprintf ( stderr , " \t -y 64bit mode \n " ) ;
fprintf ( stderr , " \t -n 32bit mode \n " ) ;
x86/tools: Add decoded instruction dump mode
Add instruction dump mode to insn_sanity tool for
checking decoder really decoded instructions.
This mode is enabled when passing double -v (-vv) to
insn_sanity. It is useful for who wants to check whether
the decoder can decode some instructions correctly.
e.g.
$ echo 0f 73 10 11 | ./insn_sanity -y -vv -i -
Instruction = {
.prefixes = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 1, .nbytes = 0},
.rex_prefix = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 1, .nbytes = 0},
.vex_prefix = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 1, .nbytes = 0},
.opcode = {
.value = 29455, bytes[] = {f, 73, 0, 0},
.got = 1, .nbytes = 2},
.modrm = {
.value = 16, bytes[] = {10, 0, 0, 0},
.got = 1, .nbytes = 1},
.sib = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 1, .nbytes = 0},
.displacement = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 1, .nbytes = 0},
.immediate1 = {
.value = 17, bytes[] = {11, 0, 0, 0},
.got = 1, .nbytes = 1},
.immediate2 = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 0, .nbytes = 0},
.attr = 44800, .opnd_bytes = 4, .addr_bytes = 8,
.length = 4, .x86_64 = 1, .kaddr = 0x7fff0f7d9430}
Success: decoded and checked 1 given instructions with 0 errors (seed:0x0)
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20111205120603.15475.91192.stgit@cloud
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2011-12-05 16:06:03 +04:00
fprintf ( stderr , " \t -v Verbosity(-vv dumps any decoded result) \n " ) ;
2011-10-20 18:01:09 +04:00
fprintf ( stderr , " \t -s Give a random seed (and iteration number) \n " ) ;
fprintf ( stderr , " \t -m Give a maximum iteration number \n " ) ;
fprintf ( stderr , " \t -i Give an input file with decoded binary \n " ) ;
exit ( 1 ) ;
}
static void dump_field ( FILE * fp , const char * name , const char * indent ,
struct insn_field * field )
{
fprintf ( fp , " %s.%s = { \n " , indent , name ) ;
fprintf ( fp , " %s \t .value = %d, bytes[] = {%x, %x, %x, %x}, \n " ,
indent , field - > value , field - > bytes [ 0 ] , field - > bytes [ 1 ] ,
field - > bytes [ 2 ] , field - > bytes [ 3 ] ) ;
fprintf ( fp , " %s \t .got = %d, .nbytes = %d}, \n " , indent ,
field - > got , field - > nbytes ) ;
}
static void dump_insn ( FILE * fp , struct insn * insn )
{
fprintf ( fp , " Instruction = { \n " ) ;
dump_field ( fp , " prefixes " , " \t " , & insn - > prefixes ) ;
dump_field ( fp , " rex_prefix " , " \t " , & insn - > rex_prefix ) ;
dump_field ( fp , " vex_prefix " , " \t " , & insn - > vex_prefix ) ;
dump_field ( fp , " opcode " , " \t " , & insn - > opcode ) ;
dump_field ( fp , " modrm " , " \t " , & insn - > modrm ) ;
dump_field ( fp , " sib " , " \t " , & insn - > sib ) ;
dump_field ( fp , " displacement " , " \t " , & insn - > displacement ) ;
dump_field ( fp , " immediate1 " , " \t " , & insn - > immediate1 ) ;
dump_field ( fp , " immediate2 " , " \t " , & insn - > immediate2 ) ;
fprintf ( fp , " \t .attr = %x, .opnd_bytes = %d, .addr_bytes = %d, \n " ,
insn - > attr , insn - > opnd_bytes , insn - > addr_bytes ) ;
fprintf ( fp , " \t .length = %d, .x86_64 = %d, .kaddr = %p} \n " ,
insn - > length , insn - > x86_64 , insn - > kaddr ) ;
}
static void dump_stream ( FILE * fp , const char * msg , unsigned long nr_iter ,
2019-04-25 14:03:31 +03:00
unsigned char * insn_buff , struct insn * insn )
2011-10-20 18:01:09 +04:00
{
int i ;
fprintf ( fp , " %s: \n " , msg ) ;
2011-12-05 16:05:50 +04:00
dump_insn ( fp , insn ) ;
2011-10-20 18:01:09 +04:00
fprintf ( fp , " You can reproduce this with below command(s); \n " ) ;
/* Input a decoded instruction sequence directly */
fprintf ( fp , " $ echo " ) ;
for ( i = 0 ; i < MAX_INSN_SIZE ; i + + )
2019-04-25 14:03:31 +03:00
fprintf ( fp , " %02x " , insn_buff [ i ] ) ;
2011-10-20 18:01:09 +04:00
fprintf ( fp , " | %s -i - \n " , prog ) ;
if ( ! input_file ) {
fprintf ( fp , " Or \n " ) ;
/* Give a seed and iteration number */
fprintf ( fp , " $ %s -s 0x%x,%lu \n " , prog , seed , nr_iter ) ;
}
}
static void init_random_seed ( void )
{
int fd ;
fd = open ( " /dev/urandom " , O_RDONLY ) ;
if ( fd < 0 )
goto fail ;
if ( read ( fd , & seed , sizeof ( seed ) ) ! = sizeof ( seed ) )
goto fail ;
close ( fd ) ;
return ;
fail :
usage ( " Failed to open /dev/urandom " ) ;
}
/* Read given instruction sequence from the input file */
2019-04-25 14:03:31 +03:00
static int read_next_insn ( unsigned char * insn_buff )
2011-10-20 18:01:09 +04:00
{
char buf [ 256 ] = " " , * tmp ;
int i ;
tmp = fgets ( buf , ARRAY_SIZE ( buf ) , input_file ) ;
if ( tmp = = NULL | | feof ( input_file ) )
return 0 ;
for ( i = 0 ; i < MAX_INSN_SIZE ; i + + ) {
2019-04-25 14:03:31 +03:00
insn_buff [ i ] = ( unsigned char ) strtoul ( tmp , & tmp , 16 ) ;
2011-10-20 18:01:09 +04:00
if ( * tmp ! = ' ' )
break ;
}
return i ;
}
2019-04-25 14:03:31 +03:00
static int generate_insn ( unsigned char * insn_buff )
2011-10-20 18:01:09 +04:00
{
int i ;
if ( input_file )
2019-04-25 14:03:31 +03:00
return read_next_insn ( insn_buff ) ;
2011-10-20 18:01:09 +04:00
/* Fills buffer with random binary up to MAX_INSN_SIZE */
for ( i = 0 ; i < MAX_INSN_SIZE - 1 ; i + = 2 )
2019-04-25 14:03:31 +03:00
* ( unsigned short * ) ( & insn_buff [ i ] ) = random ( ) & 0xffff ;
2011-10-20 18:01:09 +04:00
while ( i < MAX_INSN_SIZE )
2019-04-25 14:03:31 +03:00
insn_buff [ i + + ] = random ( ) & 0xff ;
2011-10-20 18:01:09 +04:00
return i ;
}
static void parse_args ( int argc , char * * argv )
{
int c ;
char * tmp = NULL ;
int set_seed = 0 ;
prog = argv [ 0 ] ;
while ( ( c = getopt ( argc , argv , " ynvs:m:i: " ) ) ! = - 1 ) {
switch ( c ) {
case ' y ' :
x86_64 = 1 ;
break ;
case ' n ' :
x86_64 = 0 ;
break ;
case ' v ' :
x86/tools: Add decoded instruction dump mode
Add instruction dump mode to insn_sanity tool for
checking decoder really decoded instructions.
This mode is enabled when passing double -v (-vv) to
insn_sanity. It is useful for who wants to check whether
the decoder can decode some instructions correctly.
e.g.
$ echo 0f 73 10 11 | ./insn_sanity -y -vv -i -
Instruction = {
.prefixes = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 1, .nbytes = 0},
.rex_prefix = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 1, .nbytes = 0},
.vex_prefix = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 1, .nbytes = 0},
.opcode = {
.value = 29455, bytes[] = {f, 73, 0, 0},
.got = 1, .nbytes = 2},
.modrm = {
.value = 16, bytes[] = {10, 0, 0, 0},
.got = 1, .nbytes = 1},
.sib = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 1, .nbytes = 0},
.displacement = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 1, .nbytes = 0},
.immediate1 = {
.value = 17, bytes[] = {11, 0, 0, 0},
.got = 1, .nbytes = 1},
.immediate2 = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 0, .nbytes = 0},
.attr = 44800, .opnd_bytes = 4, .addr_bytes = 8,
.length = 4, .x86_64 = 1, .kaddr = 0x7fff0f7d9430}
Success: decoded and checked 1 given instructions with 0 errors (seed:0x0)
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20111205120603.15475.91192.stgit@cloud
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2011-12-05 16:06:03 +04:00
verbose + + ;
2011-10-20 18:01:09 +04:00
break ;
case ' i ' :
if ( strcmp ( " - " , optarg ) = = 0 )
input_file = stdin ;
else
input_file = fopen ( optarg , " r " ) ;
if ( ! input_file )
usage ( " Failed to open input file " ) ;
break ;
case ' s ' :
seed = ( unsigned int ) strtoul ( optarg , & tmp , 0 ) ;
if ( * tmp = = ' , ' ) {
optarg = tmp + 1 ;
iter_start = strtoul ( optarg , & tmp , 0 ) ;
}
if ( * tmp ! = ' \0 ' | | tmp = = optarg )
usage ( " Failed to parse seed " ) ;
set_seed = 1 ;
break ;
case ' m ' :
iter_end = strtoul ( optarg , & tmp , 0 ) ;
if ( * tmp ! = ' \0 ' | | tmp = = optarg )
usage ( " Failed to parse max_iter " ) ;
break ;
default :
usage ( NULL ) ;
}
}
/* Check errors */
if ( iter_end < iter_start )
usage ( " Max iteration number must be bigger than iter-num " ) ;
if ( set_seed & & input_file )
usage ( " Don't use input file (-i) with random seed (-s) " ) ;
/* Initialize random seed */
if ( ! input_file ) {
if ( ! set_seed ) /* No seed is given */
init_random_seed ( ) ;
srand ( seed ) ;
}
}
int main ( int argc , char * * argv )
{
2020-11-22 20:11:10 +03:00
int insns = 0 , ret ;
2011-10-20 18:01:09 +04:00
struct insn insn ;
int errors = 0 ;
unsigned long i ;
2019-04-25 14:03:31 +03:00
unsigned char insn_buff [ MAX_INSN_SIZE * 2 ] ;
2011-10-20 18:01:09 +04:00
parse_args ( argc , argv ) ;
/* Prepare stop bytes with NOPs */
2019-04-25 14:03:31 +03:00
memset ( insn_buff + MAX_INSN_SIZE , INSN_NOP , MAX_INSN_SIZE ) ;
2011-10-20 18:01:09 +04:00
for ( i = 0 ; i < iter_end ; i + + ) {
2019-04-25 14:03:31 +03:00
if ( generate_insn ( insn_buff ) < = 0 )
2011-10-20 18:01:09 +04:00
break ;
if ( i < iter_start ) /* Skip to given iteration number */
continue ;
/* Decode an instruction */
2020-11-22 20:11:10 +03:00
ret = insn_decode ( & insn , insn_buff , sizeof ( insn_buff ) ,
x86_64 ? INSN_MODE_64 : INSN_MODE_32 ) ;
2011-10-20 18:01:09 +04:00
if ( insn . next_byte < = insn . kaddr | |
insn . kaddr + MAX_INSN_SIZE < insn . next_byte ) {
/* Access out-of-range memory */
2019-04-25 14:03:31 +03:00
dump_stream ( stderr , " Error: Found an access violation " , i , insn_buff , & insn ) ;
2011-10-20 18:01:09 +04:00
errors + + ;
2020-11-22 20:11:10 +03:00
} else if ( verbose & & ret < 0 )
2019-04-25 14:03:31 +03:00
dump_stream ( stdout , " Info: Found an undecodable input " , i , insn_buff , & insn ) ;
x86/tools: Add decoded instruction dump mode
Add instruction dump mode to insn_sanity tool for
checking decoder really decoded instructions.
This mode is enabled when passing double -v (-vv) to
insn_sanity. It is useful for who wants to check whether
the decoder can decode some instructions correctly.
e.g.
$ echo 0f 73 10 11 | ./insn_sanity -y -vv -i -
Instruction = {
.prefixes = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 1, .nbytes = 0},
.rex_prefix = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 1, .nbytes = 0},
.vex_prefix = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 1, .nbytes = 0},
.opcode = {
.value = 29455, bytes[] = {f, 73, 0, 0},
.got = 1, .nbytes = 2},
.modrm = {
.value = 16, bytes[] = {10, 0, 0, 0},
.got = 1, .nbytes = 1},
.sib = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 1, .nbytes = 0},
.displacement = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 1, .nbytes = 0},
.immediate1 = {
.value = 17, bytes[] = {11, 0, 0, 0},
.got = 1, .nbytes = 1},
.immediate2 = {
.value = 0, bytes[] = {0, 0, 0, 0},
.got = 0, .nbytes = 0},
.attr = 44800, .opnd_bytes = 4, .addr_bytes = 8,
.length = 4, .x86_64 = 1, .kaddr = 0x7fff0f7d9430}
Success: decoded and checked 1 given instructions with 0 errors (seed:0x0)
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20111205120603.15475.91192.stgit@cloud
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2011-12-05 16:06:03 +04:00
else if ( verbose > = 2 )
dump_insn ( stdout , & insn ) ;
2011-10-20 18:01:09 +04:00
insns + + ;
}
2016-10-25 23:56:05 +03:00
fprintf ( ( errors ) ? stderr : stdout ,
" %s: %s: decoded and checked %d %s instructions with %d errors (seed:0x%x) \n " ,
2012-12-19 00:22:12 +04:00
prog ,
( errors ) ? " Failure " : " Success " ,
insns ,
( input_file ) ? " given " : " random " ,
errors ,
seed ) ;
2011-10-20 18:01:09 +04:00
return errors ? 1 : 0 ;
}