disas.c 5.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 5
#include "dis-asm.h"
#include "disas.h"
#include "elf.h"
B
bellard 已提交
6
#include <errno.h>
B
bellard 已提交
7

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

B
bellard 已提交
11 12 13 14 15
/* Filled in by elfload.c.  Simplistic, but will do for now. */
unsigned int disas_num_syms;
void *disas_symtab;
const char *disas_strtab;

B
bellard 已提交
16 17 18 19 20 21 22 23 24
/* 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;
{
25 26 27 28 29 30
    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 已提交
31 32
}

33 34 35 36 37 38 39 40 41 42 43 44
#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 已提交
45
        myaddr[i] = ldub_code((void *)((long)memaddr + i));
46 47 48 49 50
    }
    return 0;
}
#endif

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

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

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

116 117 118
/* 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 已提交
119 120 121 122 123 124 125 126
{
    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);

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

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

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

    for (pc = code; pc < (uint8_t *)code + size; pc += count) {
	fprintf(out, "0x%08lx:  ", (long)pc);
B
bellard 已提交
184 185 186
#ifdef __arm__
        /* since data are included in the code, it is better to
           display code data too */
187
        if (is_host) {
B
bellard 已提交
188 189 190
            fprintf(out, "%08x  ", (int)bfd_getl32((const bfd_byte *)pc));
        }
#endif
B
bellard 已提交
191
	count = print_insn((unsigned long)pc, &disasm_info);
B
bellard 已提交
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
	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. */
    Elf32_Sym *sym = disas_symtab;

    for (i = 0; i < disas_num_syms; i++) {
	if (sym[i].st_shndx == SHN_UNDEF
	    || sym[i].st_shndx >= SHN_LORESERVE)
	    continue;

	if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
	    continue;

	if ((long)orig_addr >= sym[i].st_value
	    && (long)orig_addr < sym[i].st_value + sym[i].st_size)
	    return disas_strtab + sym[i].st_name;
    }
    return "";
}