[DBGHELP] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / win32 / dbghelp / cpu_i386.c
1 /*
2 * File cpu_i386.c
3 *
4 * Copyright (C) 2009-2009, Eric Pouech.
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include <assert.h>
22
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "dbghelp_private.h"
26 #ifndef DBGHELP_STATIC_LIB
27 #include "wine/winbase16.h"
28 #include "winternl.h"
29 #include "wine/debug.h"
30 #endif
31
32 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
33
34 #define V86_FLAG 0x00020000
35
36 #define IS_VM86_MODE(ctx) (ctx->EFlags & V86_FLAG)
37
38 #if defined(__i386__) && !defined(DBGHELP_STATIC_LIB)
39 static ADDRESS_MODE get_selector_type(HANDLE hThread, const CONTEXT* ctx, WORD sel)
40 {
41 LDT_ENTRY le;
42
43 if (IS_VM86_MODE(ctx)) return AddrModeReal;
44 /* null or system selector */
45 if (!(sel & 4) || ((sel >> 3) < 17)) return AddrModeFlat;
46 if (hThread && GetThreadSelectorEntry(hThread, sel, &le))
47 return le.HighWord.Bits.Default_Big ? AddrMode1632 : AddrMode1616;
48 /* selector doesn't exist */
49 return -1;
50 }
51
52 static BOOL i386_build_addr(HANDLE hThread, const CONTEXT* ctx, ADDRESS64* addr,
53 unsigned seg, unsigned long offset)
54 {
55 addr->Mode = AddrModeFlat;
56 addr->Segment = seg;
57 addr->Offset = offset;
58 if (seg)
59 {
60 switch (addr->Mode = get_selector_type(hThread, ctx, seg))
61 {
62 case AddrModeReal:
63 case AddrMode1616:
64 addr->Offset &= 0xffff;
65 break;
66 case AddrModeFlat:
67 case AddrMode1632:
68 break;
69 default:
70 return FALSE;
71 }
72 }
73 return TRUE;
74 }
75 #endif
76
77 #ifndef DBGHELP_STATIC_LIB
78 static BOOL i386_get_addr(HANDLE hThread, const CONTEXT* ctx,
79 enum cpu_addr ca, ADDRESS64* addr)
80 {
81 #ifdef __i386__
82 switch (ca)
83 {
84 case cpu_addr_pc: return i386_build_addr(hThread, ctx, addr, ctx->SegCs, ctx->Eip);
85 case cpu_addr_stack: return i386_build_addr(hThread, ctx, addr, ctx->SegSs, ctx->Esp);
86 case cpu_addr_frame: return i386_build_addr(hThread, ctx, addr, ctx->SegSs, ctx->Ebp);
87 }
88 #endif
89 return FALSE;
90 }
91 #endif /* DBGHELP_STATIC_LIB */
92
93 #if defined(__i386__) && !defined(DBGHELP_STATIC_LIB)
94 /* fetch_next_frame32()
95 *
96 * modify (at least) context.{eip, esp, ebp} using unwind information
97 * either out of debug info (dwarf, pdb), or simple stack unwind
98 */
99 static BOOL fetch_next_frame32(struct cpu_stack_walk* csw,
100 CONTEXT* context, DWORD_PTR curr_pc)
101 {
102 DWORD_PTR xframe;
103 struct pdb_cmd_pair cpair[4];
104 DWORD val32;
105
106 if (dwarf2_virtual_unwind(csw, curr_pc, context, &xframe))
107 {
108 context->Esp = xframe;
109 return TRUE;
110 }
111 cpair[0].name = "$ebp"; cpair[0].pvalue = &context->Ebp;
112 cpair[1].name = "$esp"; cpair[1].pvalue = &context->Esp;
113 cpair[2].name = "$eip"; cpair[2].pvalue = &context->Eip;
114 cpair[3].name = NULL; cpair[3].pvalue = NULL;
115
116 #ifndef DBGHELP_STATIC_LIB
117 if (!pdb_virtual_unwind(csw, curr_pc, context, cpair))
118 #endif
119 {
120 /* do a simple unwind using ebp
121 * we assume a "regular" prologue in the function has been used
122 */
123 if (!context->Ebp) return FALSE;
124 context->Esp = context->Ebp + 2 * sizeof(DWORD);
125 if (!sw_read_mem(csw, context->Ebp + sizeof(DWORD), &val32, sizeof(DWORD)))
126 {
127 WARN("Cannot read new frame offset %p\n",
128 (void*)(DWORD_PTR)(context->Ebp + (int)sizeof(DWORD)));
129 return FALSE;
130 }
131 context->Eip = val32;
132 /* "pop up" previous EBP value */
133 if (!sw_read_mem(csw, context->Ebp, &val32, sizeof(DWORD)))
134 return FALSE;
135 context->Ebp = val32;
136 }
137 return TRUE;
138 }
139 #endif
140
141 enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done};
142
143 /* indexes in Reserved array */
144 #define __CurrentModeCount 0
145 #define __CurrentSwitch 1
146 #define __NextSwitch 2
147
148 #define curr_mode (frame->Reserved[__CurrentModeCount] & 0x0F)
149 #define curr_count (frame->Reserved[__CurrentModeCount] >> 4)
150 #define curr_switch (frame->Reserved[__CurrentSwitch])
151 #define next_switch (frame->Reserved[__NextSwitch])
152
153 #define set_curr_mode(m) {frame->Reserved[__CurrentModeCount] &= ~0x0F; frame->Reserved[__CurrentModeCount] |= (m & 0x0F);}
154 #define inc_curr_count() (frame->Reserved[__CurrentModeCount] += 0x10)
155
156 #ifndef DBGHELP_STATIC_LIB
157 static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CONTEXT* context)
158 {
159 STACK32FRAME frame32;
160 STACK16FRAME frame16;
161 char ch;
162 ADDRESS64 tmp;
163 DWORD p;
164 WORD val16;
165 DWORD val32;
166 BOOL do_switch;
167 #ifdef __i386__
168 unsigned deltapc;
169 CONTEXT _context;
170 #endif
171
172 /* sanity check */
173 if (curr_mode >= stm_done) return FALSE;
174
175 TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s Count=%s cSwitch=%p nSwitch=%p\n",
176 wine_dbgstr_addr(&frame->AddrPC),
177 wine_dbgstr_addr(&frame->AddrFrame),
178 wine_dbgstr_addr(&frame->AddrReturn),
179 wine_dbgstr_addr(&frame->AddrStack),
180 curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
181 wine_dbgstr_longlong(curr_count),
182 (void*)(DWORD_PTR)curr_switch, (void*)(DWORD_PTR)next_switch);
183
184 #ifdef __i386__
185 /* if we're at first call (which doesn't actually unwind, it just computes ReturnPC,
186 * or if we're doing the first real unwind (count == 1), then we can directly use
187 * eip. otherwise, eip is *after* the insn that actually made the call to
188 * previous frame, so decrease eip by delta pc (1!) so that we're inside previous
189 * insn.
190 * Doing so, we ensure that the pc used for unwinding is always inside the function
191 * we want to use for next frame
192 */
193 deltapc = curr_count <= 1 ? 0 : 1;
194
195 if (!context)
196 {
197 /* setup a pseudo context for the rest of the code (esp. unwinding) */
198 context = &_context;
199 memset(context, 0, sizeof(*context));
200 context->ContextFlags = CONTEXT_CONTROL | CONTEXT_SEGMENTS;
201 if (frame->AddrPC.Mode != AddrModeFlat) context->SegCs = frame->AddrPC.Segment;
202 context->Eip = frame->AddrPC.Offset;
203 if (frame->AddrFrame.Mode != AddrModeFlat) context->SegSs = frame->AddrFrame.Segment;
204 context->Ebp = frame->AddrFrame.Offset;
205 if (frame->AddrStack.Mode != AddrModeFlat) context->SegSs = frame->AddrStack.Segment;
206 context->Esp = frame->AddrStack.Offset;
207 }
208 #endif
209 if (curr_mode == stm_start)
210 {
211 THREAD_BASIC_INFORMATION info;
212
213 if ((frame->AddrPC.Mode == AddrModeFlat) &&
214 (frame->AddrFrame.Mode != AddrModeFlat))
215 {
216 WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n");
217 goto done_err;
218 }
219
220 /* Init done */
221 set_curr_mode((frame->AddrPC.Mode == AddrModeFlat) ? stm_32bit : stm_16bit);
222
223 /* cur_switch holds address of SystemReserved1[0] field in TEB in debuggee
224 * address space
225 */
226 if (NtQueryInformationThread(csw->hThread, ThreadBasicInformation, &info,
227 sizeof(info), NULL) == STATUS_SUCCESS)
228 {
229 curr_switch = (DWORD_PTR)info.TebBaseAddress + FIELD_OFFSET(TEB, SystemReserved1[0]);
230 if (!sw_read_mem(csw, curr_switch, &p, sizeof(p)))
231 {
232 WARN("Can't read TEB:SystemReserved1[0]\n");
233 goto done_err;
234 }
235 next_switch = p;
236 if (!next_switch) /* no 16-bit stack */
237 {
238 curr_switch = 0;
239 }
240 else if (curr_mode == stm_16bit)
241 {
242 if (!sw_read_mem(csw, next_switch, &frame32, sizeof(frame32)))
243 {
244 WARN("Bad stack frame %p\n", (void*)(DWORD_PTR)next_switch);
245 goto done_err;
246 }
247 curr_switch = (DWORD)frame32.frame16;
248 tmp.Mode = AddrMode1616;
249 tmp.Segment = SELECTOROF(curr_switch);
250 tmp.Offset = OFFSETOF(curr_switch);
251 if (!sw_read_mem(csw, sw_xlat_addr(csw, &tmp), &ch, sizeof(ch)))
252 curr_switch = 0xFFFFFFFF;
253 }
254 else
255 {
256 tmp.Mode = AddrMode1616;
257 tmp.Segment = SELECTOROF(next_switch);
258 tmp.Offset = OFFSETOF(next_switch);
259 p = sw_xlat_addr(csw, &tmp);
260 if (!sw_read_mem(csw, p, &frame16, sizeof(frame16)))
261 {
262 WARN("Bad stack frame 0x%08x\n", p);
263 goto done_err;
264 }
265 curr_switch = (DWORD_PTR)frame16.frame32;
266 if (!sw_read_mem(csw, curr_switch, &ch, sizeof(ch)))
267 curr_switch = 0xFFFFFFFF;
268 }
269 }
270 else
271 /* FIXME: this will allow it to work when we're not attached to a live target,
272 * but the 16 <=> 32 switch facility won't be available.
273 */
274 curr_switch = 0;
275 frame->AddrReturn.Mode = frame->AddrStack.Mode = (curr_mode == stm_16bit) ? AddrMode1616 : AddrModeFlat;
276 /* don't set up AddrStack on first call. Either the caller has set it up, or
277 * we will get it in the next frame
278 */
279 memset(&frame->AddrBStore, 0, sizeof(frame->AddrBStore));
280 }
281 else
282 {
283 if (frame->AddrFrame.Mode == AddrModeFlat)
284 {
285 assert(curr_mode == stm_32bit);
286 do_switch = curr_switch && frame->AddrFrame.Offset >= curr_switch;
287 }
288 else
289 {
290 assert(curr_mode == stm_16bit);
291 do_switch = curr_switch &&
292 frame->AddrFrame.Segment == SELECTOROF(curr_switch) &&
293 frame->AddrFrame.Offset >= OFFSETOF(curr_switch);
294 }
295
296 if (do_switch)
297 {
298 if (curr_mode == stm_16bit)
299 {
300 if (!sw_read_mem(csw, next_switch, &frame32, sizeof(frame32)))
301 {
302 WARN("Bad stack frame %p\n", (void*)(DWORD_PTR)next_switch);
303 goto done_err;
304 }
305
306 frame->AddrPC.Mode = AddrModeFlat;
307 frame->AddrPC.Segment = 0;
308 frame->AddrPC.Offset = frame32.retaddr;
309 frame->AddrFrame.Mode = AddrModeFlat;
310 frame->AddrFrame.Segment = 0;
311 frame->AddrFrame.Offset = frame32.ebp;
312
313 frame->AddrStack.Mode = AddrModeFlat;
314 frame->AddrStack.Segment = 0;
315 frame->AddrReturn.Mode = AddrModeFlat;
316 frame->AddrReturn.Segment = 0;
317
318 next_switch = curr_switch;
319 tmp.Mode = AddrMode1616;
320 tmp.Segment = SELECTOROF(next_switch);
321 tmp.Offset = OFFSETOF(next_switch);
322 p = sw_xlat_addr(csw, &tmp);
323
324 if (!sw_read_mem(csw, p, &frame16, sizeof(frame16)))
325 {
326 WARN("Bad stack frame 0x%08x\n", p);
327 goto done_err;
328 }
329 curr_switch = (DWORD_PTR)frame16.frame32;
330 set_curr_mode(stm_32bit);
331 if (!sw_read_mem(csw, curr_switch, &ch, sizeof(ch)))
332 curr_switch = 0;
333 }
334 else
335 {
336 tmp.Mode = AddrMode1616;
337 tmp.Segment = SELECTOROF(next_switch);
338 tmp.Offset = OFFSETOF(next_switch);
339 p = sw_xlat_addr(csw, &tmp);
340
341 if (!sw_read_mem(csw, p, &frame16, sizeof(frame16)))
342 {
343 WARN("Bad stack frame 0x%08x\n", p);
344 goto done_err;
345 }
346
347 TRACE("Got a 16 bit stack switch:"
348 "\n\tframe32: %p"
349 "\n\tedx:%08x ecx:%08x ebp:%08x"
350 "\n\tds:%04x es:%04x fs:%04x gs:%04x"
351 "\n\tcall_from_ip:%08x module_cs:%04x relay=%08x"
352 "\n\tentry_ip:%04x entry_point:%08x"
353 "\n\tbp:%04x ip:%04x cs:%04x\n",
354 frame16.frame32,
355 frame16.edx, frame16.ecx, frame16.ebp,
356 frame16.ds, frame16.es, frame16.fs, frame16.gs,
357 frame16.callfrom_ip, frame16.module_cs, frame16.relay,
358 frame16.entry_ip, frame16.entry_point,
359 frame16.bp, frame16.ip, frame16.cs);
360
361 frame->AddrPC.Mode = AddrMode1616;
362 frame->AddrPC.Segment = frame16.cs;
363 frame->AddrPC.Offset = frame16.ip;
364
365 frame->AddrFrame.Mode = AddrMode1616;
366 frame->AddrFrame.Segment = SELECTOROF(next_switch);
367 frame->AddrFrame.Offset = frame16.bp;
368
369 frame->AddrStack.Mode = AddrMode1616;
370 frame->AddrStack.Segment = SELECTOROF(next_switch);
371
372 frame->AddrReturn.Mode = AddrMode1616;
373 frame->AddrReturn.Segment = frame16.cs;
374
375 next_switch = curr_switch;
376 if (!sw_read_mem(csw, next_switch, &frame32, sizeof(frame32)))
377 {
378 WARN("Bad stack frame %p\n", (void*)(DWORD_PTR)next_switch);
379 goto done_err;
380 }
381 curr_switch = (DWORD)frame32.frame16;
382 tmp.Mode = AddrMode1616;
383 tmp.Segment = SELECTOROF(curr_switch);
384 tmp.Offset = OFFSETOF(curr_switch);
385
386 if (!sw_read_mem(csw, sw_xlat_addr(csw, &tmp), &ch, sizeof(ch)))
387 curr_switch = 0;
388 set_curr_mode(stm_16bit);
389 }
390 }
391 else
392 {
393 if (curr_mode == stm_16bit)
394 {
395 frame->AddrPC = frame->AddrReturn;
396 frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(WORD);
397 /* "pop up" previous BP value */
398 if (!frame->AddrFrame.Offset ||
399 !sw_read_mem(csw, sw_xlat_addr(csw, &frame->AddrFrame),
400 &val16, sizeof(WORD)))
401 goto done_err;
402 frame->AddrFrame.Offset = val16;
403 }
404 else
405 {
406 #ifdef __i386__
407 if (!fetch_next_frame32(csw, context, sw_xlat_addr(csw, &frame->AddrPC) - deltapc))
408 goto done_err;
409
410 frame->AddrStack.Mode = frame->AddrFrame.Mode = frame->AddrPC.Mode = AddrModeFlat;
411 frame->AddrStack.Offset = context->Esp;
412 frame->AddrFrame.Offset = context->Ebp;
413 if (frame->AddrReturn.Offset != context->Eip)
414 FIXME("new PC=%s different from Eip=%x\n",
415 wine_dbgstr_longlong(frame->AddrReturn.Offset), context->Eip);
416 frame->AddrPC.Offset = context->Eip;
417 #endif
418 }
419 }
420 }
421
422 if (curr_mode == stm_16bit)
423 {
424 unsigned int i;
425
426 p = sw_xlat_addr(csw, &frame->AddrFrame);
427 if (!sw_read_mem(csw, p + sizeof(WORD), &val16, sizeof(WORD)))
428 goto done_err;
429 frame->AddrReturn.Offset = val16;
430 /* get potential cs if a far call was used */
431 if (!sw_read_mem(csw, p + 2 * sizeof(WORD), &val16, sizeof(WORD)))
432 goto done_err;
433 if (frame->AddrFrame.Offset & 1)
434 frame->AddrReturn.Segment = val16; /* far call assumed */
435 else
436 {
437 /* not explicitly marked as far call,
438 * but check whether it could be anyway
439 */
440 if ((val16 & 7) == 7 && val16 != frame->AddrReturn.Segment)
441 {
442 LDT_ENTRY le;
443
444 if (GetThreadSelectorEntry(csw->hThread, val16, &le) &&
445 (le.HighWord.Bits.Type & 0x08)) /* code segment */
446 {
447 /* it is very uncommon to push a code segment cs as
448 * a parameter, so this should work in most cases
449 */
450 frame->AddrReturn.Segment = val16;
451 }
452 }
453 }
454 frame->AddrFrame.Offset &= ~1;
455 /* we "pop" parameters as 16 bit entities... of course, this won't
456 * work if the parameter is in fact bigger than 16bit, but
457 * there's no way to know that here
458 */
459 for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++)
460 {
461 sw_read_mem(csw, p + (2 + i) * sizeof(WORD), &val16, sizeof(val16));
462 frame->Params[i] = val16;
463 }
464 #ifdef __i386__
465 if (context)
466 {
467 #define SET(field, seg, reg) \
468 switch (frame->field.Mode) \
469 { \
470 case AddrModeFlat: context->reg = frame->field.Offset; break; \
471 case AddrMode1616: context->seg = frame->field.Segment; context->reg = frame->field.Offset; break; \
472 default: assert(0); \
473 }
474 SET(AddrStack, SegSs, Esp);
475 SET(AddrFrame, SegSs, Ebp);
476 SET(AddrReturn, SegCs, Eip);
477 #undef SET
478 }
479 #endif
480 }
481 else
482 {
483 unsigned int i;
484 #ifdef __i386__
485 CONTEXT newctx = *context;
486
487 if (!fetch_next_frame32(csw, &newctx, frame->AddrPC.Offset - deltapc))
488 goto done_err;
489 frame->AddrReturn.Mode = AddrModeFlat;
490 frame->AddrReturn.Offset = newctx.Eip;
491 #endif
492 for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++)
493 {
494 sw_read_mem(csw, frame->AddrFrame.Offset + (2 + i) * sizeof(DWORD), &val32, sizeof(val32));
495 frame->Params[i] = val32;
496 }
497 }
498
499 frame->Far = TRUE;
500 frame->Virtual = TRUE;
501 p = sw_xlat_addr(csw, &frame->AddrPC);
502 if (p && sw_module_base(csw, p))
503 frame->FuncTableEntry = sw_table_access(csw, p);
504 else
505 frame->FuncTableEntry = NULL;
506
507 inc_curr_count();
508 TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s Count=%s cSwitch=%p nSwitch=%p FuncTable=%p\n",
509 wine_dbgstr_addr(&frame->AddrPC),
510 wine_dbgstr_addr(&frame->AddrFrame),
511 wine_dbgstr_addr(&frame->AddrReturn),
512 wine_dbgstr_addr(&frame->AddrStack),
513 curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
514 wine_dbgstr_longlong(curr_count),
515 (void*)(DWORD_PTR)curr_switch, (void*)(DWORD_PTR)next_switch, frame->FuncTableEntry);
516
517 return TRUE;
518 done_err:
519 set_curr_mode(stm_done);
520 return FALSE;
521 }
522 #endif /* DBGHELP_STATIC_LIB */
523
524 static unsigned i386_map_dwarf_register(unsigned regno, BOOL eh_frame)
525 {
526 unsigned reg;
527
528 switch (regno)
529 {
530 case 0: reg = CV_REG_EAX; break;
531 case 1: reg = CV_REG_ECX; break;
532 case 2: reg = CV_REG_EDX; break;
533 case 3: reg = CV_REG_EBX; break;
534 case 4:
535 case 5:
536 #ifdef __APPLE__
537 /* On OS X, DWARF eh_frame uses a different mapping for the registers. It's
538 apparently the mapping as emitted by GCC, at least at some point in its history. */
539 if (eh_frame)
540 reg = (regno == 4) ? CV_REG_EBP : CV_REG_ESP;
541 else
542 #endif
543 reg = (regno == 4) ? CV_REG_ESP : CV_REG_EBP;
544 break;
545 case 6: reg = CV_REG_ESI; break;
546 case 7: reg = CV_REG_EDI; break;
547 case 8: reg = CV_REG_EIP; break;
548 case 9: reg = CV_REG_EFLAGS; break;
549 case 10: reg = CV_REG_CS; break;
550 case 11: reg = CV_REG_SS; break;
551 case 12: reg = CV_REG_DS; break;
552 case 13: reg = CV_REG_ES; break;
553 case 14: reg = CV_REG_FS; break;
554 case 15: reg = CV_REG_GS; break;
555 case 16: case 17: case 18: case 19:
556 case 20: case 21: case 22: case 23:
557 reg = CV_REG_ST0 + regno - 16; break;
558 case 24: reg = CV_REG_CTRL; break;
559 case 25: reg = CV_REG_STAT; break;
560 case 26: reg = CV_REG_TAG; break;
561 case 27: reg = CV_REG_FPCS; break;
562 case 28: reg = CV_REG_FPIP; break;
563 case 29: reg = CV_REG_FPDS; break;
564 case 30: reg = CV_REG_FPDO; break;
565 /*
566 reg: fop 31
567 */
568 case 32: case 33: case 34: case 35:
569 case 36: case 37: case 38: case 39:
570 reg = CV_REG_XMM0 + regno - 32; break;
571 case 40: reg = CV_REG_MXCSR; break;
572 default:
573 FIXME("Don't know how to map register %d\n", regno);
574 return 0;
575 }
576 return reg;
577 }
578
579 static void* i386_fetch_context_reg(CONTEXT* ctx, unsigned regno, unsigned* size)
580 {
581 #ifdef __i386__
582 switch (regno)
583 {
584 case CV_REG_EAX: *size = sizeof(ctx->Eax); return &ctx->Eax;
585 case CV_REG_EDX: *size = sizeof(ctx->Edx); return &ctx->Edx;
586 case CV_REG_ECX: *size = sizeof(ctx->Ecx); return &ctx->Ecx;
587 case CV_REG_EBX: *size = sizeof(ctx->Ebx); return &ctx->Ebx;
588 case CV_REG_ESI: *size = sizeof(ctx->Esi); return &ctx->Esi;
589 case CV_REG_EDI: *size = sizeof(ctx->Edi); return &ctx->Edi;
590 case CV_REG_EBP: *size = sizeof(ctx->Ebp); return &ctx->Ebp;
591 case CV_REG_ESP: *size = sizeof(ctx->Esp); return &ctx->Esp;
592 case CV_REG_EIP: *size = sizeof(ctx->Eip); return &ctx->Eip;
593
594 /* These are x87 floating point registers... They do not match a C type in
595 * the Linux ABI, so hardcode their 80-bitness. */
596 case CV_REG_ST0 + 0: *size = 10; return &ctx->FloatSave.RegisterArea[0*10];
597 case CV_REG_ST0 + 1: *size = 10; return &ctx->FloatSave.RegisterArea[1*10];
598 case CV_REG_ST0 + 2: *size = 10; return &ctx->FloatSave.RegisterArea[2*10];
599 case CV_REG_ST0 + 3: *size = 10; return &ctx->FloatSave.RegisterArea[3*10];
600 case CV_REG_ST0 + 4: *size = 10; return &ctx->FloatSave.RegisterArea[4*10];
601 case CV_REG_ST0 + 5: *size = 10; return &ctx->FloatSave.RegisterArea[5*10];
602 case CV_REG_ST0 + 6: *size = 10; return &ctx->FloatSave.RegisterArea[6*10];
603 case CV_REG_ST0 + 7: *size = 10; return &ctx->FloatSave.RegisterArea[7*10];
604
605 case CV_REG_CTRL: *size = sizeof(DWORD); return &ctx->FloatSave.ControlWord;
606 case CV_REG_STAT: *size = sizeof(DWORD); return &ctx->FloatSave.StatusWord;
607 case CV_REG_TAG: *size = sizeof(DWORD); return &ctx->FloatSave.TagWord;
608 case CV_REG_FPCS: *size = sizeof(DWORD); return &ctx->FloatSave.ErrorSelector;
609 case CV_REG_FPIP: *size = sizeof(DWORD); return &ctx->FloatSave.ErrorOffset;
610 case CV_REG_FPDS: *size = sizeof(DWORD); return &ctx->FloatSave.DataSelector;
611 case CV_REG_FPDO: *size = sizeof(DWORD); return &ctx->FloatSave.DataOffset;
612
613 case CV_REG_EFLAGS: *size = sizeof(ctx->EFlags); return &ctx->EFlags;
614 case CV_REG_ES: *size = sizeof(ctx->SegEs); return &ctx->SegEs;
615 case CV_REG_CS: *size = sizeof(ctx->SegCs); return &ctx->SegCs;
616 case CV_REG_SS: *size = sizeof(ctx->SegSs); return &ctx->SegSs;
617 case CV_REG_DS: *size = sizeof(ctx->SegDs); return &ctx->SegDs;
618 case CV_REG_FS: *size = sizeof(ctx->SegFs); return &ctx->SegFs;
619 case CV_REG_GS: *size = sizeof(ctx->SegGs); return &ctx->SegGs;
620
621 }
622 #endif
623 FIXME("Unknown register %x\n", regno);
624 return NULL;
625 }
626
627 static const char* i386_fetch_regname(unsigned regno)
628 {
629 switch (regno)
630 {
631 case CV_REG_EAX: return "eax";
632 case CV_REG_EDX: return "edx";
633 case CV_REG_ECX: return "ecx";
634 case CV_REG_EBX: return "ebx";
635 case CV_REG_ESI: return "esi";
636 case CV_REG_EDI: return "edi";
637 case CV_REG_EBP: return "ebp";
638 case CV_REG_ESP: return "esp";
639 case CV_REG_EIP: return "eip";
640
641 case CV_REG_ST0 + 0: return "st0";
642 case CV_REG_ST0 + 1: return "st1";
643 case CV_REG_ST0 + 2: return "st2";
644 case CV_REG_ST0 + 3: return "st3";
645 case CV_REG_ST0 + 4: return "st4";
646 case CV_REG_ST0 + 5: return "st5";
647 case CV_REG_ST0 + 6: return "st6";
648 case CV_REG_ST0 + 7: return "st7";
649
650 case CV_REG_EFLAGS: return "eflags";
651 case CV_REG_ES: return "es";
652 case CV_REG_CS: return "cs";
653 case CV_REG_SS: return "ss";
654 case CV_REG_DS: return "ds";
655 case CV_REG_FS: return "fs";
656 case CV_REG_GS: return "gs";
657
658 case CV_REG_CTRL: return "fpControl";
659 case CV_REG_STAT: return "fpStatus";
660 case CV_REG_TAG: return "fpTag";
661 case CV_REG_FPCS: return "fpCS";
662 case CV_REG_FPIP: return "fpIP";
663 case CV_REG_FPDS: return "fpDS";
664 case CV_REG_FPDO: return "fpData";
665
666 case CV_REG_XMM0 + 0: return "xmm0";
667 case CV_REG_XMM0 + 1: return "xmm1";
668 case CV_REG_XMM0 + 2: return "xmm2";
669 case CV_REG_XMM0 + 3: return "xmm3";
670 case CV_REG_XMM0 + 4: return "xmm4";
671 case CV_REG_XMM0 + 5: return "xmm5";
672 case CV_REG_XMM0 + 6: return "xmm6";
673 case CV_REG_XMM0 + 7: return "xmm7";
674
675 case CV_REG_MXCSR: return "MxCSR";
676 }
677 FIXME("Unknown register %x\n", regno);
678 return NULL;
679 }
680
681 #ifndef DBGHELP_STATIC_LIB
682 static BOOL i386_fetch_minidump_thread(struct dump_context* dc, unsigned index, unsigned flags, const CONTEXT* ctx)
683 {
684 if (ctx->ContextFlags && (flags & ThreadWriteInstructionWindow))
685 {
686 /* FIXME: crop values across module boundaries, */
687 #ifdef __i386__
688 ULONG base = ctx->Eip <= 0x80 ? 0 : ctx->Eip - 0x80;
689 minidump_add_memory_block(dc, base, ctx->Eip + 0x80 - base, 0);
690 #endif
691 }
692
693 return TRUE;
694 }
695 #endif
696
697 static BOOL i386_fetch_minidump_module(struct dump_context* dc, unsigned index, unsigned flags)
698 {
699 /* FIXME: actually, we should probably take care of FPO data, unless it's stored in
700 * function table minidump stream
701 */
702 return FALSE;
703 }
704
705 DECLSPEC_HIDDEN struct cpu cpu_i386 = {
706 IMAGE_FILE_MACHINE_I386,
707 4,
708 CV_REG_EBP,
709 #ifndef DBGHELP_STATIC_LIB
710 i386_get_addr,
711 i386_stack_walk,
712 #else
713 NULL,
714 NULL,
715 #endif
716 NULL,
717 i386_map_dwarf_register,
718 i386_fetch_context_reg,
719 i386_fetch_regname,
720 #ifndef DBGHELP_STATIC_LIB
721 i386_fetch_minidump_thread,
722 i386_fetch_minidump_module,
723 #else
724 NULL,
725 NULL,
726 #endif
727 };