1 /****************************************************************************
2 *
3 *						Realmode X86 Emulator Library
4 *
5 *            	Copyright (C) 1996-1999 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 <stdio.h>
42 #include <string.h>
43 #include <stdarg.h>
44 #ifndef NO_SYS_HEADERS
45 #include <stdlib.h>
46 #endif
47 
48 /*----------------------------- Implementation ----------------------------*/
49 
50 #ifdef DEBUG
51 
52 static void print_encoded_bytes(u16 s, u16 o);
53 static void print_decoded_instruction(void);
54 static int parse_line(char *s, int *ps, int *n);
55 
56 /* should look something like debug's output. */
57 void
X86EMU_trace_regs(void)58 X86EMU_trace_regs(void)
59 {
60     if (DEBUG_TRACE()) {
61         x86emu_dump_regs();
62     }
63     if (DEBUG_DECODE() && !DEBUG_DECODE_NOPRINT()) {
64         printk("%04x:%04x ", M.x86.saved_cs, M.x86.saved_ip);
65         print_encoded_bytes(M.x86.saved_cs, M.x86.saved_ip);
66         print_decoded_instruction();
67     }
68 }
69 
70 void
X86EMU_trace_xregs(void)71 X86EMU_trace_xregs(void)
72 {
73     if (DEBUG_TRACE()) {
74         x86emu_dump_xregs();
75     }
76 }
77 
78 void
x86emu_just_disassemble(void)79 x86emu_just_disassemble(void)
80 {
81     /*
82      * This routine called if the flag DEBUG_DISASSEMBLE is set kind
83      * of a hack!
84      */
85     printk("%04x:%04x ", M.x86.saved_cs, M.x86.saved_ip);
86     print_encoded_bytes(M.x86.saved_cs, M.x86.saved_ip);
87     print_decoded_instruction();
88 }
89 
90 static void
disassemble_forward(u16 seg,u16 off,int n)91 disassemble_forward(u16 seg, u16 off, int n)
92 {
93     X86EMU_sysEnv tregs;
94     int i;
95     u8 op1;
96 
97     /*
98      * hack, hack, hack.  What we do is use the exact machinery set up
99      * for execution, except that now there is an additional state
100      * flag associated with the "execution", and we are using a copy
101      * of the register struct.  All the major opcodes, once fully
102      * decoded, have the following two steps: TRACE_REGS(r,m);
103      * SINGLE_STEP(r,m); which disappear if DEBUG is not defined to
104      * the preprocessor.  The TRACE_REGS macro expands to:
105      *
106      * if (debug&DEBUG_DISASSEMBLE)
107      *     {just_disassemble(); goto EndOfInstruction;}
108      *     if (debug&DEBUG_TRACE) trace_regs(r,m);
109      *
110      * ......  and at the last line of the routine.
111      *
112      * EndOfInstruction: end_instr();
113      *
114      * Up to the point where TRACE_REG is expanded, NO modifications
115      * are done to any register EXCEPT the IP register, for fetch and
116      * decoding purposes.
117      *
118      * This was done for an entirely different reason, but makes a
119      * nice way to get the system to help debug codes.
120      */
121     tregs = M;
122     tregs.x86.R_IP = off;
123     tregs.x86.R_CS = seg;
124 
125     /* reset the decoding buffers */
126     tregs.x86.enc_str_pos = 0;
127     tregs.x86.enc_pos = 0;
128 
129     /* turn on the "disassemble only, no execute" flag */
130     tregs.x86.debug |= DEBUG_DISASSEMBLE_F;
131 
132     /* DUMP NEXT n instructions to screen in straight_line fashion */
133     /*
134      * This looks like the regular instruction fetch stream, except
135      * that when this occurs, each fetched opcode, upon seeing the
136      * DEBUG_DISASSEMBLE flag set, exits immediately after decoding
137      * the instruction.  XXX --- CHECK THAT MEM IS NOT AFFECTED!!!
138      * Note the use of a copy of the register structure...
139      */
140     for (i = 0; i < n; i++) {
141         op1 = (*sys_rdb) (((u32) M.x86.R_CS << 4) + (M.x86.R_IP++));
142         (x86emu_optab[op1]) (op1);
143     }
144     /* end major hack mode. */
145 }
146 
147 void
x86emu_check_ip_access(void)148 x86emu_check_ip_access(void)
149 {
150     /* NULL as of now */
151 }
152 
153 void
x86emu_check_sp_access(void)154 x86emu_check_sp_access(void)
155 {
156 }
157 
158 void
x86emu_check_mem_access(u32 dummy)159 x86emu_check_mem_access(u32 dummy)
160 {
161     /*  check bounds, etc */
162 }
163 
164 void
x86emu_check_data_access(uint dummy1,uint dummy2)165 x86emu_check_data_access(uint dummy1, uint dummy2)
166 {
167     /*  check bounds, etc */
168 }
169 
170 void
x86emu_inc_decoded_inst_len(int x)171 x86emu_inc_decoded_inst_len(int x)
172 {
173     M.x86.enc_pos += x;
174 }
175 
176 void
x86emu_decode_printf(const char * x,...)177 x86emu_decode_printf(const char *x, ...)
178 {
179     va_list ap;
180     char temp[100];
181 
182     va_start(ap, x);
183     vsnprintf(temp, sizeof(temp), x, ap);
184     va_end(ap);
185     sprintf(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", temp);
186     M.x86.enc_str_pos += strlen(temp);
187 }
188 
189 void
x86emu_end_instr(void)190 x86emu_end_instr(void)
191 {
192     M.x86.enc_str_pos = 0;
193     M.x86.enc_pos = 0;
194 }
195 
196 static void
print_encoded_bytes(u16 s,u16 o)197 print_encoded_bytes(u16 s, u16 o)
198 {
199     int i;
200     char buf1[64];
201 
202     for (i = 0; i < M.x86.enc_pos; i++) {
203         sprintf(buf1 + 2 * i, "%02x", fetch_data_byte_abs(s, o + i));
204     }
205     printk("%-20s", buf1);
206 }
207 
208 static void
print_decoded_instruction(void)209 print_decoded_instruction(void)
210 {
211     printk("%s", M.x86.decoded_buf);
212 }
213 
214 void
x86emu_print_int_vect(u16 iv)215 x86emu_print_int_vect(u16 iv)
216 {
217     u16 seg, off;
218 
219     if (iv > 256)
220         return;
221     seg = fetch_data_word_abs(0, iv * 4);
222     off = fetch_data_word_abs(0, iv * 4 + 2);
223     printk("%04x:%04x ", seg, off);
224 }
225 
226 void
X86EMU_dump_memory(u16 seg,u16 off,u32 amt)227 X86EMU_dump_memory(u16 seg, u16 off, u32 amt)
228 {
229     u32 start = off & 0xfffffff0;
230     u32 end = (off + 16) & 0xfffffff0;
231     u32 i;
232 
233     while (end <= off + amt) {
234         printk("%04x:%04x ", seg, start);
235         for (i = start; i < off; i++)
236             printk("   ");
237         for (; i < end; i++)
238             printk("%02x ", fetch_data_byte_abs(seg, i));
239         printk("\n");
240         start = end;
241         end = start + 16;
242     }
243 }
244 
245 void
x86emu_single_step(void)246 x86emu_single_step(void)
247 {
248     char s[1024];
249     int ps[10];
250     int ntok;
251     int cmd;
252     int done;
253     int segment;
254     int offset;
255     static int breakpoint;
256     static int noDecode = 1;
257 
258     if (DEBUG_BREAK()) {
259         if (M.x86.saved_ip != breakpoint) {
260             return;
261         }
262         else {
263             M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
264             M.x86.debug |= DEBUG_TRACE_F;
265             M.x86.debug &= ~DEBUG_BREAK_F;
266             print_decoded_instruction();
267             X86EMU_trace_regs();
268         }
269     }
270     done = 0;
271     offset = M.x86.saved_ip;
272     while (!done) {
273         printk("-");
274         (void)fgets(s, 1023, stdin);
275         cmd = parse_line(s, ps, &ntok);
276         switch (cmd) {
277         case 'u':
278             disassemble_forward(M.x86.saved_cs, (u16) offset, 10);
279             break;
280         case 'd':
281             if (ntok == 2) {
282                 segment = M.x86.saved_cs;
283                 offset = ps[1];
284                 X86EMU_dump_memory(segment, (u16) offset, 16);
285                 offset += 16;
286             }
287             else if (ntok == 3) {
288                 segment = ps[1];
289                 offset = ps[2];
290                 X86EMU_dump_memory(segment, (u16) offset, 16);
291                 offset += 16;
292             }
293             else {
294                 segment = M.x86.saved_cs;
295                 X86EMU_dump_memory(segment, (u16) offset, 16);
296                 offset += 16;
297             }
298             break;
299         case 'c':
300             M.x86.debug ^= DEBUG_TRACECALL_F;
301             break;
302         case 's':
303             M.x86.debug ^= DEBUG_SVC_F | DEBUG_SYS_F | DEBUG_SYSINT_F;
304             break;
305         case 'r':
306             X86EMU_trace_regs();
307             break;
308         case 'x':
309             X86EMU_trace_xregs();
310             break;
311         case 'g':
312             if (ntok == 2) {
313                 breakpoint = ps[1];
314                 if (noDecode) {
315                     M.x86.debug |= DEBUG_DECODE_NOPRINT_F;
316                 }
317                 else {
318                     M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
319                 }
320                 M.x86.debug &= ~DEBUG_TRACE_F;
321                 M.x86.debug |= DEBUG_BREAK_F;
322                 done = 1;
323             }
324             break;
325         case 'q':
326             M.x86.debug |= DEBUG_EXIT;
327             return;
328         case 'P':
329             noDecode = (noDecode) ? 0 : 1;
330             printk("Toggled decoding to %s\n", (noDecode) ? "FALSE" : "TRUE");
331             break;
332         case 't':
333         case 0:
334             done = 1;
335             break;
336         }
337     }
338 }
339 
340 int
X86EMU_trace_on(void)341 X86EMU_trace_on(void)
342 {
343     return M.x86.debug |= DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F;
344 }
345 
346 int
X86EMU_trace_off(void)347 X86EMU_trace_off(void)
348 {
349     return M.x86.debug &= ~(DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F);
350 }
351 
352 static int
parse_line(char * s,int * ps,int * n)353 parse_line(char *s, int *ps, int *n)
354 {
355     int cmd;
356 
357     *n = 0;
358     while (*s == ' ' || *s == '\t')
359         s++;
360     ps[*n] = *s;
361     switch (*s) {
362     case '\n':
363         *n += 1;
364         return 0;
365     default:
366         cmd = *s;
367         *n += 1;
368     }
369 
370     while (1) {
371         while (*s != ' ' && *s != '\t' && *s != '\n')
372             s++;
373 
374         if (*s == '\n')
375             return cmd;
376 
377         while (*s == ' ' || *s == '\t')
378             s++;
379 
380         sscanf(s, "%x", &ps[*n]);
381         *n += 1;
382     }
383 }
384 
385 #endif                          /* DEBUG */
386 
387 void
x86emu_dump_regs(void)388 x86emu_dump_regs(void)
389 {
390     printk("\tAX=%04x  ", M.x86.R_AX);
391     printk("BX=%04x  ", M.x86.R_BX);
392     printk("CX=%04x  ", M.x86.R_CX);
393     printk("DX=%04x  ", M.x86.R_DX);
394     printk("SP=%04x  ", M.x86.R_SP);
395     printk("BP=%04x  ", M.x86.R_BP);
396     printk("SI=%04x  ", M.x86.R_SI);
397     printk("DI=%04x\n", M.x86.R_DI);
398     printk("\tDS=%04x  ", M.x86.R_DS);
399     printk("ES=%04x  ", M.x86.R_ES);
400     printk("SS=%04x  ", M.x86.R_SS);
401     printk("CS=%04x  ", M.x86.R_CS);
402     printk("IP=%04x   ", M.x86.R_IP);
403     if (ACCESS_FLAG(F_OF))
404         printk("OV ");          /* CHECKED... */
405     else
406         printk("NV ");
407     if (ACCESS_FLAG(F_DF))
408         printk("DN ");
409     else
410         printk("UP ");
411     if (ACCESS_FLAG(F_IF))
412         printk("EI ");
413     else
414         printk("DI ");
415     if (ACCESS_FLAG(F_SF))
416         printk("NG ");
417     else
418         printk("PL ");
419     if (ACCESS_FLAG(F_ZF))
420         printk("ZR ");
421     else
422         printk("NZ ");
423     if (ACCESS_FLAG(F_AF))
424         printk("AC ");
425     else
426         printk("NA ");
427     if (ACCESS_FLAG(F_PF))
428         printk("PE ");
429     else
430         printk("PO ");
431     if (ACCESS_FLAG(F_CF))
432         printk("CY ");
433     else
434         printk("NC ");
435     printk("\n");
436 }
437 
438 void
x86emu_dump_xregs(void)439 x86emu_dump_xregs(void)
440 {
441     printk("\tEAX=%08x  ", M.x86.R_EAX);
442     printk("EBX=%08x  ", M.x86.R_EBX);
443     printk("ECX=%08x  ", M.x86.R_ECX);
444     printk("EDX=%08x  \n", M.x86.R_EDX);
445     printk("\tESP=%08x  ", M.x86.R_ESP);
446     printk("EBP=%08x  ", M.x86.R_EBP);
447     printk("ESI=%08x  ", M.x86.R_ESI);
448     printk("EDI=%08x\n", M.x86.R_EDI);
449     printk("\tDS=%04x  ", M.x86.R_DS);
450     printk("ES=%04x  ", M.x86.R_ES);
451     printk("SS=%04x  ", M.x86.R_SS);
452     printk("CS=%04x  ", M.x86.R_CS);
453     printk("EIP=%08x\n\t", M.x86.R_EIP);
454     if (ACCESS_FLAG(F_OF))
455         printk("OV ");          /* CHECKED... */
456     else
457         printk("NV ");
458     if (ACCESS_FLAG(F_DF))
459         printk("DN ");
460     else
461         printk("UP ");
462     if (ACCESS_FLAG(F_IF))
463         printk("EI ");
464     else
465         printk("DI ");
466     if (ACCESS_FLAG(F_SF))
467         printk("NG ");
468     else
469         printk("PL ");
470     if (ACCESS_FLAG(F_ZF))
471         printk("ZR ");
472     else
473         printk("NZ ");
474     if (ACCESS_FLAG(F_AF))
475         printk("AC ");
476     else
477         printk("NA ");
478     if (ACCESS_FLAG(F_PF))
479         printk("PE ");
480     else
481         printk("PO ");
482     if (ACCESS_FLAG(F_CF))
483         printk("CY ");
484     else
485         printk("NC ");
486     printk("\n");
487 }
488