filename | src/x86dasm/x86dasm.c |
changeset | 1091:186558374345 |
prev | 1087:d54c499b48c7 |
next | 1092:7c4ffe27e7b5 |
author | nkeynes |
date | Tue Dec 15 08:46:37 2009 +1000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Add side-by-side x86+sh4 disassembly output Print SH4 state information and disassembly of the current block when crashing. Fix delay slot instruction in conditional branch not being marked as a delay-slot instruction in the branch-not-taken path. Rename REG_* defines in cpu.h to avoid conflict with translation defs |
file | annotate | diff | log | raw |
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@755 | 22 | #include "x86dasm/x86dasm.h" |
nkeynes@755 | 23 | #include "x86dasm/bfd.h" |
nkeynes@755 | 24 | #include "x86dasm/dis-asm.h" |
nkeynes@564 | 25 | #include "sh4/sh4.h" |
nkeynes@527 | 26 | #include "sh4/sh4trans.h" |
nkeynes@362 | 27 | |
nkeynes@362 | 28 | const struct cpu_desc_struct x86_cpu_desc = |
nkeynes@755 | 29 | { "x86", (disasm_func_t)x86_disasm_instruction, NULL, mem_has_page, |
nkeynes@1026 | 30 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1, |
nkeynes@1026 | 31 | NULL, 0, NULL, 0, 0, |
nkeynes@362 | 32 | &sh4r.pc }; |
nkeynes@362 | 33 | |
nkeynes@362 | 34 | static int x86_disasm_output( void *data, const char *format, ... ); |
nkeynes@429 | 35 | static void x86_print_address( bfd_vma memaddr, struct disassemble_info *info ); |
nkeynes@362 | 36 | |
nkeynes@362 | 37 | static struct disassemble_info x86_disasm_info; |
nkeynes@362 | 38 | |
nkeynes@365 | 39 | static x86_symbol *x86_symtab; |
nkeynes@365 | 40 | static int x86_num_symbols = 0; |
nkeynes@365 | 41 | |
nkeynes@1087 | 42 | void xlat_dump_block( void *block ) |
nkeynes@1087 | 43 | { |
nkeynes@1087 | 44 | xlat_disasm_block( stderr, block ); |
nkeynes@1087 | 45 | } |
nkeynes@515 | 46 | |
nkeynes@515 | 47 | void xlat_disasm_block( FILE *out, void *block ) |
nkeynes@515 | 48 | { |
nkeynes@571 | 49 | uint32_t buflen = xlat_get_code_size(block); |
nkeynes@515 | 50 | x86_set_symtab( NULL, 0 ); |
nkeynes@515 | 51 | x86_disasm_block( out, block, buflen ); |
nkeynes@515 | 52 | } |
nkeynes@515 | 53 | |
nkeynes@376 | 54 | void x86_disasm_block(FILE *out, void *start, uint32_t len) |
nkeynes@376 | 55 | { |
nkeynes@527 | 56 | uintptr_t start_addr = (uintptr_t)start; |
nkeynes@925 | 57 | uintptr_t pc; |
nkeynes@376 | 58 | x86_disasm_init( start, start_addr, len ); |
nkeynes@376 | 59 | for( pc = start_addr; pc < start_addr + len; ) { |
nkeynes@376 | 60 | char buf[256]; |
nkeynes@376 | 61 | char op[256]; |
nkeynes@925 | 62 | uintptr_t pc2 = x86_disasm_instruction( pc, buf, sizeof(buf), op ); |
nkeynes@968 | 63 | fprintf( out, "%08X: %-20s %s\n", (unsigned int)pc, op, buf ); |
nkeynes@376 | 64 | pc = pc2; |
nkeynes@376 | 65 | } |
nkeynes@376 | 66 | } |
nkeynes@376 | 67 | |
nkeynes@1091 | 68 | void x86_disasm_init() |
nkeynes@362 | 69 | { |
nkeynes@362 | 70 | init_disassemble_info( &x86_disasm_info, NULL, x86_disasm_output ); |
nkeynes@362 | 71 | x86_disasm_info.arch = bfd_arch_i386; |
nkeynes@925 | 72 | #if SIZEOF_VOID_P == 8 |
nkeynes@527 | 73 | x86_disasm_info.mach = bfd_mach_x86_64_intel_syntax; |
nkeynes@527 | 74 | #else |
nkeynes@362 | 75 | x86_disasm_info.mach = bfd_mach_i386_i386_intel_syntax; |
nkeynes@527 | 76 | #endif |
nkeynes@362 | 77 | x86_disasm_info.endian = BFD_ENDIAN_LITTLE; |
nkeynes@1091 | 78 | x86_disasm_info.buffer = 0; |
nkeynes@1091 | 79 | x86_disasm_info.buffer_vma = 0; |
nkeynes@1091 | 80 | x86_disasm_info.buffer_length = -1; |
nkeynes@365 | 81 | x86_disasm_info.print_address_func = x86_print_address; |
nkeynes@362 | 82 | } |
nkeynes@362 | 83 | |
nkeynes@365 | 84 | void x86_set_symtab( x86_symbol *symtab, int num_symbols ) |
nkeynes@365 | 85 | { |
nkeynes@365 | 86 | x86_symtab = symtab; |
nkeynes@365 | 87 | x86_num_symbols = num_symbols; |
nkeynes@365 | 88 | } |
nkeynes@365 | 89 | |
nkeynes@365 | 90 | static const char *x86_find_symbol( bfd_vma memaddr, struct disassemble_info *info ) |
nkeynes@365 | 91 | { |
nkeynes@365 | 92 | int i; |
nkeynes@365 | 93 | for( i=0; i<x86_num_symbols; i++ ) { |
nkeynes@527 | 94 | if( x86_symtab[i].ptr == (void *)(uintptr_t)memaddr ) { |
nkeynes@365 | 95 | return x86_symtab[i].name; |
nkeynes@365 | 96 | } |
nkeynes@365 | 97 | } |
nkeynes@365 | 98 | return NULL; |
nkeynes@365 | 99 | } |
nkeynes@365 | 100 | |
nkeynes@429 | 101 | static void x86_print_address( bfd_vma memaddr, struct disassemble_info *info ) |
nkeynes@365 | 102 | { |
nkeynes@365 | 103 | const char *sym = x86_find_symbol(memaddr, info); |
nkeynes@365 | 104 | info->fprintf_func( info->stream, "%08X", memaddr ); |
nkeynes@365 | 105 | if( sym != NULL ) { |
nkeynes@365 | 106 | info->fprintf_func( info->stream, " <%s>", sym ); |
nkeynes@365 | 107 | } |
nkeynes@365 | 108 | } |
nkeynes@362 | 109 | |
nkeynes@920 | 110 | void x86_print_symbolic_operand( char *buf, int hex, unsigned int disp ) |
nkeynes@920 | 111 | { |
nkeynes@920 | 112 | const char *sym = x86_find_symbol(disp, NULL); |
nkeynes@920 | 113 | if( sym != NULL ) { |
nkeynes@920 | 114 | snprintf( buf, 50, "<%s>", sym ); |
nkeynes@920 | 115 | } else if( hex ) { |
nkeynes@920 | 116 | sprintf( buf, "0x%x", disp ); |
nkeynes@920 | 117 | } else { |
nkeynes@920 | 118 | sprintf( buf, "%d", (int)disp ); |
nkeynes@920 | 119 | } |
nkeynes@920 | 120 | } |
nkeynes@920 | 121 | |
nkeynes@925 | 122 | uintptr_t x86_disasm_instruction( uintptr_t pc, char *buf, int len, char *opcode ) |
nkeynes@362 | 123 | { |
nkeynes@362 | 124 | int count, i; |
nkeynes@362 | 125 | |
nkeynes@362 | 126 | x86_disasm_info.stream = buf; |
nkeynes@362 | 127 | buf[0] = 0; |
nkeynes@362 | 128 | count = print_insn_i386_att( pc, &x86_disasm_info ); |
nkeynes@362 | 129 | if( count != 0 ) { |
nkeynes@429 | 130 | unsigned char tmp[count]; |
nkeynes@362 | 131 | x86_disasm_info.read_memory_func( pc, tmp, count, &x86_disasm_info ); |
nkeynes@362 | 132 | for( i=0; i<count; i++ ) { |
nkeynes@362 | 133 | sprintf( opcode, "%02X ", ((unsigned int)tmp[i])&0xFF ); |
nkeynes@362 | 134 | opcode += 3; |
nkeynes@362 | 135 | } |
nkeynes@362 | 136 | *(opcode-1) = '\0'; |
nkeynes@362 | 137 | } |
nkeynes@362 | 138 | return pc + count; |
nkeynes@362 | 139 | } |
nkeynes@362 | 140 | |
nkeynes@362 | 141 | int x86_disasm_output( void *data, const char *format, ... ) |
nkeynes@362 | 142 | { |
nkeynes@362 | 143 | char *p = (char *)data; |
nkeynes@362 | 144 | va_list ap; |
nkeynes@362 | 145 | int n; |
nkeynes@362 | 146 | p += strlen(p); |
nkeynes@362 | 147 | va_start( ap, format ); |
nkeynes@362 | 148 | n = vsprintf( p, format, ap ); |
nkeynes@362 | 149 | va_end( ap ); |
nkeynes@362 | 150 | return n; |
nkeynes@362 | 151 | } |
.