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