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