@ -418,6 +418,7 @@ static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count)
# define cap_disas_target(i, p, s) false
# define cap_disas_host(i, p, s) false
# define cap_disas_monitor(i, p, c) false
# define cap_disas_plugin(i, p, c) false
# endif /* CONFIG_CAPSTONE */
/* Disassemble this for me please... (debugging). */
@ -475,6 +476,115 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code,
}
}
static __thread GString plugin_disas_output ;
static int plugin_printf ( FILE * stream , const char * fmt , . . . )
{
va_list va ;
GString * s = & plugin_disas_output ;
int initial_len = s - > len ;
va_start ( va , fmt ) ;
g_string_append_vprintf ( s , fmt , va ) ;
va_end ( va ) ;
return s - > len - initial_len ;
}
static void plugin_print_address ( bfd_vma addr , struct disassemble_info * info )
{
/* does nothing */
}
# ifdef CONFIG_CAPSTONE
/* Disassemble a single instruction directly into plugin output */
static
bool cap_disas_plugin ( disassemble_info * info , uint64_t pc , size_t size )
{
uint8_t cap_buf [ 1024 ] ;
csh handle ;
cs_insn * insn ;
size_t csize = 0 ;
int count ;
GString * s = & plugin_disas_output ;
if ( cap_disas_start ( info , & handle ) ! = CS_ERR_OK ) {
return false ;
}
insn = cap_insn ;
size_t tsize = MIN ( sizeof ( cap_buf ) - csize , size ) ;
const uint8_t * cbuf = cap_buf ;
target_read_memory ( pc , cap_buf , tsize , info ) ;
count = cs_disasm ( handle , cbuf , size , 0 , 1 , & insn ) ;
if ( count ) {
g_string_printf ( s , " %s %s " , insn - > mnemonic , insn - > op_str ) ;
} else {
g_string_printf ( s , " cs_disasm failed " ) ;
}
cs_close ( & handle ) ;
return true ;
}
# endif
/*
* We should only be dissembling one instruction at a time here . If
* there is left over it usually indicates the front end has read more
* bytes than it needed .
*/
char * plugin_disas ( CPUState * cpu , uint64_t addr , size_t size )
{
CPUClass * cc = CPU_GET_CLASS ( cpu ) ;
int count ;
CPUDebug s ;
GString * ds = g_string_set_size ( & plugin_disas_output , 0 ) ;
g_assert ( ds = = & plugin_disas_output ) ;
INIT_DISASSEMBLE_INFO ( s . info , NULL , plugin_printf ) ;
s . cpu = cpu ;
s . info . read_memory_func = target_read_memory ;
s . info . buffer_vma = addr ;
s . info . buffer_length = size ;
s . info . print_address_func = plugin_print_address ;
s . info . cap_arch = - 1 ;
s . info . cap_mode = 0 ;
s . info . cap_insn_unit = 4 ;
s . info . cap_insn_split = 4 ;
# ifdef TARGET_WORDS_BIGENDIAN
s . info . endian = BFD_ENDIAN_BIG ;
# else
s . info . endian = BFD_ENDIAN_LITTLE ;
# endif
if ( cc - > disas_set_info ) {
cc - > disas_set_info ( cpu , & s . info ) ;
}
if ( s . info . cap_arch > = 0 & & cap_disas_plugin ( & s . info , addr , size ) ) {
return g_strdup ( ds - > str ) ;
}
if ( s . info . print_insn = = NULL ) {
s . info . print_insn = print_insn_od_target ;
}
count = s . info . print_insn ( addr , & s . info ) ;
/* The decoder probably read more than it needed it's not critical */
if ( count < size ) {
warn_report ( " %s: %zu bytes left over " , __func__ , size - count ) ;
}
return g_strdup ( ds - > str ) ;
}
/* Disassemble this for me please... (debugging). */
void disas ( FILE * out , void * code , unsigned long size )
{