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