hidclass.sys: Use IoRegisterDeviceInterface.
[wine.git] / programs / winedbg / be_i386.c
blob3a2b91afe5a2c4ece515e3ec235b523338192a0f
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 #if defined(__i386__) || defined(__x86_64__)
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 #ifndef __x86_64__
37 typedef struct DECLSPEC_ALIGN(16) _M128A {
38 ULONGLONG Low;
39 LONGLONG High;
40 } M128A, *PM128A;
42 typedef struct _XMM_SAVE_AREA32 {
43 WORD ControlWord; /* 000 */
44 WORD StatusWord; /* 002 */
45 BYTE TagWord; /* 004 */
46 BYTE Reserved1; /* 005 */
47 WORD ErrorOpcode; /* 006 */
48 DWORD ErrorOffset; /* 008 */
49 WORD ErrorSelector; /* 00c */
50 WORD Reserved2; /* 00e */
51 DWORD DataOffset; /* 010 */
52 WORD DataSelector; /* 014 */
53 WORD Reserved3; /* 016 */
54 DWORD MxCsr; /* 018 */
55 DWORD MxCsr_Mask; /* 01c */
56 M128A FloatRegisters[8]; /* 020 */
57 M128A XmmRegisters[16]; /* 0a0 */
58 BYTE Reserved4[96]; /* 1a0 */
59 } XMM_SAVE_AREA32, *PXMM_SAVE_AREA32;
60 #endif
62 static ADDRESS_MODE get_selector_type(HANDLE hThread, const WOW64_CONTEXT *ctx, WORD sel)
64 LDT_ENTRY le;
66 if (IS_VM86_MODE(ctx)) return AddrModeReal;
67 /* null or system selector */
68 if (!(sel & 4) || ((sel >> 3) < 17)) return AddrModeFlat;
69 if (dbg_curr_process->process_io->get_selector(hThread, sel, &le))
70 return le.HighWord.Bits.Default_Big ? AddrMode1632 : AddrMode1616;
71 /* selector doesn't exist */
72 return -1;
75 static void* be_i386_linearize(HANDLE hThread, const ADDRESS64* addr)
77 LDT_ENTRY le;
79 switch (addr->Mode)
81 case AddrModeReal:
82 return (void*)((DWORD_PTR)(LOWORD(addr->Segment) << 4) + (DWORD_PTR)addr->Offset);
83 case AddrMode1632:
84 if (!(addr->Segment & 4) || ((addr->Segment >> 3) < 17))
85 return (void*)(DWORD_PTR)addr->Offset;
86 /* fall through */
87 case AddrMode1616:
88 if (!dbg_curr_process->process_io->get_selector(hThread, addr->Segment, &le)) return NULL;
89 return (void*)((le.HighWord.Bits.BaseHi << 24) +
90 (le.HighWord.Bits.BaseMid << 16) + le.BaseLow +
91 (DWORD_PTR)addr->Offset);
92 case AddrModeFlat:
93 return (void*)(DWORD_PTR)addr->Offset;
95 return NULL;
98 static BOOL be_i386_build_addr(HANDLE hThread, const dbg_ctx_t *ctx, ADDRESS64* addr,
99 unsigned seg, unsigned long offset)
101 addr->Mode = AddrModeFlat;
102 addr->Segment = seg;
103 addr->Offset = offset;
104 if (seg)
106 addr->Mode = get_selector_type(hThread, &ctx->x86, seg);
107 switch (addr->Mode)
109 case AddrModeReal:
110 case AddrMode1616:
111 addr->Offset &= 0xffff;
112 break;
113 case AddrModeFlat:
114 case AddrMode1632:
115 break;
116 default:
117 addr->Mode = -1;
118 return FALSE;
121 return TRUE;
124 static BOOL be_i386_get_addr(HANDLE hThread, const dbg_ctx_t *ctx,
125 enum be_cpu_addr bca, ADDRESS64* addr)
127 switch (bca)
129 case be_cpu_addr_pc:
130 return be_i386_build_addr(hThread, ctx, addr, ctx->x86.SegCs, ctx->x86.Eip);
131 case be_cpu_addr_stack:
132 return be_i386_build_addr(hThread, ctx, addr, ctx->x86.SegSs, ctx->x86.Esp);
133 case be_cpu_addr_frame:
134 return be_i386_build_addr(hThread, ctx, addr, ctx->x86.SegSs, ctx->x86.Ebp);
136 return FALSE;
139 static BOOL be_i386_get_register_info(int regno, enum be_cpu_addr* kind)
141 switch (regno)
143 case CV_REG_EIP: *kind = be_cpu_addr_pc; return TRUE;
144 case CV_REG_EBP: *kind = be_cpu_addr_frame; return TRUE;
145 case CV_REG_ESP: *kind = be_cpu_addr_stack; return TRUE;
147 return FALSE;
150 static void be_i386_single_step(dbg_ctx_t *ctx, BOOL enable)
152 if (enable) ctx->x86.EFlags |= STEP_FLAG;
153 else ctx->x86.EFlags &= ~STEP_FLAG;
156 static void be_i386_all_print_context(HANDLE hThread, const dbg_ctx_t *pctx)
158 static const char mxcsr_flags[16][4] = { "IE", "DE", "ZE", "OE", "UE", "PE", "DAZ", "IM",
159 "DM", "ZM", "OM", "UM", "PM", "R-", "R+", "FZ" };
160 const WOW64_CONTEXT *ctx = &pctx->x86;
161 XMM_SAVE_AREA32 *xmm_area;
162 long double ST[8]; /* These are for floating regs */
163 int cnt;
165 /* Break out the FPU state and the floating point registers */
166 dbg_printf("Floating Point Unit status:\n");
167 dbg_printf(" FLCW:%04x ", LOWORD(ctx->FloatSave.ControlWord));
168 dbg_printf(" FLTW:%04x ", LOWORD(ctx->FloatSave.TagWord));
169 dbg_printf(" FLEO:%08x ", (unsigned int) ctx->FloatSave.ErrorOffset);
170 dbg_printf(" FLSW:%04x", LOWORD(ctx->FloatSave.StatusWord));
172 /* Isolate the condition code bits - note they are not contiguous */
173 dbg_printf("(CC:%d%d%d%d", (ctx->FloatSave.StatusWord & 0x00004000) >> 14,
174 (ctx->FloatSave.StatusWord & 0x00000400) >> 10,
175 (ctx->FloatSave.StatusWord & 0x00000200) >> 9,
176 (ctx->FloatSave.StatusWord & 0x00000100) >> 8);
178 /* Now pull out the 3 bit of the TOP stack pointer */
179 dbg_printf(" TOP:%01x", (unsigned int) (ctx->FloatSave.StatusWord & 0x00003800) >> 11);
181 /* Lets analyse the error bits and indicate the status
182 * the Invalid Op flag has sub status which is tested as follows */
183 if (ctx->FloatSave.StatusWord & 0x00000001) { /* Invalid Fl OP */
184 if (ctx->FloatSave.StatusWord & 0x00000040) { /* Stack Fault */
185 if (ctx->FloatSave.StatusWord & 0x00000200) /* C1 says Overflow */
186 dbg_printf(" #IE(Stack Overflow)");
187 else
188 dbg_printf(" #IE(Stack Underflow)"); /* Underflow */
190 else dbg_printf(" #IE(Arthimetic error)"); /* Invalid Fl OP */
193 if (ctx->FloatSave.StatusWord & 0x00000002) dbg_printf(" #DE"); /* Denormalised OP */
194 if (ctx->FloatSave.StatusWord & 0x00000004) dbg_printf(" #ZE"); /* Zero Divide */
195 if (ctx->FloatSave.StatusWord & 0x00000008) dbg_printf(" #OE"); /* Overflow */
196 if (ctx->FloatSave.StatusWord & 0x00000010) dbg_printf(" #UE"); /* Underflow */
197 if (ctx->FloatSave.StatusWord & 0x00000020) dbg_printf(" #PE"); /* Precision error */
198 if (ctx->FloatSave.StatusWord & 0x00000040)
199 if (!(ctx->FloatSave.StatusWord & 0x00000001))
200 dbg_printf(" #SE"); /* Stack Fault (don't think this can occur) */
201 if (ctx->FloatSave.StatusWord & 0x00000080) dbg_printf(" #ES"); /* Error Summary */
202 if (ctx->FloatSave.StatusWord & 0x00008000) dbg_printf(" #FB"); /* FPU Busy */
203 dbg_printf(")\n");
205 /* Here are the rest of the registers */
206 dbg_printf(" FLES:%08x FLDO:%08x FLDS:%08x FLCNS:%08x\n",
207 ctx->FloatSave.ErrorSelector,
208 ctx->FloatSave.DataOffset,
209 ctx->FloatSave.DataSelector,
210 ctx->FloatSave.Cr0NpxState);
212 /* Now for the floating point registers */
213 dbg_printf("Floating Point Registers:\n");
214 for (cnt = 0; cnt < 4; cnt++)
216 memcpy(&ST[cnt], &ctx->FloatSave.RegisterArea[cnt * 10], 10);
217 dbg_printf(" ST%d:%Lf ", cnt, ST[cnt]);
219 dbg_printf("\n");
220 for (cnt = 4; cnt < 8; cnt++)
222 memcpy(&ST[cnt], &ctx->FloatSave.RegisterArea[cnt * 10], 10);
223 dbg_printf(" ST%d:%Lf ", cnt, ST[cnt]);
226 xmm_area = (XMM_SAVE_AREA32 *) &ctx->ExtendedRegisters;
228 dbg_printf(" mxcsr: %04x (", xmm_area->MxCsr );
229 for (cnt = 0; cnt < 16; cnt++)
230 if (xmm_area->MxCsr & (1 << cnt)) dbg_printf( " %s", mxcsr_flags[cnt] );
231 dbg_printf(" )\n");
233 for (cnt = 0; cnt < 8; cnt++)
235 dbg_printf( " xmm%u: uint=%08x%08x%08x%08x", cnt,
236 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 3),
237 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 2),
238 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 1),
239 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 0));
240 dbg_printf( " double={%g; %g}", *(double *)&xmm_area->XmmRegisters[cnt].Low,
241 *(double *)&xmm_area->XmmRegisters[cnt].High );
242 dbg_printf( " float={%g; %g; %g; %g}\n",
243 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 0),
244 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 1),
245 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 2),
246 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 3) );
248 dbg_printf("\n");
251 static void be_i386_print_context(HANDLE hThread, const dbg_ctx_t *pctx, int all_regs)
253 static const char flags[] = "aVR-N--ODITSZ-A-P-C";
254 const WOW64_CONTEXT *ctx = &pctx->x86;
255 int i;
256 char buf[33];
258 dbg_printf("Register dump:\n");
260 /* First get the segment registers out of the way */
261 dbg_printf(" CS:%04x SS:%04x DS:%04x ES:%04x FS:%04x GS:%04x",
262 (WORD)ctx->SegCs, (WORD)ctx->SegSs,
263 (WORD)ctx->SegDs, (WORD)ctx->SegEs,
264 (WORD)ctx->SegFs, (WORD)ctx->SegGs);
266 strcpy(buf, flags);
267 for (i = 0; buf[i]; i++)
268 if (buf[i] != '-' && !(ctx->EFlags & (1 << (sizeof(flags) - 2 - i))))
269 buf[i] = ' ';
271 switch (get_selector_type(hThread, ctx, ctx->SegCs))
273 case AddrMode1616:
274 case AddrModeReal:
275 dbg_printf("\n IP:%04x SP:%04x BP:%04x FLAGS:%04x(%s)\n",
276 LOWORD(ctx->Eip), LOWORD(ctx->Esp),
277 LOWORD(ctx->Ebp), LOWORD(ctx->EFlags), buf);
278 dbg_printf(" AX:%04x BX:%04x CX:%04x DX:%04x SI:%04x DI:%04x\n",
279 LOWORD(ctx->Eax), LOWORD(ctx->Ebx),
280 LOWORD(ctx->Ecx), LOWORD(ctx->Edx),
281 LOWORD(ctx->Esi), LOWORD(ctx->Edi));
282 break;
283 case AddrModeFlat:
284 case AddrMode1632:
285 dbg_printf("\n EIP:%08x ESP:%08x EBP:%08x EFLAGS:%08x(%s)\n",
286 ctx->Eip, ctx->Esp, ctx->Ebp, ctx->EFlags, buf);
287 dbg_printf(" EAX:%08x EBX:%08x ECX:%08x EDX:%08x\n",
288 ctx->Eax, ctx->Ebx, ctx->Ecx, ctx->Edx);
289 dbg_printf(" ESI:%08x EDI:%08x\n",
290 ctx->Esi, ctx->Edi);
291 break;
294 if (all_regs) be_i386_all_print_context(hThread, pctx);
298 static void be_i386_print_segment_info(HANDLE hThread, const dbg_ctx_t *ctx)
300 if (get_selector_type(hThread, &ctx->x86, ctx->x86.SegCs) == AddrMode1616)
302 info_win32_segments(ctx->x86.SegDs >> 3, 1);
303 if (ctx->x86.SegEs != ctx->x86.SegDs)
304 info_win32_segments(ctx->x86.SegEs >> 3, 1);
306 info_win32_segments(ctx->x86.SegFs >> 3, 1);
309 static struct dbg_internal_var be_i386_ctx[] =
311 {CV_REG_AL, "AL", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Eax), dbg_itype_unsigned_char_int},
312 {CV_REG_CL, "CL", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ecx), dbg_itype_unsigned_char_int},
313 {CV_REG_DL, "DL", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Edx), dbg_itype_unsigned_char_int},
314 {CV_REG_BL, "BL", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ebx), dbg_itype_unsigned_char_int},
315 {CV_REG_AH, "AH", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, Eax)+1), dbg_itype_unsigned_char_int},
316 {CV_REG_CH, "CH", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, Ecx)+1), dbg_itype_unsigned_char_int},
317 {CV_REG_DH, "DH", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, Edx)+1), dbg_itype_unsigned_char_int},
318 {CV_REG_BH, "BH", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, Ebx)+1), dbg_itype_unsigned_char_int},
319 {CV_REG_AX, "AX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Eax), dbg_itype_unsigned_short_int},
320 {CV_REG_CX, "CX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ecx), dbg_itype_unsigned_short_int},
321 {CV_REG_DX, "DX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Edx), dbg_itype_unsigned_short_int},
322 {CV_REG_BX, "BX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ebx), dbg_itype_unsigned_short_int},
323 {CV_REG_SP, "SP", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Esp), dbg_itype_unsigned_short_int},
324 {CV_REG_BP, "BP", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ebp), dbg_itype_unsigned_short_int},
325 {CV_REG_SI, "SI", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Esi), dbg_itype_unsigned_short_int},
326 {CV_REG_DI, "DI", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Edi), dbg_itype_unsigned_short_int},
327 {CV_REG_EAX, "EAX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Eax), dbg_itype_unsigned_int},
328 {CV_REG_ECX, "ECX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ecx), dbg_itype_unsigned_int},
329 {CV_REG_EDX, "EDX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Edx), dbg_itype_unsigned_int},
330 {CV_REG_EBX, "EBX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ebx), dbg_itype_unsigned_int},
331 {CV_REG_ESP, "ESP", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Esp), dbg_itype_unsigned_int},
332 {CV_REG_EBP, "EBP", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ebp), dbg_itype_unsigned_int},
333 {CV_REG_ESI, "ESI", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Esi), dbg_itype_unsigned_int},
334 {CV_REG_EDI, "EDI", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Edi), dbg_itype_unsigned_int},
335 {CV_REG_ES, "ES", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, SegEs), dbg_itype_unsigned_short_int},
336 {CV_REG_CS, "CS", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, SegCs), dbg_itype_unsigned_short_int},
337 {CV_REG_SS, "SS", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, SegSs), dbg_itype_unsigned_short_int},
338 {CV_REG_DS, "DS", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, SegDs), dbg_itype_unsigned_short_int},
339 {CV_REG_FS, "FS", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, SegFs), dbg_itype_unsigned_short_int},
340 {CV_REG_GS, "GS", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, SegGs), dbg_itype_unsigned_short_int},
341 {CV_REG_IP, "IP", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Eip), dbg_itype_unsigned_short_int},
342 {CV_REG_FLAGS, "FLAGS", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, EFlags), dbg_itype_unsigned_short_int},
343 {CV_REG_EIP, "EIP", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Eip), dbg_itype_unsigned_int},
344 {CV_REG_EFLAGS, "EFLAGS", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, EFlags), dbg_itype_unsigned_int},
345 {CV_REG_ST0, "ST0", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[ 0]), dbg_itype_long_real},
346 {CV_REG_ST0+1, "ST1", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[10]), dbg_itype_long_real},
347 {CV_REG_ST0+2, "ST2", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[20]), dbg_itype_long_real},
348 {CV_REG_ST0+3, "ST3", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[30]), dbg_itype_long_real},
349 {CV_REG_ST0+4, "ST4", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[40]), dbg_itype_long_real},
350 {CV_REG_ST0+5, "ST5", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[50]), dbg_itype_long_real},
351 {CV_REG_ST0+6, "ST6", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[60]), dbg_itype_long_real},
352 {CV_REG_ST0+7, "ST7", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[70]), dbg_itype_long_real},
353 {CV_AMD64_XMM0, "XMM0", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[0])), dbg_itype_m128a},
354 {CV_AMD64_XMM0+1, "XMM1", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[1])), dbg_itype_m128a},
355 {CV_AMD64_XMM0+2, "XMM2", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[2])), dbg_itype_m128a},
356 {CV_AMD64_XMM0+3, "XMM3", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[3])), dbg_itype_m128a},
357 {CV_AMD64_XMM0+4, "XMM4", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[4])), dbg_itype_m128a},
358 {CV_AMD64_XMM0+5, "XMM5", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[5])), dbg_itype_m128a},
359 {CV_AMD64_XMM0+6, "XMM6", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[6])), dbg_itype_m128a},
360 {CV_AMD64_XMM0+7, "XMM7", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[7])), dbg_itype_m128a},
361 {0, NULL, 0, dbg_itype_none}
364 static BOOL be_i386_is_step_over_insn(const void* insn)
366 BYTE ch;
368 for (;;)
370 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
372 switch (ch)
374 /* Skip all prefixes */
375 case 0x2e: /* cs: */
376 case 0x36: /* ss: */
377 case 0x3e: /* ds: */
378 case 0x26: /* es: */
379 case 0x64: /* fs: */
380 case 0x65: /* gs: */
381 case 0x66: /* opcode size prefix */
382 case 0x67: /* addr size prefix */
383 case 0xf0: /* lock */
384 case 0xf2: /* repne */
385 case 0xf3: /* repe */
386 insn = (const char*)insn + 1;
387 continue;
389 /* Handle call instructions */
390 case 0xcd: /* int <intno> */
391 case 0xe8: /* call <offset> */
392 case 0x9a: /* lcall <seg>:<off> */
393 return TRUE;
395 case 0xff: /* call <regmodrm> */
396 if (!dbg_read_memory((const char*)insn + 1, &ch, sizeof(ch)))
397 return FALSE;
398 return (((ch & 0x38) == 0x10) || ((ch & 0x38) == 0x18));
400 /* Handle string instructions */
401 case 0x6c: /* insb */
402 case 0x6d: /* insw */
403 case 0x6e: /* outsb */
404 case 0x6f: /* outsw */
405 case 0xa4: /* movsb */
406 case 0xa5: /* movsw */
407 case 0xa6: /* cmpsb */
408 case 0xa7: /* cmpsw */
409 case 0xaa: /* stosb */
410 case 0xab: /* stosw */
411 case 0xac: /* lodsb */
412 case 0xad: /* lodsw */
413 case 0xae: /* scasb */
414 case 0xaf: /* scasw */
415 return TRUE;
417 default:
418 return FALSE;
423 static BOOL be_i386_is_function_return(const void* insn)
425 BYTE ch;
427 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
428 if (ch == 0xF3) /* REP */
430 insn = (const char*)insn + 1;
431 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
433 return (ch == 0xC2) || (ch == 0xC3);
436 static BOOL be_i386_is_break_insn(const void* insn)
438 BYTE c;
440 if (!dbg_read_memory(insn, &c, sizeof(c))) return FALSE;
441 return c == 0xCC;
444 static unsigned get_size(ADDRESS_MODE am)
446 if (am == AddrModeReal || am == AddrMode1616) return 16;
447 return 32;
450 static BOOL fetch_value(const char* addr, unsigned sz, int* value)
452 char value8;
453 short value16;
455 switch (sz)
457 case 8:
458 if (!dbg_read_memory(addr, &value8, sizeof(value8)))
459 return FALSE;
460 *value = value8;
461 break;
462 case 16:
463 if (!dbg_read_memory(addr, &value16, sizeof(value16)))
464 return FALSE;
465 *value = value16;
466 break;
467 case 32:
468 if (!dbg_read_memory(addr, value, sizeof(*value)))
469 return FALSE;
470 break;
471 default: return FALSE;
473 return TRUE;
476 static BOOL be_i386_is_func_call(const void* insn, ADDRESS64* callee)
478 BYTE ch;
479 int delta;
480 short segment;
481 unsigned dst = 0;
482 unsigned operand_size;
483 ADDRESS_MODE cs_addr_mode;
485 cs_addr_mode = get_selector_type(dbg_curr_thread->handle, &dbg_context.x86,
486 dbg_context.x86.SegCs);
487 operand_size = get_size(cs_addr_mode);
489 /* get operand_size (also getting rid of the various prefixes */
492 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
493 if (ch == 0x66)
495 operand_size = 48 - operand_size; /* 16 => 32, 32 => 16 */
496 insn = (const char*)insn + 1;
498 } while (ch == 0x66 || ch == 0x67);
500 switch (ch)
502 case 0xe8: /* relative near call */
503 callee->Mode = cs_addr_mode;
504 if (!fetch_value((const char*)insn + 1, operand_size, &delta))
505 return FALSE;
506 callee->Segment = dbg_context.x86.SegCs;
507 callee->Offset = (DWORD_PTR)insn + 1 + (operand_size / 8) + delta;
508 return TRUE;
510 case 0x9a: /* absolute far call */
511 if (!dbg_read_memory((const char*)insn + 1 + operand_size / 8,
512 &segment, sizeof(segment)))
513 return FALSE;
514 callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context.x86,
515 segment);
516 if (!fetch_value((const char*)insn + 1, operand_size, &delta))
517 return FALSE;
518 callee->Segment = segment;
519 callee->Offset = delta;
520 return TRUE;
522 case 0xff:
523 if (!dbg_read_memory((const char*)insn + 1, &ch, sizeof(ch)))
524 return FALSE;
525 /* keep only the CALL and LCALL insn:s */
526 switch ((ch >> 3) & 0x07)
528 case 0x02:
529 segment = dbg_context.x86.SegCs;
530 break;
531 case 0x03:
532 if (!dbg_read_memory((const char*)insn + 1 + operand_size / 8,
533 &segment, sizeof(segment)))
534 return FALSE;
535 break;
536 default: return FALSE;
538 /* FIXME: we only support the 32 bit far calls for now */
539 if (operand_size != 32)
541 WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) with 16 bit operand-size at %p\n", ch, insn);
542 return FALSE;
544 switch (ch & 0xC7) /* keep Mod R/M only (skip reg) */
546 case 0x04:
547 case 0x44:
548 case 0x84:
549 WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) (SIB bytes) at %p\n", ch, insn);
550 return FALSE;
551 case 0x05: /* addr32 */
552 if ((ch & 0x38) == 0x10 || /* call */
553 (ch & 0x38) == 0x18) /* lcall */
555 void *addr;
556 if (!dbg_read_memory((const char *)insn + 2, &addr, sizeof(addr)))
557 return FALSE;
558 if ((ch & 0x38) == 0x18) /* lcall */
560 if (!dbg_read_memory((const char*)addr + operand_size, &segment, sizeof(segment)))
561 return FALSE;
563 else segment = dbg_context.x86.SegCs;
564 if (!dbg_read_memory((const char*)addr, &dst, sizeof(dst)))
565 return FALSE;
566 callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context.x86, segment);
567 callee->Segment = segment;
568 callee->Offset = dst;
569 return TRUE;
571 return FALSE;
572 default:
573 switch (ch & 0x07)
575 case 0x00: dst = dbg_context.x86.Eax; break;
576 case 0x01: dst = dbg_context.x86.Ecx; break;
577 case 0x02: dst = dbg_context.x86.Edx; break;
578 case 0x03: dst = dbg_context.x86.Ebx; break;
579 case 0x04: dst = dbg_context.x86.Esp; break;
580 case 0x05: dst = dbg_context.x86.Ebp; break;
581 case 0x06: dst = dbg_context.x86.Esi; break;
582 case 0x07: dst = dbg_context.x86.Edi; break;
584 if ((ch >> 6) != 0x03) /* indirect address */
586 if (ch >> 6) /* we got a displacement */
588 if (!fetch_value((const char*)insn + 2, (ch >> 6) == 0x01 ? 8 : 32, &delta))
589 return FALSE;
590 dst += delta;
592 if (((ch >> 3) & 0x07) == 0x03) /* LCALL */
594 if (!dbg_read_memory((const char*)(UINT_PTR)dst + operand_size, &segment, sizeof(segment)))
595 return FALSE;
597 else segment = dbg_context.x86.SegCs;
598 if (!dbg_read_memory((const char*)(UINT_PTR)dst, &delta, sizeof(delta)))
599 return FALSE;
600 callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context.x86,
601 segment);
602 callee->Segment = segment;
603 callee->Offset = delta;
605 else
607 callee->Mode = cs_addr_mode;
608 callee->Segment = dbg_context.x86.SegCs;
609 callee->Offset = dst;
612 return TRUE;
614 default:
615 return FALSE;
619 static BOOL be_i386_is_jump(const void* insn, ADDRESS64* jumpee)
621 BYTE ch;
622 int delta;
623 unsigned operand_size;
624 ADDRESS_MODE cs_addr_mode;
626 cs_addr_mode = get_selector_type(dbg_curr_thread->handle, &dbg_context.x86,
627 dbg_context.x86.SegCs);
628 operand_size = get_size(cs_addr_mode);
630 /* get operand_size (also getting rid of the various prefixes */
633 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
634 if (ch == 0x66)
636 operand_size = 48 - operand_size; /* 16 => 32, 32 => 16 */
637 insn = (const char*)insn + 1;
639 } while (ch == 0x66 || ch == 0x67);
641 switch (ch)
643 case 0xe9: /* jmp near */
644 jumpee->Mode = cs_addr_mode;
645 if (!fetch_value((const char*)insn + 1, operand_size, &delta))
646 return FALSE;
647 jumpee->Segment = dbg_context.x86.SegCs;
648 jumpee->Offset = (DWORD_PTR)insn + 1 + (operand_size / 8) + delta;
649 return TRUE;
650 default: WINE_FIXME("unknown %x\n", ch); return FALSE;
652 return FALSE;
655 #define DR7_CONTROL_SHIFT 16
656 #define DR7_CONTROL_SIZE 4
658 #define DR7_RW_EXECUTE (0x0)
659 #define DR7_RW_WRITE (0x1)
660 #define DR7_RW_READ (0x3)
662 #define DR7_LEN_1 (0x0)
663 #define DR7_LEN_2 (0x4)
664 #define DR7_LEN_4 (0xC)
666 #define DR7_LOCAL_ENABLE_SHIFT 0
667 #define DR7_GLOBAL_ENABLE_SHIFT 1
668 #define DR7_ENABLE_SIZE 2
670 #define DR7_LOCAL_ENABLE_MASK (0x55)
671 #define DR7_GLOBAL_ENABLE_MASK (0xAA)
673 #define DR7_CONTROL_RESERVED (0xFC00)
674 #define DR7_LOCAL_SLOWDOWN (0x100)
675 #define DR7_GLOBAL_SLOWDOWN (0x200)
677 #define DR7_ENABLE_MASK(dr) (1<<(DR7_LOCAL_ENABLE_SHIFT+DR7_ENABLE_SIZE*(dr)))
678 #define IS_DR7_SET(ctrl,dr) ((ctrl)&DR7_ENABLE_MASK(dr))
680 static inline int be_i386_get_unused_DR(dbg_ctx_t *pctx, DWORD** r)
682 WOW64_CONTEXT *ctx = &pctx->x86;
684 if (!IS_DR7_SET(ctx->Dr7, 0))
686 *r = &ctx->Dr0;
687 return 0;
689 if (!IS_DR7_SET(ctx->Dr7, 1))
691 *r = &ctx->Dr1;
692 return 1;
694 if (!IS_DR7_SET(ctx->Dr7, 2))
696 *r = &ctx->Dr2;
697 return 2;
699 if (!IS_DR7_SET(ctx->Dr7, 3))
701 *r = &ctx->Dr3;
702 return 3;
704 dbg_printf("All hardware registers have been used\n");
706 return -1;
709 static BOOL be_i386_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
710 dbg_ctx_t *ctx, enum be_xpoint_type type,
711 void* addr, unsigned long* val, unsigned size)
713 unsigned char ch;
714 SIZE_T sz;
715 DWORD *pr;
716 int reg;
717 unsigned long bits;
719 switch (type)
721 case be_xpoint_break:
722 if (size != 0) return FALSE;
723 if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
724 *val = ch;
725 ch = 0xcc;
726 if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
727 break;
728 case be_xpoint_watch_exec:
729 bits = DR7_RW_EXECUTE;
730 goto hw_bp;
731 case be_xpoint_watch_read:
732 bits = DR7_RW_READ;
733 goto hw_bp;
734 case be_xpoint_watch_write:
735 bits = DR7_RW_WRITE;
736 hw_bp:
737 if ((reg = be_i386_get_unused_DR(ctx, &pr)) == -1) return FALSE;
738 *pr = (DWORD_PTR)addr;
739 if (type != be_xpoint_watch_exec) switch (size)
741 case 4: bits |= DR7_LEN_4; break;
742 case 2: bits |= DR7_LEN_2; break;
743 case 1: bits |= DR7_LEN_1; break;
744 default: return FALSE;
746 *val = reg;
747 /* clear old values */
748 ctx->x86.Dr7 &= ~(0x0F << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg));
749 /* set the correct ones */
750 ctx->x86.Dr7 |= bits << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg);
751 ctx->x86.Dr7 |= DR7_ENABLE_MASK(reg) | DR7_LOCAL_SLOWDOWN;
752 break;
753 default:
754 dbg_printf("Unknown bp type %c\n", type);
755 return FALSE;
757 return TRUE;
760 static BOOL be_i386_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
761 dbg_ctx_t *ctx, enum be_xpoint_type type,
762 void* addr, unsigned long val, unsigned size)
764 SIZE_T sz;
765 unsigned char ch;
767 switch (type)
769 case be_xpoint_break:
770 if (size != 0) return FALSE;
771 if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
772 if (ch != (unsigned char)0xCC)
773 WINE_FIXME("Cannot get back %02x instead of 0xCC at %08lx\n",
774 ch, (unsigned long)addr);
775 ch = (unsigned char)val;
776 if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
777 break;
778 case be_xpoint_watch_exec:
779 case be_xpoint_watch_read:
780 case be_xpoint_watch_write:
781 /* simply disable the entry */
782 ctx->x86.Dr7 &= ~DR7_ENABLE_MASK(val);
783 break;
784 default:
785 dbg_printf("Unknown bp type %c\n", type);
786 return FALSE;
788 return TRUE;
791 static BOOL be_i386_is_watchpoint_set(const dbg_ctx_t *ctx, unsigned idx)
793 return ctx->x86.Dr6 & (1 << idx);
796 static void be_i386_clear_watchpoint(dbg_ctx_t *ctx, unsigned idx)
798 ctx->x86.Dr6 &= ~(1 << idx);
801 static int be_i386_adjust_pc_for_break(dbg_ctx_t *ctx, BOOL way)
803 if (way)
805 ctx->x86.Eip--;
806 return -1;
808 ctx->x86.Eip++;
809 return 1;
812 static BOOL be_i386_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
813 BOOL is_signed, LONGLONG* ret)
815 if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) return FALSE;
817 memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
818 /* FIXME: this assumes that debuggee and debugger use the same
819 * integral representation
821 if (!memory_read_value(lvalue, size, ret)) return FALSE;
823 /* propagate sign information */
824 if (is_signed && size < 8 && (*ret >> (size * 8 - 1)) != 0)
826 ULONGLONG neg = -1;
827 *ret |= neg << (size * 8);
829 return TRUE;
832 static BOOL be_i386_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
833 long double* ret)
835 char tmp[sizeof(long double)];
837 /* FIXME: this assumes that debuggee and debugger use the same
838 * representation for reals
840 if (!memory_read_value(lvalue, size, tmp)) return FALSE;
842 /* float & double types have to be promoted to a long double */
843 if (size == 4) *ret = *(float*)tmp;
844 else if (size == 8) *ret = *(double*)tmp;
845 else if (size == 10) *ret = *(long double*)tmp;
846 else return FALSE;
848 return TRUE;
851 static BOOL be_i386_store_integer(const struct dbg_lvalue* lvalue, unsigned size,
852 BOOL is_signed, LONGLONG val)
854 /* this is simple as we're on a little endian CPU */
855 return memory_write_value(lvalue, size, &val);
858 static BOOL be_i386_get_context(HANDLE thread, dbg_ctx_t *ctx)
860 ctx->x86.ContextFlags = WOW64_CONTEXT_ALL;
861 return Wow64GetThreadContext(thread, &ctx->x86);
864 static BOOL be_i386_set_context(HANDLE thread, const dbg_ctx_t *ctx)
866 return Wow64SetThreadContext(thread, &ctx->x86);
869 #define REG(r,gs) {FIELD_OFFSET(WOW64_CONTEXT, r), sizeof(((WOW64_CONTEXT*)NULL)->r), gs}
871 static struct gdb_register be_i386_gdb_register_map[] = {
872 REG(Eax, 4),
873 REG(Ecx, 4),
874 REG(Edx, 4),
875 REG(Ebx, 4),
876 REG(Esp, 4),
877 REG(Ebp, 4),
878 REG(Esi, 4),
879 REG(Edi, 4),
880 REG(Eip, 4),
881 REG(EFlags, 4),
882 REG(SegCs, 4),
883 REG(SegSs, 4),
884 REG(SegDs, 4),
885 REG(SegEs, 4),
886 REG(SegFs, 4),
887 REG(SegGs, 4),
888 { FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[ 0]), 10, 10 },
889 { FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[10]), 10, 10 },
890 { FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[20]), 10, 10 },
891 { FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[30]), 10, 10 },
892 { FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[40]), 10, 10 },
893 { FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[50]), 10, 10 },
894 { FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[60]), 10, 10 },
895 { FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[70]), 10, 10 },
896 { FIELD_OFFSET(WOW64_CONTEXT, FloatSave.ControlWord), 2, 4 },
897 { FIELD_OFFSET(WOW64_CONTEXT, FloatSave.StatusWord), 2, 4 },
898 { FIELD_OFFSET(WOW64_CONTEXT, FloatSave.TagWord), 2, 4 },
899 { FIELD_OFFSET(WOW64_CONTEXT, FloatSave.ErrorSelector), 2, 4 },
900 REG(FloatSave.ErrorOffset, 4 ),
901 { FIELD_OFFSET(WOW64_CONTEXT, FloatSave.DataSelector), 2, 4 },
902 REG(FloatSave.DataOffset, 4 ),
903 { FIELD_OFFSET(WOW64_CONTEXT, FloatSave.ErrorSelector)+2, 2, 4 },
904 { FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[0]), 16, 16 },
905 { FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[1]), 16, 16 },
906 { FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[2]), 16, 16 },
907 { FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[3]), 16, 16 },
908 { FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[4]), 16, 16 },
909 { FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[5]), 16, 16 },
910 { FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[6]), 16, 16 },
911 { FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, XmmRegisters[7]), 16, 16 },
912 { FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XMM_SAVE_AREA32, MxCsr), 4, 4 },
915 struct backend_cpu be_i386 =
917 IMAGE_FILE_MACHINE_I386,
919 be_i386_linearize,
920 be_i386_build_addr,
921 be_i386_get_addr,
922 be_i386_get_register_info,
923 be_i386_single_step,
924 be_i386_print_context,
925 be_i386_print_segment_info,
926 be_i386_ctx,
927 be_i386_is_step_over_insn,
928 be_i386_is_function_return,
929 be_i386_is_break_insn,
930 be_i386_is_func_call,
931 be_i386_is_jump,
932 be_i386_disasm_one_insn,
933 be_i386_insert_Xpoint,
934 be_i386_remove_Xpoint,
935 be_i386_is_watchpoint_set,
936 be_i386_clear_watchpoint,
937 be_i386_adjust_pc_for_break,
938 be_i386_fetch_integer,
939 be_i386_fetch_float,
940 be_i386_store_integer,
941 be_i386_get_context,
942 be_i386_set_context,
943 be_i386_gdb_register_map,
944 ARRAY_SIZE(be_i386_gdb_register_map),
946 #endif