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