b69b86f8bef383573c5563959e3a203f619b781c
[coreboot.git] / util / vgabios / x86emu / src / x86emu / debug.c
1 /****************************************************************************
2 *
3 *                       Realmode X86 Emulator Library
4 *
5 *               Copyright (C) 1991-2004 SciTech Software, Inc.
6 *                    Copyright (C) David Mosberger-Tang
7 *                      Copyright (C) 1999 Egbert Eich
8 *
9 *  ========================================================================
10 *
11 *  Permission to use, copy, modify, distribute, and sell this software and
12 *  its documentation for any purpose is hereby granted without fee,
13 *  provided that the above copyright notice appear in all copies and that
14 *  both that copyright notice and this permission notice appear in
15 *  supporting documentation, and that the name of the authors not be used
16 *  in advertising or publicity pertaining to distribution of the software
17 *  without specific, written prior permission.  The authors makes no
18 *  representations about the suitability of this software for any purpose.
19 *  It is provided "as is" without express or implied warranty.
20 *
21 *  THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
22 *  INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
23 *  EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
24 *  CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
25 *  USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
26 *  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
27 *  PERFORMANCE OF THIS SOFTWARE.
28 *
29 *  ========================================================================
30 *
31 * Language:     ANSI C
32 * Environment:  Any
33 * Developer:    Kendall Bennett
34 *
35 * Description:  This file contains the code to handle debugging of the
36 *               emulator.
37 *
38 ****************************************************************************/
39
40 #include "x86emu/x86emui.h"
41 #include <stdarg.h>
42
43 /*----------------------------- Implementation ----------------------------*/
44
45 #ifdef DEBUG
46
47 static void     print_encoded_bytes (u16 s, u16 o);
48 static void     print_decoded_instruction (void);
49 static int      parse_line (char *s, int *ps, int *n);
50
51 /* should look something like debug's output. */
52 void X86EMU_trace_regs (void)
53 {
54     if (DEBUG_TRACE()) {
55         x86emu_dump_regs();
56     }
57     if (DEBUG_DECODE() && ! DEBUG_DECODE_NOPRINT()) {
58         printk("%04x:%04x ",M.x86.saved_cs, M.x86.saved_ip);
59         print_encoded_bytes( M.x86.saved_cs, M.x86.saved_ip);
60         print_decoded_instruction();
61     }
62 }
63
64 void X86EMU_trace_xregs (void)
65 {
66     if (DEBUG_TRACE()) {
67         x86emu_dump_xregs();
68     }
69 }
70
71 void x86emu_just_disassemble (void)
72 {
73     /*
74      * This routine called if the flag DEBUG_DISASSEMBLE is set kind
75      * of a hack!
76      */
77     printk("%04x:%04x ",M.x86.saved_cs, M.x86.saved_ip);
78     print_encoded_bytes( M.x86.saved_cs, M.x86.saved_ip);
79     print_decoded_instruction();
80 }
81
82 static void disassemble_forward (u16 seg, u16 off, int n)
83 {
84     X86EMU_sysEnv tregs;
85     int i;
86     u8 op1;
87     /*
88      * hack, hack, hack.  What we do is use the exact machinery set up
89      * for execution, except that now there is an additional state
90      * flag associated with the "execution", and we are using a copy
91      * of the register struct.  All the major opcodes, once fully
92      * decoded, have the following two steps: TRACE_REGS(r,m);
93      * SINGLE_STEP(r,m); which disappear if DEBUG is not defined to
94      * the preprocessor.  The TRACE_REGS macro expands to:
95      *
96      * if (debug&DEBUG_DISASSEMBLE)
97      *     {just_disassemble(); goto EndOfInstruction;}
98      *     if (debug&DEBUG_TRACE) trace_regs(r,m);
99      *
100      * ......  and at the last line of the routine.
101      *
102      * EndOfInstruction: end_instr();
103      *
104      * Up to the point where TRACE_REG is expanded, NO modifications
105      * are done to any register EXCEPT the IP register, for fetch and
106      * decoding purposes.
107      *
108      * This was done for an entirely different reason, but makes a
109      * nice way to get the system to help debug codes.
110      */
111     tregs = M;
112     tregs.x86.R_IP = off;
113     tregs.x86.R_CS = seg;
114
115     /* reset the decoding buffers */
116     tregs.x86.enc_str_pos = 0;
117     tregs.x86.enc_pos = 0;
118
119     /* turn on the "disassemble only, no execute" flag */
120     tregs.x86.debug |= DEBUG_DISASSEMBLE_F;
121
122     /* DUMP NEXT n instructions to screen in straight_line fashion */
123     /*
124      * This looks like the regular instruction fetch stream, except
125      * that when this occurs, each fetched opcode, upon seeing the
126      * DEBUG_DISASSEMBLE flag set, exits immediately after decoding
127      * the instruction.  XXX --- CHECK THAT MEM IS NOT AFFECTED!!!
128      * Note the use of a copy of the register structure...
129      */
130     for (i=0; i<n; i++) {
131         op1 = (*sys_rdb)(((u32)M.x86.R_CS<<4) + (M.x86.R_IP++));
132         (x86emu_optab[op1])(op1);
133     }
134     /* end major hack mode. */
135 }
136
137 void x86emu_check_ip_access (void)
138 {
139     /* NULL as of now */
140 }
141
142 void x86emu_check_sp_access (void)
143 {
144 }
145
146 void x86emu_check_mem_access (u32 dummy)
147 {
148     /*  check bounds, etc */
149 }
150
151 void x86emu_check_data_access (uint dummy1, uint dummy2)
152 {
153     /*  check bounds, etc */
154 }
155
156 void x86emu_inc_decoded_inst_len (int x)
157 {
158     M.x86.enc_pos += x;
159 }
160
161 void x86emu_decode_printf (char *x)
162 {
163     sprintf(M.x86.decoded_buf+M.x86.enc_str_pos,"%s",x);
164     M.x86.enc_str_pos += strlen(x);
165 }
166
167 void x86emu_decode_printf2 (char *x, int y)
168 {
169     char temp[100];
170     sprintf(temp,x,y);
171     sprintf(M.x86.decoded_buf+M.x86.enc_str_pos,"%s",temp);
172     M.x86.enc_str_pos += strlen(temp);
173 }
174
175 void x86emu_end_instr (void)
176 {
177     M.x86.enc_str_pos = 0;
178     M.x86.enc_pos = 0;
179 }
180
181 static void print_encoded_bytes (u16 s, u16 o)
182 {
183     int i;
184     char buf1[64];
185     for (i=0; i< M.x86.enc_pos; i++) {
186         sprintf(buf1+2*i,"%02x", fetch_data_byte_abs(s,o+i));
187     }
188     printk("%-20s",buf1);
189 }
190
191 static void print_decoded_instruction (void)
192 {
193     printk("%s", M.x86.decoded_buf);
194 }
195
196 void x86emu_print_int_vect (u16 iv)
197 {
198     u16 seg,off;
199
200     if (iv > 256) return;
201     seg   = fetch_data_word_abs(0,iv*4);
202     off   = fetch_data_word_abs(0,iv*4+2);
203     printk("%04x:%04x ", seg, off);
204 }
205
206 void X86EMU_dump_memory (u16 seg, u16 off, u32 amt)
207 {
208     u32 start = off & 0xfffffff0;
209     u32 end  = (off+16) & 0xfffffff0;
210     u32 i;
211     u32 current;
212
213     current = start;
214     while (end <= off + amt) {
215         printk("%04x:%04x ", seg, start);
216         for (i=start; i< off; i++)
217           printk("   ");
218         for (       ; i< end; i++)
219           printk("%02x ", fetch_data_byte_abs(seg,i));
220         printk("\n");
221         start = end;
222         end = start + 16;
223     }
224 }
225
226 void x86emu_single_step (void)
227 {
228     char s[1024];
229     int ps[10];
230     int ntok;
231     int cmd;
232     int done;
233         int segment;
234     int offset;
235     static int breakpoint;
236     static int noDecode = 1;
237
238     char *p;
239
240         if (DEBUG_BREAK()) {
241                 if (M.x86.saved_ip != breakpoint) {
242                         return;
243                 } else {
244               M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
245                         M.x86.debug |= DEBUG_TRACE_F;
246                         M.x86.debug &= ~DEBUG_BREAK_F;
247                         print_decoded_instruction ();
248                         X86EMU_trace_regs();
249                 }
250         }
251     done=0;
252     offset = M.x86.saved_ip;
253     while (!done) {
254         printk("-");
255         p = fgets(s, 1023, stdin);
256         cmd = parse_line(s, ps, &ntok);
257         switch(cmd) {
258           case 'u':
259             disassemble_forward(M.x86.saved_cs,(u16)offset,10);
260             break;
261           case 'd':
262                             if (ntok == 2) {
263                                     segment = M.x86.saved_cs;
264                                     offset = ps[1];
265                                     X86EMU_dump_memory(segment,(u16)offset,16);
266                                     offset += 16;
267                             } else if (ntok == 3) {
268                                     segment = ps[1];
269                                     offset = ps[2];
270                                     X86EMU_dump_memory(segment,(u16)offset,16);
271                                     offset += 16;
272                             } else {
273                                     segment = M.x86.saved_cs;
274                                     X86EMU_dump_memory(segment,(u16)offset,16);
275                                     offset += 16;
276                             }
277             break;
278           case 'c':
279             M.x86.debug ^= DEBUG_TRACECALL_F;
280             break;
281           case 's':
282             M.x86.debug ^= DEBUG_SVC_F | DEBUG_SYS_F | DEBUG_SYSINT_F;
283             break;
284           case 'r':
285             X86EMU_trace_regs();
286             break;
287           case 'x':
288             X86EMU_trace_xregs();
289             break;
290           case 'g':
291             if (ntok == 2) {
292                 breakpoint = ps[1];
293         if (noDecode) {
294                         M.x86.debug |= DEBUG_DECODE_NOPRINT_F;
295         } else {
296                         M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
297         }
298         M.x86.debug &= ~DEBUG_TRACE_F;
299         M.x86.debug |= DEBUG_BREAK_F;
300         done = 1;
301             }
302             break;
303           case 'q':
304           M.x86.debug |= DEBUG_EXIT;
305           return;
306       case 'P':
307           noDecode = (noDecode)?0:1;
308           printk("Toggled decoding to %s\n",(noDecode)?"FALSE":"TRUE");
309           break;
310           case 't':
311       case 0:
312             done = 1;
313             break;
314         }
315     }
316 }
317
318 int X86EMU_trace_on(void)
319 {
320     return M.x86.debug |= DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F;
321 }
322
323 int X86EMU_trace_off(void)
324 {
325     return M.x86.debug &= ~(DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F);
326 }
327
328 static int parse_line (char *s, int *ps, int *n)
329 {
330     int cmd;
331
332     *n = 0;
333     while(*s == ' ' || *s == '\t') s++;
334     ps[*n] = *s;
335     switch (*s) {
336       case '\n':
337         *n += 1;
338         return 0;
339       default:
340         cmd = *s;
341         *n += 1;
342     }
343
344     while (1) {
345         while (*s != ' ' && *s != '\t' && *s != '\n')  s++;
346
347         if (*s == '\n')
348             return cmd;
349
350         while(*s == ' ' || *s == '\t') s++;
351
352         sscanf(s,"%x",&ps[*n]);
353         *n += 1;
354     }
355 }
356
357 #endif /* DEBUG */
358
359 void x86emu_dump_regs (void)
360 {
361     printk("\tAX=%04x  ", M.x86.R_AX );
362     printk("BX=%04x  ", M.x86.R_BX );
363     printk("CX=%04x  ", M.x86.R_CX );
364     printk("DX=%04x  ", M.x86.R_DX );
365     printk("SP=%04x  ", M.x86.R_SP );
366     printk("BP=%04x  ", M.x86.R_BP );
367     printk("SI=%04x  ", M.x86.R_SI );
368     printk("DI=%04x\n", M.x86.R_DI );
369     printk("\tDS=%04x  ", M.x86.R_DS );
370     printk("ES=%04x  ", M.x86.R_ES );
371     printk("SS=%04x  ", M.x86.R_SS );
372     printk("CS=%04x  ", M.x86.R_CS );
373     printk("IP=%04x   ", M.x86.R_IP );
374     if (ACCESS_FLAG(F_OF))    printk("OV ");     /* CHECKED... */
375     else                        printk("NV ");
376     if (ACCESS_FLAG(F_DF))    printk("DN ");
377     else                        printk("UP ");
378     if (ACCESS_FLAG(F_IF))    printk("EI ");
379     else                        printk("DI ");
380     if (ACCESS_FLAG(F_SF))    printk("NG ");
381     else                        printk("PL ");
382     if (ACCESS_FLAG(F_ZF))    printk("ZR ");
383     else                        printk("NZ ");
384     if (ACCESS_FLAG(F_AF))    printk("AC ");
385     else                        printk("NA ");
386     if (ACCESS_FLAG(F_PF))    printk("PE ");
387     else                        printk("PO ");
388     if (ACCESS_FLAG(F_CF))    printk("CY ");
389     else                        printk("NC ");
390     printk("\n");
391 }
392
393 void x86emu_dump_xregs (void)
394 {
395     printk("\tEAX=%08x  ", M.x86.R_EAX );
396     printk("EBX=%08x  ", M.x86.R_EBX );
397     printk("ECX=%08x  ", M.x86.R_ECX );
398     printk("EDX=%08x  \n", M.x86.R_EDX );
399     printk("\tESP=%08x  ", M.x86.R_ESP );
400     printk("EBP=%08x  ", M.x86.R_EBP );
401     printk("ESI=%08x  ", M.x86.R_ESI );
402     printk("EDI=%08x\n", M.x86.R_EDI );
403     printk("\tDS=%04x  ", M.x86.R_DS );
404     printk("ES=%04x  ", M.x86.R_ES );
405     printk("SS=%04x  ", M.x86.R_SS );
406     printk("CS=%04x  ", M.x86.R_CS );
407     printk("EIP=%08x\n\t", M.x86.R_EIP );
408     if (ACCESS_FLAG(F_OF))    printk("OV ");     /* CHECKED... */
409     else                        printk("NV ");
410     if (ACCESS_FLAG(F_DF))    printk("DN ");
411     else                        printk("UP ");
412     if (ACCESS_FLAG(F_IF))    printk("EI ");
413     else                        printk("DI ");
414     if (ACCESS_FLAG(F_SF))    printk("NG ");
415     else                        printk("PL ");
416     if (ACCESS_FLAG(F_ZF))    printk("ZR ");
417     else                        printk("NZ ");
418     if (ACCESS_FLAG(F_AF))    printk("AC ");
419     else                        printk("NA ");
420     if (ACCESS_FLAG(F_PF))    printk("PE ");
421     else                        printk("PO ");
422     if (ACCESS_FLAG(F_CF))    printk("CY ");
423     else                        printk("NC ");
424     printk("\n");
425 }