]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/lib/disasm/disasm.c
update
[l4.git] / kernel / fiasco / src / lib / disasm / disasm.c
1
2 #include <malloc.h>
3 #include <stdarg.h>
4 #include <string.h>
5
6 #include "include/dis-asm.h"
7 #include "disasm.h"
8
9 /* local variables */
10 static char *out_buf;
11 static int out_len;
12 static int use_syms;
13 static struct Space *dis_task;
14 static disassemble_info dis_info;
15 static Peek_task dis_peek_task;
16 static Get_symbol dis_get_symbol;
17
18 extern int print_insn_i386 PARAMS ((bfd_vma, disassemble_info*));
19
20 /* read <length> bytes starting at memaddr */
21 static int
22 my_read_memory(bfd_vma memaddr, bfd_byte *myaddr, unsigned length,
23                struct disassemble_info *info __attribute__ ((unused)))
24 {
25   unsigned i;
26
27   for (i=0; i<length; i++)
28     {
29       Mword value;
30       if (dis_peek_task(memaddr+i, dis_task, &value, 1) == -1)
31         return -1;
32       *myaddr++ = (bfd_byte)value;
33     }
34
35   return 0;
36 }
37
38 /* XXX return byte without range check */
39 static unsigned char
40 my_get_data(bfd_vma memaddr)
41 {
42   Mword value;
43   if (dis_peek_task(memaddr, dis_task, &value, 1) == -1)
44     return -1;
45
46   return value;
47 }
48
49 /* print address (using symbols if possible) */
50 static void
51 my_print_address(bfd_vma memaddr, struct disassemble_info *info)
52 {
53   const char *symbol;
54
55   if (use_syms && dis_get_symbol
56       && (symbol = dis_get_symbol(memaddr, dis_task)))
57     {
58       unsigned i;
59       char buf[48];
60       const char *s;
61       
62       buf[0] = ' ';
63       buf[1] = '<';
64       for (i=2, s=symbol; i<(sizeof(buf)-3); )
65         {
66           if (*s=='\0' || *s=='\n')
67             break;
68           buf[i++] = *s++;
69           if (*(s-1)=='(')
70             while ((*s != ')') && (*s != '\n') && (*s != '\0'))
71               s++;
72         }
73       buf[i++] = '>';
74       buf[i++] = '\0';
75
76       (*info->fprintf_func)(info->stream, "%s", buf);
77     }
78 }
79
80 static int
81 my_printf(void* stream __attribute__ ((unused)), const char *format, ...)
82 {
83   if (out_len)
84     {
85       int len;
86       va_list list;
87   
88       va_start(list, format);
89       len = vsnprintf(out_buf, out_len, format, list);
90       if (len >= out_len)
91         len = out_len - 1;
92       out_buf += len;
93       out_len -= len;
94       va_end(list);
95     }
96   
97   return 0;
98 }
99
100 static void
101 my_putchar(int c)
102 {
103   if (out_len)
104     {
105       out_len--;
106       *out_buf++ = c;
107     }
108 }
109
110 /* check for special L4 int3-opcodes */
111 static int
112 special_l4_ops(bfd_vma memaddr)
113 {
114   int len, bytes, i;
115   const char *op;
116   bfd_vma str, s;
117   
118   switch (my_get_data(memaddr))
119     {
120     case 0xeb:
121       op  = "enter_kdebug";
122       len = my_get_data(memaddr+1);
123       str = memaddr+2;
124       bytes = 3+len;
125       goto printstr;
126     case 0x90:
127       if (my_get_data(memaddr+1) != 0xeb)
128         break;
129       op  = "kd_display";
130       len = my_get_data(memaddr+2);
131       str = memaddr+3;
132       bytes = 4+len;
133     printstr:
134       /* do a quick test if it is really an int3-str function by
135        * analyzing the bytes we shall display. */
136       for (i=len, s=str; i--; )
137         if (my_get_data(s++) > 126)
138           return 0;
139       /* test well done */
140       my_printf(0, "<%s (\"", op);
141       if ((out_len > 2) && (len > 0))
142         {
143           out_len -= 3;
144           if (out_len > len)
145             out_len = len;
146           /* do not use my_printf here because the string
147            * can contain special characters (e.g. tabs) which 
148            * we do not want to display */
149           while (out_len)
150             {
151               unsigned char c = my_get_data(str++);
152               my_putchar((c<' ') ? ' ' : c);
153             }
154           out_len += 3;
155         }
156       my_printf(0, "\")>");
157       return bytes;
158     case 0x3c:
159       op = NULL;
160       switch (my_get_data(memaddr+1))
161         {
162         case 0: op = "outchar (%al)";  break;
163         case 2: op = "outstring (*%eax)"; break;
164         case 5: op = "outhex32 (%eax)"; break;
165         case 6: op = "outhex20 (%eax)"; break;
166         case 7: op = "outhex16 (%eax)"; break;
167         case 8: op = "outhex12 (%eax)"; break;
168         case 9: op = "outhex8 (%al)"; break;
169         case 11: op = "outdec (%eax)"; break;
170         case 13: op = "%al = inchar ()"; break;
171         case 24: op = "fiasco_start_profile()"; break;
172         case 25: op = "fiasco_stop_and_dump()"; break;
173         case 26: op = "fiasco_stop_profile()"; break;
174         case 29: op = "fiasco_tbuf (%eax)"; break;
175         case 30: op = "fiasco_register (%eax, %ecx)"; break;
176         }
177       if (op)
178         my_printf(0, "<%s>", op);
179       else if (my_get_data(memaddr+1) >= ' ')
180         my_printf(0, "<ko ('%c')>", my_get_data(memaddr+1));
181       else break;
182       return 3;
183     }
184
185   return 0;
186 }
187
188 /* WARNING: This function is not reentrant because it accesses some
189  * global static variables (out_buf, out_len, dis_task, ...) */
190 unsigned int
191 disasm_bytes(char *buffer, unsigned len, Address addr,
192              struct Space *task, int show_symbols, int show_intel_syntax,
193              Peek_task peek_task, Get_symbol get_symbol)
194 {
195   use_syms       = show_symbols;
196   out_buf        = buffer;
197   out_len        = len;
198   dis_task       = task;
199   dis_peek_task  = peek_task;
200   dis_get_symbol = get_symbol;
201
202   /* terminate string */
203   if (out_len)
204     out_buf[--out_len] = '\0';
205
206   /* test for special L4 opcodes */
207   if (my_get_data(addr) == 0xcc && (len = special_l4_ops(addr+1)))
208     return len;
209
210   /* one step back for special L4 opcodes */
211   if (my_get_data(addr-1) == 0xcc && (len = special_l4_ops(addr)))
212     return len-1;
213
214   INIT_DISASSEMBLE_INFO(dis_info, NULL, my_printf);
215   
216   dis_info.print_address_func = my_print_address;
217   dis_info.read_memory_func = my_read_memory;
218   dis_info.buffer = (bfd_byte*)addr;
219   dis_info.buffer_length = 99; /* XXX */
220   dis_info.buffer_vma = addr;
221 #if defined CONFIG_ARM
222   dis_info.mach = bfd_mach_arm_5;
223 #elif defined CONFIG_PPC32
224   dis_info.mach = bfd_mach_ppc_ec603e;
225   (void)show_intel_syntax;
226 #elif defined CONFIG_IA32
227   dis_info.mach = show_intel_syntax ? bfd_mach_i386_i386_intel_syntax
228                                     : bfd_mach_i386_i386;
229 #else
230   dis_info.mach = show_intel_syntax ? bfd_mach_x86_64_intel_syntax
231                                     : bfd_mach_x86_64;
232 #endif
233
234
235 #if defined CONFIG_ARM
236   return print_insn_little_arm (addr, &dis_info);
237 #elif defined CONFIG_PPC32
238   return print_insn_big_powerpc(addr, &dis_info);
239 #else
240   return print_insn_i386 (addr, &dis_info);
241 #endif
242 }