reg: Avoid an uninitialized variable warning.
[wine.git] / programs / winedbg / be_i386.c
blob4d22708fd6d318a1f994b9d94ef4526cdb1f8375
1 /*
2 * Debugger i386 specific functions
4 * Copyright 2004 Eric Pouech
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "debugger.h"
22 #include "wine/debug.h"
24 #ifdef __i386__
26 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
28 /* db_disasm.c */
29 extern void be_i386_disasm_one_insn(ADDRESS64* addr, int display);
31 #define STEP_FLAG 0x00000100 /* single step flag */
32 #define V86_FLAG 0x00020000
34 #define IS_VM86_MODE(ctx) (ctx->EFlags & V86_FLAG)
36 typedef struct DECLSPEC_ALIGN(16) _M128A {
37 ULONGLONG Low;
38 LONGLONG High;
39 } M128A, *PM128A;
41 typedef struct _XMM_SAVE_AREA32 {
42 WORD ControlWord; /* 000 */
43 WORD StatusWord; /* 002 */
44 BYTE TagWord; /* 004 */
45 BYTE Reserved1; /* 005 */
46 WORD ErrorOpcode; /* 006 */
47 DWORD ErrorOffset; /* 008 */
48 WORD ErrorSelector; /* 00c */
49 WORD Reserved2; /* 00e */
50 DWORD DataOffset; /* 010 */
51 WORD DataSelector; /* 014 */
52 WORD Reserved3; /* 016 */
53 DWORD MxCsr; /* 018 */
54 DWORD MxCsr_Mask; /* 01c */
55 M128A FloatRegisters[8]; /* 020 */
56 M128A XmmRegisters[16]; /* 0a0 */
57 BYTE Reserved4[96]; /* 1a0 */
58 } XMM_SAVE_AREA32, *PXMM_SAVE_AREA32;
60 static ADDRESS_MODE get_selector_type(HANDLE hThread, const CONTEXT* ctx, WORD sel)
62 LDT_ENTRY le;
64 if (IS_VM86_MODE(ctx)) return AddrModeReal;
65 /* null or system selector */
66 if (!(sel & 4) || ((sel >> 3) < 17)) return AddrModeFlat;
67 if (dbg_curr_process->process_io->get_selector(hThread, sel, &le))
68 return le.HighWord.Bits.Default_Big ? AddrMode1632 : AddrMode1616;
69 /* selector doesn't exist */
70 return -1;
73 static void* be_i386_linearize(HANDLE hThread, const ADDRESS64* addr)
75 LDT_ENTRY le;
77 switch (addr->Mode)
79 case AddrModeReal:
80 return (void*)((DWORD)(LOWORD(addr->Segment) << 4) + (DWORD)addr->Offset);
81 case AddrMode1632:
82 if (!(addr->Segment & 4) || ((addr->Segment >> 3) < 17))
83 return (void*)(DWORD)addr->Offset;
84 /* fall through */
85 case AddrMode1616:
86 if (!dbg_curr_process->process_io->get_selector(hThread, addr->Segment, &le)) return NULL;
87 return (void*)((le.HighWord.Bits.BaseHi << 24) +
88 (le.HighWord.Bits.BaseMid << 16) + le.BaseLow +
89 (DWORD)addr->Offset);
90 case AddrModeFlat:
91 return (void*)(DWORD)addr->Offset;
93 return NULL;
96 static BOOL be_i386_build_addr(HANDLE hThread, const CONTEXT* ctx, ADDRESS64* addr,
97 unsigned seg, unsigned long offset)
99 addr->Mode = AddrModeFlat;
100 addr->Segment = seg;
101 addr->Offset = offset;
102 if (seg)
104 addr->Mode = get_selector_type(hThread, ctx, seg);
105 switch (addr->Mode)
107 case AddrModeReal:
108 case AddrMode1616:
109 addr->Offset &= 0xffff;
110 break;
111 case AddrModeFlat:
112 case AddrMode1632:
113 break;
114 default:
115 addr->Mode = -1;
116 return FALSE;
119 return TRUE;
122 static BOOL be_i386_get_addr(HANDLE hThread, const CONTEXT* ctx,
123 enum be_cpu_addr bca, ADDRESS64* addr)
125 switch (bca)
127 case be_cpu_addr_pc:
128 return be_i386_build_addr(hThread, ctx, addr, ctx->SegCs, ctx->Eip);
129 case be_cpu_addr_stack:
130 return be_i386_build_addr(hThread, ctx, addr, ctx->SegSs, ctx->Esp);
131 case be_cpu_addr_frame:
132 return be_i386_build_addr(hThread, ctx, addr, ctx->SegSs, ctx->Ebp);
134 return FALSE;
137 static BOOL be_i386_get_register_info(int regno, enum be_cpu_addr* kind)
139 switch (regno)
141 case CV_REG_EIP: *kind = be_cpu_addr_pc; return TRUE;
142 case CV_REG_EBP: *kind = be_cpu_addr_frame; return TRUE;
143 case CV_REG_ESP: *kind = be_cpu_addr_stack; return TRUE;
145 return FALSE;
148 static void be_i386_single_step(CONTEXT* ctx, BOOL enable)
150 if (enable) ctx->EFlags |= STEP_FLAG;
151 else ctx->EFlags &= ~STEP_FLAG;
154 static void be_i386_all_print_context(HANDLE hThread, const CONTEXT* ctx)
156 static const char mxcsr_flags[16][4] = { "IE", "DE", "ZE", "OE", "UE", "PE", "DAZ", "IM",
157 "DM", "ZM", "OM", "UM", "PM", "R-", "R+", "FZ" };
158 XMM_SAVE_AREA32 *xmm_area;
159 long double ST[8]; /* These are for floating regs */
160 int cnt;
162 /* Break out the FPU state and the floating point registers */
163 dbg_printf("Floating Point Unit status:\n");
164 dbg_printf(" FLCW:%04x ", LOWORD(ctx->FloatSave.ControlWord));
165 dbg_printf(" FLTW:%04x ", LOWORD(ctx->FloatSave.TagWord));
166 dbg_printf(" FLEO:%08x ", (unsigned int) ctx->FloatSave.ErrorOffset);
167 dbg_printf(" FLSW:%04x", LOWORD(ctx->FloatSave.StatusWord));
169 /* Isolate the condition code bits - note they are not contiguous */
170 dbg_printf("(CC:%d%d%d%d", (ctx->FloatSave.StatusWord & 0x00004000) >> 14,
171 (ctx->FloatSave.StatusWord & 0x00000400) >> 10,
172 (ctx->FloatSave.StatusWord & 0x00000200) >> 9,
173 (ctx->FloatSave.StatusWord & 0x00000100) >> 8);
175 /* Now pull out the 3 bit of the TOP stack pointer */
176 dbg_printf(" TOP:%01x", (unsigned int) (ctx->FloatSave.StatusWord & 0x00003800) >> 11);
178 /* Lets analyse the error bits and indicate the status
179 * the Invalid Op flag has sub status which is tested as follows */
180 if (ctx->FloatSave.StatusWord & 0x00000001) { /* Invalid Fl OP */
181 if (ctx->FloatSave.StatusWord & 0x00000040) { /* Stack Fault */
182 if (ctx->FloatSave.StatusWord & 0x00000200) /* C1 says Overflow */
183 dbg_printf(" #IE(Stack Overflow)");
184 else
185 dbg_printf(" #IE(Stack Underflow)"); /* Underflow */
187 else dbg_printf(" #IE(Arthimetic error)"); /* Invalid Fl OP */
190 if (ctx->FloatSave.StatusWord & 0x00000002) dbg_printf(" #DE"); /* Denormalised OP */
191 if (ctx->FloatSave.StatusWord & 0x00000004) dbg_printf(" #ZE"); /* Zero Divide */
192 if (ctx->FloatSave.StatusWord & 0x00000008) dbg_printf(" #OE"); /* Overflow */
193 if (ctx->FloatSave.StatusWord & 0x00000010) dbg_printf(" #UE"); /* Underflow */
194 if (ctx->FloatSave.StatusWord & 0x00000020) dbg_printf(" #PE"); /* Precision error */
195 if (ctx->FloatSave.StatusWord & 0x00000040)
196 if (!(ctx->FloatSave.StatusWord & 0x00000001))
197 dbg_printf(" #SE"); /* Stack Fault (don't think this can occur) */
198 if (ctx->FloatSave.StatusWord & 0x00000080) dbg_printf(" #ES"); /* Error Summary */
199 if (ctx->FloatSave.StatusWord & 0x00008000) dbg_printf(" #FB"); /* FPU Busy */
200 dbg_printf(")\n");
202 /* Here are the rest of the registers */
203 dbg_printf(" FLES:%08x FLDO:%08x FLDS:%08x FLCNS:%08x\n",
204 ctx->FloatSave.ErrorSelector,
205 ctx->FloatSave.DataOffset,
206 ctx->FloatSave.DataSelector,
207 ctx->FloatSave.Cr0NpxState);
209 /* Now for the floating point registers */
210 dbg_printf("Floating Point Registers:\n");
211 for (cnt = 0; cnt < 4; cnt++)
213 memcpy(&ST[cnt], &ctx->FloatSave.RegisterArea[cnt * 10], 10);
214 dbg_printf(" ST%d:%Lf ", cnt, ST[cnt]);
216 dbg_printf("\n");
217 for (cnt = 4; cnt < 8; cnt++)
219 memcpy(&ST[cnt], &ctx->FloatSave.RegisterArea[cnt * 10], 10);
220 dbg_printf(" ST%d:%Lf ", cnt, ST[cnt]);
223 xmm_area = (XMM_SAVE_AREA32 *) &ctx->ExtendedRegisters;
225 dbg_printf(" mxcsr: %04x (", xmm_area->MxCsr );
226 for (cnt = 0; cnt < 16; cnt++)
227 if (xmm_area->MxCsr & (1 << cnt)) dbg_printf( " %s", mxcsr_flags[cnt] );
228 dbg_printf(" )\n");
230 for (cnt = 0; cnt < 8; cnt++)
232 dbg_printf( " xmm%u: uint=%08x%08x%08x%08x", cnt,
233 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 3),
234 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 2),
235 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 1),
236 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 0));
237 dbg_printf( " double={%g; %g}", *(double *)&xmm_area->XmmRegisters[cnt].Low,
238 *(double *)&xmm_area->XmmRegisters[cnt].High );
239 dbg_printf( " float={%g; %g; %g; %g}\n",
240 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 0),
241 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 1),
242 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 2),
243 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 3) );
245 dbg_printf("\n");
248 static void be_i386_print_context(HANDLE hThread, const CONTEXT* ctx, int all_regs)
250 static const char flags[] = "aVR-N--ODITSZ-A-P-C";
251 int i;
252 char buf[33];
254 dbg_printf("Register dump:\n");
256 /* First get the segment registers out of the way */
257 dbg_printf(" CS:%04x SS:%04x DS:%04x ES:%04x FS:%04x GS:%04x",
258 (WORD)ctx->SegCs, (WORD)ctx->SegSs,
259 (WORD)ctx->SegDs, (WORD)ctx->SegEs,
260 (WORD)ctx->SegFs, (WORD)ctx->SegGs);
262 strcpy(buf, flags);
263 for (i = 0; buf[i]; i++)
264 if (buf[i] != '-' && !(ctx->EFlags & (1 << (sizeof(flags) - 2 - i))))
265 buf[i] = ' ';
267 switch (get_selector_type(hThread, ctx, ctx->SegCs))
269 case AddrMode1616:
270 case AddrModeReal:
271 dbg_printf("\n IP:%04x SP:%04x BP:%04x FLAGS:%04x(%s)\n",
272 LOWORD(ctx->Eip), LOWORD(ctx->Esp),
273 LOWORD(ctx->Ebp), LOWORD(ctx->EFlags), buf);
274 dbg_printf(" AX:%04x BX:%04x CX:%04x DX:%04x SI:%04x DI:%04x\n",
275 LOWORD(ctx->Eax), LOWORD(ctx->Ebx),
276 LOWORD(ctx->Ecx), LOWORD(ctx->Edx),
277 LOWORD(ctx->Esi), LOWORD(ctx->Edi));
278 break;
279 case AddrModeFlat:
280 case AddrMode1632:
281 dbg_printf("\n EIP:%08x ESP:%08x EBP:%08x EFLAGS:%08x(%s)\n",
282 ctx->Eip, ctx->Esp, ctx->Ebp, ctx->EFlags, buf);
283 dbg_printf(" EAX:%08x EBX:%08x ECX:%08x EDX:%08x\n",
284 ctx->Eax, ctx->Ebx, ctx->Ecx, ctx->Edx);
285 dbg_printf(" ESI:%08x EDI:%08x\n",
286 ctx->Esi, ctx->Edi);
287 break;
290 if (all_regs) be_i386_all_print_context(hThread, ctx); /* print floating regs */
294 static void be_i386_print_segment_info(HANDLE hThread, const CONTEXT* ctx)
296 if (get_selector_type(hThread, ctx, ctx->SegCs) == AddrMode1616)
298 info_win32_segments(ctx->SegDs >> 3, 1);
299 if (ctx->SegEs != ctx->SegDs) info_win32_segments(ctx->SegEs >> 3, 1);
301 info_win32_segments(ctx->SegFs >> 3, 1);
304 static struct dbg_internal_var be_i386_ctx[] =
306 {CV_REG_AL, "AL", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Eax), dbg_itype_unsigned_char_int},
307 {CV_REG_CL, "CL", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Ecx), dbg_itype_unsigned_char_int},
308 {CV_REG_DL, "DL", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Edx), dbg_itype_unsigned_char_int},
309 {CV_REG_BL, "BL", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Ebx), dbg_itype_unsigned_char_int},
310 {CV_REG_AH, "AH", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, Eax)+1), dbg_itype_unsigned_char_int},
311 {CV_REG_CH, "CH", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, Ecx)+1), dbg_itype_unsigned_char_int},
312 {CV_REG_DH, "DH", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, Edx)+1), dbg_itype_unsigned_char_int},
313 {CV_REG_BH, "BH", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, Ebx)+1), dbg_itype_unsigned_char_int},
314 {CV_REG_AX, "AX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Eax), dbg_itype_unsigned_short_int},
315 {CV_REG_CX, "CX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Ecx), dbg_itype_unsigned_short_int},
316 {CV_REG_DX, "DX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Edx), dbg_itype_unsigned_short_int},
317 {CV_REG_BX, "BX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Ebx), dbg_itype_unsigned_short_int},
318 {CV_REG_SP, "SP", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Esp), dbg_itype_unsigned_short_int},
319 {CV_REG_BP, "BP", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Ebp), dbg_itype_unsigned_short_int},
320 {CV_REG_SI, "SI", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Esi), dbg_itype_unsigned_short_int},
321 {CV_REG_DI, "DI", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Edi), dbg_itype_unsigned_short_int},
322 {CV_REG_EAX, "EAX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Eax), dbg_itype_unsigned_int},
323 {CV_REG_ECX, "ECX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Ecx), dbg_itype_unsigned_int},
324 {CV_REG_EDX, "EDX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Edx), dbg_itype_unsigned_int},
325 {CV_REG_EBX, "EBX", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Ebx), dbg_itype_unsigned_int},
326 {CV_REG_ESP, "ESP", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Esp), dbg_itype_unsigned_int},
327 {CV_REG_EBP, "EBP", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Ebp), dbg_itype_unsigned_int},
328 {CV_REG_ESI, "ESI", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Esi), dbg_itype_unsigned_int},
329 {CV_REG_EDI, "EDI", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Edi), dbg_itype_unsigned_int},
330 {CV_REG_ES, "ES", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, SegEs), dbg_itype_unsigned_short_int},
331 {CV_REG_CS, "CS", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, SegCs), dbg_itype_unsigned_short_int},
332 {CV_REG_SS, "SS", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, SegSs), dbg_itype_unsigned_short_int},
333 {CV_REG_DS, "DS", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, SegDs), dbg_itype_unsigned_short_int},
334 {CV_REG_FS, "FS", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, SegFs), dbg_itype_unsigned_short_int},
335 {CV_REG_GS, "GS", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, SegGs), dbg_itype_unsigned_short_int},
336 {CV_REG_IP, "IP", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Eip), dbg_itype_unsigned_short_int},
337 {CV_REG_FLAGS, "FLAGS", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, EFlags), dbg_itype_unsigned_short_int},
338 {CV_REG_EIP, "EIP", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, Eip), dbg_itype_unsigned_int},
339 {CV_REG_EFLAGS, "EFLAGS", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, EFlags), dbg_itype_unsigned_int},
340 {CV_REG_ST0, "ST0", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, FloatSave.RegisterArea[ 0]), dbg_itype_long_real},
341 {CV_REG_ST0+1, "ST1", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, FloatSave.RegisterArea[10]), dbg_itype_long_real},
342 {CV_REG_ST0+2, "ST2", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, FloatSave.RegisterArea[20]), dbg_itype_long_real},
343 {CV_REG_ST0+3, "ST3", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, FloatSave.RegisterArea[30]), dbg_itype_long_real},
344 {CV_REG_ST0+4, "ST4", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, FloatSave.RegisterArea[40]), dbg_itype_long_real},
345 {CV_REG_ST0+5, "ST5", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, FloatSave.RegisterArea[50]), dbg_itype_long_real},
346 {CV_REG_ST0+6, "ST6", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, FloatSave.RegisterArea[60]), dbg_itype_long_real},
347 {CV_REG_ST0+7, "ST7", (DWORD_PTR*)FIELD_OFFSET(CONTEXT, FloatSave.RegisterArea[70]), dbg_itype_long_real},
348 {CV_AMD64_XMM0, "XMM0", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[0])), dbg_itype_m128a},
349 {CV_AMD64_XMM0+1, "XMM1", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[1])), dbg_itype_m128a},
350 {CV_AMD64_XMM0+2, "XMM2", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[2])), dbg_itype_m128a},
351 {CV_AMD64_XMM0+3, "XMM3", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[3])), dbg_itype_m128a},
352 {CV_AMD64_XMM0+4, "XMM4", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[4])), dbg_itype_m128a},
353 {CV_AMD64_XMM0+5, "XMM5", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[5])), dbg_itype_m128a},
354 {CV_AMD64_XMM0+6, "XMM6", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[6])), dbg_itype_m128a},
355 {CV_AMD64_XMM0+7, "XMM7", (DWORD_PTR*)(FIELD_OFFSET(CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[7])), dbg_itype_m128a},
356 {0, NULL, 0, dbg_itype_none}
359 static BOOL be_i386_is_step_over_insn(const void* insn)
361 BYTE ch;
363 for (;;)
365 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
367 switch (ch)
369 /* Skip all prefixes */
370 case 0x2e: /* cs: */
371 case 0x36: /* ss: */
372 case 0x3e: /* ds: */
373 case 0x26: /* es: */
374 case 0x64: /* fs: */
375 case 0x65: /* gs: */
376 case 0x66: /* opcode size prefix */
377 case 0x67: /* addr size prefix */
378 case 0xf0: /* lock */
379 case 0xf2: /* repne */
380 case 0xf3: /* repe */
381 insn = (const char*)insn + 1;
382 continue;
384 /* Handle call instructions */
385 case 0xcd: /* int <intno> */
386 case 0xe8: /* call <offset> */
387 case 0x9a: /* lcall <seg>:<off> */
388 return TRUE;
390 case 0xff: /* call <regmodrm> */
391 if (!dbg_read_memory((const char*)insn + 1, &ch, sizeof(ch)))
392 return FALSE;
393 return (((ch & 0x38) == 0x10) || ((ch & 0x38) == 0x18));
395 /* Handle string instructions */
396 case 0x6c: /* insb */
397 case 0x6d: /* insw */
398 case 0x6e: /* outsb */
399 case 0x6f: /* outsw */
400 case 0xa4: /* movsb */
401 case 0xa5: /* movsw */
402 case 0xa6: /* cmpsb */
403 case 0xa7: /* cmpsw */
404 case 0xaa: /* stosb */
405 case 0xab: /* stosw */
406 case 0xac: /* lodsb */
407 case 0xad: /* lodsw */
408 case 0xae: /* scasb */
409 case 0xaf: /* scasw */
410 return TRUE;
412 default:
413 return FALSE;
418 static BOOL be_i386_is_function_return(const void* insn)
420 BYTE ch;
422 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
423 if (ch == 0xF3) /* REP */
425 insn = (const char*)insn + 1;
426 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
428 return (ch == 0xC2) || (ch == 0xC3);
431 static BOOL be_i386_is_break_insn(const void* insn)
433 BYTE c;
435 if (!dbg_read_memory(insn, &c, sizeof(c))) return FALSE;
436 return c == 0xCC;
439 static unsigned get_size(ADDRESS_MODE am)
441 if (am == AddrModeReal || am == AddrMode1616) return 16;
442 return 32;
445 static BOOL fetch_value(const char* addr, unsigned sz, int* value)
447 char value8;
448 short value16;
450 switch (sz)
452 case 8:
453 if (!dbg_read_memory(addr, &value8, sizeof(value8)))
454 return FALSE;
455 *value = value8;
456 break;
457 case 16:
458 if (!dbg_read_memory(addr, &value16, sizeof(value16)))
459 return FALSE;
460 *value = value16;
461 break;
462 case 32:
463 if (!dbg_read_memory(addr, value, sizeof(*value)))
464 return FALSE;
465 break;
466 default: return FALSE;
468 return TRUE;
471 static BOOL be_i386_is_func_call(const void* insn, ADDRESS64* callee)
473 BYTE ch;
474 int delta;
475 short segment;
476 unsigned dst = 0;
477 unsigned operand_size;
478 ADDRESS_MODE cs_addr_mode;
480 cs_addr_mode = get_selector_type(dbg_curr_thread->handle, &dbg_context,
481 dbg_context.SegCs);
482 operand_size = get_size(cs_addr_mode);
484 /* get operand_size (also getting rid of the various prefixes */
487 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
488 if (ch == 0x66)
490 operand_size = 48 - operand_size; /* 16 => 32, 32 => 16 */
491 insn = (const char*)insn + 1;
493 } while (ch == 0x66 || ch == 0x67);
495 switch (ch)
497 case 0xe8: /* relative near call */
498 callee->Mode = cs_addr_mode;
499 if (!fetch_value((const char*)insn + 1, operand_size, &delta))
500 return FALSE;
501 callee->Segment = dbg_context.SegCs;
502 callee->Offset = (DWORD)insn + 1 + (operand_size / 8) + delta;
503 return TRUE;
505 case 0x9a: /* absolute far call */
506 if (!dbg_read_memory((const char*)insn + 1 + operand_size / 8,
507 &segment, sizeof(segment)))
508 return FALSE;
509 callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context,
510 segment);
511 if (!fetch_value((const char*)insn + 1, operand_size, &delta))
512 return FALSE;
513 callee->Segment = segment;
514 callee->Offset = delta;
515 return TRUE;
517 case 0xff:
518 if (!dbg_read_memory((const char*)insn + 1, &ch, sizeof(ch)))
519 return FALSE;
520 /* keep only the CALL and LCALL insn:s */
521 switch ((ch >> 3) & 0x07)
523 case 0x02:
524 segment = dbg_context.SegCs;
525 break;
526 case 0x03:
527 if (!dbg_read_memory((const char*)insn + 1 + operand_size / 8,
528 &segment, sizeof(segment)))
529 return FALSE;
530 break;
531 default: return FALSE;
533 /* FIXME: we only support the 32 bit far calls for now */
534 if (operand_size != 32)
536 WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) with 16 bit operand-size at %p\n", ch, insn);
537 return FALSE;
539 switch (ch & 0xC7) /* keep Mod R/M only (skip reg) */
541 case 0x04:
542 case 0x44:
543 case 0x84:
544 WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) (SIB bytes) at %p\n", ch, insn);
545 return FALSE;
546 case 0x05: /* addr32 */
547 if ((ch & 0x38) == 0x10 || /* call */
548 (ch & 0x38) == 0x18) /* lcall */
550 void *addr;
551 if (!dbg_read_memory((const char *)insn + 2, &addr, sizeof(addr)))
552 return FALSE;
553 if ((ch & 0x38) == 0x18) /* lcall */
555 if (!dbg_read_memory((const char*)addr + operand_size, &segment, sizeof(segment)))
556 return FALSE;
558 else segment = dbg_context.SegCs;
559 if (!dbg_read_memory((const char*)addr, &dst, sizeof(dst)))
560 return FALSE;
561 callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context, segment);
562 callee->Segment = segment;
563 callee->Offset = dst;
564 return TRUE;
566 return FALSE;
567 default:
568 switch (ch & 0x07)
570 case 0x00: dst = dbg_context.Eax; break;
571 case 0x01: dst = dbg_context.Ecx; break;
572 case 0x02: dst = dbg_context.Edx; break;
573 case 0x03: dst = dbg_context.Ebx; break;
574 case 0x04: dst = dbg_context.Esp; break;
575 case 0x05: dst = dbg_context.Ebp; break;
576 case 0x06: dst = dbg_context.Esi; break;
577 case 0x07: dst = dbg_context.Edi; break;
579 if ((ch >> 6) != 0x03) /* indirect address */
581 if (ch >> 6) /* we got a displacement */
583 if (!fetch_value((const char*)insn + 2, (ch >> 6) == 0x01 ? 8 : 32, &delta))
584 return FALSE;
585 dst += delta;
587 if (((ch >> 3) & 0x07) == 0x03) /* LCALL */
589 if (!dbg_read_memory((const char*)dst + operand_size, &segment, sizeof(segment)))
590 return FALSE;
592 else segment = dbg_context.SegCs;
593 if (!dbg_read_memory((const char*)dst, &delta, sizeof(delta)))
594 return FALSE;
595 callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context,
596 segment);
597 callee->Segment = segment;
598 callee->Offset = delta;
600 else
602 callee->Mode = cs_addr_mode;
603 callee->Segment = dbg_context.SegCs;
604 callee->Offset = dst;
607 return TRUE;
609 default:
610 return FALSE;
614 static BOOL be_i386_is_jump(const void* insn, ADDRESS64* jumpee)
616 BYTE ch;
617 int delta;
618 unsigned operand_size;
619 ADDRESS_MODE cs_addr_mode;
621 cs_addr_mode = get_selector_type(dbg_curr_thread->handle, &dbg_context,
622 dbg_context.SegCs);
623 operand_size = get_size(cs_addr_mode);
625 /* get operand_size (also getting rid of the various prefixes */
628 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
629 if (ch == 0x66)
631 operand_size = 48 - operand_size; /* 16 => 32, 32 => 16 */
632 insn = (const char*)insn + 1;
634 } while (ch == 0x66 || ch == 0x67);
636 switch (ch)
638 case 0xe9: /* jmp near */
639 jumpee->Mode = cs_addr_mode;
640 if (!fetch_value((const char*)insn + 1, operand_size, &delta))
641 return FALSE;
642 jumpee->Segment = dbg_context.SegCs;
643 jumpee->Offset = (DWORD)insn + 1 + (operand_size / 8) + delta;
644 return TRUE;
645 default: WINE_FIXME("unknown %x\n", ch); return FALSE;
647 return FALSE;
650 #define DR7_CONTROL_SHIFT 16
651 #define DR7_CONTROL_SIZE 4
653 #define DR7_RW_EXECUTE (0x0)
654 #define DR7_RW_WRITE (0x1)
655 #define DR7_RW_READ (0x3)
657 #define DR7_LEN_1 (0x0)
658 #define DR7_LEN_2 (0x4)
659 #define DR7_LEN_4 (0xC)
661 #define DR7_LOCAL_ENABLE_SHIFT 0
662 #define DR7_GLOBAL_ENABLE_SHIFT 1
663 #define DR7_ENABLE_SIZE 2
665 #define DR7_LOCAL_ENABLE_MASK (0x55)
666 #define DR7_GLOBAL_ENABLE_MASK (0xAA)
668 #define DR7_CONTROL_RESERVED (0xFC00)
669 #define DR7_LOCAL_SLOWDOWN (0x100)
670 #define DR7_GLOBAL_SLOWDOWN (0x200)
672 #define DR7_ENABLE_MASK(dr) (1<<(DR7_LOCAL_ENABLE_SHIFT+DR7_ENABLE_SIZE*(dr)))
673 #define IS_DR7_SET(ctrl,dr) ((ctrl)&DR7_ENABLE_MASK(dr))
675 static inline int be_i386_get_unused_DR(CONTEXT* ctx, DWORD** r)
677 if (!IS_DR7_SET(ctx->Dr7, 0))
679 *r = &ctx->Dr0;
680 return 0;
682 if (!IS_DR7_SET(ctx->Dr7, 1))
684 *r = &ctx->Dr1;
685 return 1;
687 if (!IS_DR7_SET(ctx->Dr7, 2))
689 *r = &ctx->Dr2;
690 return 2;
692 if (!IS_DR7_SET(ctx->Dr7, 3))
694 *r = &ctx->Dr3;
695 return 3;
697 dbg_printf("All hardware registers have been used\n");
699 return -1;
702 static BOOL be_i386_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
703 CONTEXT* ctx, enum be_xpoint_type type,
704 void* addr, unsigned long* val, unsigned size)
706 unsigned char ch;
707 SIZE_T sz;
708 DWORD *pr;
709 int reg;
710 unsigned long bits;
712 switch (type)
714 case be_xpoint_break:
715 if (size != 0) return FALSE;
716 if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
717 *val = ch;
718 ch = 0xcc;
719 if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
720 break;
721 case be_xpoint_watch_exec:
722 bits = DR7_RW_EXECUTE;
723 goto hw_bp;
724 case be_xpoint_watch_read:
725 bits = DR7_RW_READ;
726 goto hw_bp;
727 case be_xpoint_watch_write:
728 bits = DR7_RW_WRITE;
729 hw_bp:
730 if ((reg = be_i386_get_unused_DR(ctx, &pr)) == -1) return FALSE;
731 *pr = (DWORD)addr;
732 if (type != be_xpoint_watch_exec) switch (size)
734 case 4: bits |= DR7_LEN_4; break;
735 case 2: bits |= DR7_LEN_2; break;
736 case 1: bits |= DR7_LEN_1; break;
737 default: return FALSE;
739 *val = reg;
740 /* clear old values */
741 ctx->Dr7 &= ~(0x0F << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg));
742 /* set the correct ones */
743 ctx->Dr7 |= bits << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg);
744 ctx->Dr7 |= DR7_ENABLE_MASK(reg) | DR7_LOCAL_SLOWDOWN;
745 break;
746 default:
747 dbg_printf("Unknown bp type %c\n", type);
748 return FALSE;
750 return TRUE;
753 static BOOL be_i386_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
754 CONTEXT* ctx, enum be_xpoint_type type,
755 void* addr, unsigned long val, unsigned size)
757 SIZE_T sz;
758 unsigned char ch;
760 switch (type)
762 case be_xpoint_break:
763 if (size != 0) return FALSE;
764 if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
765 if (ch != (unsigned char)0xCC)
766 WINE_FIXME("Cannot get back %02x instead of 0xCC at %08lx\n",
767 ch, (unsigned long)addr);
768 ch = (unsigned char)val;
769 if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
770 break;
771 case be_xpoint_watch_exec:
772 case be_xpoint_watch_read:
773 case be_xpoint_watch_write:
774 /* simply disable the entry */
775 ctx->Dr7 &= ~DR7_ENABLE_MASK(val);
776 break;
777 default:
778 dbg_printf("Unknown bp type %c\n", type);
779 return FALSE;
781 return TRUE;
784 static BOOL be_i386_is_watchpoint_set(const CONTEXT* ctx, unsigned idx)
786 return ctx->Dr6 & (1 << idx);
789 static void be_i386_clear_watchpoint(CONTEXT* ctx, unsigned idx)
791 ctx->Dr6 &= ~(1 << idx);
794 static int be_i386_adjust_pc_for_break(CONTEXT* ctx, BOOL way)
796 if (way)
798 ctx->Eip--;
799 return -1;
801 ctx->Eip++;
802 return 1;
805 static BOOL be_i386_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
806 BOOL is_signed, LONGLONG* ret)
808 if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) return FALSE;
810 memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
811 /* FIXME: this assumes that debuggee and debugger use the same
812 * integral representation
814 if (!memory_read_value(lvalue, size, ret)) return FALSE;
816 /* propagate sign information */
817 if (is_signed && size < 8 && (*ret >> (size * 8 - 1)) != 0)
819 ULONGLONG neg = -1;
820 *ret |= neg << (size * 8);
822 return TRUE;
825 static BOOL be_i386_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
826 long double* ret)
828 char tmp[sizeof(long double)];
830 /* FIXME: this assumes that debuggee and debugger use the same
831 * representation for reals
833 if (!memory_read_value(lvalue, size, tmp)) return FALSE;
835 /* float & double types have to be promoted to a long double */
836 if (size == 4) *ret = *(float*)tmp;
837 else if (size == 8) *ret = *(double*)tmp;
838 else if (size == 10) *ret = *(long double*)tmp;
839 else return FALSE;
841 return TRUE;
844 static BOOL be_i386_store_integer(const struct dbg_lvalue* lvalue, unsigned size,
845 BOOL is_signed, LONGLONG val)
847 /* this is simple as we're on a little endian CPU */
848 return memory_write_value(lvalue, size, &val);
851 struct backend_cpu be_i386 =
853 IMAGE_FILE_MACHINE_I386,
855 be_i386_linearize,
856 be_i386_build_addr,
857 be_i386_get_addr,
858 be_i386_get_register_info,
859 be_i386_single_step,
860 be_i386_print_context,
861 be_i386_print_segment_info,
862 be_i386_ctx,
863 be_i386_is_step_over_insn,
864 be_i386_is_function_return,
865 be_i386_is_break_insn,
866 be_i386_is_func_call,
867 be_i386_is_jump,
868 be_i386_disasm_one_insn,
869 be_i386_insert_Xpoint,
870 be_i386_remove_Xpoint,
871 be_i386_is_watchpoint_set,
872 be_i386_clear_watchpoint,
873 be_i386_adjust_pc_for_break,
874 be_i386_fetch_integer,
875 be_i386_fetch_float,
876 be_i386_store_integer,
878 #endif