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