xref: /haiku/src/libs/x86emu/debug.c (revision 25a7b01d15612846f332751841da3579db313082)
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 #ifndef NO_SYS_HEADERS
44 #include <stdarg.h>
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     sprintf(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", x);
180     M.x86.enc_str_pos += strlen(x);
181 }
182 
183 void
x86emu_decode_printf2(const char * x,int y)184 x86emu_decode_printf2(const char *x, int y)
185 {
186     char temp[100];
187 
188     snprintf(temp, sizeof(temp), x, y);
189     sprintf(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", temp);
190     M.x86.enc_str_pos += strlen(temp);
191 }
192 
193 void
x86emu_end_instr(void)194 x86emu_end_instr(void)
195 {
196     M.x86.enc_str_pos = 0;
197     M.x86.enc_pos = 0;
198 }
199 
200 static void
print_encoded_bytes(u16 s,u16 o)201 print_encoded_bytes(u16 s, u16 o)
202 {
203     int i;
204     char buf1[64];
205 
206     for (i = 0; i < M.x86.enc_pos; i++) {
207         sprintf(buf1 + 2 * i, "%02x", fetch_data_byte_abs(s, o + i));
208     }
209     printk("%-20s", buf1);
210 }
211 
212 static void
print_decoded_instruction(void)213 print_decoded_instruction(void)
214 {
215     printk("%s", M.x86.decoded_buf);
216 }
217 
218 void
x86emu_print_int_vect(u16 iv)219 x86emu_print_int_vect(u16 iv)
220 {
221     u16 seg, off;
222 
223     if (iv > 256)
224         return;
225     seg = fetch_data_word_abs(0, iv * 4);
226     off = fetch_data_word_abs(0, iv * 4 + 2);
227     printk("%04x:%04x ", seg, off);
228 }
229 
230 void
X86EMU_dump_memory(u16 seg,u16 off,u32 amt)231 X86EMU_dump_memory(u16 seg, u16 off, u32 amt)
232 {
233     u32 start = off & 0xfffffff0;
234     u32 end = (off + 16) & 0xfffffff0;
235     u32 i;
236     u32 current;
237 
238     current = start;
239     while (end <= off + amt) {
240         printk("%04x:%04x ", seg, start);
241         for (i = start; i < off; i++)
242             printk("   ");
243         for (; i < end; i++)
244             printk("%02x ", fetch_data_byte_abs(seg, i));
245         printk("\n");
246         start = end;
247         end = start + 16;
248     }
249 }
250 
251 void
x86emu_single_step(void)252 x86emu_single_step(void)
253 {
254 	return;
255     char s[1024];
256     int ps[10];
257     int ntok;
258     int cmd;
259     int done;
260     int segment;
261     int offset;
262     static int breakpoint;
263     static int noDecode = 1;
264 
265     //char *p;
266 
267     if (DEBUG_BREAK()) {
268         if (M.x86.saved_ip != breakpoint) {
269             return;
270         }
271         else {
272             M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
273             M.x86.debug |= DEBUG_TRACE_F;
274             M.x86.debug &= ~DEBUG_BREAK_F;
275             print_decoded_instruction();
276             X86EMU_trace_regs();
277         }
278     }
279     done = 0;
280     offset = M.x86.saved_ip;
281     while (!done) {
282         printk("-");
283         //p = fgets(s, 1023, stdin);
284         cmd = parse_line(s, ps, &ntok);
285         switch (cmd) {
286         case 'u':
287             disassemble_forward(M.x86.saved_cs, (u16) offset, 10);
288             break;
289         case 'd':
290             if (ntok == 2) {
291                 segment = M.x86.saved_cs;
292                 offset = ps[1];
293                 X86EMU_dump_memory(segment, (u16) offset, 16);
294                 offset += 16;
295             }
296             else if (ntok == 3) {
297                 segment = ps[1];
298                 offset = ps[2];
299                 X86EMU_dump_memory(segment, (u16) offset, 16);
300                 offset += 16;
301             }
302             else {
303                 segment = M.x86.saved_cs;
304                 X86EMU_dump_memory(segment, (u16) offset, 16);
305                 offset += 16;
306             }
307             break;
308         case 'c':
309             M.x86.debug ^= DEBUG_TRACECALL_F;
310             break;
311         case 's':
312             M.x86.debug ^= DEBUG_SVC_F | DEBUG_SYS_F | DEBUG_SYSINT_F;
313             break;
314         case 'r':
315             X86EMU_trace_regs();
316             break;
317         case 'x':
318             X86EMU_trace_xregs();
319             break;
320         case 'g':
321             if (ntok == 2) {
322                 breakpoint = ps[1];
323                 if (noDecode) {
324                     M.x86.debug |= DEBUG_DECODE_NOPRINT_F;
325                 }
326                 else {
327                     M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
328                 }
329                 M.x86.debug &= ~DEBUG_TRACE_F;
330                 M.x86.debug |= DEBUG_BREAK_F;
331                 done = 1;
332             }
333             break;
334         case 'q':
335             M.x86.debug |= DEBUG_EXIT;
336             return;
337         case 'P':
338             noDecode = (noDecode) ? 0 : 1;
339             printk("Toggled decoding to %s\n", (noDecode) ? "FALSE" : "TRUE");
340             break;
341         case 't':
342         case 0:
343             done = 1;
344             break;
345         }
346     }
347 }
348 
349 int
X86EMU_trace_on(void)350 X86EMU_trace_on(void)
351 {
352     return M.x86.debug |= DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F;
353 }
354 
355 int
X86EMU_trace_off(void)356 X86EMU_trace_off(void)
357 {
358     return M.x86.debug &= ~(DEBUG_STEP_F | DEBUG_DECODE_F | DEBUG_TRACE_F);
359 }
360 
361 static int
parse_line(char * s,int * ps,int * n)362 parse_line(char *s, int *ps, int *n)
363 {
364     int cmd;
365 
366     *n = 0;
367     while (*s == ' ' || *s == '\t')
368         s++;
369     ps[*n] = *s;
370     switch (*s) {
371     case '\n':
372         *n += 1;
373         return 0;
374     default:
375         cmd = *s;
376         *n += 1;
377     }
378 
379     while (1) {
380         while (*s != ' ' && *s != '\t' && *s != '\n')
381             s++;
382 
383         if (*s == '\n')
384             return cmd;
385 
386         while (*s == ' ' || *s == '\t')
387             s++;
388 
389         //sscanf(s, "%x", &ps[*n]);
390         *n += 1;
391     }
392 }
393 
394 #endif                          /* DEBUG */
395 
396 void
x86emu_dump_regs(void)397 x86emu_dump_regs(void)
398 {
399     printk("\tAX=%04x  ", M.x86.R_AX);
400     printk("BX=%04x  ", M.x86.R_BX);
401     printk("CX=%04x  ", M.x86.R_CX);
402     printk("DX=%04x  ", M.x86.R_DX);
403     printk("SP=%04x  ", M.x86.R_SP);
404     printk("BP=%04x  ", M.x86.R_BP);
405     printk("SI=%04x  ", M.x86.R_SI);
406     printk("DI=%04x\n", M.x86.R_DI);
407     printk("\tDS=%04x  ", M.x86.R_DS);
408     printk("ES=%04x  ", M.x86.R_ES);
409     printk("SS=%04x  ", M.x86.R_SS);
410     printk("CS=%04x  ", M.x86.R_CS);
411     printk("IP=%04x   ", M.x86.R_IP);
412     if (ACCESS_FLAG(F_OF))
413         printk("OV ");          /* CHECKED... */
414     else
415         printk("NV ");
416     if (ACCESS_FLAG(F_DF))
417         printk("DN ");
418     else
419         printk("UP ");
420     if (ACCESS_FLAG(F_IF))
421         printk("EI ");
422     else
423         printk("DI ");
424     if (ACCESS_FLAG(F_SF))
425         printk("NG ");
426     else
427         printk("PL ");
428     if (ACCESS_FLAG(F_ZF))
429         printk("ZR ");
430     else
431         printk("NZ ");
432     if (ACCESS_FLAG(F_AF))
433         printk("AC ");
434     else
435         printk("NA ");
436     if (ACCESS_FLAG(F_PF))
437         printk("PE ");
438     else
439         printk("PO ");
440     if (ACCESS_FLAG(F_CF))
441         printk("CY ");
442     else
443         printk("NC ");
444     printk("\n");
445 }
446 
447 void
x86emu_dump_xregs(void)448 x86emu_dump_xregs(void)
449 {
450     printk("\tEAX=%08x  ", M.x86.R_EAX);
451     printk("EBX=%08x  ", M.x86.R_EBX);
452     printk("ECX=%08x  ", M.x86.R_ECX);
453     printk("EDX=%08x  \n", M.x86.R_EDX);
454     printk("\tESP=%08x  ", M.x86.R_ESP);
455     printk("EBP=%08x  ", M.x86.R_EBP);
456     printk("ESI=%08x  ", M.x86.R_ESI);
457     printk("EDI=%08x\n", M.x86.R_EDI);
458     printk("\tDS=%04x  ", M.x86.R_DS);
459     printk("ES=%04x  ", M.x86.R_ES);
460     printk("SS=%04x  ", M.x86.R_SS);
461     printk("CS=%04x  ", M.x86.R_CS);
462     printk("EIP=%08x\n\t", M.x86.R_EIP);
463     if (ACCESS_FLAG(F_OF))
464         printk("OV ");          /* CHECKED... */
465     else
466         printk("NV ");
467     if (ACCESS_FLAG(F_DF))
468         printk("DN ");
469     else
470         printk("UP ");
471     if (ACCESS_FLAG(F_IF))
472         printk("EI ");
473     else
474         printk("DI ");
475     if (ACCESS_FLAG(F_SF))
476         printk("NG ");
477     else
478         printk("PL ");
479     if (ACCESS_FLAG(F_ZF))
480         printk("ZR ");
481     else
482         printk("NZ ");
483     if (ACCESS_FLAG(F_AF))
484         printk("AC ");
485     else
486         printk("NA ");
487     if (ACCESS_FLAG(F_PF))
488         printk("PE ");
489     else
490         printk("PO ");
491     if (ACCESS_FLAG(F_CF))
492         printk("CY ");
493     else
494         printk("NC ");
495     printk("\n");
496 }
497