nkeynes@362 | 1 | /**
|
nkeynes@561 | 2 | * $Id$
|
nkeynes@362 | 3 | *
|
nkeynes@362 | 4 | * Wrapper around i386-dis to supply the same behaviour as the other
|
nkeynes@362 | 5 | * disassembly functions.
|
nkeynes@362 | 6 | *
|
nkeynes@362 | 7 | * Copyright (c) 2005 Nathan Keynes.
|
nkeynes@362 | 8 | *
|
nkeynes@362 | 9 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@362 | 10 | * it under the terms of the GNU General Public License as published by
|
nkeynes@362 | 11 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@362 | 12 | * (at your option) any later version.
|
nkeynes@362 | 13 | *
|
nkeynes@362 | 14 | * This program is distributed in the hope that it will be useful,
|
nkeynes@362 | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@362 | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@362 | 17 | * GNU General Public License for more details.
|
nkeynes@362 | 18 | */
|
nkeynes@362 | 19 |
|
nkeynes@362 | 20 | #include <stdarg.h>
|
nkeynes@480 | 21 | #include <string.h>
|
nkeynes@1263 | 22 | #include "xlat/xltcache.h"
|
nkeynes@1263 | 23 | #include "xlat/xlatdasm.h"
|
nkeynes@755 | 24 | #include "x86dasm/bfd.h"
|
nkeynes@755 | 25 | #include "x86dasm/dis-asm.h"
|
nkeynes@564 | 26 | #include "sh4/sh4.h"
|
nkeynes@362 | 27 |
|
nkeynes@1263 | 28 | #if defined(__i386__)
|
nkeynes@1263 | 29 | #define HOST_CPU_NAME "x86"
|
nkeynes@1263 | 30 | #define HOST_PRINT print_insn_i386_att
|
nkeynes@1263 | 31 | #define HOST_SYNTAX bfd_mach_i386_i386_intel_syntax
|
nkeynes@1263 | 32 | #elif defined(__x86_64__) || defined(__amd64__)
|
nkeynes@1263 | 33 | #define HOST_CPU_NAME "x86"
|
nkeynes@1263 | 34 | #define HOST_PRINT print_insn_i386_att
|
nkeynes@1263 | 35 | #define HOST_SYNTAX bfd_mach_x86_64_intel_syntax
|
nkeynes@1263 | 36 | #elif defined(__arm__)
|
nkeynes@1263 | 37 | #define HOST_CPU_NAME "arm"
|
nkeynes@1263 | 38 | #define HOST_PRINT print_insn_little_arm
|
nkeynes@1263 | 39 | #define HOST_SYNTAX bfd_mach_arm_unknown
|
nkeynes@1263 | 40 | #else
|
nkeynes@1263 | 41 | #error Unidentified host platform
|
nkeynes@1263 | 42 | #endif
|
nkeynes@1263 | 43 |
|
nkeynes@1263 | 44 | const struct cpu_desc_struct xlat_cpu_desc =
|
nkeynes@1263 | 45 | { HOST_CPU_NAME, (disasm_func_t)xlat_disasm_instruction, NULL, mem_has_page,
|
nkeynes@1026 | 46 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1,
|
nkeynes@1026 | 47 | NULL, 0, NULL, 0, 0,
|
nkeynes@362 | 48 | &sh4r.pc };
|
nkeynes@362 | 49 |
|
nkeynes@1263 | 50 | static int xlat_disasm_output( void *data, const char *format, ... );
|
nkeynes@1263 | 51 | static void xlat_print_address( bfd_vma memaddr, struct disassemble_info *info );
|
nkeynes@362 | 52 |
|
nkeynes@1263 | 53 | static struct disassemble_info xlat_disasm_info;
|
nkeynes@362 | 54 |
|
nkeynes@1263 | 55 | static xlat_symbol *xlat_symtab;
|
nkeynes@1263 | 56 | static int xlat_num_symbols = 0;
|
nkeynes@365 | 57 |
|
nkeynes@1087 | 58 | void xlat_dump_block( void *block )
|
nkeynes@1087 | 59 | {
|
nkeynes@1087 | 60 | xlat_disasm_block( stderr, block );
|
nkeynes@1087 | 61 | }
|
nkeynes@515 | 62 |
|
nkeynes@515 | 63 | void xlat_disasm_block( FILE *out, void *block )
|
nkeynes@515 | 64 | {
|
nkeynes@571 | 65 | uint32_t buflen = xlat_get_code_size(block);
|
nkeynes@1263 | 66 | xlat_disasm_region( out, block, buflen );
|
nkeynes@515 | 67 | }
|
nkeynes@515 | 68 |
|
nkeynes@1263 | 69 | void xlat_disasm_region(FILE *out, void *start, uint32_t len)
|
nkeynes@376 | 70 | {
|
nkeynes@527 | 71 | uintptr_t start_addr = (uintptr_t)start;
|
nkeynes@925 | 72 | uintptr_t pc;
|
nkeynes@376 | 73 | for( pc = start_addr; pc < start_addr + len; ) {
|
nkeynes@376 | 74 | char buf[256];
|
nkeynes@376 | 75 | char op[256];
|
nkeynes@1263 | 76 | uintptr_t pc2 = xlat_disasm_instruction( pc, buf, sizeof(buf), op );
|
nkeynes@968 | 77 | fprintf( out, "%08X: %-20s %s\n", (unsigned int)pc, op, buf );
|
nkeynes@376 | 78 | pc = pc2;
|
nkeynes@376 | 79 | }
|
nkeynes@376 | 80 | }
|
nkeynes@376 | 81 |
|
nkeynes@1263 | 82 | void xlat_disasm_init( xlat_symbol *symtab, int num_symbols )
|
nkeynes@362 | 83 | {
|
nkeynes@1263 | 84 | init_disassemble_info( &xlat_disasm_info, NULL, xlat_disasm_output );
|
nkeynes@1263 | 85 | xlat_disasm_info.arch = bfd_arch_i386;
|
nkeynes@1263 | 86 | xlat_disasm_info.mach = HOST_SYNTAX;
|
nkeynes@1263 | 87 | xlat_disasm_info.endian = BFD_ENDIAN_LITTLE;
|
nkeynes@1263 | 88 | xlat_disasm_info.buffer = 0;
|
nkeynes@1263 | 89 | xlat_disasm_info.print_address_func = xlat_print_address;
|
nkeynes@1263 | 90 | xlat_symtab = symtab;
|
nkeynes@1263 | 91 | xlat_num_symbols = num_symbols;
|
nkeynes@362 | 92 | }
|
nkeynes@362 | 93 |
|
nkeynes@1263 | 94 | static const char *xlat_find_symbol( bfd_vma memaddr, struct disassemble_info *info )
|
nkeynes@365 | 95 | {
|
nkeynes@365 | 96 | int i;
|
nkeynes@1263 | 97 | for( i=0; i<xlat_num_symbols; i++ ) {
|
nkeynes@1263 | 98 | if( xlat_symtab[i].ptr == (void *)(uintptr_t)memaddr ) {
|
nkeynes@1263 | 99 | return xlat_symtab[i].name;
|
nkeynes@365 | 100 | }
|
nkeynes@365 | 101 | }
|
nkeynes@365 | 102 | return NULL;
|
nkeynes@365 | 103 | }
|
nkeynes@365 | 104 |
|
nkeynes@1263 | 105 | static void xlat_print_address( bfd_vma memaddr, struct disassemble_info *info )
|
nkeynes@365 | 106 | {
|
nkeynes@1263 | 107 | const char *sym = xlat_find_symbol(memaddr, info);
|
nkeynes@365 | 108 | info->fprintf_func( info->stream, "%08X", memaddr );
|
nkeynes@365 | 109 | if( sym != NULL ) {
|
nkeynes@365 | 110 | info->fprintf_func( info->stream, " <%s>", sym );
|
nkeynes@365 | 111 | }
|
nkeynes@365 | 112 | }
|
nkeynes@362 | 113 |
|
nkeynes@1263 | 114 | void xlat_print_symbolic_operand( char *buf, int hex, uintptr_t disp )
|
nkeynes@920 | 115 | {
|
nkeynes@1263 | 116 | const char *sym = xlat_find_symbol(disp, NULL);
|
nkeynes@920 | 117 | if( sym != NULL ) {
|
nkeynes@920 | 118 | snprintf( buf, 50, "<%s>", sym );
|
nkeynes@920 | 119 | } else if( hex ) {
|
nkeynes@1263 | 120 | sprintf( buf, "0x%lx", disp );
|
nkeynes@920 | 121 | } else {
|
nkeynes@920 | 122 | sprintf( buf, "%d", (int)disp );
|
nkeynes@920 | 123 | }
|
nkeynes@920 | 124 | }
|
nkeynes@920 | 125 |
|
nkeynes@1263 | 126 | uintptr_t xlat_disasm_instruction( uintptr_t pc, char *buf, int len, char *opcode )
|
nkeynes@362 | 127 | {
|
nkeynes@362 | 128 | int count, i;
|
nkeynes@362 | 129 |
|
nkeynes@1263 | 130 | xlat_disasm_info.stream = buf;
|
nkeynes@362 | 131 | buf[0] = 0;
|
nkeynes@1263 | 132 | count = HOST_PRINT( pc, &xlat_disasm_info );
|
nkeynes@362 | 133 | if( count != 0 ) {
|
nkeynes@429 | 134 | unsigned char tmp[count];
|
nkeynes@1263 | 135 | xlat_disasm_info.read_memory_func( pc, tmp, count, &xlat_disasm_info );
|
nkeynes@362 | 136 | for( i=0; i<count; i++ ) {
|
nkeynes@362 | 137 | sprintf( opcode, "%02X ", ((unsigned int)tmp[i])&0xFF );
|
nkeynes@362 | 138 | opcode += 3;
|
nkeynes@362 | 139 | }
|
nkeynes@362 | 140 | *(opcode-1) = '\0';
|
nkeynes@362 | 141 | }
|
nkeynes@362 | 142 | return pc + count;
|
nkeynes@362 | 143 | }
|
nkeynes@362 | 144 |
|
nkeynes@1263 | 145 | static int xlat_disasm_output( void *data, const char *format, ... )
|
nkeynes@362 | 146 | {
|
nkeynes@362 | 147 | char *p = (char *)data;
|
nkeynes@362 | 148 | va_list ap;
|
nkeynes@362 | 149 | int n;
|
nkeynes@362 | 150 | p += strlen(p);
|
nkeynes@362 | 151 | va_start( ap, format );
|
nkeynes@362 | 152 | n = vsprintf( p, format, ap );
|
nkeynes@362 | 153 | va_end( ap );
|
nkeynes@362 | 154 | return n;
|
nkeynes@362 | 155 | }
|