ReactOS 0.4.15-dev-7961-gdcf9eb0
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); \
}
@ AddrModeFlat
Definition: compat.h:1159
@ AddrMode1616
Definition: compat.h:1156
#define assert(x)
Definition: debug.h:53
Definition: http.c:7252

◆ 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.

@ stm_start
Definition: cpu_i386.c:139
@ stm_done
Definition: cpu_i386.c:139
@ stm_16bit
Definition: cpu_i386.c:139
@ stm_32bit
Definition: cpu_i386.c:139

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

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}
#define FIXME(fmt,...)
Definition: debug.h:111
@ CV_REG_MXCSR
Definition: compat.h:1748
@ CV_REG_EFLAGS
Definition: compat.h:1713
@ CV_REG_SS
Definition: compat.h:1706
@ CV_REG_EBX
Definition: compat.h:1699
@ CV_REG_XMM0
Definition: compat.h:1744
@ CV_REG_ESI
Definition: compat.h:1702
@ CV_REG_TAG
Definition: compat.h:1735
@ CV_REG_EIP
Definition: compat.h:1712
@ CV_REG_FPDS
Definition: compat.h:1739
@ CV_REG_ECX
Definition: compat.h:1697
@ CV_REG_ST0
Definition: compat.h:1732
@ CV_REG_EBP
Definition: compat.h:1701
@ CV_REG_CS
Definition: compat.h:1705
@ CV_REG_EAX
Definition: compat.h:1696
@ CV_REG_FS
Definition: compat.h:1708
@ CV_REG_STAT
Definition: compat.h:1734
@ CV_REG_CTRL
Definition: compat.h:1733
@ CV_REG_EDI
Definition: compat.h:1703
@ CV_REG_ES
Definition: compat.h:1704
@ CV_REG_ESP
Definition: compat.h:1700
@ CV_REG_FPCS
Definition: compat.h:1737
@ CV_REG_GS
Definition: compat.h:1709
@ CV_REG_DS
Definition: compat.h:1707
@ CV_REG_EDX
Definition: compat.h:1698
@ CV_REG_FPIP
Definition: compat.h:1736
@ CV_REG_FPDO
Definition: compat.h:1738
GLsizeiptr size
Definition: glext.h:5919

◆ 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}

◆ 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}
void minidump_add_memory_block(struct dump_context *dc, ULONG64 base, ULONG size, ULONG rva) DECLSPEC_HIDDEN
Definition: minidump.c:355
@ ThreadWriteInstructionWindow
Definition: compat.h:1150
GLbitfield flags
Definition: glext.h:7161
static const WCHAR dc[]
uint32_t ULONG
Definition: typedefs.h:59

◆ 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}

◆ 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}
@ cpu_addr_frame
@ cpu_addr_pc
@ cpu_addr_stack
static const WCHAR ca[]
Definition: main.c:455
GLenum const GLvoid * addr
Definition: glext.h:9621
HANDLE hThread
Definition: wizard.c:28

◆ 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/*
557reg: 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}
@ DMT_MACHO
static int reg
Definition: i386-dis.c:1290
enum module_type type

◆ 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),
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;
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;
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;
314 frame->AddrReturn.Segment = 0;
315
317 tmp.Mode = AddrMode1616;
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;
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
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;
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",
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;
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
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),
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;
511done_err:
513 return FALSE;
514}
#define ARRAY_SIZE(A)
Definition: main.h:33
#define next_switch
Definition: cpu_i386.c:149
#define set_curr_mode(m)
Definition: cpu_i386.c:151
#define curr_count
Definition: cpu_i386.c:147
#define curr_mode
Definition: cpu_i386.c:146
static BOOL fetch_next_frame32(struct cpu_stack_walk *csw, union ctx *pcontext, DWORD_PTR curr_pc)
Definition: cpu_i386.c:99
#define inc_curr_count()
Definition: cpu_i386.c:152
#define curr_switch
Definition: cpu_i386.c:148
#define SET(field, seg, reg)
void * sw_table_access(struct cpu_stack_walk *csw, DWORD64 addr) DECLSPEC_HIDDEN
Definition: stack.c:119
DWORD64 sw_module_base(struct cpu_stack_walk *csw, DWORD64 addr) DECLSPEC_HIDDEN
Definition: stack.c:127
DWORD64 sw_xlat_addr(struct cpu_stack_walk *csw, ADDRESS64 *addr) DECLSPEC_HIDDEN
Definition: stack.c:104
#define WOW64_CONTEXT_CONTROL
Definition: compat.h:218
@ ThreadBasicInformation
Definition: compat.h:935
static __inline const char * wine_dbgstr_longlong(ULONGLONG ll)
Definition: compat.h:49
#define WOW64_CONTEXT_SEGMENTS
Definition: compat.h:220
const char * wine_dbgstr_addr(const ADDRESS64 *addr)
Definition: dbghelp.c:142
BOOL WINAPI GetThreadSelectorEntry(IN HANDLE hThread, IN DWORD dwSelector, OUT LPLDT_ENTRY lpSelectorEntry)
Definition: thread.c:830
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned short WORD
Definition: ntddk_ex.h:93
GLfloat GLfloat p
Definition: glext.h:8902
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
if(dx< 0)
Definition: linetemp.h:194
NTSTATUS NTAPI NtQueryInformationThread(IN HANDLE ThreadHandle, IN THREADINFOCLASS ThreadInformationClass, OUT PVOID ThreadInformation, IN ULONG ThreadInformationLength, OUT PULONG ReturnLength OPTIONAL)
Definition: query.c:2624
#define memset(x, y, z)
Definition: compat.h:39
#define STATUS_SUCCESS
Definition: shellext.h:65
#define TRACE(s)
Definition: solgame.cpp:4
Definition: compat.h:777
union _LDT_ENTRY::@358 HighWord
struct _LDT_ENTRY::@358::@360 Bits
DWORD relay
Definition: compat.h:2475
DWORD ecx
Definition: compat.h:2467
DWORD ebp
Definition: compat.h:2468
DWORD callfrom_ip
Definition: compat.h:2473
DWORD edx
Definition: compat.h:2466
WORD entry_ip
Definition: compat.h:2476
STACK32FRAME * frame32
Definition: compat.h:2465
DWORD entry_point
Definition: compat.h:2477
DWORD module_cs
Definition: compat.h:2474
DWORD retaddr
Definition: compat.h:2457
DWORD ebp
Definition: compat.h:2456
SEGPTR frame16
Definition: compat.h:2452
PVOID FuncTableEntry
Definition: compat.h:1406
ADDRESS64 AddrBStore
Definition: compat.h:1405
ADDRESS64 AddrStack
Definition: compat.h:1404
ADDRESS64 AddrFrame
Definition: compat.h:1403
ADDRESS64 AddrPC
Definition: compat.h:1401
DWORD64 Params[4]
Definition: compat.h:1407
BOOL Virtual
Definition: compat.h:1409
ADDRESS64 AddrReturn
Definition: compat.h:1402
Definition: compat.h:836
DWORD Eip
Definition: compat.h:274
WORD Segment
Definition: compat.h:1175
ADDRESS_MODE Mode
Definition: compat.h:1176
DWORD64 Offset
Definition: compat.h:1174
#define DWORD_PTR
Definition: treelist.c:76
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define SELECTOROF(ptr)
Definition: windef16.h:50
#define OFFSETOF(ptr)
Definition: windef16.h:51

◆ WINE_DEFAULT_DEBUG_CHANNEL()

WINE_DEFAULT_DEBUG_CHANNEL ( dbghelp  )

Variable Documentation

◆ cpu_i386

Initial value:
= {
4,
}
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
static BOOL i386_get_addr(HANDLE hThread, const CONTEXT *ctx, enum cpu_addr ca, ADDRESS64 *addr)
Definition: cpu_i386.c:80
static unsigned i386_map_dwarf_register(unsigned regno, const struct module *module, BOOL eh_frame)
Definition: cpu_i386.c:517
static BOOL i386_fetch_minidump_thread(struct dump_context *dc, unsigned index, unsigned flags, const CONTEXT *ctx)
Definition: cpu_i386.c:683
static BOOL i386_stack_walk(struct cpu_stack_walk *csw, STACKFRAME64 *frame, union ctx *context)
Definition: cpu_i386.c:154
static void * i386_fetch_context_reg(union ctx *pctx, unsigned regno, unsigned *size)
Definition: cpu_i386.c:570
#define IMAGE_FILE_MACHINE_I386
Definition: pedump.c:174

Definition at line 706 of file cpu_i386.c.