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