gdiplus: Support recording pen custom end line cap.
[wine.git] / programs / winedbg / be_i386.c
blob503a182641d7afafd87ef97688eabefe7c2cac92
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 #define STEP_FLAG 0x00000100 /* single step flag */
29 #define V86_FLAG 0x00020000
31 #define IS_VM86_MODE(ctx) (ctx->EFlags & V86_FLAG)
33 static ADDRESS_MODE get_selector_type(HANDLE hThread, const WOW64_CONTEXT *ctx, WORD sel)
35 LDT_ENTRY le;
37 if (IS_VM86_MODE(ctx)) return AddrModeReal;
38 /* null or system selector */
39 if (!(sel & 4) || ((sel >> 3) < 17)) return AddrModeFlat;
40 if (dbg_curr_process->process_io->get_selector(hThread, sel, &le))
41 return le.HighWord.Bits.Default_Big ? AddrMode1632 : AddrMode1616;
42 /* selector doesn't exist */
43 return -1;
46 static void* be_i386_linearize(HANDLE hThread, const ADDRESS64* addr)
48 LDT_ENTRY le;
50 switch (addr->Mode)
52 case AddrModeReal:
53 return (void*)((DWORD_PTR)(LOWORD(addr->Segment) << 4) + (DWORD_PTR)addr->Offset);
54 case AddrMode1632:
55 if (!(addr->Segment & 4) || ((addr->Segment >> 3) < 17))
56 return (void*)(DWORD_PTR)addr->Offset;
57 /* fall through */
58 case AddrMode1616:
59 if (!dbg_curr_process->process_io->get_selector(hThread, addr->Segment, &le)) return NULL;
60 return (void*)((le.HighWord.Bits.BaseHi << 24) +
61 (le.HighWord.Bits.BaseMid << 16) + le.BaseLow +
62 (DWORD_PTR)addr->Offset);
63 case AddrModeFlat:
64 return (void*)(DWORD_PTR)addr->Offset;
66 return NULL;
69 static BOOL be_i386_build_addr(HANDLE hThread, const dbg_ctx_t *ctx, ADDRESS64* addr,
70 unsigned seg, DWORD64 offset)
72 addr->Mode = AddrModeFlat;
73 addr->Segment = seg;
74 addr->Offset = offset;
75 if (seg)
77 addr->Mode = get_selector_type(hThread, &ctx->x86, seg);
78 switch (addr->Mode)
80 case AddrModeReal:
81 case AddrMode1616:
82 addr->Offset &= 0xffff;
83 break;
84 case AddrModeFlat:
85 case AddrMode1632:
86 break;
87 default:
88 addr->Mode = -1;
89 return FALSE;
92 return TRUE;
95 static BOOL be_i386_get_addr(HANDLE hThread, const dbg_ctx_t *ctx,
96 enum be_cpu_addr bca, ADDRESS64* addr)
98 switch (bca)
100 case be_cpu_addr_pc:
101 return be_i386_build_addr(hThread, ctx, addr, ctx->x86.SegCs, ctx->x86.Eip);
102 case be_cpu_addr_stack:
103 return be_i386_build_addr(hThread, ctx, addr, ctx->x86.SegSs, ctx->x86.Esp);
104 case be_cpu_addr_frame:
105 return be_i386_build_addr(hThread, ctx, addr, ctx->x86.SegSs, ctx->x86.Ebp);
107 return FALSE;
110 static BOOL be_i386_get_register_info(int regno, enum be_cpu_addr* kind)
112 switch (regno)
114 case CV_REG_EIP: *kind = be_cpu_addr_pc; return TRUE;
115 case CV_REG_EBP: *kind = be_cpu_addr_frame; return TRUE;
116 case CV_REG_ESP: *kind = be_cpu_addr_stack; return TRUE;
118 return FALSE;
121 static void be_i386_single_step(dbg_ctx_t *ctx, BOOL enable)
123 if (enable) ctx->x86.EFlags |= STEP_FLAG;
124 else ctx->x86.EFlags &= ~STEP_FLAG;
127 static void be_i386_all_print_context(HANDLE hThread, const dbg_ctx_t *pctx)
129 static const char mxcsr_flags[16][4] = { "IE", "DE", "ZE", "OE", "UE", "PE", "DAZ", "IM",
130 "DM", "ZM", "OM", "UM", "PM", "R-", "R+", "FZ" };
131 const WOW64_CONTEXT *ctx = &pctx->x86;
132 XSAVE_FORMAT *xmm_area;
133 int cnt;
135 /* Break out the FPU state and the floating point registers */
136 dbg_printf("Floating Point Unit status:\n");
137 dbg_printf(" FLCW:%04x ", LOWORD(ctx->FloatSave.ControlWord));
138 dbg_printf(" FLTW:%04x ", LOWORD(ctx->FloatSave.TagWord));
139 dbg_printf(" FLEO:%08x ", (unsigned int) ctx->FloatSave.ErrorOffset);
140 dbg_printf(" FLSW:%04x", LOWORD(ctx->FloatSave.StatusWord));
142 /* Isolate the condition code bits - note they are not contiguous */
143 dbg_printf("(CC:%ld%ld%ld%ld", (ctx->FloatSave.StatusWord & 0x00004000) >> 14,
144 (ctx->FloatSave.StatusWord & 0x00000400) >> 10,
145 (ctx->FloatSave.StatusWord & 0x00000200) >> 9,
146 (ctx->FloatSave.StatusWord & 0x00000100) >> 8);
148 /* Now pull out the 3 bit of the TOP stack pointer */
149 dbg_printf(" TOP:%01x", (unsigned int) (ctx->FloatSave.StatusWord & 0x00003800) >> 11);
151 /* Lets analyse the error bits and indicate the status
152 * the Invalid Op flag has sub status which is tested as follows */
153 if (ctx->FloatSave.StatusWord & 0x00000001) { /* Invalid Fl OP */
154 if (ctx->FloatSave.StatusWord & 0x00000040) { /* Stack Fault */
155 if (ctx->FloatSave.StatusWord & 0x00000200) /* C1 says Overflow */
156 dbg_printf(" #IE(Stack Overflow)");
157 else
158 dbg_printf(" #IE(Stack Underflow)"); /* Underflow */
160 else dbg_printf(" #IE(Arthimetic error)"); /* Invalid Fl OP */
163 if (ctx->FloatSave.StatusWord & 0x00000002) dbg_printf(" #DE"); /* Denormalised OP */
164 if (ctx->FloatSave.StatusWord & 0x00000004) dbg_printf(" #ZE"); /* Zero Divide */
165 if (ctx->FloatSave.StatusWord & 0x00000008) dbg_printf(" #OE"); /* Overflow */
166 if (ctx->FloatSave.StatusWord & 0x00000010) dbg_printf(" #UE"); /* Underflow */
167 if (ctx->FloatSave.StatusWord & 0x00000020) dbg_printf(" #PE"); /* Precision error */
168 if (ctx->FloatSave.StatusWord & 0x00000040)
169 if (!(ctx->FloatSave.StatusWord & 0x00000001))
170 dbg_printf(" #SE"); /* Stack Fault (don't think this can occur) */
171 if (ctx->FloatSave.StatusWord & 0x00000080) dbg_printf(" #ES"); /* Error Summary */
172 if (ctx->FloatSave.StatusWord & 0x00008000) dbg_printf(" #FB"); /* FPU Busy */
173 dbg_printf(")\n");
175 /* Here are the rest of the registers */
176 dbg_printf(" FLES:%08lx FLDO:%08lx FLDS:%08lx FLCNS:%08lx\n",
177 ctx->FloatSave.ErrorSelector,
178 ctx->FloatSave.DataOffset,
179 ctx->FloatSave.DataSelector,
180 ctx->FloatSave.Cr0NpxState);
182 /* Now for the floating point registers */
183 dbg_printf("Floating Point Registers:\n");
184 for (cnt = 0; cnt < 8; cnt++)
186 const BYTE *p = &ctx->FloatSave.RegisterArea[cnt * 10];
187 if (cnt == 4) dbg_printf("\n");
188 dbg_printf(" ST%d:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x ", cnt,
189 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9] );
192 xmm_area = (XSAVE_FORMAT *) &ctx->ExtendedRegisters;
194 dbg_printf(" mxcsr: %04lx (", xmm_area->MxCsr );
195 for (cnt = 0; cnt < 16; cnt++)
196 if (xmm_area->MxCsr & (1 << cnt)) dbg_printf( " %s", mxcsr_flags[cnt] );
197 dbg_printf(" )\n");
199 for (cnt = 0; cnt < 8; cnt++)
201 dbg_printf( " xmm%u: uint=%08x%08x%08x%08x", cnt,
202 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 3),
203 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 2),
204 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 1),
205 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 0));
206 dbg_printf( " double={%g; %g}", *(double *)&xmm_area->XmmRegisters[cnt].Low,
207 *(double *)&xmm_area->XmmRegisters[cnt].High );
208 dbg_printf( " float={%g; %g; %g; %g}\n",
209 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 0),
210 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 1),
211 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 2),
212 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 3) );
214 dbg_printf("\n");
217 static void be_i386_print_context(HANDLE hThread, const dbg_ctx_t *pctx, int all_regs)
219 static const char flags[] = "aVR-N--ODITSZ-A-P-C";
220 const WOW64_CONTEXT *ctx = &pctx->x86;
221 int i;
222 char buf[33];
224 dbg_printf("Register dump:\n");
226 /* First get the segment registers out of the way */
227 dbg_printf(" CS:%04x SS:%04x DS:%04x ES:%04x FS:%04x GS:%04x",
228 (WORD)ctx->SegCs, (WORD)ctx->SegSs,
229 (WORD)ctx->SegDs, (WORD)ctx->SegEs,
230 (WORD)ctx->SegFs, (WORD)ctx->SegGs);
232 strcpy(buf, flags);
233 for (i = 0; buf[i]; i++)
234 if (buf[i] != '-' && !(ctx->EFlags & (1 << (sizeof(flags) - 2 - i))))
235 buf[i] = ' ';
237 switch (get_selector_type(hThread, ctx, ctx->SegCs))
239 case AddrMode1616:
240 case AddrModeReal:
241 dbg_printf("\n IP:%04x SP:%04x BP:%04x FLAGS:%04x(%s)\n",
242 LOWORD(ctx->Eip), LOWORD(ctx->Esp),
243 LOWORD(ctx->Ebp), LOWORD(ctx->EFlags), buf);
244 dbg_printf(" AX:%04x BX:%04x CX:%04x DX:%04x SI:%04x DI:%04x\n",
245 LOWORD(ctx->Eax), LOWORD(ctx->Ebx),
246 LOWORD(ctx->Ecx), LOWORD(ctx->Edx),
247 LOWORD(ctx->Esi), LOWORD(ctx->Edi));
248 break;
249 case AddrModeFlat:
250 case AddrMode1632:
251 dbg_printf("\n EIP:%08lx ESP:%08lx EBP:%08lx EFLAGS:%08lx(%s)\n",
252 ctx->Eip, ctx->Esp, ctx->Ebp, ctx->EFlags, buf);
253 dbg_printf(" EAX:%08lx EBX:%08lx ECX:%08lx EDX:%08lx\n",
254 ctx->Eax, ctx->Ebx, ctx->Ecx, ctx->Edx);
255 dbg_printf(" ESI:%08lx EDI:%08lx\n",
256 ctx->Esi, ctx->Edi);
257 break;
260 if (all_regs) be_i386_all_print_context(hThread, pctx);
264 static void be_i386_print_segment_info(HANDLE hThread, const dbg_ctx_t *ctx)
266 if (get_selector_type(hThread, &ctx->x86, ctx->x86.SegCs) == AddrMode1616)
268 info_win32_segments(ctx->x86.SegDs >> 3, 1);
269 if (ctx->x86.SegEs != ctx->x86.SegDs)
270 info_win32_segments(ctx->x86.SegEs >> 3, 1);
272 info_win32_segments(ctx->x86.SegFs >> 3, 1);
275 static struct dbg_internal_var be_i386_ctx[] =
277 {CV_REG_AL, "AL", (void*)FIELD_OFFSET(WOW64_CONTEXT, Eax), dbg_itype_unsigned_int8},
278 {CV_REG_CL, "CL", (void*)FIELD_OFFSET(WOW64_CONTEXT, Ecx), dbg_itype_unsigned_int8},
279 {CV_REG_DL, "DL", (void*)FIELD_OFFSET(WOW64_CONTEXT, Edx), dbg_itype_unsigned_int8},
280 {CV_REG_BL, "BL", (void*)FIELD_OFFSET(WOW64_CONTEXT, Ebx), dbg_itype_unsigned_int8},
281 {CV_REG_AH, "AH", (void*)(FIELD_OFFSET(WOW64_CONTEXT, Eax)+1), dbg_itype_unsigned_int8},
282 {CV_REG_CH, "CH", (void*)(FIELD_OFFSET(WOW64_CONTEXT, Ecx)+1), dbg_itype_unsigned_int8},
283 {CV_REG_DH, "DH", (void*)(FIELD_OFFSET(WOW64_CONTEXT, Edx)+1), dbg_itype_unsigned_int8},
284 {CV_REG_BH, "BH", (void*)(FIELD_OFFSET(WOW64_CONTEXT, Ebx)+1), dbg_itype_unsigned_int8},
285 {CV_REG_AX, "AX", (void*)FIELD_OFFSET(WOW64_CONTEXT, Eax), dbg_itype_unsigned_int16},
286 {CV_REG_CX, "CX", (void*)FIELD_OFFSET(WOW64_CONTEXT, Ecx), dbg_itype_unsigned_int16},
287 {CV_REG_DX, "DX", (void*)FIELD_OFFSET(WOW64_CONTEXT, Edx), dbg_itype_unsigned_int16},
288 {CV_REG_BX, "BX", (void*)FIELD_OFFSET(WOW64_CONTEXT, Ebx), dbg_itype_unsigned_int16},
289 {CV_REG_SP, "SP", (void*)FIELD_OFFSET(WOW64_CONTEXT, Esp), dbg_itype_unsigned_int16},
290 {CV_REG_BP, "BP", (void*)FIELD_OFFSET(WOW64_CONTEXT, Ebp), dbg_itype_unsigned_int16},
291 {CV_REG_SI, "SI", (void*)FIELD_OFFSET(WOW64_CONTEXT, Esi), dbg_itype_unsigned_int16},
292 {CV_REG_DI, "DI", (void*)FIELD_OFFSET(WOW64_CONTEXT, Edi), dbg_itype_unsigned_int16},
293 {CV_REG_EAX, "EAX", (void*)FIELD_OFFSET(WOW64_CONTEXT, Eax), dbg_itype_unsigned_int32},
294 {CV_REG_ECX, "ECX", (void*)FIELD_OFFSET(WOW64_CONTEXT, Ecx), dbg_itype_unsigned_int32},
295 {CV_REG_EDX, "EDX", (void*)FIELD_OFFSET(WOW64_CONTEXT, Edx), dbg_itype_unsigned_int32},
296 {CV_REG_EBX, "EBX", (void*)FIELD_OFFSET(WOW64_CONTEXT, Ebx), dbg_itype_unsigned_int32},
297 {CV_REG_ESP, "ESP", (void*)FIELD_OFFSET(WOW64_CONTEXT, Esp), dbg_itype_unsigned_int32},
298 {CV_REG_EBP, "EBP", (void*)FIELD_OFFSET(WOW64_CONTEXT, Ebp), dbg_itype_unsigned_int32},
299 {CV_REG_ESI, "ESI", (void*)FIELD_OFFSET(WOW64_CONTEXT, Esi), dbg_itype_unsigned_int32},
300 {CV_REG_EDI, "EDI", (void*)FIELD_OFFSET(WOW64_CONTEXT, Edi), dbg_itype_unsigned_int32},
301 {CV_REG_ES, "ES", (void*)FIELD_OFFSET(WOW64_CONTEXT, SegEs), dbg_itype_unsigned_int16},
302 {CV_REG_CS, "CS", (void*)FIELD_OFFSET(WOW64_CONTEXT, SegCs), dbg_itype_unsigned_int16},
303 {CV_REG_SS, "SS", (void*)FIELD_OFFSET(WOW64_CONTEXT, SegSs), dbg_itype_unsigned_int16},
304 {CV_REG_DS, "DS", (void*)FIELD_OFFSET(WOW64_CONTEXT, SegDs), dbg_itype_unsigned_int16},
305 {CV_REG_FS, "FS", (void*)FIELD_OFFSET(WOW64_CONTEXT, SegFs), dbg_itype_unsigned_int16},
306 {CV_REG_GS, "GS", (void*)FIELD_OFFSET(WOW64_CONTEXT, SegGs), dbg_itype_unsigned_int16},
307 {CV_REG_IP, "IP", (void*)FIELD_OFFSET(WOW64_CONTEXT, Eip), dbg_itype_unsigned_int16},
308 {CV_REG_FLAGS, "FLAGS", (void*)FIELD_OFFSET(WOW64_CONTEXT, EFlags), dbg_itype_unsigned_int16},
309 {CV_REG_EIP, "EIP", (void*)FIELD_OFFSET(WOW64_CONTEXT, Eip), dbg_itype_unsigned_int32},
310 {CV_REG_EFLAGS, "EFLAGS", (void*)FIELD_OFFSET(WOW64_CONTEXT, EFlags), dbg_itype_unsigned_int32},
311 {CV_REG_ST0, "ST0", (void*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[ 0]), dbg_itype_long_real},
312 {CV_REG_ST0+1, "ST1", (void*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[10]), dbg_itype_long_real},
313 {CV_REG_ST0+2, "ST2", (void*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[20]), dbg_itype_long_real},
314 {CV_REG_ST0+3, "ST3", (void*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[30]), dbg_itype_long_real},
315 {CV_REG_ST0+4, "ST4", (void*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[40]), dbg_itype_long_real},
316 {CV_REG_ST0+5, "ST5", (void*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[50]), dbg_itype_long_real},
317 {CV_REG_ST0+6, "ST6", (void*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[60]), dbg_itype_long_real},
318 {CV_REG_ST0+7, "ST7", (void*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[70]), dbg_itype_long_real},
319 {CV_AMD64_XMM0, "XMM0", (void*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[0])), dbg_itype_m128a},
320 {CV_AMD64_XMM0+1, "XMM1", (void*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[1])), dbg_itype_m128a},
321 {CV_AMD64_XMM0+2, "XMM2", (void*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[2])), dbg_itype_m128a},
322 {CV_AMD64_XMM0+3, "XMM3", (void*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[3])), dbg_itype_m128a},
323 {CV_AMD64_XMM0+4, "XMM4", (void*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[4])), dbg_itype_m128a},
324 {CV_AMD64_XMM0+5, "XMM5", (void*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[5])), dbg_itype_m128a},
325 {CV_AMD64_XMM0+6, "XMM6", (void*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[6])), dbg_itype_m128a},
326 {CV_AMD64_XMM0+7, "XMM7", (void*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[7])), dbg_itype_m128a},
327 {0, NULL, 0, dbg_itype_none}
330 static BOOL be_i386_is_step_over_insn(const void* insn)
332 BYTE ch;
334 for (;;)
336 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
338 switch (ch)
340 /* Skip all prefixes */
341 case 0x2e: /* cs: */
342 case 0x36: /* ss: */
343 case 0x3e: /* ds: */
344 case 0x26: /* es: */
345 case 0x64: /* fs: */
346 case 0x65: /* gs: */
347 case 0x66: /* opcode size prefix */
348 case 0x67: /* addr size prefix */
349 case 0xf0: /* lock */
350 case 0xf2: /* repne */
351 case 0xf3: /* repe */
352 insn = (const char*)insn + 1;
353 continue;
355 /* Handle call instructions */
356 case 0xcd: /* int <intno> */
357 case 0xe8: /* call <offset> */
358 case 0x9a: /* lcall <seg>:<off> */
359 return TRUE;
361 case 0xff: /* call <regmodrm> */
362 if (!dbg_read_memory((const char*)insn + 1, &ch, sizeof(ch)))
363 return FALSE;
364 return (((ch & 0x38) == 0x10) || ((ch & 0x38) == 0x18));
366 /* Handle string instructions */
367 case 0x6c: /* insb */
368 case 0x6d: /* insw */
369 case 0x6e: /* outsb */
370 case 0x6f: /* outsw */
371 case 0xa4: /* movsb */
372 case 0xa5: /* movsw */
373 case 0xa6: /* cmpsb */
374 case 0xa7: /* cmpsw */
375 case 0xaa: /* stosb */
376 case 0xab: /* stosw */
377 case 0xac: /* lodsb */
378 case 0xad: /* lodsw */
379 case 0xae: /* scasb */
380 case 0xaf: /* scasw */
381 return TRUE;
383 default:
384 return FALSE;
389 static BOOL be_i386_is_function_return(const void* insn)
391 BYTE ch;
393 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
394 if (ch == 0xF3) /* REP */
396 insn = (const char*)insn + 1;
397 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
399 return (ch == 0xC2) || (ch == 0xC3);
402 static BOOL be_i386_is_break_insn(const void* insn)
404 BYTE c;
406 if (!dbg_read_memory(insn, &c, sizeof(c))) return FALSE;
407 return c == 0xCC;
410 static unsigned get_size(ADDRESS_MODE am)
412 if (am == AddrModeReal || am == AddrMode1616) return 16;
413 return 32;
416 static BOOL fetch_value(const char* addr, unsigned sz, int* value)
418 char value8;
419 short value16;
421 switch (sz)
423 case 8:
424 if (!dbg_read_memory(addr, &value8, sizeof(value8)))
425 return FALSE;
426 *value = value8;
427 break;
428 case 16:
429 if (!dbg_read_memory(addr, &value16, sizeof(value16)))
430 return FALSE;
431 *value = value16;
432 break;
433 case 32:
434 if (!dbg_read_memory(addr, value, sizeof(*value)))
435 return FALSE;
436 break;
437 default: return FALSE;
439 return TRUE;
442 static BOOL be_i386_is_func_call(const void* insn, ADDRESS64* callee)
444 BYTE ch;
445 int delta;
446 short segment;
447 unsigned dst = 0;
448 unsigned operand_size;
449 ADDRESS_MODE cs_addr_mode;
451 cs_addr_mode = get_selector_type(dbg_curr_thread->handle, &dbg_context.x86,
452 dbg_context.x86.SegCs);
453 operand_size = get_size(cs_addr_mode);
455 /* get operand_size (also getting rid of the various prefixes */
458 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
459 if (ch == 0x66)
461 operand_size = 48 - operand_size; /* 16 => 32, 32 => 16 */
462 insn = (const char*)insn + 1;
464 } while (ch == 0x66 || ch == 0x67);
466 switch (ch)
468 case 0xe8: /* relative near call */
469 callee->Mode = cs_addr_mode;
470 if (!fetch_value((const char*)insn + 1, operand_size, &delta))
471 return FALSE;
472 callee->Segment = dbg_context.x86.SegCs;
473 callee->Offset = (DWORD_PTR)insn + 1 + (operand_size / 8) + delta;
474 return TRUE;
476 case 0x9a: /* absolute far call */
477 if (!dbg_read_memory((const char*)insn + 1 + operand_size / 8,
478 &segment, sizeof(segment)))
479 return FALSE;
480 callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context.x86,
481 segment);
482 if (!fetch_value((const char*)insn + 1, operand_size, &delta))
483 return FALSE;
484 callee->Segment = segment;
485 callee->Offset = delta;
486 return TRUE;
488 case 0xff:
489 if (!dbg_read_memory((const char*)insn + 1, &ch, sizeof(ch)))
490 return FALSE;
491 /* keep only the CALL and LCALL insn:s */
492 switch ((ch >> 3) & 0x07)
494 case 0x02:
495 segment = dbg_context.x86.SegCs;
496 break;
497 case 0x03:
498 if (!dbg_read_memory((const char*)insn + 1 + operand_size / 8,
499 &segment, sizeof(segment)))
500 return FALSE;
501 break;
502 default: return FALSE;
504 /* FIXME: we only support the 32 bit far calls for now */
505 if (operand_size != 32)
507 WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) with 16 bit operand-size at %p\n", ch, insn);
508 return FALSE;
510 switch (ch & 0xC7) /* keep Mod R/M only (skip reg) */
512 case 0x04:
513 case 0x44:
514 case 0x84:
515 WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) (SIB bytes) at %p\n", ch, insn);
516 return FALSE;
517 case 0x05: /* addr32 */
518 if ((ch & 0x38) == 0x10 || /* call */
519 (ch & 0x38) == 0x18) /* lcall */
521 void *addr;
522 if (!dbg_read_memory((const char *)insn + 2, &addr, sizeof(addr)))
523 return FALSE;
524 if ((ch & 0x38) == 0x18) /* lcall */
526 if (!dbg_read_memory((const char*)addr + operand_size, &segment, sizeof(segment)))
527 return FALSE;
529 else segment = dbg_context.x86.SegCs;
530 if (!dbg_read_memory((const char*)addr, &dst, sizeof(dst)))
531 return FALSE;
532 callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context.x86, segment);
533 callee->Segment = segment;
534 callee->Offset = dst;
535 return TRUE;
537 return FALSE;
538 default:
539 switch (ch & 0x07)
541 case 0x00: dst = dbg_context.x86.Eax; break;
542 case 0x01: dst = dbg_context.x86.Ecx; break;
543 case 0x02: dst = dbg_context.x86.Edx; break;
544 case 0x03: dst = dbg_context.x86.Ebx; break;
545 case 0x04: dst = dbg_context.x86.Esp; break;
546 case 0x05: dst = dbg_context.x86.Ebp; break;
547 case 0x06: dst = dbg_context.x86.Esi; break;
548 case 0x07: dst = dbg_context.x86.Edi; break;
550 if ((ch >> 6) != 0x03) /* indirect address */
552 if (ch >> 6) /* we got a displacement */
554 if (!fetch_value((const char*)insn + 2, (ch >> 6) == 0x01 ? 8 : 32, &delta))
555 return FALSE;
556 dst += delta;
558 if (((ch >> 3) & 0x07) == 0x03) /* LCALL */
560 if (!dbg_read_memory((const char*)(UINT_PTR)dst + operand_size, &segment, sizeof(segment)))
561 return FALSE;
563 else segment = dbg_context.x86.SegCs;
564 if (!dbg_read_memory((const char*)(UINT_PTR)dst, &delta, sizeof(delta)))
565 return FALSE;
566 callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context.x86,
567 segment);
568 callee->Segment = segment;
569 callee->Offset = delta;
571 else
573 callee->Mode = cs_addr_mode;
574 callee->Segment = dbg_context.x86.SegCs;
575 callee->Offset = dst;
578 return TRUE;
580 default:
581 return FALSE;
585 static BOOL be_i386_is_jump(const void* insn, ADDRESS64* jumpee)
587 BYTE ch;
588 int delta;
589 unsigned operand_size;
590 ADDRESS_MODE cs_addr_mode;
592 cs_addr_mode = get_selector_type(dbg_curr_thread->handle, &dbg_context.x86,
593 dbg_context.x86.SegCs);
594 operand_size = get_size(cs_addr_mode);
596 /* get operand_size (also getting rid of the various prefixes */
599 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
600 if (ch == 0x66)
602 operand_size = 48 - operand_size; /* 16 => 32, 32 => 16 */
603 insn = (const char*)insn + 1;
605 } while (ch == 0x66 || ch == 0x67);
607 switch (ch)
609 case 0xe9: /* jmp near */
610 jumpee->Mode = cs_addr_mode;
611 if (!fetch_value((const char*)insn + 1, operand_size, &delta))
612 return FALSE;
613 jumpee->Segment = dbg_context.x86.SegCs;
614 jumpee->Offset = (DWORD_PTR)insn + 1 + (operand_size / 8) + delta;
615 return TRUE;
616 default: WINE_FIXME("unknown %x\n", ch); return FALSE;
618 return FALSE;
621 #define DR7_CONTROL_SHIFT 16
622 #define DR7_CONTROL_SIZE 4
624 #define DR7_RW_EXECUTE (0x0)
625 #define DR7_RW_WRITE (0x1)
626 #define DR7_RW_READ (0x3)
628 #define DR7_LEN_1 (0x0)
629 #define DR7_LEN_2 (0x4)
630 #define DR7_LEN_4 (0xC)
632 #define DR7_LOCAL_ENABLE_SHIFT 0
633 #define DR7_GLOBAL_ENABLE_SHIFT 1
634 #define DR7_ENABLE_SIZE 2
636 #define DR7_LOCAL_ENABLE_MASK (0x55)
637 #define DR7_GLOBAL_ENABLE_MASK (0xAA)
639 #define DR7_CONTROL_RESERVED (0xFC00)
640 #define DR7_LOCAL_SLOWDOWN (0x100)
641 #define DR7_GLOBAL_SLOWDOWN (0x200)
643 #define DR7_ENABLE_MASK(dr) (1<<(DR7_LOCAL_ENABLE_SHIFT+DR7_ENABLE_SIZE*(dr)))
644 #define IS_DR7_SET(ctrl,dr) ((ctrl)&DR7_ENABLE_MASK(dr))
646 static inline int be_i386_get_unused_DR(dbg_ctx_t *pctx, DWORD** r)
648 WOW64_CONTEXT *ctx = &pctx->x86;
650 if (!IS_DR7_SET(ctx->Dr7, 0))
652 *r = &ctx->Dr0;
653 return 0;
655 if (!IS_DR7_SET(ctx->Dr7, 1))
657 *r = &ctx->Dr1;
658 return 1;
660 if (!IS_DR7_SET(ctx->Dr7, 2))
662 *r = &ctx->Dr2;
663 return 2;
665 if (!IS_DR7_SET(ctx->Dr7, 3))
667 *r = &ctx->Dr3;
668 return 3;
670 dbg_printf("All hardware registers have been used\n");
672 return -1;
675 static BOOL be_i386_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
676 dbg_ctx_t *ctx, enum be_xpoint_type type,
677 void* addr, unsigned *val, unsigned size)
679 unsigned char ch;
680 SIZE_T sz;
681 DWORD *pr;
682 int reg;
683 unsigned int bits;
685 switch (type)
687 case be_xpoint_break:
688 if (size != 0) return FALSE;
689 if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
690 *val = ch;
691 ch = 0xcc;
692 if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
693 break;
694 case be_xpoint_watch_exec:
695 bits = DR7_RW_EXECUTE;
696 goto hw_bp;
697 case be_xpoint_watch_read:
698 bits = DR7_RW_READ;
699 goto hw_bp;
700 case be_xpoint_watch_write:
701 bits = DR7_RW_WRITE;
702 hw_bp:
703 if ((reg = be_i386_get_unused_DR(ctx, &pr)) == -1) return FALSE;
704 *pr = (DWORD_PTR)addr;
705 if (type != be_xpoint_watch_exec) switch (size)
707 case 4: bits |= DR7_LEN_4; break;
708 case 2: bits |= DR7_LEN_2; break;
709 case 1: bits |= DR7_LEN_1; break;
710 default: return FALSE;
712 *val = reg;
713 /* clear old values */
714 ctx->x86.Dr7 &= ~(0x0F << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg));
715 /* set the correct ones */
716 ctx->x86.Dr7 |= bits << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg);
717 ctx->x86.Dr7 |= DR7_ENABLE_MASK(reg) | DR7_LOCAL_SLOWDOWN;
718 break;
719 default:
720 dbg_printf("Unknown bp type %c\n", type);
721 return FALSE;
723 return TRUE;
726 static BOOL be_i386_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
727 dbg_ctx_t *ctx, enum be_xpoint_type type,
728 void* addr, unsigned val, unsigned size)
730 SIZE_T sz;
731 unsigned char ch;
733 switch (type)
735 case be_xpoint_break:
736 if (size != 0) return FALSE;
737 if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
738 if (ch != (unsigned char)0xCC)
739 WINE_FIXME("Cannot get back %02x instead of 0xCC at %p\n", ch, addr);
740 ch = (unsigned char)val;
741 if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
742 break;
743 case be_xpoint_watch_exec:
744 case be_xpoint_watch_read:
745 case be_xpoint_watch_write:
746 /* simply disable the entry */
747 ctx->x86.Dr7 &= ~DR7_ENABLE_MASK(val);
748 break;
749 default:
750 dbg_printf("Unknown bp type %c\n", type);
751 return FALSE;
753 return TRUE;
756 static BOOL be_i386_is_watchpoint_set(const dbg_ctx_t *ctx, unsigned idx)
758 return ctx->x86.Dr6 & (1 << idx);
761 static void be_i386_clear_watchpoint(dbg_ctx_t *ctx, unsigned idx)
763 ctx->x86.Dr6 &= ~(1 << idx);
766 static int be_i386_adjust_pc_for_break(dbg_ctx_t *ctx, BOOL way)
768 if (way)
770 ctx->x86.Eip--;
771 return -1;
773 ctx->x86.Eip++;
774 return 1;
777 static BOOL be_i386_get_context(HANDLE thread, dbg_ctx_t *ctx)
779 ctx->x86.ContextFlags = WOW64_CONTEXT_ALL;
780 return Wow64GetThreadContext(thread, &ctx->x86);
783 static BOOL be_i386_set_context(HANDLE thread, const dbg_ctx_t *ctx)
785 return Wow64SetThreadContext(thread, &ctx->x86);
788 #define REG(f,n,t,r) {f, n, t, FIELD_OFFSET(WOW64_CONTEXT, r), sizeof(((WOW64_CONTEXT*)NULL)->r)}
790 static struct gdb_register be_i386_gdb_register_map[] = {
791 REG("core", "eax", NULL, Eax),
792 REG(NULL, "ecx", NULL, Ecx),
793 REG(NULL, "edx", NULL, Edx),
794 REG(NULL, "ebx", NULL, Ebx),
795 REG(NULL, "esp", "data_ptr", Esp),
796 REG(NULL, "ebp", "data_ptr", Ebp),
797 REG(NULL, "esi", NULL, Esi),
798 REG(NULL, "edi", NULL, Edi),
799 REG(NULL, "eip", "code_ptr", Eip),
800 REG(NULL, "eflags", "i386_eflags", EFlags),
801 REG(NULL, "cs", NULL, SegCs),
802 REG(NULL, "ss", NULL, SegSs),
803 REG(NULL, "ds", NULL, SegDs),
804 REG(NULL, "es", NULL, SegEs),
805 REG(NULL, "fs", NULL, SegFs),
806 REG(NULL, "gs", NULL, SegGs),
807 { NULL, "st0", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[ 0]), 10},
808 { NULL, "st1", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[10]), 10},
809 { NULL, "st2", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[20]), 10},
810 { NULL, "st3", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[30]), 10},
811 { NULL, "st4", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[40]), 10},
812 { NULL, "st5", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[50]), 10},
813 { NULL, "st6", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[60]), 10},
814 { NULL, "st7", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[70]), 10},
815 { NULL, "fctrl", NULL, FIELD_OFFSET(WOW64_CONTEXT, FloatSave.ControlWord), 2},
816 { NULL, "fstat", NULL, FIELD_OFFSET(WOW64_CONTEXT, FloatSave.StatusWord), 2},
817 { NULL, "ftag", NULL, FIELD_OFFSET(WOW64_CONTEXT, FloatSave.TagWord), 2},
818 { NULL, "fiseg", NULL, FIELD_OFFSET(WOW64_CONTEXT, FloatSave.ErrorSelector), 2},
819 REG(NULL, "fioff", NULL, FloatSave.ErrorOffset),
820 { NULL, "foseg", NULL, FIELD_OFFSET(WOW64_CONTEXT, FloatSave.DataSelector), 2},
821 REG(NULL, "fooff", NULL, FloatSave.DataOffset),
822 { NULL, "fop", NULL, FIELD_OFFSET(WOW64_CONTEXT, FloatSave.ErrorSelector)+2, 2},
824 { "sse", "xmm0", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[0]), 16},
825 { NULL, "xmm1", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[1]), 16},
826 { NULL, "xmm2", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[2]), 16},
827 { NULL, "xmm3", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[3]), 16},
828 { NULL, "xmm4", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[4]), 16},
829 { NULL, "xmm5", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[5]), 16},
830 { NULL, "xmm6", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[6]), 16},
831 { NULL, "xmm7", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[7]), 16},
832 { NULL, "mxcsr", "i386_mxcsr", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, MxCsr), 4},
835 struct backend_cpu be_i386 =
837 IMAGE_FILE_MACHINE_I386,
839 be_i386_linearize,
840 be_i386_build_addr,
841 be_i386_get_addr,
842 be_i386_get_register_info,
843 be_i386_single_step,
844 be_i386_print_context,
845 be_i386_print_segment_info,
846 be_i386_ctx,
847 be_i386_is_step_over_insn,
848 be_i386_is_function_return,
849 be_i386_is_break_insn,
850 be_i386_is_func_call,
851 be_i386_is_jump,
852 memory_disasm_one_x86_insn,
853 be_i386_insert_Xpoint,
854 be_i386_remove_Xpoint,
855 be_i386_is_watchpoint_set,
856 be_i386_clear_watchpoint,
857 be_i386_adjust_pc_for_break,
858 be_i386_get_context,
859 be_i386_set_context,
860 be_i386_gdb_register_map,
861 ARRAY_SIZE(be_i386_gdb_register_map),
863 #endif