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