msvcrt: Remove MSVCRT_ prefix from exit.c functions.
[wine.git] / programs / winedbg / be_i386.c
blob427d76a35ad8e4afbb8ae834c3a8d612339acc4e
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, unsigned long 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 long double ST[8]; /* These are for floating regs */
137 int cnt;
139 /* Break out the FPU state and the floating point registers */
140 dbg_printf("Floating Point Unit status:\n");
141 dbg_printf(" FLCW:%04x ", LOWORD(ctx->FloatSave.ControlWord));
142 dbg_printf(" FLTW:%04x ", LOWORD(ctx->FloatSave.TagWord));
143 dbg_printf(" FLEO:%08x ", (unsigned int) ctx->FloatSave.ErrorOffset);
144 dbg_printf(" FLSW:%04x", LOWORD(ctx->FloatSave.StatusWord));
146 /* Isolate the condition code bits - note they are not contiguous */
147 dbg_printf("(CC:%d%d%d%d", (ctx->FloatSave.StatusWord & 0x00004000) >> 14,
148 (ctx->FloatSave.StatusWord & 0x00000400) >> 10,
149 (ctx->FloatSave.StatusWord & 0x00000200) >> 9,
150 (ctx->FloatSave.StatusWord & 0x00000100) >> 8);
152 /* Now pull out the 3 bit of the TOP stack pointer */
153 dbg_printf(" TOP:%01x", (unsigned int) (ctx->FloatSave.StatusWord & 0x00003800) >> 11);
155 /* Lets analyse the error bits and indicate the status
156 * the Invalid Op flag has sub status which is tested as follows */
157 if (ctx->FloatSave.StatusWord & 0x00000001) { /* Invalid Fl OP */
158 if (ctx->FloatSave.StatusWord & 0x00000040) { /* Stack Fault */
159 if (ctx->FloatSave.StatusWord & 0x00000200) /* C1 says Overflow */
160 dbg_printf(" #IE(Stack Overflow)");
161 else
162 dbg_printf(" #IE(Stack Underflow)"); /* Underflow */
164 else dbg_printf(" #IE(Arthimetic error)"); /* Invalid Fl OP */
167 if (ctx->FloatSave.StatusWord & 0x00000002) dbg_printf(" #DE"); /* Denormalised OP */
168 if (ctx->FloatSave.StatusWord & 0x00000004) dbg_printf(" #ZE"); /* Zero Divide */
169 if (ctx->FloatSave.StatusWord & 0x00000008) dbg_printf(" #OE"); /* Overflow */
170 if (ctx->FloatSave.StatusWord & 0x00000010) dbg_printf(" #UE"); /* Underflow */
171 if (ctx->FloatSave.StatusWord & 0x00000020) dbg_printf(" #PE"); /* Precision error */
172 if (ctx->FloatSave.StatusWord & 0x00000040)
173 if (!(ctx->FloatSave.StatusWord & 0x00000001))
174 dbg_printf(" #SE"); /* Stack Fault (don't think this can occur) */
175 if (ctx->FloatSave.StatusWord & 0x00000080) dbg_printf(" #ES"); /* Error Summary */
176 if (ctx->FloatSave.StatusWord & 0x00008000) dbg_printf(" #FB"); /* FPU Busy */
177 dbg_printf(")\n");
179 /* Here are the rest of the registers */
180 dbg_printf(" FLES:%08x FLDO:%08x FLDS:%08x FLCNS:%08x\n",
181 ctx->FloatSave.ErrorSelector,
182 ctx->FloatSave.DataOffset,
183 ctx->FloatSave.DataSelector,
184 ctx->FloatSave.Cr0NpxState);
186 /* Now for the floating point registers */
187 dbg_printf("Floating Point Registers:\n");
188 for (cnt = 0; cnt < 4; cnt++)
190 memcpy(&ST[cnt], &ctx->FloatSave.RegisterArea[cnt * 10], 10);
191 dbg_printf(" ST%d:%Lf ", cnt, ST[cnt]);
193 dbg_printf("\n");
194 for (cnt = 4; cnt < 8; cnt++)
196 memcpy(&ST[cnt], &ctx->FloatSave.RegisterArea[cnt * 10], 10);
197 dbg_printf(" ST%d:%Lf ", cnt, ST[cnt]);
200 xmm_area = (XSAVE_FORMAT *) &ctx->ExtendedRegisters;
202 dbg_printf(" mxcsr: %04x (", xmm_area->MxCsr );
203 for (cnt = 0; cnt < 16; cnt++)
204 if (xmm_area->MxCsr & (1 << cnt)) dbg_printf( " %s", mxcsr_flags[cnt] );
205 dbg_printf(" )\n");
207 for (cnt = 0; cnt < 8; cnt++)
209 dbg_printf( " xmm%u: uint=%08x%08x%08x%08x", cnt,
210 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 3),
211 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 2),
212 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 1),
213 *((unsigned int *)&xmm_area->XmmRegisters[cnt] + 0));
214 dbg_printf( " double={%g; %g}", *(double *)&xmm_area->XmmRegisters[cnt].Low,
215 *(double *)&xmm_area->XmmRegisters[cnt].High );
216 dbg_printf( " float={%g; %g; %g; %g}\n",
217 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 0),
218 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 1),
219 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 2),
220 (double)*((float *)&xmm_area->XmmRegisters[cnt] + 3) );
222 dbg_printf("\n");
225 static void be_i386_print_context(HANDLE hThread, const dbg_ctx_t *pctx, int all_regs)
227 static const char flags[] = "aVR-N--ODITSZ-A-P-C";
228 const WOW64_CONTEXT *ctx = &pctx->x86;
229 int i;
230 char buf[33];
232 dbg_printf("Register dump:\n");
234 /* First get the segment registers out of the way */
235 dbg_printf(" CS:%04x SS:%04x DS:%04x ES:%04x FS:%04x GS:%04x",
236 (WORD)ctx->SegCs, (WORD)ctx->SegSs,
237 (WORD)ctx->SegDs, (WORD)ctx->SegEs,
238 (WORD)ctx->SegFs, (WORD)ctx->SegGs);
240 strcpy(buf, flags);
241 for (i = 0; buf[i]; i++)
242 if (buf[i] != '-' && !(ctx->EFlags & (1 << (sizeof(flags) - 2 - i))))
243 buf[i] = ' ';
245 switch (get_selector_type(hThread, ctx, ctx->SegCs))
247 case AddrMode1616:
248 case AddrModeReal:
249 dbg_printf("\n IP:%04x SP:%04x BP:%04x FLAGS:%04x(%s)\n",
250 LOWORD(ctx->Eip), LOWORD(ctx->Esp),
251 LOWORD(ctx->Ebp), LOWORD(ctx->EFlags), buf);
252 dbg_printf(" AX:%04x BX:%04x CX:%04x DX:%04x SI:%04x DI:%04x\n",
253 LOWORD(ctx->Eax), LOWORD(ctx->Ebx),
254 LOWORD(ctx->Ecx), LOWORD(ctx->Edx),
255 LOWORD(ctx->Esi), LOWORD(ctx->Edi));
256 break;
257 case AddrModeFlat:
258 case AddrMode1632:
259 dbg_printf("\n EIP:%08x ESP:%08x EBP:%08x EFLAGS:%08x(%s)\n",
260 ctx->Eip, ctx->Esp, ctx->Ebp, ctx->EFlags, buf);
261 dbg_printf(" EAX:%08x EBX:%08x ECX:%08x EDX:%08x\n",
262 ctx->Eax, ctx->Ebx, ctx->Ecx, ctx->Edx);
263 dbg_printf(" ESI:%08x EDI:%08x\n",
264 ctx->Esi, ctx->Edi);
265 break;
268 if (all_regs) be_i386_all_print_context(hThread, pctx);
272 static void be_i386_print_segment_info(HANDLE hThread, const dbg_ctx_t *ctx)
274 if (get_selector_type(hThread, &ctx->x86, ctx->x86.SegCs) == AddrMode1616)
276 info_win32_segments(ctx->x86.SegDs >> 3, 1);
277 if (ctx->x86.SegEs != ctx->x86.SegDs)
278 info_win32_segments(ctx->x86.SegEs >> 3, 1);
280 info_win32_segments(ctx->x86.SegFs >> 3, 1);
283 static struct dbg_internal_var be_i386_ctx[] =
285 {CV_REG_AL, "AL", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Eax), dbg_itype_unsigned_char_int},
286 {CV_REG_CL, "CL", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ecx), dbg_itype_unsigned_char_int},
287 {CV_REG_DL, "DL", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Edx), dbg_itype_unsigned_char_int},
288 {CV_REG_BL, "BL", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ebx), dbg_itype_unsigned_char_int},
289 {CV_REG_AH, "AH", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, Eax)+1), dbg_itype_unsigned_char_int},
290 {CV_REG_CH, "CH", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, Ecx)+1), dbg_itype_unsigned_char_int},
291 {CV_REG_DH, "DH", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, Edx)+1), dbg_itype_unsigned_char_int},
292 {CV_REG_BH, "BH", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, Ebx)+1), dbg_itype_unsigned_char_int},
293 {CV_REG_AX, "AX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Eax), dbg_itype_unsigned_short_int},
294 {CV_REG_CX, "CX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ecx), dbg_itype_unsigned_short_int},
295 {CV_REG_DX, "DX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Edx), dbg_itype_unsigned_short_int},
296 {CV_REG_BX, "BX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ebx), dbg_itype_unsigned_short_int},
297 {CV_REG_SP, "SP", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Esp), dbg_itype_unsigned_short_int},
298 {CV_REG_BP, "BP", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ebp), dbg_itype_unsigned_short_int},
299 {CV_REG_SI, "SI", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Esi), dbg_itype_unsigned_short_int},
300 {CV_REG_DI, "DI", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Edi), dbg_itype_unsigned_short_int},
301 {CV_REG_EAX, "EAX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Eax), dbg_itype_unsigned_int},
302 {CV_REG_ECX, "ECX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ecx), dbg_itype_unsigned_int},
303 {CV_REG_EDX, "EDX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Edx), dbg_itype_unsigned_int},
304 {CV_REG_EBX, "EBX", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ebx), dbg_itype_unsigned_int},
305 {CV_REG_ESP, "ESP", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Esp), dbg_itype_unsigned_int},
306 {CV_REG_EBP, "EBP", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Ebp), dbg_itype_unsigned_int},
307 {CV_REG_ESI, "ESI", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Esi), dbg_itype_unsigned_int},
308 {CV_REG_EDI, "EDI", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Edi), dbg_itype_unsigned_int},
309 {CV_REG_ES, "ES", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, SegEs), dbg_itype_unsigned_short_int},
310 {CV_REG_CS, "CS", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, SegCs), dbg_itype_unsigned_short_int},
311 {CV_REG_SS, "SS", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, SegSs), dbg_itype_unsigned_short_int},
312 {CV_REG_DS, "DS", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, SegDs), dbg_itype_unsigned_short_int},
313 {CV_REG_FS, "FS", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, SegFs), dbg_itype_unsigned_short_int},
314 {CV_REG_GS, "GS", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, SegGs), dbg_itype_unsigned_short_int},
315 {CV_REG_IP, "IP", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Eip), dbg_itype_unsigned_short_int},
316 {CV_REG_FLAGS, "FLAGS", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, EFlags), dbg_itype_unsigned_short_int},
317 {CV_REG_EIP, "EIP", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, Eip), dbg_itype_unsigned_int},
318 {CV_REG_EFLAGS, "EFLAGS", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, EFlags), dbg_itype_unsigned_int},
319 {CV_REG_ST0, "ST0", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[ 0]), dbg_itype_long_real},
320 {CV_REG_ST0+1, "ST1", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[10]), dbg_itype_long_real},
321 {CV_REG_ST0+2, "ST2", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[20]), dbg_itype_long_real},
322 {CV_REG_ST0+3, "ST3", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[30]), dbg_itype_long_real},
323 {CV_REG_ST0+4, "ST4", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[40]), dbg_itype_long_real},
324 {CV_REG_ST0+5, "ST5", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[50]), dbg_itype_long_real},
325 {CV_REG_ST0+6, "ST6", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[60]), dbg_itype_long_real},
326 {CV_REG_ST0+7, "ST7", (DWORD_PTR*)FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[70]), dbg_itype_long_real},
327 {CV_AMD64_XMM0, "XMM0", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[0])), dbg_itype_m128a},
328 {CV_AMD64_XMM0+1, "XMM1", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[1])), dbg_itype_m128a},
329 {CV_AMD64_XMM0+2, "XMM2", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[2])), dbg_itype_m128a},
330 {CV_AMD64_XMM0+3, "XMM3", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[3])), dbg_itype_m128a},
331 {CV_AMD64_XMM0+4, "XMM4", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[4])), dbg_itype_m128a},
332 {CV_AMD64_XMM0+5, "XMM5", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[5])), dbg_itype_m128a},
333 {CV_AMD64_XMM0+6, "XMM6", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[6])), dbg_itype_m128a},
334 {CV_AMD64_XMM0+7, "XMM7", (DWORD_PTR*)(FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[7])), dbg_itype_m128a},
335 {0, NULL, 0, dbg_itype_none}
338 static BOOL be_i386_is_step_over_insn(const void* insn)
340 BYTE ch;
342 for (;;)
344 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
346 switch (ch)
348 /* Skip all prefixes */
349 case 0x2e: /* cs: */
350 case 0x36: /* ss: */
351 case 0x3e: /* ds: */
352 case 0x26: /* es: */
353 case 0x64: /* fs: */
354 case 0x65: /* gs: */
355 case 0x66: /* opcode size prefix */
356 case 0x67: /* addr size prefix */
357 case 0xf0: /* lock */
358 case 0xf2: /* repne */
359 case 0xf3: /* repe */
360 insn = (const char*)insn + 1;
361 continue;
363 /* Handle call instructions */
364 case 0xcd: /* int <intno> */
365 case 0xe8: /* call <offset> */
366 case 0x9a: /* lcall <seg>:<off> */
367 return TRUE;
369 case 0xff: /* call <regmodrm> */
370 if (!dbg_read_memory((const char*)insn + 1, &ch, sizeof(ch)))
371 return FALSE;
372 return (((ch & 0x38) == 0x10) || ((ch & 0x38) == 0x18));
374 /* Handle string instructions */
375 case 0x6c: /* insb */
376 case 0x6d: /* insw */
377 case 0x6e: /* outsb */
378 case 0x6f: /* outsw */
379 case 0xa4: /* movsb */
380 case 0xa5: /* movsw */
381 case 0xa6: /* cmpsb */
382 case 0xa7: /* cmpsw */
383 case 0xaa: /* stosb */
384 case 0xab: /* stosw */
385 case 0xac: /* lodsb */
386 case 0xad: /* lodsw */
387 case 0xae: /* scasb */
388 case 0xaf: /* scasw */
389 return TRUE;
391 default:
392 return FALSE;
397 static BOOL be_i386_is_function_return(const void* insn)
399 BYTE ch;
401 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
402 if (ch == 0xF3) /* REP */
404 insn = (const char*)insn + 1;
405 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
407 return (ch == 0xC2) || (ch == 0xC3);
410 static BOOL be_i386_is_break_insn(const void* insn)
412 BYTE c;
414 if (!dbg_read_memory(insn, &c, sizeof(c))) return FALSE;
415 return c == 0xCC;
418 static unsigned get_size(ADDRESS_MODE am)
420 if (am == AddrModeReal || am == AddrMode1616) return 16;
421 return 32;
424 static BOOL fetch_value(const char* addr, unsigned sz, int* value)
426 char value8;
427 short value16;
429 switch (sz)
431 case 8:
432 if (!dbg_read_memory(addr, &value8, sizeof(value8)))
433 return FALSE;
434 *value = value8;
435 break;
436 case 16:
437 if (!dbg_read_memory(addr, &value16, sizeof(value16)))
438 return FALSE;
439 *value = value16;
440 break;
441 case 32:
442 if (!dbg_read_memory(addr, value, sizeof(*value)))
443 return FALSE;
444 break;
445 default: return FALSE;
447 return TRUE;
450 static BOOL be_i386_is_func_call(const void* insn, ADDRESS64* callee)
452 BYTE ch;
453 int delta;
454 short segment;
455 unsigned dst = 0;
456 unsigned operand_size;
457 ADDRESS_MODE cs_addr_mode;
459 cs_addr_mode = get_selector_type(dbg_curr_thread->handle, &dbg_context.x86,
460 dbg_context.x86.SegCs);
461 operand_size = get_size(cs_addr_mode);
463 /* get operand_size (also getting rid of the various prefixes */
466 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
467 if (ch == 0x66)
469 operand_size = 48 - operand_size; /* 16 => 32, 32 => 16 */
470 insn = (const char*)insn + 1;
472 } while (ch == 0x66 || ch == 0x67);
474 switch (ch)
476 case 0xe8: /* relative near call */
477 callee->Mode = cs_addr_mode;
478 if (!fetch_value((const char*)insn + 1, operand_size, &delta))
479 return FALSE;
480 callee->Segment = dbg_context.x86.SegCs;
481 callee->Offset = (DWORD_PTR)insn + 1 + (operand_size / 8) + delta;
482 return TRUE;
484 case 0x9a: /* absolute far call */
485 if (!dbg_read_memory((const char*)insn + 1 + operand_size / 8,
486 &segment, sizeof(segment)))
487 return FALSE;
488 callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context.x86,
489 segment);
490 if (!fetch_value((const char*)insn + 1, operand_size, &delta))
491 return FALSE;
492 callee->Segment = segment;
493 callee->Offset = delta;
494 return TRUE;
496 case 0xff:
497 if (!dbg_read_memory((const char*)insn + 1, &ch, sizeof(ch)))
498 return FALSE;
499 /* keep only the CALL and LCALL insn:s */
500 switch ((ch >> 3) & 0x07)
502 case 0x02:
503 segment = dbg_context.x86.SegCs;
504 break;
505 case 0x03:
506 if (!dbg_read_memory((const char*)insn + 1 + operand_size / 8,
507 &segment, sizeof(segment)))
508 return FALSE;
509 break;
510 default: return FALSE;
512 /* FIXME: we only support the 32 bit far calls for now */
513 if (operand_size != 32)
515 WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) with 16 bit operand-size at %p\n", ch, insn);
516 return FALSE;
518 switch (ch & 0xC7) /* keep Mod R/M only (skip reg) */
520 case 0x04:
521 case 0x44:
522 case 0x84:
523 WINE_FIXME("Unsupported yet call insn (0xFF 0x%02x) (SIB bytes) at %p\n", ch, insn);
524 return FALSE;
525 case 0x05: /* addr32 */
526 if ((ch & 0x38) == 0x10 || /* call */
527 (ch & 0x38) == 0x18) /* lcall */
529 void *addr;
530 if (!dbg_read_memory((const char *)insn + 2, &addr, sizeof(addr)))
531 return FALSE;
532 if ((ch & 0x38) == 0x18) /* lcall */
534 if (!dbg_read_memory((const char*)addr + operand_size, &segment, sizeof(segment)))
535 return FALSE;
537 else segment = dbg_context.x86.SegCs;
538 if (!dbg_read_memory((const char*)addr, &dst, sizeof(dst)))
539 return FALSE;
540 callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context.x86, segment);
541 callee->Segment = segment;
542 callee->Offset = dst;
543 return TRUE;
545 return FALSE;
546 default:
547 switch (ch & 0x07)
549 case 0x00: dst = dbg_context.x86.Eax; break;
550 case 0x01: dst = dbg_context.x86.Ecx; break;
551 case 0x02: dst = dbg_context.x86.Edx; break;
552 case 0x03: dst = dbg_context.x86.Ebx; break;
553 case 0x04: dst = dbg_context.x86.Esp; break;
554 case 0x05: dst = dbg_context.x86.Ebp; break;
555 case 0x06: dst = dbg_context.x86.Esi; break;
556 case 0x07: dst = dbg_context.x86.Edi; break;
558 if ((ch >> 6) != 0x03) /* indirect address */
560 if (ch >> 6) /* we got a displacement */
562 if (!fetch_value((const char*)insn + 2, (ch >> 6) == 0x01 ? 8 : 32, &delta))
563 return FALSE;
564 dst += delta;
566 if (((ch >> 3) & 0x07) == 0x03) /* LCALL */
568 if (!dbg_read_memory((const char*)(UINT_PTR)dst + operand_size, &segment, sizeof(segment)))
569 return FALSE;
571 else segment = dbg_context.x86.SegCs;
572 if (!dbg_read_memory((const char*)(UINT_PTR)dst, &delta, sizeof(delta)))
573 return FALSE;
574 callee->Mode = get_selector_type(dbg_curr_thread->handle, &dbg_context.x86,
575 segment);
576 callee->Segment = segment;
577 callee->Offset = delta;
579 else
581 callee->Mode = cs_addr_mode;
582 callee->Segment = dbg_context.x86.SegCs;
583 callee->Offset = dst;
586 return TRUE;
588 default:
589 return FALSE;
593 static BOOL be_i386_is_jump(const void* insn, ADDRESS64* jumpee)
595 BYTE ch;
596 int delta;
597 unsigned operand_size;
598 ADDRESS_MODE cs_addr_mode;
600 cs_addr_mode = get_selector_type(dbg_curr_thread->handle, &dbg_context.x86,
601 dbg_context.x86.SegCs);
602 operand_size = get_size(cs_addr_mode);
604 /* get operand_size (also getting rid of the various prefixes */
607 if (!dbg_read_memory(insn, &ch, sizeof(ch))) return FALSE;
608 if (ch == 0x66)
610 operand_size = 48 - operand_size; /* 16 => 32, 32 => 16 */
611 insn = (const char*)insn + 1;
613 } while (ch == 0x66 || ch == 0x67);
615 switch (ch)
617 case 0xe9: /* jmp near */
618 jumpee->Mode = cs_addr_mode;
619 if (!fetch_value((const char*)insn + 1, operand_size, &delta))
620 return FALSE;
621 jumpee->Segment = dbg_context.x86.SegCs;
622 jumpee->Offset = (DWORD_PTR)insn + 1 + (operand_size / 8) + delta;
623 return TRUE;
624 default: WINE_FIXME("unknown %x\n", ch); return FALSE;
626 return FALSE;
629 #define DR7_CONTROL_SHIFT 16
630 #define DR7_CONTROL_SIZE 4
632 #define DR7_RW_EXECUTE (0x0)
633 #define DR7_RW_WRITE (0x1)
634 #define DR7_RW_READ (0x3)
636 #define DR7_LEN_1 (0x0)
637 #define DR7_LEN_2 (0x4)
638 #define DR7_LEN_4 (0xC)
640 #define DR7_LOCAL_ENABLE_SHIFT 0
641 #define DR7_GLOBAL_ENABLE_SHIFT 1
642 #define DR7_ENABLE_SIZE 2
644 #define DR7_LOCAL_ENABLE_MASK (0x55)
645 #define DR7_GLOBAL_ENABLE_MASK (0xAA)
647 #define DR7_CONTROL_RESERVED (0xFC00)
648 #define DR7_LOCAL_SLOWDOWN (0x100)
649 #define DR7_GLOBAL_SLOWDOWN (0x200)
651 #define DR7_ENABLE_MASK(dr) (1<<(DR7_LOCAL_ENABLE_SHIFT+DR7_ENABLE_SIZE*(dr)))
652 #define IS_DR7_SET(ctrl,dr) ((ctrl)&DR7_ENABLE_MASK(dr))
654 static inline int be_i386_get_unused_DR(dbg_ctx_t *pctx, DWORD** r)
656 WOW64_CONTEXT *ctx = &pctx->x86;
658 if (!IS_DR7_SET(ctx->Dr7, 0))
660 *r = &ctx->Dr0;
661 return 0;
663 if (!IS_DR7_SET(ctx->Dr7, 1))
665 *r = &ctx->Dr1;
666 return 1;
668 if (!IS_DR7_SET(ctx->Dr7, 2))
670 *r = &ctx->Dr2;
671 return 2;
673 if (!IS_DR7_SET(ctx->Dr7, 3))
675 *r = &ctx->Dr3;
676 return 3;
678 dbg_printf("All hardware registers have been used\n");
680 return -1;
683 static BOOL be_i386_insert_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
684 dbg_ctx_t *ctx, enum be_xpoint_type type,
685 void* addr, unsigned long* val, unsigned size)
687 unsigned char ch;
688 SIZE_T sz;
689 DWORD *pr;
690 int reg;
691 unsigned long bits;
693 switch (type)
695 case be_xpoint_break:
696 if (size != 0) return FALSE;
697 if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
698 *val = ch;
699 ch = 0xcc;
700 if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
701 break;
702 case be_xpoint_watch_exec:
703 bits = DR7_RW_EXECUTE;
704 goto hw_bp;
705 case be_xpoint_watch_read:
706 bits = DR7_RW_READ;
707 goto hw_bp;
708 case be_xpoint_watch_write:
709 bits = DR7_RW_WRITE;
710 hw_bp:
711 if ((reg = be_i386_get_unused_DR(ctx, &pr)) == -1) return FALSE;
712 *pr = (DWORD_PTR)addr;
713 if (type != be_xpoint_watch_exec) switch (size)
715 case 4: bits |= DR7_LEN_4; break;
716 case 2: bits |= DR7_LEN_2; break;
717 case 1: bits |= DR7_LEN_1; break;
718 default: return FALSE;
720 *val = reg;
721 /* clear old values */
722 ctx->x86.Dr7 &= ~(0x0F << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg));
723 /* set the correct ones */
724 ctx->x86.Dr7 |= bits << (DR7_CONTROL_SHIFT + DR7_CONTROL_SIZE * reg);
725 ctx->x86.Dr7 |= DR7_ENABLE_MASK(reg) | DR7_LOCAL_SLOWDOWN;
726 break;
727 default:
728 dbg_printf("Unknown bp type %c\n", type);
729 return FALSE;
731 return TRUE;
734 static BOOL be_i386_remove_Xpoint(HANDLE hProcess, const struct be_process_io* pio,
735 dbg_ctx_t *ctx, enum be_xpoint_type type,
736 void* addr, unsigned long val, unsigned size)
738 SIZE_T sz;
739 unsigned char ch;
741 switch (type)
743 case be_xpoint_break:
744 if (size != 0) return FALSE;
745 if (!pio->read(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
746 if (ch != (unsigned char)0xCC)
747 WINE_FIXME("Cannot get back %02x instead of 0xCC at %p\n", ch, addr);
748 ch = (unsigned char)val;
749 if (!pio->write(hProcess, addr, &ch, 1, &sz) || sz != 1) return FALSE;
750 break;
751 case be_xpoint_watch_exec:
752 case be_xpoint_watch_read:
753 case be_xpoint_watch_write:
754 /* simply disable the entry */
755 ctx->x86.Dr7 &= ~DR7_ENABLE_MASK(val);
756 break;
757 default:
758 dbg_printf("Unknown bp type %c\n", type);
759 return FALSE;
761 return TRUE;
764 static BOOL be_i386_is_watchpoint_set(const dbg_ctx_t *ctx, unsigned idx)
766 return ctx->x86.Dr6 & (1 << idx);
769 static void be_i386_clear_watchpoint(dbg_ctx_t *ctx, unsigned idx)
771 ctx->x86.Dr6 &= ~(1 << idx);
774 static int be_i386_adjust_pc_for_break(dbg_ctx_t *ctx, BOOL way)
776 if (way)
778 ctx->x86.Eip--;
779 return -1;
781 ctx->x86.Eip++;
782 return 1;
785 static BOOL be_i386_fetch_integer(const struct dbg_lvalue* lvalue, unsigned size,
786 BOOL is_signed, LONGLONG* ret)
788 if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) return FALSE;
790 memset(ret, 0, sizeof(*ret)); /* clear unread bytes */
791 /* FIXME: this assumes that debuggee and debugger use the same
792 * integral representation
794 if (!memory_read_value(lvalue, size, ret)) return FALSE;
796 /* propagate sign information */
797 if (is_signed && size < 8 && (*ret >> (size * 8 - 1)) != 0)
799 ULONGLONG neg = -1;
800 *ret |= neg << (size * 8);
802 return TRUE;
805 static BOOL be_i386_fetch_float(const struct dbg_lvalue* lvalue, unsigned size,
806 long double* ret)
808 char tmp[sizeof(long double)];
810 /* FIXME: this assumes that debuggee and debugger use the same
811 * representation for reals
813 if (!memory_read_value(lvalue, size, tmp)) return FALSE;
815 /* float & double types have to be promoted to a long double */
816 if (size == 4) *ret = *(float*)tmp;
817 else if (size == 8) *ret = *(double*)tmp;
818 else if (size == 10) *ret = *(long double*)tmp;
819 else return FALSE;
821 return TRUE;
824 static BOOL be_i386_store_integer(const struct dbg_lvalue* lvalue, unsigned size,
825 BOOL is_signed, LONGLONG val)
827 /* this is simple as we're on a little endian CPU */
828 return memory_write_value(lvalue, size, &val);
831 static BOOL be_i386_get_context(HANDLE thread, dbg_ctx_t *ctx)
833 ctx->x86.ContextFlags = WOW64_CONTEXT_ALL;
834 return Wow64GetThreadContext(thread, &ctx->x86);
837 static BOOL be_i386_set_context(HANDLE thread, const dbg_ctx_t *ctx)
839 return Wow64SetThreadContext(thread, &ctx->x86);
842 #define REG(f,n,t,r) {f, n, t, FIELD_OFFSET(WOW64_CONTEXT, r), sizeof(((WOW64_CONTEXT*)NULL)->r)}
844 static struct gdb_register be_i386_gdb_register_map[] = {
845 REG("core", "eax", NULL, Eax),
846 REG(NULL, "ecx", NULL, Ecx),
847 REG(NULL, "edx", NULL, Edx),
848 REG(NULL, "ebx", NULL, Ebx),
849 REG(NULL, "esp", "data_ptr", Esp),
850 REG(NULL, "ebp", "data_ptr", Ebp),
851 REG(NULL, "esi", NULL, Esi),
852 REG(NULL, "edi", NULL, Edi),
853 REG(NULL, "eip", "code_ptr", Eip),
854 REG(NULL, "eflags", "i386_eflags", EFlags),
855 REG(NULL, "cs", NULL, SegCs),
856 REG(NULL, "ss", NULL, SegSs),
857 REG(NULL, "ds", NULL, SegDs),
858 REG(NULL, "es", NULL, SegEs),
859 REG(NULL, "fs", NULL, SegFs),
860 REG(NULL, "gs", NULL, SegGs),
861 { NULL, "st0", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[ 0]), 10},
862 { NULL, "st1", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[10]), 10},
863 { NULL, "st2", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[20]), 10},
864 { NULL, "st3", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[30]), 10},
865 { NULL, "st4", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[40]), 10},
866 { NULL, "st5", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[50]), 10},
867 { NULL, "st6", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[60]), 10},
868 { NULL, "st7", "i387_ext", FIELD_OFFSET(WOW64_CONTEXT, FloatSave.RegisterArea[70]), 10},
869 { NULL, "fctrl", NULL, FIELD_OFFSET(WOW64_CONTEXT, FloatSave.ControlWord), 2},
870 { NULL, "fstat", NULL, FIELD_OFFSET(WOW64_CONTEXT, FloatSave.StatusWord), 2},
871 { NULL, "ftag", NULL, FIELD_OFFSET(WOW64_CONTEXT, FloatSave.TagWord), 2},
872 { NULL, "fiseg", NULL, FIELD_OFFSET(WOW64_CONTEXT, FloatSave.ErrorSelector), 2},
873 REG(NULL, "fioff", NULL, FloatSave.ErrorOffset),
874 { NULL, "foseg", NULL, FIELD_OFFSET(WOW64_CONTEXT, FloatSave.DataSelector), 2},
875 REG(NULL, "fooff", NULL, FloatSave.DataOffset),
876 { NULL, "fop", NULL, FIELD_OFFSET(WOW64_CONTEXT, FloatSave.ErrorSelector)+2, 2},
878 { "sse", "xmm0", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[0]), 16},
879 { NULL, "xmm1", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[1]), 16},
880 { NULL, "xmm2", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[2]), 16},
881 { NULL, "xmm3", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[3]), 16},
882 { NULL, "xmm4", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[4]), 16},
883 { NULL, "xmm5", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[5]), 16},
884 { NULL, "xmm6", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[6]), 16},
885 { NULL, "xmm7", "vec128", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, XmmRegisters[7]), 16},
886 { NULL, "mxcsr", "i386_mxcsr", FIELD_OFFSET(WOW64_CONTEXT, ExtendedRegisters) + FIELD_OFFSET(XSAVE_FORMAT, MxCsr), 4},
889 struct backend_cpu be_i386 =
891 IMAGE_FILE_MACHINE_I386,
893 be_i386_linearize,
894 be_i386_build_addr,
895 be_i386_get_addr,
896 be_i386_get_register_info,
897 be_i386_single_step,
898 be_i386_print_context,
899 be_i386_print_segment_info,
900 be_i386_ctx,
901 be_i386_is_step_over_insn,
902 be_i386_is_function_return,
903 be_i386_is_break_insn,
904 be_i386_is_func_call,
905 be_i386_is_jump,
906 be_i386_disasm_one_insn,
907 be_i386_insert_Xpoint,
908 be_i386_remove_Xpoint,
909 be_i386_is_watchpoint_set,
910 be_i386_clear_watchpoint,
911 be_i386_adjust_pc_for_break,
912 be_i386_fetch_integer,
913 be_i386_fetch_float,
914 be_i386_store_integer,
915 be_i386_get_context,
916 be_i386_set_context,
917 be_i386_gdb_register_map,
918 ARRAY_SIZE(be_i386_gdb_register_map),
920 #endif