disas.c 7.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 34 35 36 37 38 39 40 41 42
#if !defined(CONFIG_USER_ONLY)
/* Get LENGTH bytes from info's buffer, at target address memaddr.
   Transfer them to myaddr.  */
static int
target_read_memory (memaddr, myaddr, length, info)
     bfd_vma memaddr;
     bfd_byte *myaddr;
     int length;
     struct disassemble_info *info;
{
    int i;
    for(i = 0; i < length; i++) {
B
bellard 已提交
43
        myaddr[i] = ldub_code((void *)((long)memaddr + i));
44 45 46 47 48
    }
    return 0;
}
#endif

B
bellard 已提交
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
/* 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 已提交
64
			   "Address 0x%llx is out of bounds.\n", memaddr);
B
bellard 已提交
65 66 67 68 69 70 71 72 73 74 75 76 77 78
}

/* 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 已提交
79
  (*info->fprintf_func) (info->stream, "0x%llx", addr);
B
bellard 已提交
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 111 112 113
}

/* 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;
}

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

    INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);

125 126 127 128 129 130
#if !defined(CONFIG_USER_ONLY)
    if (!is_host) {
        disasm_info.read_memory_func = target_read_memory;
    }
#endif

B
bellard 已提交
131 132 133 134
    disasm_info.buffer = code;
    disasm_info.buffer_vma = (unsigned long)code;
    disasm_info.buffer_length = size;

135
    if (is_host) {
B
bellard 已提交
136 137 138 139 140
#ifdef WORDS_BIGENDIAN
	disasm_info.endian = BFD_ENDIAN_BIG;
#else
	disasm_info.endian = BFD_ENDIAN_LITTLE;
#endif
141
#if defined(__i386__)
B
bellard 已提交
142 143
	disasm_info.mach = bfd_mach_i386_i386;
	print_insn = print_insn_i386;
144 145 146
#elif defined(__x86_64__)
	disasm_info.mach = bfd_mach_x86_64;
	print_insn = print_insn_i386;
B
bellard 已提交
147 148
#elif defined(__powerpc__)
	print_insn = print_insn_ppc;
B
bellard 已提交
149 150
#elif defined(__alpha__)
	print_insn = print_insn_alpha;
B
bellard 已提交
151 152 153 154
#elif defined(__sparc__)
	print_insn = print_insn_sparc;
#elif defined(__arm__) 
        print_insn = print_insn_arm;
B
bellard 已提交
155 156 157 158 159
#else
	fprintf(out, "Asm output not supported on this arch\n");
	return;
#endif
    } else {
160 161 162
#ifdef TARGET_WORDS_BIGENDIAN
	disasm_info.endian = BFD_ENDIAN_BIG;
#else
B
bellard 已提交
163
	disasm_info.endian = BFD_ENDIAN_LITTLE;
164 165 166
#endif
#if defined(TARGET_I386)
        if (!flags)
B
bellard 已提交
167 168 169 170
	    disasm_info.mach = bfd_mach_i386_i386;
	else
	    disasm_info.mach = bfd_mach_i386_i8086;
	print_insn = print_insn_i386;
171 172
#elif defined(TARGET_ARM)
	print_insn = print_insn_arm;
173 174
#elif defined(TARGET_SPARC)
	print_insn = print_insn_sparc;
175 176
#elif defined(TARGET_PPC)
	print_insn = print_insn_ppc;
177 178 179 180
#else
	fprintf(out, "Asm output not supported on this arch\n");
	return;
#endif
B
bellard 已提交
181 182 183 184
    }

    for (pc = code; pc < (uint8_t *)code + size; pc += count) {
	fprintf(out, "0x%08lx:  ", (long)pc);
B
bellard 已提交
185 186 187
#ifdef __arm__
        /* since data are included in the code, it is better to
           display code data too */
188
        if (is_host) {
B
bellard 已提交
189 190 191
            fprintf(out, "%08x  ", (int)bfd_getl32((const bfd_byte *)pc));
        }
#endif
B
bellard 已提交
192
	count = print_insn((unsigned long)pc, &disasm_info);
B
bellard 已提交
193 194 195 196 197 198 199 200 201 202 203
	fprintf(out, "\n");
	if (count < 0)
	    break;
    }
}

/* Look up symbol for debugging purpose.  Returns "" if unknown. */
const char *lookup_symbol(void *orig_addr)
{
    unsigned int i;
    /* Hack, because we know this is x86. */
B
bellard 已提交
204 205 206 207 208 209 210 211 212
    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 已提交
213

B
bellard 已提交
214 215
	    if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
		continue;
B
bellard 已提交
216

B
bellard 已提交
217 218 219 220
	    if ((long)orig_addr >= sym[i].st_value
		&& (long)orig_addr < sym[i].st_value + sym[i].st_size)
		return s->disas_strtab + sym[i].st_name;
	}
B
bellard 已提交
221 222 223
    }
    return "";
}
224 225 226

#if !defined(CONFIG_USER_ONLY)

227 228 229
void term_vprintf(const char *fmt, va_list ap);
void term_printf(const char *fmt, ...);

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
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;
}

247 248 249 250 251 252 253 254 255
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;
}

256 257 258 259 260 261
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);

262
    INIT_DISASSEMBLE_INFO(disasm_info, NULL, monitor_fprintf);
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286

    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)
    if (!flags)
        disasm_info.mach = bfd_mach_i386_i386;
    else
        disasm_info.mach = bfd_mach_i386_i8086;
    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 已提交
287
    term_printf("Asm output not supported on this arch\n");
288 289 290 291
    return;
#endif

    for(i = 0; i < nb_insn; i++) {
292
	term_printf("0x%08lx:  ", (unsigned long)pc);
293
	count = print_insn(pc, &disasm_info);
294
	term_printf("\n");
295 296 297 298 299 300
	if (count < 0)
	    break;
        pc += count;
    }
}
#endif