ReactOS  0.4.15-dev-1206-g731eddf
cpu_i386.c
Go to the documentation of this file.
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 
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)
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 
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
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  */
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 
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 
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"),
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));
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  {
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 */
220 
221  /* cur_switch holds address of SystemReserved1[0] field in TEB in debuggee
222  * address space
223  */
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;
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;
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;
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  {
284  do_switch = curr_switch && frame->AddrFrame.Offset >= curr_switch;
285  }
286  else
287  {
289  do_switch = 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 
317  tmp.Mode = AddrMode1616;
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;
329  if (!sw_read_mem(csw, curr_switch, &ch, sizeof(ch)))
330  curr_switch = 0;
331  }
332  else
333  {
334  tmp.Mode = AddrMode1616;
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;
365  frame->AddrFrame.Offset = frame16.bp;
366 
367  frame->AddrStack.Mode = AddrMode1616;
369 
370  frame->AddrReturn.Mode = AddrMode1616;
371  frame->AddrReturn.Segment = frame16.cs;
372 
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;
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;
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"),
508  (void*)(DWORD_PTR)curr_switch, (void*)(DWORD_PTR)next_switch, frame->FuncTableEntry);
509 
510  return TRUE;
511 done_err:
513  return FALSE;
514 }
515 #endif /* DBGHELP_STATIC_LIB */
516 
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 
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 
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
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 
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 
708  4,
709  CV_REG_EBP,
710 #ifndef DBGHELP_STATIC_LIB
713 #else
714  NULL,
715  NULL,
716 #endif
717  NULL,
721 #ifndef DBGHELP_STATIC_LIB
724 #else
725  NULL,
726  NULL,
727 #endif
728 };
const char * name
BOOL dwarf2_virtual_unwind(struct cpu_stack_walk *csw, DWORD_PTR ip, union ctx *ctx, DWORD64 *cfa) DECLSPEC_HIDDEN
Definition: dwarf.c:3258
WOW64_CONTEXT x86
#define OFFSETOF(ptr)
Definition: windef16.h:51
#define set_curr_mode(m)
Definition: cpu_i386.c:151
#define IS_VM86_MODE(ctx)
Definition: cpu_i386.c:38
#define SET(field, seg, reg)
#define DWORD_PTR
Definition: treelist.c:76
Definition: http.c:7094
#define WOW64_CONTEXT_CONTROL
Definition: compat.h:218
#define TRUE
Definition: types.h:120
STACK32FRAME * frame32
Definition: compat.h:2324
#define WARN(fmt,...)
Definition: debug.h:112
GLintptr offset
Definition: glext.h:5920
#define DECLSPEC_HIDDEN
Definition: precomp.h:8
void * sw_table_access(struct cpu_stack_walk *csw, DWORD64 addr) DECLSPEC_HIDDEN
Definition: stack.c:119
#define assert(x)
Definition: debug.h:53
DWORD64 Params[4]
Definition: compat.h:1266
ADDRESS64 AddrBStore
Definition: compat.h:1264
void minidump_add_memory_block(struct dump_context *dc, ULONG64 base, ULONG size, ULONG rva) DECLSPEC_HIDDEN
Definition: minidump.c:355
#define curr_mode
Definition: cpu_i386.c:146
#define DWORD
Definition: nt_native.h:44
WORD Segment
Definition: compat.h:1034
struct _test_info info[]
Definition: SetCursorPos.c:19
enum module_type type
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define SELECTOROF(ptr)
Definition: windef16.h:50
static unsigned i386_map_dwarf_register(unsigned regno, const struct module *module, BOOL eh_frame)
Definition: cpu_i386.c:517
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define FALSE
Definition: types.h:117
DWORD ebp
Definition: compat.h:2315
ADDRESS_MODE
Definition: compat.h:1013
unsigned int BOOL
Definition: ntddk_ex.h:94
DWORD callfrom_ip
Definition: compat.h:2332
static void * i386_fetch_context_reg(union ctx *pctx, unsigned regno, unsigned *size)
Definition: cpu_i386.c:570
#define FIXME(fmt,...)
Definition: debug.h:111
struct _LDT_ENTRY::@349::@351 Bits
cpu_addr
DWORD64 sw_module_base(struct cpu_stack_walk *csw, DWORD64 addr) DECLSPEC_HIDDEN
Definition: stack.c:127
#define inc_curr_count()
Definition: cpu_i386.c:152
#define next_switch
Definition: cpu_i386.c:149
smooth NULL
Definition: ftsmooth.c:416
SEGPTR frame16
Definition: compat.h:2311
const char * wine_dbgstr_addr(const ADDRESS64 *addr)
Definition: dbghelp.c:142
DWORD64 sw_xlat_addr(struct cpu_stack_walk *csw, ADDRESS64 *addr) DECLSPEC_HIDDEN
Definition: stack.c:104
GLuint index
Definition: glext.h:6031
#define curr_switch
Definition: cpu_i386.c:148
static BOOL fetch_next_frame32(struct cpu_stack_walk *csw, union ctx *pcontext, DWORD_PTR curr_pc)
Definition: cpu_i386.c:99
DWORD ecx
Definition: compat.h:2326
#define WOW64_CONTEXT_SEGMENTS
Definition: compat.h:220
static BOOL i386_fetch_minidump_thread(struct dump_context *dc, unsigned index, unsigned flags, const CONTEXT *ctx)
Definition: cpu_i386.c:683
DWORD ebp
Definition: compat.h:2327
#define IMAGE_FILE_MACHINE_I386
Definition: pedump.c:174
#define TRACE(s)
Definition: solgame.cpp:4
GLsizeiptr size
Definition: glext.h:5919
if(!(yy_init))
Definition: macro.lex.yy.c:714
DWORD retaddr
Definition: compat.h:2316
DWORD entry_point
Definition: compat.h:2336
static BOOL i386_stack_walk(struct cpu_stack_walk *csw, STACKFRAME64 *frame, union ctx *context)
Definition: cpu_i386.c:154
DWORD64 Offset
Definition: compat.h:1033
ADDRESS64 AddrReturn
Definition: compat.h:1261
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned long DWORD
Definition: ntddk_ex.h:95
DWORD module_cs
Definition: compat.h:2333
NTSTATUS NTAPI NtQueryInformationThread(IN HANDLE ThreadHandle, IN THREADINFOCLASS ThreadInformationClass, OUT PVOID ThreadInformation, IN ULONG ThreadInformationLength, OUT PULONG ReturnLength OPTIONAL)
Definition: query.c:2501
GLbitfield flags
Definition: glext.h:7161
PVOID FuncTableEntry
Definition: compat.h:1265
ADDRESS64 AddrStack
Definition: compat.h:1263
GLenum const GLvoid * addr
Definition: glext.h:9621
DECLSPEC_HIDDEN struct cpu cpu_i386
Definition: cpu_i386.c:706
BOOL pdb_virtual_unwind(struct cpu_stack_walk *csw, DWORD_PTR ip, union ctx *context, struct pdb_cmd_pair *cpair) DECLSPEC_HIDDEN
Definition: msc.c:3200
seg
Definition: i386-dis.c:3857
uint32_t DWORD_PTR
Definition: typedefs.h:65
union _LDT_ENTRY::@349 HighWord
DWORD relay
Definition: compat.h:2334
Definition: compat.h:636
BOOL sw_read_mem(struct cpu_stack_walk *csw, DWORD64 addr, void *ptr, DWORD sz) DECLSPEC_HIDDEN
Definition: stack.c:95
Definition: compat.h:694
st_mode
Definition: cpu_i386.c:139
static const char * i386_fetch_regname(unsigned regno)
Definition: cpu_i386.c:628
uint64_t DWORD64
Definition: typedefs.h:67
WORD entry_ip
Definition: compat.h:2335
#define ARRAY_SIZE(a)
Definition: main.h:24
BOOL WINAPI GetThreadSelectorEntry(IN HANDLE hThread, IN DWORD dwSelector, OUT LPLDT_ENTRY lpSelectorEntry)
Definition: thread.c:829
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
static BOOL i386_fetch_minidump_module(struct dump_context *dc, unsigned index, unsigned flags)
Definition: cpu_i386.c:698
ADDRESS64 AddrPC
Definition: compat.h:1260
static int reg
Definition: i386-dis.c:1275
HANDLE hThread
Definition: wizard.c:27
DWORD Eip
Definition: compat.h:274
unsigned int ULONG
Definition: retypes.h:1
static __inline const char * wine_dbgstr_longlong(ULONGLONG ll)
Definition: compat.h:49
static const WCHAR dc[]
#define curr_count
Definition: cpu_i386.c:147
GLfloat GLfloat p
Definition: glext.h:8902
static const WCHAR ca[]
Definition: main.c:455
return STATUS_SUCCESS
Definition: btrfs.c:3014
#define memset(x, y, z)
Definition: compat.h:39
ADDRESS_MODE Mode
Definition: compat.h:1035
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp)
DWORD edx
Definition: compat.h:2325
ADDRESS64 AddrFrame
Definition: compat.h:1262
BOOL Virtual
Definition: compat.h:1268
static BOOL i386_get_addr(HANDLE hThread, const CONTEXT *ctx, enum cpu_addr ca, ADDRESS64 *addr)
Definition: cpu_i386.c:80