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 }; 730