2019-05-27 08:55:06 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2009-08-13 16:34:21 -04:00
/*
*
* Copyright ( C ) IBM Corporation , 2009
*/
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <assert.h>
2009-11-16 18:06:18 -05:00
# include <unistd.h>
2017-11-25 00:11:22 +09:00
# include <stdarg.h>
2009-08-13 16:34:21 -04:00
# define unlikely(cond) (cond)
# include <asm/insn.h>
# include <inat.c>
# include <insn.c>
/*
* Test of instruction analysis in general and insn_get_length ( ) in
* particular . See if insn_get_length ( ) and the disassembler agree
* on the length of each instruction in an elf disassembly .
*
2017-11-25 00:10:54 +09:00
* Usage : objdump - d a . out | awk - f objdump_reformat . awk | . / insn_decoder_test
2009-08-13 16:34:21 -04:00
*/
const char * prog ;
2009-11-16 18:06:18 -05:00
static int verbose ;
static int x86_64 ;
2009-08-13 16:34:21 -04:00
static void usage ( void )
{
2017-11-25 00:10:54 +09:00
fprintf ( stderr , " Usage: objdump -d a.out | awk -f objdump_reformat.awk "
" | %s [-y|-n] [-v] \n " , prog ) ;
2009-11-16 18:06:18 -05:00
fprintf ( stderr , " \t -y 64bit mode \n " ) ;
fprintf ( stderr , " \t -n 32bit mode \n " ) ;
fprintf ( stderr , " \t -v verbose mode \n " ) ;
2009-08-13 16:34:21 -04:00
exit ( 1 ) ;
}
static void malformed_line ( const char * line , int line_nr )
{
2017-11-25 00:11:22 +09:00
fprintf ( stderr , " %s: error: malformed line %d: \n %s " ,
prog , line_nr , line ) ;
2009-08-13 16:34:21 -04:00
exit ( 3 ) ;
}
2017-11-25 00:11:22 +09:00
static void pr_warn ( const char * fmt , . . . )
{
va_list ap ;
fprintf ( stderr , " %s: warning: " , prog ) ;
va_start ( ap , fmt ) ;
vfprintf ( stderr , fmt , ap ) ;
va_end ( ap ) ;
}
2009-11-16 18:06:18 -05:00
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 )
{
2010-02-06 18:47:17 +01:00
fprintf ( fp , " Instruction = { \n " ) ;
2009-11-16 18:06:18 -05:00
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 parse_args ( int argc , char * * argv )
{
int c ;
prog = argv [ 0 ] ;
while ( ( c = getopt ( argc , argv , " ynv " ) ) ! = - 1 ) {
switch ( c ) {
case ' y ' :
x86_64 = 1 ;
break ;
case ' n ' :
x86_64 = 0 ;
break ;
case ' v ' :
verbose = 1 ;
break ;
default :
usage ( ) ;
}
}
}
2009-08-13 16:34:21 -04:00
# define BUFSIZE 256
int main ( int argc , char * * argv )
{
2009-11-16 18:06:24 -05:00
char line [ BUFSIZE ] , sym [ BUFSIZE ] = " <unknown> " ;
2019-04-25 13:03:31 +02:00
unsigned char insn_buff [ 16 ] ;
2009-08-13 16:34:21 -04:00
struct insn insn ;
2009-12-06 12:40:59 +01:00
int insns = 0 ;
2009-11-16 18:06:31 -05:00
int warnings = 0 ;
2009-08-13 16:34:21 -04:00
2009-11-16 18:06:18 -05:00
parse_args ( argc , argv ) ;
2009-08-28 18:13:19 -04:00
2009-08-13 16:34:21 -04:00
while ( fgets ( line , BUFSIZE , stdin ) ) {
char copy [ BUFSIZE ] , * s , * tab1 , * tab2 ;
2020-11-20 15:01:20 +01:00
int nb = 0 , ret ;
2009-08-13 16:34:21 -04:00
unsigned int b ;
2009-11-16 18:06:24 -05:00
if ( line [ 0 ] = = ' < ' ) {
/* Symbol line */
strcpy ( sym , line ) ;
continue ;
}
2009-08-13 16:34:21 -04:00
insns + + ;
2019-04-25 13:03:31 +02:00
memset ( insn_buff , 0 , 16 ) ;
2009-08-13 16:34:21 -04:00
strcpy ( copy , line ) ;
tab1 = strchr ( copy , ' \t ' ) ;
if ( ! tab1 )
malformed_line ( line , insns ) ;
s = tab1 + 1 ;
s + = strspn ( s , " " ) ;
tab2 = strchr ( s , ' \t ' ) ;
if ( ! tab2 )
malformed_line ( line , insns ) ;
* tab2 = ' \0 ' ; /* Characters beyond tab2 aren't examined */
while ( s < tab2 ) {
if ( sscanf ( s , " %x " , & b ) = = 1 ) {
2019-04-25 13:03:31 +02:00
insn_buff [ nb + + ] = ( unsigned char ) b ;
2009-08-13 16:34:21 -04:00
s + = 3 ;
} else
break ;
}
2020-11-20 15:01:20 +01:00
2009-08-13 16:34:21 -04:00
/* Decode an instruction */
2020-11-20 15:01:20 +01:00
ret = insn_decode ( & insn , insn_buff , sizeof ( insn_buff ) ,
x86_64 ? INSN_MODE_64 : INSN_MODE_32 ) ;
if ( ret < 0 | | insn . length ! = nb ) {
2009-11-16 18:06:31 -05:00
warnings + + ;
2017-11-25 00:11:22 +09:00
pr_warn ( " Found an x86 instruction decoder bug, "
" please report this. \n " , sym ) ;
pr_warn ( " %s " , line ) ;
pr_warn ( " objdump says %d bytes, but insn_get_length() "
" says %d \n " , nb , insn . length ) ;
2009-11-16 18:06:18 -05:00
if ( verbose )
dump_insn ( stderr , & insn ) ;
2009-08-13 16:34:21 -04:00
}
}
2009-11-16 18:06:31 -05:00
if ( warnings )
2017-11-25 00:11:22 +09:00
pr_warn ( " Decoded and checked %d instructions with %d "
" failures \n " , insns , warnings ) ;
2009-11-16 18:06:31 -05:00
else
2017-11-25 00:11:22 +09:00
fprintf ( stdout , " %s: success: Decoded and checked %d "
" instructions \n " , prog , insns ) ;
2009-08-13 16:34:21 -04:00
return 0 ;
}