ReactOS  0.4.15-dev-1384-g878186b
cpu_i386.c File Reference
#include <assert.h>
#include "ntstatus.h"
#include "dbghelp_private.h"
#include "wine/winbase16.h"
#include "winternl.h"
#include "wine/debug.h"
Include dependency graph for cpu_i386.c:

Go to the source code of this file.

Macros

#define WIN32_NO_STATUS
 
#define V86_FLAG   0x00020000
 
#define IS_VM86_MODE(ctx)   (ctx->EFlags & V86_FLAG)
 
#define __CurrentModeCount   0
 
#define __CurrentSwitch   1
 
#define __NextSwitch   2
 
#define curr_mode   (frame->Reserved[__CurrentModeCount] & 0x0F)
 
#define curr_count   (frame->Reserved[__CurrentModeCount] >> 4)
 
#define curr_switch   (frame->Reserved[__CurrentSwitch])
 
#define next_switch   (frame->Reserved[__NextSwitch])
 
#define set_curr_mode(m)   {frame->Reserved[__CurrentModeCount] &= ~0x0F; frame->Reserved[__CurrentModeCount] |= (m & 0x0F);}
 
#define inc_curr_count()   (frame->Reserved[__CurrentModeCount] += 0x10)
 
#define SET(field, seg, reg)
 

Enumerations

enum  st_mode { stm_start, stm_32bit, stm_16bit, stm_done }
 

Functions

 WINE_DEFAULT_DEBUG_CHANNEL (dbghelp)
 
static BOOL i386_get_addr (HANDLE hThread, const CONTEXT *ctx, enum cpu_addr ca, ADDRESS64 *addr)
 
static BOOL fetch_next_frame32 (struct cpu_stack_walk *csw, union ctx *pcontext, DWORD_PTR curr_pc)
 
static BOOL i386_stack_walk (struct cpu_stack_walk *csw, STACKFRAME64 *frame, union ctx *context)
 
static unsigned i386_map_dwarf_register (unsigned regno, const struct module *module, BOOL eh_frame)
 
static voidi386_fetch_context_reg (union ctx *pctx, unsigned regno, unsigned *size)
 
static const chari386_fetch_regname (unsigned regno)
 
static BOOL i386_fetch_minidump_thread (struct dump_context *dc, unsigned index, unsigned flags, const CONTEXT *ctx)
 
static BOOL i386_fetch_minidump_module (struct dump_context *dc, unsigned index, unsigned flags)
 

Variables

DECLSPEC_HIDDEN struct cpu cpu_i386
 

Macro Definition Documentation

◆ __CurrentModeCount

#define __CurrentModeCount   0

Definition at line 142 of file cpu_i386.c.

◆ __CurrentSwitch

#define __CurrentSwitch   1

Definition at line 143 of file cpu_i386.c.

◆ __NextSwitch

#define __NextSwitch   2

Definition at line 144 of file cpu_i386.c.

◆ curr_count

#define curr_count   (frame->Reserved[__CurrentModeCount] >> 4)

Definition at line 147 of file cpu_i386.c.

◆ curr_mode

#define curr_mode   (frame->Reserved[__CurrentModeCount] & 0x0F)

Definition at line 146 of file cpu_i386.c.

◆ curr_switch

#define curr_switch   (frame->Reserved[__CurrentSwitch])

Definition at line 148 of file cpu_i386.c.

◆ inc_curr_count

#define inc_curr_count ( )    (frame->Reserved[__CurrentModeCount] += 0x10)

Definition at line 152 of file cpu_i386.c.

◆ IS_VM86_MODE

#define IS_VM86_MODE (   ctx)    (ctx->EFlags & V86_FLAG)

Definition at line 38 of file cpu_i386.c.

◆ next_switch

#define next_switch   (frame->Reserved[__NextSwitch])

Definition at line 149 of file cpu_i386.c.

◆ SET

#define SET (   field,
  seg,
  reg 
)
Value:
switch (frame->field.Mode) \
{ \
case AddrModeFlat: context->x86.reg = frame->field.Offset; break; \
case AddrMode1616: context->x86.seg = frame->field.Segment; context->x86.reg = frame->field.Offset; break; \
default: assert(0); \
}
Definition: http.c:7094
#define assert(x)
Definition: debug.h:53

◆ set_curr_mode

#define set_curr_mode (   m)    {frame->Reserved[__CurrentModeCount] &= ~0x0F; frame->Reserved[__CurrentModeCount] |= (m & 0x0F);}

Definition at line 151 of file cpu_i386.c.

◆ V86_FLAG

#define V86_FLAG   0x00020000

Definition at line 36 of file cpu_i386.c.

◆ WIN32_NO_STATUS

#define WIN32_NO_STATUS

Definition at line 25 of file cpu_i386.c.

Enumeration Type Documentation

◆ st_mode

Enumerator
stm_start 
stm_32bit 
stm_16bit 
stm_done 

Definition at line 139 of file cpu_i386.c.

Function Documentation

◆ fetch_next_frame32()

static BOOL fetch_next_frame32 ( struct cpu_stack_walk csw,
union ctx pcontext,
DWORD_PTR  curr_pc 
)
static

Definition at line 99 of file cpu_i386.c.

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 }
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
Definition: http.c:7094
#define TRUE
Definition: types.h:120
#define WARN(fmt,...)
Definition: debug.h:112
#define DWORD
Definition: nt_native.h:44
#define FALSE
Definition: types.h:117
char * name
Definition: compiler.c:66
unsigned long DWORD
Definition: ntddk_ex.h:95
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
uint32_t DWORD_PTR
Definition: typedefs.h:65
BOOL sw_read_mem(struct cpu_stack_walk *csw, DWORD64 addr, void *ptr, DWORD sz) DECLSPEC_HIDDEN
Definition: stack.c:95
uint64_t DWORD64
Definition: typedefs.h:67
#define NULL
Definition: types.h:112

Referenced by i386_stack_walk().

◆ i386_fetch_context_reg()

static void* i386_fetch_context_reg ( union ctx pctx,
unsigned  regno,
unsigned size 
)
static

Definition at line 570 of file cpu_i386.c.

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 }
WOW64_CONTEXT x86
#define DWORD
Definition: nt_native.h:44
#define FIXME(fmt,...)
Definition: debug.h:111
GLsizeiptr size
Definition: glext.h:5919
#define NULL
Definition: types.h:112

◆ i386_fetch_minidump_module()

static BOOL i386_fetch_minidump_module ( struct dump_context dc,
unsigned  index,
unsigned  flags 
)
static

Definition at line 698 of file cpu_i386.c.

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 }
#define FALSE
Definition: types.h:117

◆ i386_fetch_minidump_thread()

static BOOL i386_fetch_minidump_thread ( struct dump_context dc,
unsigned  index,
unsigned  flags,
const CONTEXT ctx 
)
static

Definition at line 683 of file cpu_i386.c.

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 }
#define TRUE
Definition: types.h:120
void minidump_add_memory_block(struct dump_context *dc, ULONG64 base, ULONG size, ULONG rva) DECLSPEC_HIDDEN
Definition: minidump.c:355
GLbitfield flags
Definition: glext.h:7161
unsigned int ULONG
Definition: retypes.h:1
static const WCHAR dc[]

◆ i386_fetch_regname()

static const char* i386_fetch_regname ( unsigned  regno)
static

Definition at line 628 of file cpu_i386.c.

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 }
#define FIXME(fmt,...)
Definition: debug.h:111
#define NULL
Definition: types.h:112

◆ i386_get_addr()

static BOOL i386_get_addr ( HANDLE  hThread,
const CONTEXT ctx,
enum cpu_addr  ca,
ADDRESS64 addr 
)
static

Definition at line 80 of file cpu_i386.c.

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 }
#define FALSE
Definition: types.h:117
GLenum const GLvoid * addr
Definition: glext.h:9621
HANDLE hThread
Definition: wizard.c:27
static const WCHAR ca[]
Definition: main.c:455

◆ i386_map_dwarf_register()

static unsigned i386_map_dwarf_register ( unsigned  regno,
const struct module module,
BOOL  eh_frame 
)
static

Definition at line 517 of file cpu_i386.c.

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 }
enum module_type type
#define FIXME(fmt,...)
Definition: debug.h:111
static int reg
Definition: i386-dis.c:1283

◆ i386_stack_walk()

static BOOL i386_stack_walk ( struct cpu_stack_walk csw,
STACKFRAME64 frame,
union ctx context 
)
static

Definition at line 154 of file cpu_i386.c.

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 }
WOW64_CONTEXT x86
#define OFFSETOF(ptr)
Definition: windef16.h:51
#define set_curr_mode(m)
Definition: cpu_i386.c:151
#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
union _LDT_ENTRY::@350 HighWord
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
#define curr_mode
Definition: cpu_i386.c:146
#define DWORD
Definition: nt_native.h:44
WORD Segment
Definition: compat.h:1034
#define SELECTOROF(ptr)
Definition: windef16.h:50
#define FALSE
Definition: types.h:117
DWORD ebp
Definition: compat.h:2315
unsigned int BOOL
Definition: ntddk_ex.h:94
DWORD callfrom_ip
Definition: compat.h:2332
#define FIXME(fmt,...)
Definition: debug.h:111
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
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
#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
DWORD ebp
Definition: compat.h:2327
#define TRACE(s)
Definition: solgame.cpp:4
if(!(yy_init))
Definition: macro.lex.yy.c:714
DWORD retaddr
Definition: compat.h:2316
DWORD entry_point
Definition: compat.h:2336
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
_In_opt_ PVOID _In_ ULONG _In_ PVOID context
Definition: wdfdriver.h:113
struct _LDT_ENTRY::@350::@352 Bits
PVOID FuncTableEntry
Definition: compat.h:1265
struct _test_info info[]
Definition: SetCursorPos.c:19
ADDRESS64 AddrStack
Definition: compat.h:1263
uint32_t DWORD_PTR
Definition: typedefs.h:65
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
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
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
#define NULL
Definition: types.h:112
ADDRESS64 AddrPC
Definition: compat.h:1260
DWORD Eip
Definition: compat.h:274
static __inline const char * wine_dbgstr_longlong(ULONGLONG ll)
Definition: compat.h:49
#define curr_count
Definition: cpu_i386.c:147
#define STATUS_SUCCESS
Definition: shellext.h:65
GLfloat GLfloat p
Definition: glext.h:8902
#define memset(x, y, z)
Definition: compat.h:39
ADDRESS_MODE Mode
Definition: compat.h:1035
DWORD edx
Definition: compat.h:2325
ADDRESS64 AddrFrame
Definition: compat.h:1262
BOOL Virtual
Definition: compat.h:1268

◆ WINE_DEFAULT_DEBUG_CHANNEL()

WINE_DEFAULT_DEBUG_CHANNEL ( dbghelp  )

Variable Documentation

◆ cpu_i386

Initial value:
= {
4,
}
static unsigned i386_map_dwarf_register(unsigned regno, const struct module *module, BOOL eh_frame)
Definition: cpu_i386.c:517
static void * i386_fetch_context_reg(union ctx *pctx, unsigned regno, unsigned *size)
Definition: cpu_i386.c:570
static BOOL i386_fetch_minidump_thread(struct dump_context *dc, unsigned index, unsigned flags, const CONTEXT *ctx)
Definition: cpu_i386.c:683
#define IMAGE_FILE_MACHINE_I386
Definition: pedump.c:174
static BOOL i386_stack_walk(struct cpu_stack_walk *csw, STACKFRAME64 *frame, union ctx *context)
Definition: cpu_i386.c:154
static const char * i386_fetch_regname(unsigned regno)
Definition: cpu_i386.c:628
static BOOL i386_fetch_minidump_module(struct dump_context *dc, unsigned index, unsigned flags)
Definition: cpu_i386.c:698
#define NULL
Definition: types.h:112
static BOOL i386_get_addr(HANDLE hThread, const CONTEXT *ctx, enum cpu_addr ca, ADDRESS64 *addr)
Definition: cpu_i386.c:80

Definition at line 706 of file cpu_i386.c.