Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

kdcpuapi.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1990 Microsoft Corporation 00004 00005 Module Name: 00006 00007 kdcpuapi.c 00008 00009 Abstract: 00010 00011 This module implements CPU specific remote debug APIs. 00012 00013 Author: 00014 00015 Mark Lucovsky (markl) 04-Sep-1990 00016 00017 Revision History: 00018 00019 24-sep-90 bryanwi 00020 00021 Port to the x86. 00022 00023 --*/ 00024 00025 #include <stdio.h> 00026 00027 #include "kdp.h" 00028 #define END_OF_CONTROL_SPACE 00029 00030 extern ULONG KdpCurrentSymbolStart, KdpCurrentSymbolEnd; 00031 extern ULONG KdSpecialCalls[]; 00032 extern ULONG KdNumberOfSpecialCalls; 00033 00034 LONG 00035 KdpLevelChange ( 00036 ULONG Pc, 00037 PCONTEXT ContextRecord, 00038 PBOOLEAN SpecialCall 00039 ); 00040 00041 LONG 00042 regValue( 00043 UCHAR reg, 00044 PCONTEXT ContextRecord 00045 ); 00046 00047 BOOLEAN 00048 KdpIsSpecialCall ( 00049 ULONG Pc, 00050 PCONTEXT ContextRecord, 00051 UCHAR opcode, 00052 UCHAR ModRM 00053 ); 00054 00055 ULONG 00056 KdpGetReturnAddress ( 00057 PCONTEXT ContextRecord 00058 ); 00059 00060 ULONG 00061 KdpGetCallNextOffset ( 00062 ULONG Pc, 00063 PCONTEXT ContextRecord 00064 ); 00065 00066 #ifdef ALLOC_PRAGMA 00067 #pragma alloc_text(PAGEKD, KdpLevelChange) 00068 #pragma alloc_text(PAGEKD, regValue) 00069 #pragma alloc_text(PAGEKD, KdpIsSpecialCall) 00070 #pragma alloc_text(PAGEKD, KdpGetReturnAddress) 00071 #pragma alloc_text(PAGEKD, KdpSetLoadState) 00072 #pragma alloc_text(PAGEKD, KdpSetStateChange) 00073 #pragma alloc_text(PAGEKD, KdpGetStateChange) 00074 #pragma alloc_text(PAGEKD, KdpReadControlSpace) 00075 #pragma alloc_text(PAGEKD, KdpWriteControlSpace) 00076 #pragma alloc_text(PAGEKD, KdpReadIoSpace) 00077 #pragma alloc_text(PAGEKD, KdpWriteIoSpace) 00078 #pragma alloc_text(PAGEKD, KdpReadMachineSpecificRegister) 00079 #pragma alloc_text(PAGEKD, KdpWriteMachineSpecificRegister) 00080 #pragma alloc_text(PAGEKD, KdpGetCallNextOffset) 00081 #endif 00082 00083 /**** KdpIsTryFinallyReturn - detect finally optimization 00084 * 00085 * Input: 00086 * pc - program counter of instruction to check 00087 * ContextRecord - machine specific context 00088 * 00089 * Output: 00090 * returns TRUE if this is a try-finally returning to the same 00091 * scope 00092 ***************************************************************************/ 00093 00094 00095 BOOLEAN 00096 KdpIsTryFinallyReturn ( 00097 ULONG Pc, 00098 PCONTEXT ContextRecord 00099 ) 00100 { 00101 ULONG retaddr; 00102 ULONG calldisp; 00103 UCHAR inst; 00104 00105 // 00106 // The complier generates code for a try-finally that involves having 00107 // a ret instruction that does not match with a call instruction. 00108 // This ret never returns a value (ie, it's a c3 return and not a 00109 // c2). It always returns into the current symbol scope. It is never 00110 // preceeded by a leave, which (hopefully) should differentiate it 00111 // from recursive returns. Check for this, and if we find it count 00112 // it as *0* level change. 00113 // 00114 // As an optimization, the compiler will often change: 00115 // CALL 00116 // RET 00117 // into: 00118 // JMP 00119 // In either case, we figure out the return address. It's the first 4 bytes 00120 // on the stack. 00121 // 00122 00123 KdpMoveMemory( (PCHAR)&retaddr, (PCHAR)ContextRecord->Esp, 4 ); 00124 00125 // DPRINT(( "Start %x return %x end %x\n", KdpCurrentSymbolStart, retaddr, KdpCurrentSymbolEnd )); 00126 00127 if ( (KdpCurrentSymbolStart < retaddr) && (retaddr < KdpCurrentSymbolEnd) ) { 00128 00129 // 00130 // Well, things aren't this nice. We may have transferred but not yet 00131 // updated the start/end. This case occurs in a call to a thunk. We 00132 // look to see if the instruction before the return address is a call. 00133 // Gross and not 100% reliable. 00134 // 00135 00136 KdpMoveMemory( (PCHAR)&inst, (PCHAR)retaddr - 5, 1 ); 00137 KdpMoveMemory( (PCHAR)&calldisp, (PCHAR)retaddr - 4, 4 ); 00138 00139 if (inst == 0xe8 && calldisp + retaddr == Pc) { 00140 // DPRINT(( "call to thunk @ %x\n", Pc )); 00141 return FALSE; 00142 } 00143 00144 // 00145 // returning to the current function. Either a finally 00146 // or a recursive return. Check for a leave. This is not 100% 00147 // reliable since we are betting on an instruction longer than a byte 00148 // and not ending with 0xc9. 00149 // 00150 00151 KdpMoveMemory( (PCHAR)&inst, (PCHAR)Pc-1, 1 ); 00152 00153 if ( inst != 0xc9 ) { 00154 // not a leave. Assume a try-finally. 00155 // DPRINT(( "transfer at %x is try-finally\n", Pc )); 00156 return TRUE; 00157 } 00158 } 00159 00160 // 00161 // This appears to be a true RET instruction 00162 // 00163 00164 return FALSE; 00165 } 00166 00167 /**** KdpLevelChange - say how the instruction affects the call level 00168 * 00169 * Input: 00170 * pc - program counter of instruction to check 00171 * ContextRecord - machine specific context 00172 * SpecialCall - pointer to returned boolean indicating if the 00173 * instruction is a transfer to a special routine 00174 * 00175 * Output: 00176 * returns -1 for a level pop, 1 for a push and 0 if it is 00177 * unchanged. 00178 * NOTE: This function belongs in some other file. I should move it. 00179 ***************************************************************************/ 00180 00181 00182 LONG 00183 KdpLevelChange ( 00184 ULONG Pc, 00185 PCONTEXT ContextRecord, 00186 PBOOLEAN SpecialCall 00187 ) 00188 { 00189 UCHAR membuf[2]; 00190 ULONG Addr; 00191 00192 KdpMoveMemory( (PCHAR)membuf, (PCHAR)Pc, 2 ); 00193 00194 switch (membuf[0]) { 00195 case 0xe8: // CALL direct w/32 bit displacement 00196 // 00197 // For try/finally, the compiler may, in addition to the push/ret trick 00198 // below, use a call to the finally thunk. Since we treat a RET to 00199 // within the same symbol scope as not changing levels, we will also 00200 // treat such a call as not changing levels either 00201 // 00202 00203 KdpMoveMemory( (PCHAR)&Addr, (PCHAR)Pc+1, 4 ); 00204 Addr += Pc + 5; 00205 00206 if ((KdpCurrentSymbolStart <= Addr) && (Addr < KdpCurrentSymbolEnd)) { 00207 *SpecialCall = FALSE; 00208 return 0; 00209 } 00210 00211 00212 case 0x9a: // CALL segmented 16:32 00213 00214 *SpecialCall = KdpIsSpecialCall( Pc, ContextRecord, membuf[0], membuf[1] ); 00215 return 1; 00216 00217 case 0xff: 00218 // 00219 // This is a compound instruction. Dispatch on operation 00220 // 00221 switch (membuf[1] & 0x38) { 00222 case 0x10: // CALL with mod r/m 00223 *SpecialCall = KdpIsSpecialCall( Pc, ContextRecord, membuf[0], membuf[1] ); 00224 return 1; 00225 case 0x20: // JMP with mod r/m 00226 *SpecialCall = KdpIsSpecialCall( Pc, ContextRecord, membuf[0], membuf[1] ); 00227 00228 // 00229 // If this is a try/finally, we'd like to treat it as call since the 00230 // return inside the destination will bring us back to this context. 00231 // However, if it is a jmp to a special routine, we must treat it 00232 // as a no-level change operation since we won't see the special 00233 // routines's return. 00234 // 00235 // If it is not a try/finally, we'd like to treat it as a no-level 00236 // change, unless again, it is a transfer to a special call which 00237 // views this as a level up. 00238 // 00239 00240 if (KdpIsTryFinallyReturn( Pc, ContextRecord )) { 00241 if (*SpecialCall) { 00242 // 00243 // We won't see the return, so pretend it is just 00244 // inline code 00245 // 00246 00247 return 0; 00248 00249 } else { 00250 // 00251 // The destinations return will bring us back to this 00252 // context 00253 // 00254 00255 return 1; 00256 } 00257 } else if (*SpecialCall) { 00258 // 00259 // We won't see the return but we are, indeed, doing one. 00260 // 00261 return -1; 00262 } else { 00263 return 0; 00264 } 00265 00266 default: 00267 *SpecialCall = FALSE; 00268 return 0; 00269 } 00270 00271 case 0xc3: // RET 00272 00273 // 00274 // If we are a try/finally ret, then we indicate that it is NOT a level 00275 // change 00276 // 00277 00278 if (KdpIsTryFinallyReturn( Pc, ContextRecord )) { 00279 *SpecialCall = FALSE; 00280 return 0; 00281 } 00282 00283 case 0xc2: // RET w/16 bit esp change 00284 case 0xca: // RETF w/16 bit esp change 00285 case 0xcb: // RETF 00286 *SpecialCall = FALSE; 00287 return -1; 00288 00289 default: 00290 *SpecialCall = FALSE; 00291 return 0; 00292 } 00293 00294 } // KdpLevelChange 00295 00296 LONG 00297 regValue( 00298 UCHAR reg, 00299 PCONTEXT ContextRecord 00300 ) 00301 { 00302 switch (reg) { 00303 case 0x0: 00304 return(ContextRecord->Eax); 00305 break; 00306 case 0x1: 00307 return(ContextRecord->Ecx); 00308 break; 00309 case 0x2: 00310 return(ContextRecord->Edx); 00311 break; 00312 case 0x3: 00313 return(ContextRecord->Ebx); 00314 break; 00315 case 0x4: 00316 return(ContextRecord->Esp); 00317 break; 00318 case 0x5: 00319 return(ContextRecord->Ebp); 00320 break; 00321 case 0x6: 00322 return(ContextRecord->Esi); 00323 break; 00324 case 0x7: 00325 return(ContextRecord->Edi); 00326 break; 00327 } 00328 } 00329 00330 BOOLEAN 00331 KdpIsSpecialCall ( 00332 ULONG Pc, 00333 PCONTEXT ContextRecord, 00334 UCHAR opcode, 00335 UCHAR modRM 00336 ) 00337 00338 /*++ 00339 00340 Routine Description: 00341 00342 Check to see if the instruction at pc is a call to one of the 00343 SpecialCall routines. 00344 00345 Argument: 00346 00347 Pc - program counter of instruction in question. 00348 00349 --*/ 00350 { 00351 UCHAR sib; 00352 USHORT twoBytes; 00353 ULONG callAddr; 00354 ULONG addrAddr; 00355 LONG offset; 00356 ULONG i; 00357 char d8; 00358 00359 if ( opcode == 0xe8 ) { 00360 00361 // 00362 // Signed offset from pc 00363 // 00364 00365 KdpMoveMemory( (PCHAR)&offset, (PCHAR)Pc+1, 4 ); 00366 00367 callAddr = Pc + offset + 5; // +5 for instr len. 00368 00369 } else if ( opcode == 0xff ) { 00370 00371 if ( ((modRM & 0x38) != 0x10) && ((modRM & 0x38) != 0x20) ) { 00372 // not call or jump 00373 return FALSE; 00374 } 00375 if ( (modRM & 0x08) == 0x08 ) { 00376 // m16:16 or m16:32 -- we don't handle this 00377 return FALSE; 00378 } 00379 00380 if ( (modRM & 0xc0) == 0xc0 ) { 00381 00382 /* Direct register addressing */ 00383 callAddr = regValue( (UCHAR)(modRM&0x7), ContextRecord ); 00384 00385 } else if ( (modRM & 0xc7) == 0x05 ) { 00386 // 00387 // Calls across dll boundaries involve a call into a jump table, 00388 // wherein the jump address is set to the real called routine at DLL 00389 // load time. Check to see if we're calling such an instruction, 00390 // and if so, compute its target address and set callAddr there. 00391 // 00392 // ff15 or ff25 -- call or jump indirect with disp32. Get 00393 // address of address 00394 // 00395 KdpMoveMemory( (PCHAR)&addrAddr, (PCHAR)Pc+2, 4 ); 00396 00397 // 00398 // Get real destination address 00399 // 00400 KdpMoveMemory( (PCHAR)&callAddr, (PCHAR)addrAddr, 4 ); 00401 // DPRINT(( "Indirect call/jmp @ %x\n", Pc )); 00402 } else if ( (modRM & 0x7) == 0x4 ) { 00403 00404 LONG indexValue; 00405 00406 /* sib byte present */ 00407 KdpMoveMemory( (PCHAR)&sib, (PCHAR)Pc+2, 1 ); 00408 indexValue = regValue( (UCHAR)((sib & 0x31) >> 3), ContextRecord ); 00409 switch ( sib&0xc0 ) { 00410 case 0x0: /* x1 */ 00411 break; 00412 case 0x40: 00413 indexValue *= 2; 00414 break; 00415 case 0x80: 00416 indexValue *= 4; 00417 break; 00418 case 0xc0: 00419 indexValue *= 8; 00420 break; 00421 } /* switch */ 00422 00423 switch ( modRM & 0xc0 ) { 00424 00425 case 0x0: /* no displacement */ 00426 if ( (sib & 0x7) == 0x5 ) { 00427 // DPRINT(("funny call #1 at %x\n", Pc)); 00428 return FALSE; 00429 } 00430 callAddr = indexValue + regValue((UCHAR)(sib&0x7), ContextRecord ); 00431 break; 00432 00433 case 0x40: 00434 if ( (sib & 0x6) == 0x4 ) { 00435 // DPRINT(("Funny call #2\n")); /* calling into the stack */ 00436 return FALSE; 00437 } 00438 KdpMoveMemory( &d8, (PCHAR)Pc+3,1 ); 00439 callAddr = indexValue + d8 + 00440 regValue((UCHAR)(sib&0x7), ContextRecord ); 00441 break; 00442 00443 case 0x80: 00444 if ( (sib & 0x6) == 0x4 ) { 00445 // DPRINT(("Funny call #3\n")); /* calling into the stack */ 00446 return FALSE; 00447 } 00448 KdpMoveMemory( (PCHAR)&offset, (PCHAR)Pc+3, 4 ); 00449 callAddr = indexValue + offset + 00450 regValue((UCHAR)(sib&0x7), ContextRecord ); 00451 break; 00452 00453 case 0xc0: 00454 ASSERT( FALSE ); 00455 break; 00456 00457 } 00458 00459 } else { 00460 //KdPrint(( "undecoded call at %x\n", 00461 // CONTEXT_TO_PROGRAM_COUNTER(ContextRecord) )); 00462 return FALSE; 00463 } 00464 00465 } else if ( opcode == 0x9a ) { 00466 00467 /* Absolute address call (best I can tell, cc doesn't generate this) */ 00468 KdpMoveMemory( (PCHAR)&callAddr, (PCHAR)Pc+1, 4 ); 00469 00470 } else { 00471 return FALSE; 00472 } 00473 00474 // 00475 // Calls across dll boundaries involve a call into a jump table, 00476 // wherein the jump address is set to the real called routine at DLL 00477 // load time. Check to see if we're calling such an instruction, 00478 // and if so, compute its target address and set callAddr there. 00479 // 00480 00481 #if 0 00482 KdpMoveMemory( (PCHAR)&twoBytes, (PCHAR)callAddr, 2 ); 00483 if ( twoBytes == 0x25ff ) { /* i386 is little-Endian; really 0xff25 */ 00484 00485 // 00486 // This is a 'jmp dword ptr [mem]' instruction, which is the sort of 00487 // jump used for a dll-boundary crossing call. Fixup callAddr. 00488 // 00489 00490 KdpMoveMemory( (PCHAR)&addrAddr, (PCHAR)callAddr+2, 4 ); 00491 KdpMoveMemory( (PCHAR)&callAddr, (PCHAR)addrAddr, 4 ); 00492 } 00493 #endif 00494 00495 for ( i = 0; i < KdNumberOfSpecialCalls; i++ ) { 00496 if ( KdSpecialCalls[i] == callAddr ) { 00497 return TRUE; 00498 } 00499 } 00500 return FALSE; 00501 00502 } 00503 00504 /* 00505 * Find the return address of the current function. Only works when 00506 * locals haven't yet been pushed (ie, on the first instruction of the 00507 * function). 00508 */ 00509 00510 ULONG 00511 KdpGetReturnAddress ( 00512 PCONTEXT ContextRecord 00513 ) 00514 { 00515 ULONG retaddr; 00516 00517 KdpMoveMemory((PCHAR)(&retaddr), (PCHAR)(ContextRecord->Esp), 4 ); 00518 return retaddr; 00519 00520 } // KdpGetReturnAddress 00521 00522 VOID 00523 KdpSetLoadState( 00524 IN PDBGKD_WAIT_STATE_CHANGE64 WaitStateChange, 00525 IN PCONTEXT ContextRecord 00526 ) 00527 00528 /*++ 00529 00530 Routine Description: 00531 00532 Fill in the Wait_State_Change message record for the load symbol case. 00533 00534 Arguments: 00535 00536 WaitStateChange - Supplies pointer to record to fill in 00537 00538 ContextRecord - Supplies a pointer to a context record. 00539 00540 Return Value: 00541 00542 None. 00543 00544 --*/ 00545 00546 { 00547 00548 ULONG Count; 00549 PVOID End; 00550 PKPRCB Prcb; 00551 00552 // 00553 // Store the special x86 register into the control report structure. 00554 // 00555 00556 Prcb = KeGetCurrentPrcb(); 00557 WaitStateChange->ControlReport.Dr6 = Prcb->ProcessorState.SpecialRegisters.KernelDr6; 00558 WaitStateChange->ControlReport.Dr7 = Prcb->ProcessorState.SpecialRegisters.KernelDr7; 00559 00560 // 00561 // Copy the immediate instruction stream into the control report structure. 00562 // 00563 00564 Count = KdpMoveMemory((PCHAR)(&(WaitStateChange->ControlReport.InstructionStream[0])), 00565 (PCHAR)(WaitStateChange->ProgramCounter), 00566 DBGKD_MAXSTREAM); 00567 00568 WaitStateChange->ControlReport.InstructionCount = (USHORT)Count; 00569 00570 // 00571 // Clear breakpoints in the copied instruction stream. If any breakpoints 00572 // are cleared, then recopy the instruction stream. 00573 // 00574 00575 End = (PVOID)((PUCHAR)(WaitStateChange->ProgramCounter) + Count - 1); 00576 if (KdpDeleteBreakpointRange((PVOID)WaitStateChange->ProgramCounter, End) != FALSE) { 00577 KdpMoveMemory(&WaitStateChange->ControlReport.InstructionStream[0], 00578 (PVOID)WaitStateChange->ProgramCounter, 00579 Count); 00580 } 00581 00582 // 00583 // Store the segment registers into the control report structure and set the 00584 // control flags. 00585 // 00586 00587 WaitStateChange->ControlReport.SegCs = (USHORT)(ContextRecord->SegCs); 00588 WaitStateChange->ControlReport.SegDs = (USHORT)(ContextRecord->SegDs); 00589 WaitStateChange->ControlReport.SegEs = (USHORT)(ContextRecord->SegEs); 00590 WaitStateChange->ControlReport.SegFs = (USHORT)(ContextRecord->SegFs); 00591 WaitStateChange->ControlReport.EFlags = ContextRecord->EFlags; 00592 WaitStateChange->ControlReport.ReportFlags = REPORT_INCLUDES_SEGS; 00593 00594 // 00595 // Copy context record into wait state change structure. 00596 // 00597 00598 KdpMoveMemory((PCHAR)(&WaitStateChange->Context), 00599 (PCHAR)ContextRecord, 00600 sizeof(CONTEXT)); 00601 00602 return; 00603 } 00604 00605 00606 VOID 00607 KdpSetStateChange( 00608 IN PDBGKD_WAIT_STATE_CHANGE64 WaitStateChange, 00609 IN PEXCEPTION_RECORD ExceptionRecord, 00610 IN PCONTEXT ContextRecord, 00611 IN BOOLEAN SecondChance 00612 ) 00613 00614 /*++ 00615 00616 Routine Description: 00617 00618 Fill in the Wait_State_Change message record. 00619 00620 Arguments: 00621 00622 WaitStateChange - Supplies pointer to record to fill in 00623 00624 ExceptionRecord - Supplies a pointer to an exception record. 00625 00626 ContextRecord - Supplies a pointer to a context record. 00627 00628 SecondChance - Supplies a boolean value that determines whether this is 00629 the first or second chance for the exception. 00630 00631 Return Value: 00632 00633 None. 00634 00635 --*/ 00636 00637 { 00638 PKPRCB Prcb; 00639 BOOLEAN status; 00640 00641 // 00642 // Set up description of event, including exception record 00643 // 00644 00645 WaitStateChange->NewState = DbgKdExceptionStateChange; 00646 WaitStateChange->ProcessorLevel = KeProcessorLevel; 00647 WaitStateChange->Processor = (USHORT)KeGetCurrentPrcb()->Number; 00648 WaitStateChange->NumberProcessors = (ULONG)KeNumberProcessors; 00649 WaitStateChange->Thread = (ULONG64)(LONG64)(LONG_PTR) KeGetCurrentThread(); 00650 WaitStateChange->ProgramCounter = (ULONG64)(LONG64)(LONG_PTR) CONTEXT_TO_PROGRAM_COUNTER(ContextRecord); 00651 if (sizeof(EXCEPTION_RECORD) == sizeof(WaitStateChange->u.Exception.ExceptionRecord)) { 00652 KdpQuickMoveMemory((PCHAR)&WaitStateChange->u.Exception.ExceptionRecord, 00653 (PCHAR)ExceptionRecord, 00654 sizeof(EXCEPTION_RECORD)); 00655 } else { 00656 ExceptionRecord32To64((PEXCEPTION_RECORD32)ExceptionRecord, 00657 &WaitStateChange->u.Exception.ExceptionRecord 00658 ); 00659 } 00660 WaitStateChange->u.Exception.FirstChance = !SecondChance; 00661 00662 // 00663 // Copy instruction stream immediately following location of event 00664 // 00665 00666 WaitStateChange->ControlReport.InstructionCount = 00667 (USHORT)KdpMoveMemory( 00668 (PCHAR)(&(WaitStateChange->ControlReport.InstructionStream[0])), 00669 (PCHAR)(WaitStateChange->ProgramCounter), 00670 DBGKD_MAXSTREAM 00671 ); 00672 00673 // 00674 // Copy context record immediately following instruction stream 00675 // 00676 00677 KdpMoveMemory( 00678 (PCHAR)(&WaitStateChange->Context), 00679 (PCHAR)ContextRecord, 00680 sizeof(*ContextRecord) 00681 ); 00682 00683 // 00684 // Clear breakpoints in copied area 00685 // 00686 00687 status = KdpDeleteBreakpointRange( 00688 (PVOID)WaitStateChange->ProgramCounter, 00689 (PVOID)((PUCHAR)WaitStateChange->ProgramCounter + 00690 WaitStateChange->ControlReport.InstructionCount - 1) 00691 ); 00692 00693 // 00694 // If there were any breakpoints cleared, recopy the area without them 00695 // 00696 00697 if (status == TRUE) { 00698 KdpMoveMemory( 00699 (PUCHAR) &(WaitStateChange->ControlReport.InstructionStream[0]), 00700 (PUCHAR) WaitStateChange->ProgramCounter, 00701 WaitStateChange->ControlReport.InstructionCount 00702 ); 00703 } 00704 00705 00706 // 00707 // Special registers for the x86 00708 // 00709 Prcb = KeGetCurrentPrcb(); 00710 00711 WaitStateChange->ControlReport.Dr6 = 00712 Prcb->ProcessorState.SpecialRegisters.KernelDr6; 00713 00714 WaitStateChange->ControlReport.Dr7 = 00715 Prcb->ProcessorState.SpecialRegisters.KernelDr7; 00716 00717 WaitStateChange->ControlReport.SegCs = (USHORT)(ContextRecord->SegCs); 00718 WaitStateChange->ControlReport.SegDs = (USHORT)(ContextRecord->SegDs); 00719 WaitStateChange->ControlReport.SegEs = (USHORT)(ContextRecord->SegEs); 00720 WaitStateChange->ControlReport.SegFs = (USHORT)(ContextRecord->SegFs); 00721 WaitStateChange->ControlReport.EFlags = ContextRecord->EFlags; 00722 00723 WaitStateChange->ControlReport.ReportFlags = REPORT_INCLUDES_SEGS; 00724 00725 } 00726 00727 VOID 00728 KdpGetStateChange( 00729 IN PDBGKD_MANIPULATE_STATE64 ManipulateState, 00730 IN PCONTEXT ContextRecord 00731 ) 00732 00733 /*++ 00734 00735 Routine Description: 00736 00737 Extract continuation control data from Manipulate_State message 00738 00739 Arguments: 00740 00741 ManipulateState - supplies pointer to Manipulate_State packet 00742 00743 ContextRecord - Supplies a pointer to a context record. 00744 00745 Return Value: 00746 00747 None. 00748 00749 --*/ 00750 00751 { 00752 PKPRCB Prcb; 00753 ULONG Processor; 00754 00755 if (NT_SUCCESS(ManipulateState->u.Continue2.ContinueStatus) == TRUE) { 00756 00757 // 00758 // If NT_SUCCESS returns TRUE, then the debugger is doing a 00759 // continue, and it makes sense to apply control changes. 00760 // Otherwise the debugger is saying that it doesn't know what 00761 // to do with this exception, so control values are ignored. 00762 // 00763 00764 if (ManipulateState->u.Continue2.ControlSet.TraceFlag == TRUE) { 00765 ContextRecord->EFlags |= 0x100L; 00766 00767 } else { 00768 ContextRecord->EFlags &= ~0x100L; 00769 00770 } 00771 00772 for (Processor = 0; Processor < (ULONG)KeNumberProcessors; Processor++) { 00773 Prcb = KiProcessorBlock[Processor]; 00774 00775 Prcb->ProcessorState.SpecialRegisters.KernelDr7 = 00776 ManipulateState->u.Continue2.ControlSet.Dr7; 00777 00778 Prcb->ProcessorState.SpecialRegisters.KernelDr6 = 0L; 00779 } 00780 if (ManipulateState->u.Continue2.ControlSet.CurrentSymbolStart != 1) { 00781 KdpCurrentSymbolStart = ManipulateState->u.Continue2.ControlSet.CurrentSymbolStart; 00782 KdpCurrentSymbolEnd = ManipulateState->u.Continue2.ControlSet.CurrentSymbolEnd; 00783 } 00784 } 00785 } 00786 00787 00788 VOID 00789 KdpReadControlSpace( 00790 IN PDBGKD_MANIPULATE_STATE64 m, 00791 IN PSTRING AdditionalData, 00792 IN PCONTEXT Context 00793 ) 00794 00795 /*++ 00796 00797 Routine Description: 00798 00799 This function is called in response of a read control space state 00800 manipulation message. Its function is to read implementation 00801 specific system data. 00802 00803 IMPLEMENTATION NOTE: 00804 00805 On the X86, control space is defined as follows: 00806 00807 0: Base of KPROCESSOR_STATE structure. (KPRCB.ProcessorState) 00808 This includes CONTEXT record, 00809 followed by a SPECIAL_REGISTERs record 00810 00811 Arguments: 00812 00813 m - Supplies the state manipulation message. 00814 00815 AdditionalData - Supplies any additional data for the message. 00816 00817 Context - Supplies the current context. 00818 00819 Return Value: 00820 00821 None. 00822 00823 --*/ 00824 00825 { 00826 PDBGKD_READ_MEMORY64 a = &m->u.ReadMemory; 00827 STRING MessageHeader; 00828 ULONG Length, t; 00829 PVOID StartAddr; 00830 00831 MessageHeader.Length = sizeof(*m); 00832 MessageHeader.Buffer = (PCHAR)m; 00833 00834 ASSERT(AdditionalData->Length == 0); 00835 00836 if (a->TransferCount > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64))) { 00837 Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64); 00838 } else { 00839 Length = a->TransferCount; 00840 } 00841 if ((a->TargetBaseAddress < (ULONG64)(sizeof(KPROCESSOR_STATE))) && 00842 (m->Processor < (USHORT)KeNumberProcessors)) { 00843 t = (ULONG)(sizeof(KPROCESSOR_STATE)) - (ULONG)(a->TargetBaseAddress); 00844 if (t < Length) { 00845 Length = t; 00846 } 00847 StartAddr = (PVOID)((ULONG)a->TargetBaseAddress + 00848 (ULONG)&(KiProcessorBlock[m->Processor]->ProcessorState)); 00849 AdditionalData->Length = (USHORT)KdpMoveMemory( 00850 AdditionalData->Buffer, 00851 StartAddr, 00852 Length 00853 ); 00854 00855 if (Length == AdditionalData->Length) { 00856 m->ReturnStatus = STATUS_SUCCESS; 00857 } else { 00858 m->ReturnStatus = STATUS_UNSUCCESSFUL; 00859 } 00860 a->ActualBytesRead = AdditionalData->Length; 00861 00862 } else { 00863 AdditionalData->Length = 0; 00864 m->ReturnStatus = STATUS_UNSUCCESSFUL; 00865 a->ActualBytesRead = 0; 00866 } 00867 00868 KdpSendPacket( 00869 PACKET_TYPE_KD_STATE_MANIPULATE, 00870 &MessageHeader, 00871 AdditionalData 00872 ); 00873 UNREFERENCED_PARAMETER(Context); 00874 } 00875 00876 VOID 00877 KdpWriteControlSpace( 00878 IN PDBGKD_MANIPULATE_STATE64 m, 00879 IN PSTRING AdditionalData, 00880 IN PCONTEXT Context 00881 ) 00882 00883 /*++ 00884 00885 Routine Description: 00886 00887 This function is called in response of a write control space state 00888 manipulation message. Its function is to write implementation 00889 specific system data. 00890 00891 Control space for x86 is as defined above. 00892 00893 Arguments: 00894 00895 m - Supplies the state manipulation message. 00896 00897 AdditionalData - Supplies any additional data for the message. 00898 00899 Context - Supplies the current context. 00900 00901 Return Value: 00902 00903 None. 00904 00905 --*/ 00906 00907 { 00908 PDBGKD_WRITE_MEMORY64 a = &m->u.WriteMemory; 00909 ULONG Length; 00910 STRING MessageHeader; 00911 PVOID StartAddr; 00912 00913 MessageHeader.Length = sizeof(*m); 00914 MessageHeader.Buffer = (PCHAR)m; 00915 00916 if ((((PUCHAR)a->TargetBaseAddress + a->TransferCount) <= 00917 (PUCHAR)(sizeof(KPROCESSOR_STATE))) && (m->Processor < (USHORT)KeNumberProcessors)) { 00918 00919 StartAddr = (PVOID)((ULONG)a->TargetBaseAddress + 00920 (ULONG)&(KiProcessorBlock[m->Processor]->ProcessorState)); 00921 00922 Length = KdpMoveMemory( 00923 StartAddr, 00924 AdditionalData->Buffer, 00925 AdditionalData->Length 00926 ); 00927 00928 if (Length == AdditionalData->Length) { 00929 m->ReturnStatus = STATUS_SUCCESS; 00930 } else { 00931 m->ReturnStatus = STATUS_UNSUCCESSFUL; 00932 } 00933 a->ActualBytesWritten = Length; 00934 00935 } else { 00936 AdditionalData->Length = 0; 00937 m->ReturnStatus = STATUS_UNSUCCESSFUL; 00938 a->ActualBytesWritten = 0; 00939 } 00940 00941 KdpSendPacket( 00942 PACKET_TYPE_KD_STATE_MANIPULATE, 00943 &MessageHeader, 00944 AdditionalData 00945 ); 00946 UNREFERENCED_PARAMETER(Context); 00947 } 00948 00949 VOID 00950 KdpReadIoSpace( 00951 IN PDBGKD_MANIPULATE_STATE64 m, 00952 IN PSTRING AdditionalData, 00953 IN PCONTEXT Context 00954 ) 00955 00956 /*++ 00957 00958 Routine Description: 00959 00960 This function is called in response of a read io space state 00961 manipulation message. Its function is to read system io 00962 locations. 00963 00964 Arguments: 00965 00966 m - Supplies the state manipulation message. 00967 00968 AdditionalData - Supplies any additional data for the message. 00969 00970 Context - Supplies the current context. 00971 00972 Return Value: 00973 00974 None. 00975 00976 --*/ 00977 00978 { 00979 PDBGKD_READ_WRITE_IO64 a = &m->u.ReadWriteIo; 00980 STRING MessageHeader; 00981 00982 MessageHeader.Length = sizeof(*m); 00983 MessageHeader.Buffer = (PCHAR)m; 00984 00985 ASSERT(AdditionalData->Length == 0); 00986 00987 m->ReturnStatus = STATUS_SUCCESS; 00988 00989 // 00990 // Check Size and Alignment 00991 // 00992 00993 switch ( a->DataSize ) { 00994 case 1: 00995 a->DataValue = (ULONG)READ_PORT_UCHAR((PUCHAR)a->IoAddress); 00996 break; 00997 case 2: 00998 if ((ULONG)a->IoAddress & 1 ) { 00999 m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT; 01000 } else { 01001 a->DataValue = (ULONG)READ_PORT_USHORT((PUSHORT)a->IoAddress); 01002 } 01003 break; 01004 case 4: 01005 if ((ULONG)a->IoAddress & 3 ) { 01006 m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT; 01007 } else { 01008 a->DataValue = READ_PORT_ULONG((PULONG)a->IoAddress); 01009 } 01010 break; 01011 default: 01012 m->ReturnStatus = STATUS_INVALID_PARAMETER; 01013 } 01014 01015 KdpSendPacket( 01016 PACKET_TYPE_KD_STATE_MANIPULATE, 01017 &MessageHeader, 01018 NULL 01019 ); 01020 UNREFERENCED_PARAMETER(Context); 01021 } 01022 01023 VOID 01024 KdpWriteIoSpace( 01025 IN PDBGKD_MANIPULATE_STATE64 m, 01026 IN PSTRING AdditionalData, 01027 IN PCONTEXT Context 01028 ) 01029 01030 /*++ 01031 01032 Routine Description: 01033 01034 This function is called in response of a write io space state 01035 manipulation message. Its function is to write to system io 01036 locations. 01037 01038 Arguments: 01039 01040 m - Supplies the state manipulation message. 01041 01042 AdditionalData - Supplies any additional data for the message. 01043 01044 Context - Supplies the current context. 01045 01046 Return Value: 01047 01048 None. 01049 01050 --*/ 01051 01052 { 01053 PDBGKD_READ_WRITE_IO64 a = &m->u.ReadWriteIo; 01054 STRING MessageHeader; 01055 01056 MessageHeader.Length = sizeof(*m); 01057 MessageHeader.Buffer = (PCHAR)m; 01058 01059 ASSERT(AdditionalData->Length == 0); 01060 01061 m->ReturnStatus = STATUS_SUCCESS; 01062 01063 // 01064 // Check Size and Alignment 01065 // 01066 01067 switch ( a->DataSize ) { 01068 case 1: 01069 WRITE_PORT_UCHAR((PUCHAR)a->IoAddress, (UCHAR)a->DataValue); 01070 break; 01071 case 2: 01072 if ((ULONG)a->IoAddress & 1 ) { 01073 m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT; 01074 } else { 01075 WRITE_PORT_USHORT((PUSHORT)a->IoAddress, (USHORT)a->DataValue); 01076 } 01077 break; 01078 case 4: 01079 if ((ULONG)a->IoAddress & 3 ) { 01080 m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT; 01081 } else { 01082 WRITE_PORT_ULONG((PULONG)a->IoAddress, a->DataValue); 01083 } 01084 break; 01085 default: 01086 m->ReturnStatus = STATUS_INVALID_PARAMETER; 01087 } 01088 01089 KdpSendPacket( 01090 PACKET_TYPE_KD_STATE_MANIPULATE, 01091 &MessageHeader, 01092 NULL 01093 ); 01094 UNREFERENCED_PARAMETER(Context); 01095 } 01096 01097 VOID 01098 KdpReadMachineSpecificRegister( 01099 IN PDBGKD_MANIPULATE_STATE64 m, 01100 IN PSTRING AdditionalData, 01101 IN PCONTEXT Context 01102 ) 01103 01104 /*++ 01105 01106 Routine Description: 01107 01108 This function is called in response of a read MSR 01109 manipulation message. Its function is to read the MSR. 01110 01111 Arguments: 01112 01113 m - Supplies the state manipulation message. 01114 01115 AdditionalData - Supplies any additional data for the message. 01116 01117 Context - Supplies the current context. 01118 01119 Return Value: 01120 01121 None. 01122 01123 --*/ 01124 01125 { 01126 PDBGKD_READ_WRITE_MSR a = &m->u.ReadWriteMsr; 01127 STRING MessageHeader; 01128 LARGE_INTEGER l; 01129 01130 MessageHeader.Length = sizeof(*m); 01131 MessageHeader.Buffer = (PCHAR)m; 01132 01133 ASSERT(AdditionalData->Length == 0); 01134 01135 m->ReturnStatus = STATUS_SUCCESS; 01136 01137 try { 01138 l.QuadPart = RDMSR(a->Msr); 01139 } except (EXCEPTION_EXECUTE_HANDLER) { 01140 l.QuadPart = 0; 01141 m->ReturnStatus = STATUS_NO_SUCH_DEVICE; 01142 } 01143 01144 a->DataValueLow = l.LowPart; 01145 a->DataValueHigh = l.HighPart; 01146 01147 KdpSendPacket( 01148 PACKET_TYPE_KD_STATE_MANIPULATE, 01149 &MessageHeader, 01150 NULL 01151 ); 01152 UNREFERENCED_PARAMETER(Context); 01153 } 01154 01155 VOID 01156 KdpWriteMachineSpecificRegister( 01157 IN PDBGKD_MANIPULATE_STATE64 m, 01158 IN PSTRING AdditionalData, 01159 IN PCONTEXT Context 01160 ) 01161 01162 /*++ 01163 01164 Routine Description: 01165 01166 This function is called in response of a write of a MSR 01167 manipulation message. Its function is to write to the MSR 01168 01169 Arguments: 01170 01171 m - Supplies the state manipulation message. 01172 01173 AdditionalData - Supplies any additional data for the message. 01174 01175 Context - Supplies the current context. 01176 01177 Return Value: 01178 01179 None. 01180 01181 --*/ 01182 01183 { 01184 PDBGKD_READ_WRITE_MSR a = &m->u.ReadWriteMsr; 01185 STRING MessageHeader; 01186 LARGE_INTEGER l; 01187 01188 MessageHeader.Length = sizeof(*m); 01189 MessageHeader.Buffer = (PCHAR)m; 01190 01191 ASSERT(AdditionalData->Length == 0); 01192 01193 m->ReturnStatus = STATUS_SUCCESS; 01194 01195 l.HighPart = a->DataValueHigh; 01196 l.LowPart = a->DataValueLow; 01197 01198 try { 01199 WRMSR (a->Msr, l.QuadPart); 01200 } except (EXCEPTION_EXECUTE_HANDLER) { 01201 m->ReturnStatus = STATUS_NO_SUCH_DEVICE; 01202 } 01203 01204 KdpSendPacket( 01205 PACKET_TYPE_KD_STATE_MANIPULATE, 01206 &MessageHeader, 01207 NULL 01208 ); 01209 UNREFERENCED_PARAMETER(Context); 01210 } 01211 01212 /*** KdpGetCallNextOffset - compute "next" instruction on a call-like instruction 01213 * 01214 * Purpose: 01215 * Compute how many bytes are in a call-type instruction 01216 * so that a breakpoint can be set upon this instruction's 01217 * return. Treat indirect jmps as if they were call/ret/ret 01218 * 01219 * Returns: 01220 * offset to "next" instruction, or 0 if it wasn't a call instruction. 01221 * 01222 *************************************************************************/ 01223 01224 ULONG 01225 KdpGetCallNextOffset ( 01226 ULONG Pc, 01227 PCONTEXT ContextRecord 01228 ) 01229 { 01230 UCHAR membuf[2]; 01231 UCHAR opcode; 01232 ULONG sib; 01233 ULONG disp; 01234 01235 KdpMoveMemory( membuf, (PVOID)Pc, 2 ); 01236 opcode = membuf[0]; 01237 01238 if ( opcode == 0xe8 ) { // CALL 32 bit disp 01239 return Pc+5; 01240 } else if ( opcode == 0x9a ) { // CALL 16:32 01241 return Pc+7; 01242 } else if ( opcode == 0xff ) { 01243 if ( membuf[1] == 0x25) { // JMP indirect 01244 return KdpGetReturnAddress( ContextRecord ); 01245 } 01246 sib = ((membuf[1] & 0x07) == 0x04) ? 1 : 0; 01247 disp = (membuf[1] & 0xc0) >> 6; 01248 switch (disp) { 01249 case 0: 01250 if ( (membuf[1] & 0x07) == 0x05 ) { 01251 disp = 4; // disp32 alone 01252 } else { 01253 // disp = 0; // no displacement with reg or sib 01254 } 01255 break; 01256 case 1: 01257 // disp = 1; // disp8 with reg or sib 01258 break; 01259 case 2: 01260 disp = 4; // disp32 with reg or sib 01261 break; 01262 case 3: 01263 disp = 0; // direct register addressing (e.g., call esi) 01264 break; 01265 } 01266 return Pc + 2 + sib + disp; 01267 } 01268 01269 return 0; 01270 01271 } // KdpGetCallNextOffset

Generated on Sat May 15 19:40:34 2004 for test by doxygen 1.3.7