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