disas.c 8.5 KB
Newer Older
B
bellard 已提交
1
/* General "disassemble this chunk" code.  Used for debugging. */
B
bellard 已提交
2
#include "config.h"
B
bellard 已提交
3 4
#include "dis-asm.h"
#include "elf.h"
B
bellard 已提交
5
#include <errno.h>
B
bellard 已提交
6

7 8
#include "cpu.h"
#include "exec-all.h"
9
#include "disas.h"
10

B
bellard 已提交
11
/* Filled in by elfload.c.  Simplistic, but will do for now. */
B
bellard 已提交
12
struct syminfo *syminfos = NULL;
B
bellard 已提交
13

B
bellard 已提交
14 15 16 17 18 19 20 21 22
/* Get LENGTH bytes from info's buffer, at target address memaddr.
   Transfer them to myaddr.  */
int
buffer_read_memory (memaddr, myaddr, length, info)
     bfd_vma memaddr;
     bfd_byte *myaddr;
     int length;
     struct disassemble_info *info;
{
23 24 25 26 27 28
    if (memaddr < info->buffer_vma
        || memaddr + length > info->buffer_vma + info->buffer_length)
        /* Out of bounds.  Use EIO because GDB uses it.  */
        return EIO;
    memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
    return 0;
B
bellard 已提交
29 30
}

31 32 33
/* Get LENGTH bytes from info's buffer, at target address memaddr.
   Transfer them to myaddr.  */
static int
B
bellard 已提交
34 35 36 37
target_read_memory (bfd_vma memaddr,
                    bfd_byte *myaddr,
                    int length,
                    struct disassemble_info *info)
38 39 40
{
    int i;
    for(i = 0; i < length; i++) {
B
bellard 已提交
41
        myaddr[i] = ldub_code(memaddr + i);
42 43 44 45
    }
    return 0;
}

B
bellard 已提交
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
/* Print an error message.  We can assume that this is in response to
   an error return from buffer_read_memory.  */
void
perror_memory (status, memaddr, info)
     int status;
     bfd_vma memaddr;
     struct disassemble_info *info;
{
  if (status != EIO)
    /* Can't happen.  */
    (*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
  else
    /* Actually, address between memaddr and memaddr + len was
       out of bounds.  */
    (*info->fprintf_func) (info->stream,
B
bellard 已提交
61
			   "Address 0x%llx is out of bounds.\n", memaddr);
B
bellard 已提交
62 63 64 65 66 67 68 69 70 71 72 73 74 75
}

/* This could be in a separate file, to save miniscule amounts of space
   in statically linked executables.  */

/* Just print the address is hex.  This is included for completeness even
   though both GDB and objdump provide their own (to print symbolic
   addresses).  */

void
generic_print_address (addr, info)
     bfd_vma addr;
     struct disassemble_info *info;
{
B
bellard 已提交
76
  (*info->fprintf_func) (info->stream, "0x%llx", addr);
B
bellard 已提交
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
}

/* Just return the given address.  */

int
generic_symbol_at_address (addr, info)
     bfd_vma addr;
     struct disassemble_info * info;
{
  return 1;
}

bfd_vma bfd_getl32 (const bfd_byte *addr)
{
  unsigned long v;

  v = (unsigned long) addr[0];
  v |= (unsigned long) addr[1] << 8;
  v |= (unsigned long) addr[2] << 16;
  v |= (unsigned long) addr[3] << 24;
  return (bfd_vma) v;
}

bfd_vma bfd_getb32 (const bfd_byte *addr)
{
  unsigned long v;

  v = (unsigned long) addr[0] << 24;
  v |= (unsigned long) addr[1] << 16;
  v |= (unsigned long) addr[2] << 8;
  v |= (unsigned long) addr[3];
  return (bfd_vma) v;
}

111 112
/* Disassemble this for me please... (debugging). 'flags' is only used
   for i386: non zero means 16 bit code */
113
void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
B
bellard 已提交
114
{
B
bellard 已提交
115
    target_ulong pc;
B
bellard 已提交
116 117 118 119 120 121
    int count;
    struct disassemble_info disasm_info;
    int (*print_insn)(bfd_vma pc, disassemble_info *info);

    INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);

B
bellard 已提交
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
    disasm_info.read_memory_func = target_read_memory;
    disasm_info.buffer_vma = code;
    disasm_info.buffer_length = size;

#ifdef TARGET_WORDS_BIGENDIAN
    disasm_info.endian = BFD_ENDIAN_BIG;
#else
    disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
#if defined(TARGET_I386)
    if (flags == 2)
        disasm_info.mach = bfd_mach_x86_64;
    else if (flags == 1) 
        disasm_info.mach = bfd_mach_i386_i8086;
    else
        disasm_info.mach = bfd_mach_i386_i386;
    print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
    print_insn = print_insn_arm;
#elif defined(TARGET_SPARC)
    print_insn = print_insn_sparc;
#elif defined(TARGET_PPC)
144 145
    if (cpu_single_env->msr[MSR_LE])
        disasm_info.endian = BFD_ENDIAN_LITTLE;
B
bellard 已提交
146 147
    print_insn = print_insn_ppc;
#else
B
bellard 已提交
148 149
    fprintf(out, "0x" TARGET_FMT_lx
	    ": Asm output not supported on this arch\n", code);
B
bellard 已提交
150
    return;
151 152
#endif

B
bellard 已提交
153
    for (pc = code; pc < code + size; pc += count) {
B
bellard 已提交
154
	fprintf(out, "0x" TARGET_FMT_lx ":  ", pc);
B
bellard 已提交
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
	count = print_insn(pc, &disasm_info);
#if 0
        {
            int i;
            uint8_t b;
            fprintf(out, " {");
            for(i = 0; i < count; i++) {
                target_read_memory(pc + i, &b, 1, &disasm_info);
                fprintf(out, " %02x", b);
            }
            fprintf(out, " }");
        }
#endif
	fprintf(out, "\n");
	if (count < 0)
	    break;
    }
}

/* Disassemble this for me please... (debugging). */
void disas(FILE *out, void *code, unsigned long size)
{
    unsigned long pc;
    int count;
    struct disassemble_info disasm_info;
    int (*print_insn)(bfd_vma pc, disassemble_info *info);

    INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);

B
bellard 已提交
184 185 186 187 188
    disasm_info.buffer = code;
    disasm_info.buffer_vma = (unsigned long)code;
    disasm_info.buffer_length = size;

#ifdef WORDS_BIGENDIAN
B
bellard 已提交
189
    disasm_info.endian = BFD_ENDIAN_BIG;
B
bellard 已提交
190
#else
B
bellard 已提交
191
    disasm_info.endian = BFD_ENDIAN_LITTLE;
B
bellard 已提交
192
#endif
193
#if defined(__i386__)
B
bellard 已提交
194 195
    disasm_info.mach = bfd_mach_i386_i386;
    print_insn = print_insn_i386;
196
#elif defined(__x86_64__)
B
bellard 已提交
197 198
    disasm_info.mach = bfd_mach_x86_64;
    print_insn = print_insn_i386;
B
bellard 已提交
199
#elif defined(__powerpc__)
B
bellard 已提交
200
    print_insn = print_insn_ppc;
B
bellard 已提交
201
#elif defined(__alpha__)
B
bellard 已提交
202
    print_insn = print_insn_alpha;
B
bellard 已提交
203
#elif defined(__sparc__)
B
bellard 已提交
204
    print_insn = print_insn_sparc;
B
bellard 已提交
205
#elif defined(__arm__) 
B
bellard 已提交
206
    print_insn = print_insn_arm;
B
bellard 已提交
207
#else
B
bellard 已提交
208 209
    fprintf(out, "0x%lx: Asm output not supported on this arch\n",
	    (long) code);
B
bellard 已提交
210
    return;
B
bellard 已提交
211
#endif
B
bellard 已提交
212 213
    for (pc = (unsigned long)code; pc < (unsigned long)code + size; pc += count) {
	fprintf(out, "0x%08lx:  ", pc);
B
bellard 已提交
214 215 216
#ifdef __arm__
        /* since data are included in the code, it is better to
           display code data too */
217
        if (is_host) {
B
bellard 已提交
218 219 220
            fprintf(out, "%08x  ", (int)bfd_getl32((const bfd_byte *)pc));
        }
#endif
B
bellard 已提交
221
	count = print_insn(pc, &disasm_info);
B
bellard 已提交
222 223 224 225 226 227 228
	fprintf(out, "\n");
	if (count < 0)
	    break;
    }
}

/* Look up symbol for debugging purpose.  Returns "" if unknown. */
B
bellard 已提交
229
const char *lookup_symbol(target_ulong orig_addr)
B
bellard 已提交
230 231 232
{
    unsigned int i;
    /* Hack, because we know this is x86. */
B
bellard 已提交
233 234 235 236 237 238 239 240 241
    Elf32_Sym *sym;
    struct syminfo *s;
    
    for (s = syminfos; s; s = s->next) {
	sym = s->disas_symtab;
	for (i = 0; i < s->disas_num_syms; i++) {
	    if (sym[i].st_shndx == SHN_UNDEF
		|| sym[i].st_shndx >= SHN_LORESERVE)
		continue;
B
bellard 已提交
242

B
bellard 已提交
243 244
	    if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
		continue;
B
bellard 已提交
245

B
bellard 已提交
246 247
	    if (orig_addr >= sym[i].st_value
		&& orig_addr < sym[i].st_value + sym[i].st_size)
B
bellard 已提交
248 249
		return s->disas_strtab + sym[i].st_name;
	}
B
bellard 已提交
250 251 252
    }
    return "";
}
253 254 255

#if !defined(CONFIG_USER_ONLY)

256 257 258
void term_vprintf(const char *fmt, va_list ap);
void term_printf(const char *fmt, ...);

259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
static int monitor_disas_is_physical;

static int
monitor_read_memory (memaddr, myaddr, length, info)
     bfd_vma memaddr;
     bfd_byte *myaddr;
     int length;
     struct disassemble_info *info;
{
    if (monitor_disas_is_physical) {
        cpu_physical_memory_rw(memaddr, myaddr, length, 0);
    } else {
        cpu_memory_rw_debug(cpu_single_env, memaddr,myaddr, length, 0);
    }
    return 0;
}

276 277 278 279 280 281 282 283 284
static int monitor_fprintf(FILE *stream, const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    term_vprintf(fmt, ap);
    va_end(ap);
    return 0;
}

285 286 287 288 289 290
void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
{
    int count, i;
    struct disassemble_info disasm_info;
    int (*print_insn)(bfd_vma pc, disassemble_info *info);

291
    INIT_DISASSEMBLE_INFO(disasm_info, NULL, monitor_fprintf);
292 293 294 295 296 297 298 299 300 301 302 303

    monitor_disas_is_physical = is_physical;
    disasm_info.read_memory_func = monitor_read_memory;

    disasm_info.buffer_vma = pc;

#ifdef TARGET_WORDS_BIGENDIAN
    disasm_info.endian = BFD_ENDIAN_BIG;
#else
    disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
#if defined(TARGET_I386)
B
bellard 已提交
304 305 306
    if (flags == 2)
        disasm_info.mach = bfd_mach_x86_64;
    else if (flags == 1) 
307
        disasm_info.mach = bfd_mach_i386_i8086;
B
bellard 已提交
308 309
    else
        disasm_info.mach = bfd_mach_i386_i386;
310 311 312 313 314 315 316 317
    print_insn = print_insn_i386;
#elif defined(TARGET_ARM)
    print_insn = print_insn_arm;
#elif defined(TARGET_SPARC)
    print_insn = print_insn_sparc;
#elif defined(TARGET_PPC)
    print_insn = print_insn_ppc;
#else
B
bellard 已提交
318 319
    term_printf("0x" TARGET_FMT_lx
		": Asm output not supported on this arch\n", pc);
320 321 322 323
    return;
#endif

    for(i = 0; i < nb_insn; i++) {
B
bellard 已提交
324
	term_printf("0x" TARGET_FMT_lx ":  ", pc);
325
	count = print_insn(pc, &disasm_info);
326
	term_printf("\n");
327 328 329 330 331 332
	if (count < 0)
	    break;
        pc += count;
    }
}
#endif