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