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