The Pedigree Project  0.1
debug.c
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "x86emu/x86emui.h"
21 #ifndef NO_SYS_HEADERS
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #endif
25 
26 /*----------------------------- Implementation ----------------------------*/
27 
28 #ifdef DEBUG
29 
30 static void print_encoded_bytes(u16 s, u16 o);
31 static void print_decoded_instruction(void);
32 static int parse_line(char *s, int *ps, int *n);
33 
34 /* should look something like debug's output. */
35 void X86EMU_trace_regs(void)
36 {
37  if (DEBUG_TRACE())
38  {
39  x86emu_dump_regs();
40  }
41  if (DEBUG_DECODE() && !DEBUG_DECODE_NOPRINT())
42  {
43  printk("%04x:%04x ", M.x86.saved_cs, M.x86.saved_ip);
44  print_encoded_bytes(M.x86.saved_cs, M.x86.saved_ip);
45  print_decoded_instruction();
46  }
47 }
48 
49 void X86EMU_trace_xregs(void)
50 {
51  if (DEBUG_TRACE())
52  {
53  x86emu_dump_xregs();
54  }
55 }
56 
57 void x86emu_just_disassemble(void)
58 {
59  /*
60  * This routine called if the flag DEBUG_DISASSEMBLE is set kind
61  * of a hack!
62  */
63  printk("%04x:%04x ", M.x86.saved_cs, M.x86.saved_ip);
64  print_encoded_bytes(M.x86.saved_cs, M.x86.saved_ip);
65  print_decoded_instruction();
66 }
67 
68 static void disassemble_forward(u16 seg, u16 off, int n)
69 {
70  X86EMU_sysEnv tregs;
71  int i;
72  u8 op1;
73  /*
74  * hack, hack, hack. What we do is use the exact machinery set up
75  * for execution, except that now there is an additional state
76  * flag associated with the "execution", and we are using a copy
77  * of the register struct. All the major opcodes, once fully
78  * decoded, have the following two steps: TRACE_REGS(r,m);
79  * SINGLE_STEP(r,m); which disappear if DEBUG is not defined to
80  * the preprocessor. The TRACE_REGS macro expands to:
81  *
82  * if (debug&DEBUG_DISASSEMBLE)
83  * {just_disassemble(); goto EndOfInstruction;}
84  * if (debug&DEBUG_TRACE) trace_regs(r,m);
85  *
86  * ...... and at the last line of the routine.
87  *
88  * EndOfInstruction: end_instr();
89  *
90  * Up to the point where TRACE_REG is expanded, NO modifications
91  * are done to any register EXCEPT the IP register, for fetch and
92  * decoding purposes.
93  *
94  * This was done for an entirely different reason, but makes a
95  * nice way to get the system to help debug codes.
96  */
97  tregs = M;
98  tregs.x86.R_IP = off;
99  tregs.x86.R_CS = seg;
100 
101  /* reset the decoding buffers */
102  tregs.x86.enc_str_pos = 0;
103  tregs.x86.enc_pos = 0;
104 
105  /* turn on the "disassemble only, no execute" flag */
106  tregs.x86.debug |= DEBUG_DISASSEMBLE_F;
107 
108  /* DUMP NEXT n instructions to screen in straight_line fashion */
109  /*
110  * This looks like the regular instruction fetch stream, except
111  * that when this occurs, each fetched opcode, upon seeing the
112  * DEBUG_DISASSEMBLE flag set, exits immediately after decoding
113  * the instruction. XXX --- CHECK THAT MEM IS NOT AFFECTED!!!
114  * Note the use of a copy of the register structure...
115  */
116  for (i = 0; i < n; i++)
117  {
118  op1 = (*sys_rdb)(((u32) M.x86.R_CS << 4) + (M.x86.R_IP++));
119  (x86emu_optab[op1])(op1);
120  }
121  /* end major hack mode. */
122 }
123 
124 void x86emu_check_ip_access(void)
125 {
126  /* NULL as of now */
127 }
128 
129 void x86emu_check_sp_access(void)
130 {
131 }
132 
133 void x86emu_check_mem_access(u32 dummy)
134 {
135  /* check bounds, etc */
136 }
137 
138 void x86emu_check_data_access(uint dummy1, uint dummy2)
139 {
140  /* check bounds, etc */
141 }
142 
143 void x86emu_inc_decoded_inst_len(int x)
144 {
145  M.x86.enc_pos += x;
146 }
147 
148 void x86emu_decode_printf(char *x)
149 {
150  StringFormat(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", x);
151  M.x86.enc_str_pos += StringLength(x);
152 }
153 
154 void x86emu_decode_printf2(char *x, int y)
155 {
156  char temp[100];
157  StringFormat(temp, x, y);
158  StringFormat(M.x86.decoded_buf + M.x86.enc_str_pos, "%s", temp);
159  M.x86.enc_str_pos += StringLength(temp);
160 }
161 
162 void x86emu_end_instr(void)
163 {
164  M.x86.enc_str_pos = 0;
165  M.x86.enc_pos = 0;
166 }
167 
168 static void print_encoded_bytes(u16 s, u16 o)
169 {
170  int i;
171  char buf1[64];
172  for (i = 0; i < M.x86.enc_pos; i++)
173  {
174  StringFormat(buf1 + 2 * i, "%02x", fetch_data_byte_abs(s, o + i));
175  }
176  printk("%-20s", buf1);
177 }
178 
179 static void print_decoded_instruction(void)
180 {
181  printk("%s", M.x86.decoded_buf);
182 }
183 
184 void x86emu_print_int_vect(u16 iv)
185 {
186  u16 seg, off;
187 
188  if (iv > 256)
189  return;
190  seg = fetch_data_word_abs(0, iv * 4);
191  off = fetch_data_word_abs(0, iv * 4 + 2);
192  printk("%04x:%04x ", seg, off);
193 }
194 
195 void X86EMU_dump_memory(u16 seg, u16 off, u32 amt)
196 {
197  u32 start = off & 0xfffffff0;
198  u32 end = (off + 16) & 0xfffffff0;
199  u32 i;
200  u32 current;
201 
202  current = start;
203  while (end <= off + amt)
204  {
205  printk("%04x:%04x ", seg, start);
206  for (i = start; i < off; i++)
207  printk(" ");
208  for (; i < end; i++)
209  printk("%02x ", fetch_data_byte_abs(seg, i));
210  printk("\n");
211  start = end;
212  end = start + 16;
213  }
214 }
215 
216 void x86emu_single_step(void)
217 {
218  char s[1024];
219  int ps[10];
220  int ntok;
221  int cmd;
222  int done;
223  int segment;
224  int offset;
225  static int breakpoint;
226  static int noDecode = 1;
227 
228  char *p;
229 
230  if (DEBUG_BREAK())
231  {
232  if (M.x86.saved_ip != breakpoint)
233  {
234  return;
235  }
236  else
237  {
238  M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F;
239  M.x86.debug |= DEBUG_TRACE_F;
240  M.x86.debug &= ~DEBUG_BREAK_F;
241  print_decoded_instruction();
242  X86EMU_trace_regs();
243  }
244  }
245  done = 0;
246  offset = M.x86.saved_ip;
247  while (!done)
248  {
249  printk("-");
250  p = fgets(s, 1023, stdin);
251  cmd = parse_line(s, ps, &ntok);
252  switch (cmd)
253  {
254  case 'u':
255  disassemble_forward(M.x86.saved_cs, (u16) offset, 10);
256  break;
257  case 'd':
258  if (ntok == 2)
259  {
260  segment = M.x86.saved_cs;
261  offset = ps[1];
262  X86EMU_dump_memory(segment, (u16) offset, 16);
263  offset += 16;
264  }
265  else if (ntok == 3)
266  {
267  segment = ps[1];
268  offset = ps[2];
269  X86EMU_dump_memory(segment, (u16) offset, 16);
270  offset += 16;
271  }
272  else
273  {
274  segment = M.x86.saved_cs;
275  X86EMU_dump_memory(segment, (u16) offset, 16);
276  offset += 16;
277  }
278  break;
279  case 'c':
280  M.x86.debug ^= DEBUG_TRACECALL_F;
281  break;
282  case 's':
283  M.x86.debug ^= DEBUG_SVC_F | DEBUG_SYS_F | DEBUG_SYSINT_F;
284  break;
285  case 'r':
286  X86EMU_trace_regs();
287  break;
288  case 'x':
289  X86EMU_trace_xregs();
290  break;
291  case 'g':
292  if (ntok == 2)
293  {
294  breakpoint = ps[1];
295  if (noDecode)
296  {
297  M.x86.debug |= DEBUG_DECODE_NOPRINT_F;
298  }
299  else
300  {
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(
314  "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')
340  s++;
341  ps[*n] = *s;
342  switch (*s)
343  {
344  case '\n':
345  *n += 1;
346  return 0;
347  default:
348  cmd = *s;
349  *n += 1;
350  }
351 
352  while (1)
353  {
354  while (*s != ' ' && *s != '\t' && *s != '\n')
355  s++;
356 
357  if (*s == '\n')
358  return cmd;
359 
360  while (*s == ' ' || *s == '\t')
361  s++;
362 
363  sscanf(s, "%x", &ps[*n]);
364  *n += 1;
365  }
366 }
367 
368 #endif /* DEBUG */
369 
370 void x86emu_dump_regs(void)
371 {
372  printk("\tAX=%04x ", M.x86.R_AX);
373  printk("BX=%04x ", M.x86.R_BX);
374  printk("CX=%04x ", M.x86.R_CX);
375  printk("DX=%04x ", M.x86.R_DX);
376  printk("SP=%04x ", M.x86.R_SP);
377  printk("BP=%04x ", M.x86.R_BP);
378  printk("SI=%04x ", M.x86.R_SI);
379  printk("DI=%04x\n", M.x86.R_DI);
380  printk("\tDS=%04x ", M.x86.R_DS);
381  printk("ES=%04x ", M.x86.R_ES);
382  printk("SS=%04x ", M.x86.R_SS);
383  printk("CS=%04x ", M.x86.R_CS);
384  printk("IP=%04x ", M.x86.R_IP);
385  if (ACCESS_FLAG(F_OF))
386  printk("OV "); /* CHECKED... */
387  else
388  printk("NV ");
389  if (ACCESS_FLAG(F_DF))
390  printk("DN ");
391  else
392  printk("UP ");
393  if (ACCESS_FLAG(F_IF))
394  printk("EI ");
395  else
396  printk("DI ");
397  if (ACCESS_FLAG(F_SF))
398  printk("NG ");
399  else
400  printk("PL ");
401  if (ACCESS_FLAG(F_ZF))
402  printk("ZR ");
403  else
404  printk("NZ ");
405  if (ACCESS_FLAG(F_AF))
406  printk("AC ");
407  else
408  printk("NA ");
409  if (ACCESS_FLAG(F_PF))
410  printk("PE ");
411  else
412  printk("PO ");
413  if (ACCESS_FLAG(F_CF))
414  printk("CY ");
415  else
416  printk("NC ");
417  printk("\n");
418 }
419 
420 void x86emu_dump_xregs(void)
421 {
422  printk("\tEAX=%08x ", M.x86.R_EAX);
423  printk("EBX=%08x ", M.x86.R_EBX);
424  printk("ECX=%08x ", M.x86.R_ECX);
425  printk("EDX=%08x \n", M.x86.R_EDX);
426  printk("\tESP=%08x ", M.x86.R_ESP);
427  printk("EBP=%08x ", M.x86.R_EBP);
428  printk("ESI=%08x ", M.x86.R_ESI);
429  printk("EDI=%08x\n", M.x86.R_EDI);
430  printk("\tDS=%04x ", M.x86.R_DS);
431  printk("ES=%04x ", M.x86.R_ES);
432  printk("SS=%04x ", M.x86.R_SS);
433  printk("CS=%04x ", M.x86.R_CS);
434  printk("EIP=%08x\n\t", M.x86.R_EIP);
435  if (ACCESS_FLAG(F_OF))
436  printk("OV "); /* CHECKED... */
437  else
438  printk("NV ");
439  if (ACCESS_FLAG(F_DF))
440  printk("DN ");
441  else
442  printk("UP ");
443  if (ACCESS_FLAG(F_IF))
444  printk("EI ");
445  else
446  printk("DI ");
447  if (ACCESS_FLAG(F_SF))
448  printk("NG ");
449  else
450  printk("PL ");
451  if (ACCESS_FLAG(F_ZF))
452  printk("ZR ");
453  else
454  printk("NZ ");
455  if (ACCESS_FLAG(F_AF))
456  printk("AC ");
457  else
458  printk("NA ");
459  if (ACCESS_FLAG(F_PF))
460  printk("PE ");
461  else
462  printk("PO ");
463  if (ACCESS_FLAG(F_CF))
464  printk("CY ");
465  else
466  printk("NC ");
467  printk("\n");
468 }
Definition: cmd.h:30