Statistics
| Branch: | Revision:

root / disas.c @ 93ac68bc

History | View | Annotate | Download (4.9 kB)

1
/* General "disassemble this chunk" code.  Used for debugging. */
2
#include "config.h"
3
#include "dis-asm.h"
4
#include "disas.h"
5
#include "elf.h"
6
#include <errno.h>
7

    
8
/* Filled in by elfload.c.  Simplistic, but will do for now. */
9
unsigned int disas_num_syms;
10
void *disas_symtab;
11
const char *disas_strtab;
12

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

    
30
/* Print an error message.  We can assume that this is in response to
31
   an error return from buffer_read_memory.  */
32
void
33
perror_memory (status, memaddr, info)
34
     int status;
35
     bfd_vma memaddr;
36
     struct disassemble_info *info;
37
{
38
  if (status != EIO)
39
    /* Can't happen.  */
40
    (*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
41
  else
42
    /* Actually, address between memaddr and memaddr + len was
43
       out of bounds.  */
44
    (*info->fprintf_func) (info->stream,
45
                           "Address 0x%llx is out of bounds.\n", memaddr);
46
}
47

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

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

    
55
void
56
generic_print_address (addr, info)
57
     bfd_vma addr;
58
     struct disassemble_info *info;
59
{
60
  (*info->fprintf_func) (info->stream, "0x%llx", addr);
61
}
62

    
63
/* Just return the given address.  */
64

    
65
int
66
generic_symbol_at_address (addr, info)
67
     bfd_vma addr;
68
     struct disassemble_info * info;
69
{
70
  return 1;
71
}
72

    
73
bfd_vma bfd_getl32 (const bfd_byte *addr)
74
{
75
  unsigned long v;
76

    
77
  v = (unsigned long) addr[0];
78
  v |= (unsigned long) addr[1] << 8;
79
  v |= (unsigned long) addr[2] << 16;
80
  v |= (unsigned long) addr[3] << 24;
81
  return (bfd_vma) v;
82
}
83

    
84
bfd_vma bfd_getb32 (const bfd_byte *addr)
85
{
86
  unsigned long v;
87

    
88
  v = (unsigned long) addr[0] << 24;
89
  v |= (unsigned long) addr[1] << 16;
90
  v |= (unsigned long) addr[2] << 8;
91
  v |= (unsigned long) addr[3];
92
  return (bfd_vma) v;
93
}
94

    
95
/* Disassemble this for me please... (debugging). 'flags' is only used
96
   for i386: non zero means 16 bit code */
97
void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
98
{
99
    uint8_t *pc;
100
    int count;
101
    struct disassemble_info disasm_info;
102
    int (*print_insn)(bfd_vma pc, disassemble_info *info);
103

    
104
    INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
105

    
106
    disasm_info.buffer = code;
107
    disasm_info.buffer_vma = (unsigned long)code;
108
    disasm_info.buffer_length = size;
109

    
110
    if (is_host) {
111
#ifdef WORDS_BIGENDIAN
112
        disasm_info.endian = BFD_ENDIAN_BIG;
113
#else
114
        disasm_info.endian = BFD_ENDIAN_LITTLE;
115
#endif
116
#ifdef __i386__
117
        disasm_info.mach = bfd_mach_i386_i386;
118
        print_insn = print_insn_i386;
119
#elif defined(__powerpc__)
120
        print_insn = print_insn_ppc;
121
#elif defined(__alpha__)
122
        print_insn = print_insn_alpha;
123
#elif defined(__sparc__)
124
        print_insn = print_insn_sparc;
125
#elif defined(__arm__) 
126
        print_insn = print_insn_arm;
127
#else
128
        fprintf(out, "Asm output not supported on this arch\n");
129
        return;
130
#endif
131
    } else {
132
#ifdef TARGET_WORDS_BIGENDIAN
133
        disasm_info.endian = BFD_ENDIAN_BIG;
134
#else
135
        disasm_info.endian = BFD_ENDIAN_LITTLE;
136
#endif
137
#if defined(TARGET_I386)
138
        if (!flags)
139
            disasm_info.mach = bfd_mach_i386_i386;
140
        else
141
            disasm_info.mach = bfd_mach_i386_i8086;
142
        print_insn = print_insn_i386;
143
#elif defined(TARGET_ARM)
144
        print_insn = print_insn_arm;
145
#elif defined(TARGET_SPARC)
146
        print_insn = print_insn_sparc;
147
#else
148
        fprintf(out, "Asm output not supported on this arch\n");
149
        return;
150
#endif
151
    }
152

    
153
    for (pc = code; pc < (uint8_t *)code + size; pc += count) {
154
        fprintf(out, "0x%08lx:  ", (long)pc);
155
#ifdef __arm__
156
        /* since data are included in the code, it is better to
157
           display code data too */
158
        if (is_host) {
159
            fprintf(out, "%08x  ", (int)bfd_getl32((const bfd_byte *)pc));
160
        }
161
#endif
162
        count = print_insn((unsigned long)pc, &disasm_info);
163
        fprintf(out, "\n");
164
        if (count < 0)
165
            break;
166
    }
167
}
168

    
169
/* Look up symbol for debugging purpose.  Returns "" if unknown. */
170
const char *lookup_symbol(void *orig_addr)
171
{
172
    unsigned int i;
173
    /* Hack, because we know this is x86. */
174
    Elf32_Sym *sym = disas_symtab;
175

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

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

    
184
        if ((long)orig_addr >= sym[i].st_value
185
            && (long)orig_addr < sym[i].st_value + sym[i].st_size)
186
            return disas_strtab + sym[i].st_name;
187
    }
188
    return "";
189
}