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, 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 80 static BOOL i386_get_addr(HANDLE hThread, const CONTEXT* ctx, 81 enum cpu_addr ca, ADDRESS64* addr) 82 { 83 #ifdef __i386__ 84 switch (ca) 85 { 86 case cpu_addr_pc: return i386_build_addr(hThread, ctx, addr, ctx->SegCs, ctx->Eip); 87 case cpu_addr_stack: return i386_build_addr(hThread, ctx, addr, ctx->SegSs, ctx->Esp); 88 case cpu_addr_frame: return i386_build_addr(hThread, ctx, addr, ctx->SegSs, ctx->Ebp); 89 } 90 #endif 91 return FALSE; 92 } 93 94 /* fetch_next_frame32() 95 * 96 * modify (at least) context.{eip, esp, ebp} using unwind information 97 * either out of debug info (dwarf, pdb), or simple stack unwind 98 */ 99 static BOOL fetch_next_frame32(struct cpu_stack_walk* csw, 100 union ctx *pcontext, DWORD_PTR curr_pc) 101 { 102 DWORD64 xframe; 103 struct pdb_cmd_pair cpair[4]; 104 DWORD val32; 105 WOW64_CONTEXT *context = &pcontext->x86; 106 107 if (dwarf2_virtual_unwind(csw, curr_pc, pcontext, &xframe)) 108 { 109 context->Esp = xframe; 110 return TRUE; 111 } 112 cpair[0].name = "$ebp"; cpair[0].pvalue = &context->Ebp; 113 cpair[1].name = "$esp"; cpair[1].pvalue = &context->Esp; 114 cpair[2].name = "$eip"; cpair[2].pvalue = &context->Eip; 115 cpair[3].name = NULL; cpair[3].pvalue = NULL; 116 117 if (!pdb_virtual_unwind(csw, curr_pc, pcontext, cpair)) 118 { 119 /* do a simple unwind using ebp 120 * we assume a "regular" prologue in the function has been used 121 */ 122 if (!context->Ebp) return FALSE; 123 context->Esp = context->Ebp + 2 * sizeof(DWORD); 124 if (!sw_read_mem(csw, context->Ebp + sizeof(DWORD), &val32, sizeof(DWORD))) 125 { 126 WARN("Cannot read new frame offset %p\n", 127 (void*)(DWORD_PTR)(context->Ebp + (int)sizeof(DWORD))); 128 return FALSE; 129 } 130 context->Eip = val32; 131 /* "pop up" previous EBP value */ 132 if (!sw_read_mem(csw, context->Ebp, &val32, sizeof(DWORD))) 133 return FALSE; 134 context->Ebp = val32; 135 } 136 return TRUE; 137 } 138 139 enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done}; 140 141 /* indexes in Reserved array */ 142 #define __CurrentModeCount 0 143 #define __CurrentSwitch 1 144 #define __NextSwitch 2 145 146 #define curr_mode (frame->Reserved[__CurrentModeCount] & 0x0F) 147 #define curr_count (frame->Reserved[__CurrentModeCount] >> 4) 148 #define curr_switch (frame->Reserved[__CurrentSwitch]) 149 #define next_switch (frame->Reserved[__NextSwitch]) 150 151 #define set_curr_mode(m) {frame->Reserved[__CurrentModeCount] &= ~0x0F; frame->Reserved[__CurrentModeCount] |= (m & 0x0F);} 152 #define inc_curr_count() (frame->Reserved[__CurrentModeCount] += 0x10) 153 154 static BOOL i386_stack_walk(struct cpu_stack_walk* csw, STACKFRAME64 *frame, 155 union ctx *context) 156 { 157 STACK32FRAME frame32; 158 STACK16FRAME frame16; 159 char ch; 160 ADDRESS64 tmp; 161 DWORD p; 162 WORD val16; 163 DWORD val32; 164 BOOL do_switch; 165 unsigned deltapc; 166 union ctx _context; 167 168 /* sanity check */ 169 if (curr_mode >= stm_done) return FALSE; 170 171 TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s Count=%s cSwitch=%p nSwitch=%p\n", 172 wine_dbgstr_addr(&frame->AddrPC), 173 wine_dbgstr_addr(&frame->AddrFrame), 174 wine_dbgstr_addr(&frame->AddrReturn), 175 wine_dbgstr_addr(&frame->AddrStack), 176 curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"), 177 wine_dbgstr_longlong(curr_count), 178 (void*)(DWORD_PTR)curr_switch, (void*)(DWORD_PTR)next_switch); 179 180 /* if we're at first call (which doesn't actually unwind, it just computes ReturnPC, 181 * or if we're doing the first real unwind (count == 1), then we can directly use 182 * eip. otherwise, eip is *after* the insn that actually made the call to 183 * previous frame, so decrease eip by delta pc (1!) so that we're inside previous 184 * insn. 185 * Doing so, we ensure that the pc used for unwinding is always inside the function 186 * we want to use for next frame 187 */ 188 deltapc = curr_count <= 1 ? 0 : 1; 189 190 if (!context) 191 { 192 /* setup a pseudo context for the rest of the code (esp. unwinding) */ 193 context = &_context; 194 memset(context, 0, sizeof(*context)); 195 context->x86.ContextFlags = WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_SEGMENTS; 196 if (frame->AddrPC.Mode != AddrModeFlat) 197 context->x86.SegCs = frame->AddrPC.Segment; 198 context->x86.Eip = frame->AddrPC.Offset; 199 if (frame->AddrFrame.Mode != AddrModeFlat) 200 context->x86.SegSs = frame->AddrFrame.Segment; 201 context->x86.Ebp = frame->AddrFrame.Offset; 202 if (frame->AddrStack.Mode != AddrModeFlat) 203 context->x86.SegSs = frame->AddrStack.Segment; 204 context->x86.Esp = frame->AddrStack.Offset; 205 } 206 207 if (curr_mode == stm_start) 208 { 209 THREAD_BASIC_INFORMATION info; 210 211 if ((frame->AddrPC.Mode == AddrModeFlat) && 212 (frame->AddrFrame.Mode != AddrModeFlat)) 213 { 214 WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n"); 215 goto done_err; 216 } 217 218 /* Init done */ 219 set_curr_mode((frame->AddrPC.Mode == AddrModeFlat) ? stm_32bit : stm_16bit); 220 221 /* cur_switch holds address of SystemReserved1[0] field in TEB in debuggee 222 * address space 223 */ 224 if (NtQueryInformationThread(csw->hThread, ThreadBasicInformation, &info, 225 sizeof(info), NULL) == STATUS_SUCCESS) 226 { 227 curr_switch = (DWORD_PTR)info.TebBaseAddress + FIELD_OFFSET(TEB, SystemReserved1[0]); 228 if (!sw_read_mem(csw, curr_switch, &p, sizeof(p))) 229 { 230 WARN("Can't read TEB:SystemReserved1[0]\n"); 231 goto done_err; 232 } 233 next_switch = p; 234 if (!next_switch) /* no 16-bit stack */ 235 { 236 curr_switch = 0; 237 } 238 else if (curr_mode == stm_16bit) 239 { 240 if (!sw_read_mem(csw, next_switch, &frame32, sizeof(frame32))) 241 { 242 WARN("Bad stack frame %p\n", (void*)(DWORD_PTR)next_switch); 243 goto done_err; 244 } 245 curr_switch = (DWORD)frame32.frame16; 246 tmp.Mode = AddrMode1616; 247 tmp.Segment = SELECTOROF(curr_switch); 248 tmp.Offset = OFFSETOF(curr_switch); 249 if (!sw_read_mem(csw, sw_xlat_addr(csw, &tmp), &ch, sizeof(ch))) 250 curr_switch = 0xFFFFFFFF; 251 } 252 else 253 { 254 tmp.Mode = AddrMode1616; 255 tmp.Segment = SELECTOROF(next_switch); 256 tmp.Offset = OFFSETOF(next_switch); 257 p = sw_xlat_addr(csw, &tmp); 258 if (!sw_read_mem(csw, p, &frame16, sizeof(frame16))) 259 { 260 WARN("Bad stack frame 0x%08x\n", p); 261 goto done_err; 262 } 263 curr_switch = (DWORD_PTR)frame16.frame32; 264 if (!sw_read_mem(csw, curr_switch, &ch, sizeof(ch))) 265 curr_switch = 0xFFFFFFFF; 266 } 267 } 268 else 269 /* FIXME: this will allow it to work when we're not attached to a live target, 270 * but the 16 <=> 32 switch facility won't be available. 271 */ 272 curr_switch = 0; 273 frame->AddrReturn.Mode = frame->AddrStack.Mode = (curr_mode == stm_16bit) ? AddrMode1616 : AddrModeFlat; 274 /* don't set up AddrStack on first call. Either the caller has set it up, or 275 * we will get it in the next frame 276 */ 277 memset(&frame->AddrBStore, 0, sizeof(frame->AddrBStore)); 278 } 279 else 280 { 281 if (frame->AddrFrame.Mode == AddrModeFlat) 282 { 283 assert(curr_mode == stm_32bit); 284 do_switch = curr_switch && frame->AddrFrame.Offset >= curr_switch; 285 } 286 else 287 { 288 assert(curr_mode == stm_16bit); 289 do_switch = curr_switch && 290 frame->AddrFrame.Segment == SELECTOROF(curr_switch) && 291 frame->AddrFrame.Offset >= OFFSETOF(curr_switch); 292 } 293 294 if (do_switch) 295 { 296 if (curr_mode == stm_16bit) 297 { 298 if (!sw_read_mem(csw, next_switch, &frame32, sizeof(frame32))) 299 { 300 WARN("Bad stack frame %p\n", (void*)(DWORD_PTR)next_switch); 301 goto done_err; 302 } 303 304 frame->AddrPC.Mode = AddrModeFlat; 305 frame->AddrPC.Segment = 0; 306 frame->AddrPC.Offset = frame32.retaddr; 307 frame->AddrFrame.Mode = AddrModeFlat; 308 frame->AddrFrame.Segment = 0; 309 frame->AddrFrame.Offset = frame32.ebp; 310 311 frame->AddrStack.Mode = AddrModeFlat; 312 frame->AddrStack.Segment = 0; 313 frame->AddrReturn.Mode = AddrModeFlat; 314 frame->AddrReturn.Segment = 0; 315 316 next_switch = curr_switch; 317 tmp.Mode = AddrMode1616; 318 tmp.Segment = SELECTOROF(next_switch); 319 tmp.Offset = OFFSETOF(next_switch); 320 p = sw_xlat_addr(csw, &tmp); 321 322 if (!sw_read_mem(csw, p, &frame16, sizeof(frame16))) 323 { 324 WARN("Bad stack frame 0x%08x\n", p); 325 goto done_err; 326 } 327 curr_switch = (DWORD_PTR)frame16.frame32; 328 set_curr_mode(stm_32bit); 329 if (!sw_read_mem(csw, curr_switch, &ch, sizeof(ch))) 330 curr_switch = 0; 331 } 332 else 333 { 334 tmp.Mode = AddrMode1616; 335 tmp.Segment = SELECTOROF(next_switch); 336 tmp.Offset = OFFSETOF(next_switch); 337 p = sw_xlat_addr(csw, &tmp); 338 339 if (!sw_read_mem(csw, p, &frame16, sizeof(frame16))) 340 { 341 WARN("Bad stack frame 0x%08x\n", p); 342 goto done_err; 343 } 344 345 TRACE("Got a 16 bit stack switch:" 346 "\n\tframe32: %p" 347 "\n\tedx:%08x ecx:%08x ebp:%08x" 348 "\n\tds:%04x es:%04x fs:%04x gs:%04x" 349 "\n\tcall_from_ip:%08x module_cs:%04x relay=%08x" 350 "\n\tentry_ip:%04x entry_point:%08x" 351 "\n\tbp:%04x ip:%04x cs:%04x\n", 352 frame16.frame32, 353 frame16.edx, frame16.ecx, frame16.ebp, 354 frame16.ds, frame16.es, frame16.fs, frame16.gs, 355 frame16.callfrom_ip, frame16.module_cs, frame16.relay, 356 frame16.entry_ip, frame16.entry_point, 357 frame16.bp, frame16.ip, frame16.cs); 358 359 frame->AddrPC.Mode = AddrMode1616; 360 frame->AddrPC.Segment = frame16.cs; 361 frame->AddrPC.Offset = frame16.ip; 362 363 frame->AddrFrame.Mode = AddrMode1616; 364 frame->AddrFrame.Segment = SELECTOROF(next_switch); 365 frame->AddrFrame.Offset = frame16.bp; 366 367 frame->AddrStack.Mode = AddrMode1616; 368 frame->AddrStack.Segment = SELECTOROF(next_switch); 369 370 frame->AddrReturn.Mode = AddrMode1616; 371 frame->AddrReturn.Segment = frame16.cs; 372 373 next_switch = curr_switch; 374 if (!sw_read_mem(csw, next_switch, &frame32, sizeof(frame32))) 375 { 376 WARN("Bad stack frame %p\n", (void*)(DWORD_PTR)next_switch); 377 goto done_err; 378 } 379 curr_switch = (DWORD)frame32.frame16; 380 tmp.Mode = AddrMode1616; 381 tmp.Segment = SELECTOROF(curr_switch); 382 tmp.Offset = OFFSETOF(curr_switch); 383 384 if (!sw_read_mem(csw, sw_xlat_addr(csw, &tmp), &ch, sizeof(ch))) 385 curr_switch = 0; 386 set_curr_mode(stm_16bit); 387 } 388 } 389 else 390 { 391 if (curr_mode == stm_16bit) 392 { 393 frame->AddrPC = frame->AddrReturn; 394 frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(WORD); 395 /* "pop up" previous BP value */ 396 if (!frame->AddrFrame.Offset || 397 !sw_read_mem(csw, sw_xlat_addr(csw, &frame->AddrFrame), 398 &val16, sizeof(WORD))) 399 goto done_err; 400 frame->AddrFrame.Offset = val16; 401 } 402 else 403 { 404 if (!fetch_next_frame32(csw, context, sw_xlat_addr(csw, &frame->AddrPC) - deltapc)) 405 goto done_err; 406 407 frame->AddrStack.Mode = frame->AddrFrame.Mode = frame->AddrPC.Mode = AddrModeFlat; 408 frame->AddrStack.Offset = context->x86.Esp; 409 frame->AddrFrame.Offset = context->x86.Ebp; 410 if (frame->AddrReturn.Offset != context->x86.Eip) 411 FIXME("new PC=%s different from Eip=%x\n", 412 wine_dbgstr_longlong(frame->AddrReturn.Offset), context->x86.Eip); 413 frame->AddrPC.Offset = context->x86.Eip; 414 } 415 } 416 } 417 418 if (curr_mode == stm_16bit) 419 { 420 unsigned int i; 421 422 p = sw_xlat_addr(csw, &frame->AddrFrame); 423 if (!sw_read_mem(csw, p + sizeof(WORD), &val16, sizeof(WORD))) 424 goto done_err; 425 frame->AddrReturn.Offset = val16; 426 /* get potential cs if a far call was used */ 427 if (!sw_read_mem(csw, p + 2 * sizeof(WORD), &val16, sizeof(WORD))) 428 goto done_err; 429 if (frame->AddrFrame.Offset & 1) 430 frame->AddrReturn.Segment = val16; /* far call assumed */ 431 else 432 { 433 /* not explicitly marked as far call, 434 * but check whether it could be anyway 435 */ 436 if ((val16 & 7) == 7 && val16 != frame->AddrReturn.Segment) 437 { 438 LDT_ENTRY le; 439 440 if (GetThreadSelectorEntry(csw->hThread, val16, &le) && 441 (le.HighWord.Bits.Type & 0x08)) /* code segment */ 442 { 443 /* it is very uncommon to push a code segment cs as 444 * a parameter, so this should work in most cases 445 */ 446 frame->AddrReturn.Segment = val16; 447 } 448 } 449 } 450 frame->AddrFrame.Offset &= ~1; 451 /* we "pop" parameters as 16 bit entities... of course, this won't 452 * work if the parameter is in fact bigger than 16bit, but 453 * there's no way to know that here 454 */ 455 for (i = 0; i < ARRAY_SIZE(frame->Params); i++) 456 { 457 sw_read_mem(csw, p + (2 + i) * sizeof(WORD), &val16, sizeof(val16)); 458 frame->Params[i] = val16; 459 } 460 if (context) 461 { 462 #define SET(field, seg, reg) \ 463 switch (frame->field.Mode) \ 464 { \ 465 case AddrModeFlat: context->x86.reg = frame->field.Offset; break; \ 466 case AddrMode1616: context->x86.seg = frame->field.Segment; context->x86.reg = frame->field.Offset; break; \ 467 default: assert(0); \ 468 } 469 SET(AddrStack, SegSs, Esp); 470 SET(AddrFrame, SegSs, Ebp); 471 SET(AddrReturn, SegCs, Eip); 472 #undef SET 473 } 474 } 475 else 476 { 477 unsigned int i; 478 union ctx newctx = *context; 479 480 if (!fetch_next_frame32(csw, &newctx, frame->AddrPC.Offset - deltapc)) 481 goto done_err; 482 frame->AddrReturn.Mode = AddrModeFlat; 483 frame->AddrReturn.Offset = newctx.x86.Eip; 484 485 for (i = 0; i < ARRAY_SIZE(frame->Params); i++) 486 { 487 sw_read_mem(csw, frame->AddrFrame.Offset + (2 + i) * sizeof(DWORD), &val32, sizeof(val32)); 488 frame->Params[i] = val32; 489 } 490 } 491 492 frame->Far = TRUE; 493 frame->Virtual = TRUE; 494 p = sw_xlat_addr(csw, &frame->AddrPC); 495 if (p && sw_module_base(csw, p)) 496 frame->FuncTableEntry = sw_table_access(csw, p); 497 else 498 frame->FuncTableEntry = NULL; 499 500 inc_curr_count(); 501 TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s Count=%s cSwitch=%p nSwitch=%p FuncTable=%p\n", 502 wine_dbgstr_addr(&frame->AddrPC), 503 wine_dbgstr_addr(&frame->AddrFrame), 504 wine_dbgstr_addr(&frame->AddrReturn), 505 wine_dbgstr_addr(&frame->AddrStack), 506 curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"), 507 wine_dbgstr_longlong(curr_count), 508 (void*)(DWORD_PTR)curr_switch, (void*)(DWORD_PTR)next_switch, frame->FuncTableEntry); 509 510 return TRUE; 511 done_err: 512 set_curr_mode(stm_done); 513 return FALSE; 514 } 515 #endif /* DBGHELP_STATIC_LIB */ 516 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 706 DECLSPEC_HIDDEN struct cpu cpu_i386 = { 707 IMAGE_FILE_MACHINE_I386, 708 4, 709 CV_REG_EBP, 710 #ifndef DBGHELP_STATIC_LIB 711 i386_get_addr, 712 i386_stack_walk, 713 #else 714 NULL, 715 NULL, 716 #endif 717 NULL, 718 i386_map_dwarf_register, 719 i386_fetch_context_reg, 720 i386_fetch_regname, 721 #ifndef DBGHELP_STATIC_LIB 722 i386_fetch_minidump_thread, 723 i386_fetch_minidump_module, 724 #else 725 NULL, 726 NULL, 727 #endif 728 }; 729