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