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 (sizeof(KPROCESSOR_STATE)) 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 return 0; // Bash compiler warning 00329 } 00330 00331 BOOLEAN 00332 KdpIsSpecialCall ( 00333 ULONG Pc, 00334 PCONTEXT ContextRecord, 00335 UCHAR opcode, 00336 UCHAR modRM 00337 ) 00338 00339 /*++ 00340 00341 Routine Description: 00342 00343 Check to see if the instruction at pc is a call to one of the 00344 SpecialCall routines. 00345 00346 Argument: 00347 00348 Pc - program counter of instruction in question. 00349 00350 --*/ 00351 { 00352 UCHAR sib; 00353 USHORT twoBytes; 00354 ULONG callAddr; 00355 ULONG addrAddr; 00356 LONG offset; 00357 ULONG i; 00358 char d8; 00359 00360 if ( opcode == 0xe8 ) { 00361 00362 // 00363 // Signed offset from pc 00364 // 00365 00366 KdpMoveMemory( (PCHAR)&offset, (PCHAR)Pc+1, 4 ); 00367 00368 callAddr = Pc + offset + 5; // +5 for instr len. 00369 00370 } else if ( opcode == 0xff ) { 00371 00372 if ( ((modRM & 0x38) != 0x10) && ((modRM & 0x38) != 0x20) ) { 00373 // not call or jump 00374 return FALSE; 00375 } 00376 if ( (modRM & 0x08) == 0x08 ) { 00377 // m16:16 or m16:32 -- we don't handle this 00378 return FALSE; 00379 } 00380 00381 if ( (modRM & 0xc0) == 0xc0 ) { 00382 00383 /* Direct register addressing */ 00384 callAddr = regValue( (UCHAR)(modRM&0x7), ContextRecord ); 00385 00386 } else if ( (modRM & 0xc7) == 0x05 ) { 00387 // 00388 // Calls across dll boundaries involve a call into a jump table, 00389 // wherein the jump address is set to the real called routine at DLL 00390 // load time. Check to see if we're calling such an instruction, 00391 // and if so, compute its target address and set callAddr there. 00392 // 00393 // ff15 or ff25 -- call or jump indirect with disp32. Get 00394 // address of address 00395 // 00396 KdpMoveMemory( (PCHAR)&addrAddr, (PCHAR)Pc+2, 4 ); 00397 00398 // 00399 // Get real destination address 00400 // 00401 KdpMoveMemory( (PCHAR)&callAddr, (PCHAR)addrAddr, 4 ); 00402 // DPRINT(( "Indirect call/jmp @ %x\n", Pc )); 00403 } else if ( (modRM & 0x7) == 0x4 ) { 00404 00405 LONG indexValue; 00406 00407 /* sib byte present */ 00408 KdpMoveMemory( (PCHAR)&sib, (PCHAR)Pc+2, 1 ); 00409 indexValue = regValue( (UCHAR)((sib & 0x31) >> 3), ContextRecord ); 00410 switch ( sib&0xc0 ) { 00411 case 0x0: /* x1 */ 00412 break; 00413 case 0x40: 00414 indexValue *= 2; 00415 break; 00416 case 0x80: 00417 indexValue *= 4; 00418 break; 00419 case 0xc0: 00420 indexValue *= 8; 00421 break; 00422 } /* switch */ 00423 00424 switch ( modRM & 0xc0 ) { 00425 00426 case 0x0: /* no displacement */ 00427 if ( (sib & 0x7) == 0x5 ) { 00428 // DPRINT(("funny call #1 at %x\n", Pc)); 00429 return FALSE; 00430 } 00431 callAddr = indexValue + regValue((UCHAR)(sib&0x7), ContextRecord ); 00432 break; 00433 00434 case 0x40: 00435 if ( (sib & 0x6) == 0x4 ) { 00436 // DPRINT(("Funny call #2\n")); /* calling into the stack */ 00437 return FALSE; 00438 } 00439 KdpMoveMemory( &d8, (PCHAR)Pc+3,1 ); 00440 callAddr = indexValue + d8 + 00441 regValue((UCHAR)(sib&0x7), ContextRecord ); 00442 break; 00443 00444 case 0x80: 00445 if ( (sib & 0x6) == 0x4 ) { 00446 // DPRINT(("Funny call #3\n")); /* calling into the stack */ 00447 return FALSE; 00448 } 00449 KdpMoveMemory( (PCHAR)&offset, (PCHAR)Pc+3, 4 ); 00450 callAddr = indexValue + offset + 00451 regValue((UCHAR)(sib&0x7), ContextRecord ); 00452 break; 00453 00454 case 0xc0: 00455 ASSERT( FALSE ); 00456 break; 00457 00458 } 00459 00460 } else { 00461 //KdPrint(( "undecoded call at %x\n", 00462 // CONTEXT_TO_PROGRAM_COUNTER(ContextRecord) )); 00463 return FALSE; 00464 } 00465 00466 } else if ( opcode == 0x9a ) { 00467 00468 /* Absolute address call (best I can tell, cc doesn't generate this) */ 00469 KdpMoveMemory( (PCHAR)&callAddr, (PCHAR)Pc+1, 4 ); 00470 00471 } else { 00472 return FALSE; 00473 } 00474 00475 // 00476 // Calls across dll boundaries involve a call into a jump table, 00477 // wherein the jump address is set to the real called routine at DLL 00478 // load time. Check to see if we're calling such an instruction, 00479 // and if so, compute its target address and set callAddr there. 00480 // 00481 00482 #if 0 00483 KdpMoveMemory( (PCHAR)&twoBytes, (PCHAR)callAddr, 2 ); 00484 if ( twoBytes == 0x25ff ) { /* i386 is little-Endian; really 0xff25 */ 00485 00486 // 00487 // This is a 'jmp dword ptr [mem]' instruction, which is the sort of 00488 // jump used for a dll-boundary crossing call. Fixup callAddr. 00489 // 00490 00491 KdpMoveMemory( (PCHAR)&addrAddr, (PCHAR)callAddr+2, 4 ); 00492 KdpMoveMemory( (PCHAR)&callAddr, (PCHAR)addrAddr, 4 ); 00493 } 00494 #endif 00495 00496 for ( i = 0; i < KdNumberOfSpecialCalls; i++ ) { 00497 if ( KdSpecialCalls[i] == callAddr ) { 00498 return TRUE; 00499 } 00500 } 00501 return FALSE; 00502 00503 } 00504 00505 /* 00506 * Find the return address of the current function. Only works when 00507 * locals haven't yet been pushed (ie, on the first instruction of the 00508 * function). 00509 */ 00510 00511 ULONG 00512 KdpGetReturnAddress ( 00513 PCONTEXT ContextRecord 00514 ) 00515 { 00516 ULONG retaddr; 00517 00518 KdpMoveMemory((PCHAR)(&retaddr), (PCHAR)(ContextRecord->Esp), 4 ); 00519 return retaddr; 00520 00521 } // KdpGetReturnAddress 00522 00523 VOID 00524 KdpSetLoadState( 00525 IN PDBGKD_WAIT_STATE_CHANGE WaitStateChange, 00526 IN PCONTEXT ContextRecord 00527 ) 00528 00529 /*++ 00530 00531 Routine Description: 00532 00533 Fill in the Wait_State_Change message record for the load symbol case. 00534 00535 Arguments: 00536 00537 WaitStateChange - Supplies pointer to record to fill in 00538 00539 ContextRecord - Supplies a pointer to a context record. 00540 00541 Return Value: 00542 00543 None. 00544 00545 --*/ 00546 00547 { 00548 00549 ULONG Count; 00550 PVOID End; 00551 PKPRCB Prcb; 00552 00553 // 00554 // Store the special x86 register into the control report structure. 00555 // 00556 00557 Prcb = KeGetCurrentPrcb(); 00558 WaitStateChange->ControlReport.Dr6 = Prcb->ProcessorState.SpecialRegisters.KernelDr6; 00559 WaitStateChange->ControlReport.Dr7 = Prcb->ProcessorState.SpecialRegisters.KernelDr7; 00560 00561 // 00562 // Copy the immediate instruction stream into the control report structure. 00563 // 00564 00565 Count = KdpMoveMemory((PCHAR)(&(WaitStateChange->ControlReport.InstructionStream[0])), 00566 (PCHAR)(WaitStateChange->ProgramCounter), 00567 DBGKD_MAXSTREAM); 00568 00569 WaitStateChange->ControlReport.InstructionCount = (USHORT)Count; 00570 00571 // 00572 // Clear breakpoints in the copied instruction stream. If any breakpoints 00573 // are cleared, then recopy the instruction stream. 00574 // 00575 00576 End = (PVOID)((PUCHAR)(WaitStateChange->ProgramCounter) + Count - 1); 00577 if (KdpDeleteBreakpointRange(WaitStateChange->ProgramCounter, End) != FALSE) { 00578 KdpMoveMemory(&(WaitStateChange->ControlReport.InstructionStream[0]), 00579 WaitStateChange->ProgramCounter, 00580 Count); 00581 } 00582 00583 // 00584 // Store the segment registers into the control report structure and set the 00585 // control flags. 00586 // 00587 00588 WaitStateChange->ControlReport.SegCs = (USHORT)(ContextRecord->SegCs); 00589 WaitStateChange->ControlReport.SegDs = (USHORT)(ContextRecord->SegDs); 00590 WaitStateChange->ControlReport.SegEs = (USHORT)(ContextRecord->SegEs); 00591 WaitStateChange->ControlReport.SegFs = (USHORT)(ContextRecord->SegFs); 00592 WaitStateChange->ControlReport.EFlags = ContextRecord->EFlags; 00593 WaitStateChange->ControlReport.ReportFlags = REPORT_INCLUDES_SEGS; 00594 00595 // 00596 // Copy context record into wait state change structure. 00597 // 00598 00599 KdpMoveMemory((PCHAR)(&WaitStateChange->Context), 00600 (PCHAR)ContextRecord, 00601 sizeof(CONTEXT)); 00602 00603 return; 00604 } 00605 00606 00607 VOID 00608 KdpSetStateChange( 00609 IN PDBGKD_WAIT_STATE_CHANGE WaitStateChange, 00610 IN PEXCEPTION_RECORD ExceptionRecord, 00611 IN PCONTEXT ContextRecord, 00612 IN BOOLEAN SecondChance 00613 ) 00614 00615 /*++ 00616 00617 Routine Description: 00618 00619 Fill in the Wait_State_Change message record. 00620 00621 Arguments: 00622 00623 WaitStateChange - Supplies pointer to record to fill in 00624 00625 ExceptionRecord - Supplies a pointer to an exception record. 00626 00627 ContextRecord - Supplies a pointer to a context record. 00628 00629 SecondChance - Supplies a boolean value that determines whether this is 00630 the first or second chance for the exception. 00631 00632 Return Value: 00633 00634 None. 00635 00636 --*/ 00637 00638 { 00639 PKPRCB Prcb; 00640 BOOLEAN status; 00641 00642 // 00643 // Set up description of event, including exception record 00644 // 00645 00646 WaitStateChange->NewState = DbgKdExceptionStateChange; 00647 WaitStateChange->ProcessorLevel = KeProcessorLevel; 00648 WaitStateChange->Processor = (USHORT)KeGetCurrentPrcb()->Number; 00649 WaitStateChange->NumberProcessors = (ULONG)KeNumberProcessors; 00650 WaitStateChange->Thread = (PVOID)KeGetCurrentThread(); 00651 WaitStateChange->ProgramCounter = (PVOID)CONTEXT_TO_PROGRAM_COUNTER(ContextRecord); 00652 KdpQuickMoveMemory( 00653 (PCHAR)&WaitStateChange->u.Exception.ExceptionRecord, 00654 (PCHAR)ExceptionRecord, 00655 sizeof(EXCEPTION_RECORD) 00656 ); 00657 WaitStateChange->u.Exception.FirstChance = !SecondChance; 00658 00659 // 00660 // Copy instruction stream immediately following location of event 00661 // 00662 00663 WaitStateChange->ControlReport.InstructionCount = 00664 (USHORT)KdpMoveMemory( 00665 (PCHAR)(&(WaitStateChange->ControlReport.InstructionStream[0])), 00666 (PCHAR)(WaitStateChange->ProgramCounter), 00667 DBGKD_MAXSTREAM 00668 ); 00669 00670 // 00671 // Copy context record immediately following instruction stream 00672 // 00673 00674 KdpMoveMemory( 00675 (PCHAR)(&WaitStateChange->Context), 00676 (PCHAR)ContextRecord, 00677 sizeof(*ContextRecord) 00678 ); 00679 00680 // 00681 // Clear breakpoints in copied area 00682 // 00683 00684 status = KdpDeleteBreakpointRange( 00685 WaitStateChange->ProgramCounter, 00686 (PVOID)((PUCHAR)WaitStateChange->ProgramCounter + 00687 WaitStateChange->ControlReport.InstructionCount - 1) 00688 ); 00689 00690 // 00691 // If there were any breakpoints cleared, recopy the area without them 00692 // 00693 00694 if (status == TRUE) { 00695 KdpMoveMemory( 00696 &(WaitStateChange->ControlReport.InstructionStream[0]), 00697 WaitStateChange->ProgramCounter, 00698 WaitStateChange->ControlReport.InstructionCount 00699 ); 00700 } 00701 00702 00703 // 00704 // Special registers for the x86 00705 // 00706 Prcb = KeGetCurrentPrcb(); 00707 00708 WaitStateChange->ControlReport.Dr6 = 00709 Prcb->ProcessorState.SpecialRegisters.KernelDr6; 00710 00711 WaitStateChange->ControlReport.Dr7 = 00712 Prcb->ProcessorState.SpecialRegisters.KernelDr7; 00713 00714 WaitStateChange->ControlReport.SegCs = (USHORT)(ContextRecord->SegCs); 00715 WaitStateChange->ControlReport.SegDs = (USHORT)(ContextRecord->SegDs); 00716 WaitStateChange->ControlReport.SegEs = (USHORT)(ContextRecord->SegEs); 00717 WaitStateChange->ControlReport.SegFs = (USHORT)(ContextRecord->SegFs); 00718 WaitStateChange->ControlReport.EFlags = ContextRecord->EFlags; 00719 00720 WaitStateChange->ControlReport.ReportFlags = REPORT_INCLUDES_SEGS; 00721 00722 } 00723 00724 VOID 00725 KdpGetStateChange( 00726 IN PDBGKD_MANIPULATE_STATE ManipulateState, 00727 IN PCONTEXT ContextRecord 00728 ) 00729 00730 /*++ 00731 00732 Routine Description: 00733 00734 Extract continuation control data from Manipulate_State message 00735 00736 Arguments: 00737 00738 ManipulateState - supplies pointer to Manipulate_State packet 00739 00740 ContextRecord - Supplies a pointer to a context record. 00741 00742 Return Value: 00743 00744 None. 00745 00746 --*/ 00747 00748 { 00749 PKPRCB Prcb; 00750 ULONG Processor; 00751 00752 if (NT_SUCCESS(ManipulateState->u.Continue2.ContinueStatus) == TRUE) { 00753 00754 // 00755 // If NT_SUCCESS returns TRUE, then the debugger is doing a 00756 // continue, and it makes sense to apply control changes. 00757 // Otherwise the debugger is saying that it doesn't know what 00758 // to do with this exception, so control values are ignored. 00759 // 00760 00761 if (ManipulateState->u.Continue2.ControlSet.TraceFlag == TRUE) { 00762 ContextRecord->EFlags |= 0x100L; 00763 00764 } else { 00765 ContextRecord->EFlags &= ~0x100L; 00766 00767 } 00768 00769 for (Processor = 0; Processor < (ULONG)KeNumberProcessors; Processor++) { 00770 Prcb = KiProcessorBlock[Processor]; 00771 00772 Prcb->ProcessorState.SpecialRegisters.KernelDr7 = 00773 ManipulateState->u.Continue2.ControlSet.Dr7; 00774 00775 Prcb->ProcessorState.SpecialRegisters.KernelDr6 = 0L; 00776 } 00777 if (ManipulateState->u.Continue2.ControlSet.CurrentSymbolStart != 1) { 00778 KdpCurrentSymbolStart = ManipulateState->u.Continue2.ControlSet.CurrentSymbolStart; 00779 KdpCurrentSymbolEnd = ManipulateState->u.Continue2.ControlSet.CurrentSymbolEnd; 00780 } 00781 } 00782 } 00783 00784 00785 VOID 00786 KdpReadControlSpace( 00787 IN PDBGKD_MANIPULATE_STATE m, 00788 IN PSTRING AdditionalData, 00789 IN PCONTEXT Context 00790 ) 00791 00792 /*++ 00793 00794 Routine Description: 00795 00796 This function is called in response of a read control space state 00797 manipulation message. Its function is to read implementation 00798 specific system data. 00799 00800 IMPLEMENTATION NOTE: 00801 00802 On the X86, control space is defined as follows: 00803 00804 0: Base of KPROCESSOR_STATE structure. (KPRCB.ProcessorState) 00805 This includes CONTEXT record, 00806 followed by a SPECIAL_REGISTERs record 00807 00808 Arguments: 00809 00810 m - Supplies the state manipulation message. 00811 00812 AdditionalData - Supplies any additional data for the message. 00813 00814 Context - Supplies the current context. 00815 00816 Return Value: 00817 00818 None. 00819 00820 --*/ 00821 00822 { 00823 PDBGKD_READ_MEMORY a = &m->u.ReadMemory; 00824 STRING MessageHeader; 00825 ULONG Length, t; 00826 PVOID StartAddr; 00827 00828 MessageHeader.Length = sizeof(*m); 00829 MessageHeader.Buffer = (PCHAR)m; 00830 00831 ASSERT(AdditionalData->Length == 0); 00832 00833 if (a->TransferCount > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE))) { 00834 Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE); 00835 } else { 00836 Length = a->TransferCount; 00837 } 00838 if ((a->TargetBaseAddress < (PVOID)END_OF_CONTROL_SPACE) && 00839 (m->Processor < (USHORT)KeNumberProcessors)) { 00840 t = (ULONG)END_OF_CONTROL_SPACE - (ULONG)(a->TargetBaseAddress); 00841 if (t < Length) { 00842 Length = t; 00843 } 00844 StartAddr = (PVOID)((ULONG)a->TargetBaseAddress + 00845 (ULONG)&(KiProcessorBlock[m->Processor]->ProcessorState)); 00846 AdditionalData->Length = (USHORT)KdpMoveMemory( 00847 AdditionalData->Buffer, 00848 StartAddr, 00849 Length 00850 ); 00851 00852 if (Length == AdditionalData->Length) { 00853 m->ReturnStatus = STATUS_SUCCESS; 00854 } else { 00855 m->ReturnStatus = STATUS_UNSUCCESSFUL; 00856 } 00857 a->ActualBytesRead = AdditionalData->Length; 00858 00859 } else { 00860 AdditionalData->Length = 0; 00861 m->ReturnStatus = STATUS_UNSUCCESSFUL; 00862 a->ActualBytesRead = 0; 00863 } 00864 00865 KdpSendPacket( 00866 PACKET_TYPE_KD_STATE_MANIPULATE, 00867 &MessageHeader, 00868 AdditionalData 00869 ); 00870 UNREFERENCED_PARAMETER(Context); 00871 } 00872 00873 VOID 00874 KdpWriteControlSpace( 00875 IN PDBGKD_MANIPULATE_STATE m, 00876 IN PSTRING AdditionalData, 00877 IN PCONTEXT Context 00878 ) 00879 00880 /*++ 00881 00882 Routine Description: 00883 00884 This function is called in response of a write control space state 00885 manipulation message. Its function is to write implementation 00886 specific system data. 00887 00888 Control space for x86 is as defined above. 00889 00890 Arguments: 00891 00892 m - Supplies the state manipulation message. 00893 00894 AdditionalData - Supplies any additional data for the message. 00895 00896 Context - Supplies the current context. 00897 00898 Return Value: 00899 00900 None. 00901 00902 --*/ 00903 00904 { 00905 PDBGKD_WRITE_MEMORY a = &m->u.WriteMemory; 00906 ULONG Length; 00907 STRING MessageHeader; 00908 PVOID StartAddr; 00909 00910 MessageHeader.Length = sizeof(*m); 00911 MessageHeader.Buffer = (PCHAR)m; 00912 00913 if ((((PUCHAR)a->TargetBaseAddress + a->TransferCount) <= 00914 (PUCHAR)END_OF_CONTROL_SPACE) && (m->Processor < (USHORT)KeNumberProcessors)) { 00915 00916 StartAddr = (PVOID)((ULONG)a->TargetBaseAddress + 00917 (ULONG)&(KiProcessorBlock[m->Processor]->ProcessorState)); 00918 00919 Length = KdpMoveMemory( 00920 StartAddr, 00921 AdditionalData->Buffer, 00922 AdditionalData->Length 00923 ); 00924 00925 if (Length == AdditionalData->Length) { 00926 m->ReturnStatus = STATUS_SUCCESS; 00927 } else { 00928 m->ReturnStatus = STATUS_UNSUCCESSFUL; 00929 } 00930 a->ActualBytesWritten = Length; 00931 00932 } else { 00933 AdditionalData->Length = 0; 00934 m->ReturnStatus = STATUS_UNSUCCESSFUL; 00935 a->ActualBytesWritten = 0; 00936 } 00937 00938 KdpSendPacket( 00939 PACKET_TYPE_KD_STATE_MANIPULATE, 00940 &MessageHeader, 00941 AdditionalData 00942 ); 00943 UNREFERENCED_PARAMETER(Context); 00944 } 00945 00946 VOID 00947 KdpReadIoSpace( 00948 IN PDBGKD_MANIPULATE_STATE m, 00949 IN PSTRING AdditionalData, 00950 IN PCONTEXT Context 00951 ) 00952 00953 /*++ 00954 00955 Routine Description: 00956 00957 This function is called in response of a read io space state 00958 manipulation message. Its function is to read system io 00959 locations. 00960 00961 Arguments: 00962 00963 m - Supplies the state manipulation message. 00964 00965 AdditionalData - Supplies any additional data for the message. 00966 00967 Context - Supplies the current context. 00968 00969 Return Value: 00970 00971 None. 00972 00973 --*/ 00974 00975 { 00976 PDBGKD_READ_WRITE_IO a = &m->u.ReadWriteIo; 00977 STRING MessageHeader; 00978 00979 MessageHeader.Length = sizeof(*m); 00980 MessageHeader.Buffer = (PCHAR)m; 00981 00982 ASSERT(AdditionalData->Length == 0); 00983 00984 m->ReturnStatus = STATUS_SUCCESS; 00985 00986 // 00987 // Check Size and Alignment 00988 // 00989 00990 switch ( a->DataSize ) { 00991 case 1: 00992 a->DataValue = (ULONG)READ_PORT_UCHAR(a->IoAddress); 00993 break; 00994 case 2: 00995 if ((ULONG)a->IoAddress & 1 ) { 00996 m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT; 00997 } else { 00998 a->DataValue = (ULONG)READ_PORT_USHORT(a->IoAddress); 00999 } 01000 break; 01001 case 4: 01002 if ((ULONG)a->IoAddress & 3 ) { 01003 m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT; 01004 } else { 01005 a->DataValue = READ_PORT_ULONG(a->IoAddress); 01006 } 01007 break; 01008 default: 01009 m->ReturnStatus = STATUS_INVALID_PARAMETER; 01010 } 01011 01012 KdpSendPacket( 01013 PACKET_TYPE_KD_STATE_MANIPULATE, 01014 &MessageHeader, 01015 NULL 01016 ); 01017 UNREFERENCED_PARAMETER(Context); 01018 } 01019 01020 VOID 01021 KdpWriteIoSpace( 01022 IN PDBGKD_MANIPULATE_STATE m, 01023 IN PSTRING AdditionalData, 01024 IN PCONTEXT Context 01025 ) 01026 01027 /*++ 01028 01029 Routine Description: 01030 01031 This function is called in response of a write io space state 01032 manipulation message. Its function is to write to system io 01033 locations. 01034 01035 Arguments: 01036 01037 m - Supplies the state manipulation message. 01038 01039 AdditionalData - Supplies any additional data for the message. 01040 01041 Context - Supplies the current context. 01042 01043 Return Value: 01044 01045 None. 01046 01047 --*/ 01048 01049 { 01050 PDBGKD_READ_WRITE_IO a = &m->u.ReadWriteIo; 01051 STRING MessageHeader; 01052 01053 MessageHeader.Length = sizeof(*m); 01054 MessageHeader.Buffer = (PCHAR)m; 01055 01056 ASSERT(AdditionalData->Length == 0); 01057 01058 m->ReturnStatus = STATUS_SUCCESS; 01059 01060 // 01061 // Check Size and Alignment 01062 // 01063 01064 switch ( a->DataSize ) { 01065 case 1: 01066 WRITE_PORT_UCHAR(a->IoAddress, (UCHAR)a->DataValue); 01067 break; 01068 case 2: 01069 if ((ULONG)a->IoAddress & 1 ) { 01070 m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT; 01071 } else { 01072 WRITE_PORT_USHORT(a->IoAddress, (USHORT)a->DataValue); 01073 } 01074 break; 01075 case 4: 01076 if ((ULONG)a->IoAddress & 3 ) { 01077 m->ReturnStatus = STATUS_DATATYPE_MISALIGNMENT; 01078 } else { 01079 WRITE_PORT_ULONG(a->IoAddress, a->DataValue); 01080 } 01081 break; 01082 default: 01083 m->ReturnStatus = STATUS_INVALID_PARAMETER; 01084 } 01085 01086 KdpSendPacket( 01087 PACKET_TYPE_KD_STATE_MANIPULATE, 01088 &MessageHeader, 01089 NULL 01090 ); 01091 UNREFERENCED_PARAMETER(Context); 01092 } 01093 01094 VOID 01095 KdpReadMachineSpecificRegister( 01096 IN PDBGKD_MANIPULATE_STATE m, 01097 IN PSTRING AdditionalData, 01098 IN PCONTEXT Context 01099 ) 01100 01101 /*++ 01102 01103 Routine Description: 01104 01105 This function is called in response of a read MSR 01106 manipulation message. Its function is to read the MSR. 01107 01108 Arguments: 01109 01110 m - Supplies the state manipulation message. 01111 01112 AdditionalData - Supplies any additional data for the message. 01113 01114 Context - Supplies the current context. 01115 01116 Return Value: 01117 01118 None. 01119 01120 --*/ 01121 01122 { 01123 PDBGKD_READ_WRITE_MSR a = &m->u.ReadWriteMsr; 01124 STRING MessageHeader; 01125 LARGE_INTEGER l; 01126 01127 MessageHeader.Length = sizeof(*m); 01128 MessageHeader.Buffer = (PCHAR)m; 01129 01130 ASSERT(AdditionalData->Length == 0); 01131 01132 m->ReturnStatus = STATUS_SUCCESS; 01133 01134 try { 01135 l.QuadPart = RDMSR(a->Msr); 01136 } except (EXCEPTION_EXECUTE_HANDLER) { 01137 l.QuadPart = 0; 01138 m->ReturnStatus = STATUS_NO_SUCH_DEVICE; 01139 } 01140 01141 a->DataValueLow = l.LowPart; 01142 a->DataValueHigh = l.HighPart; 01143 01144 KdpSendPacket( 01145 PACKET_TYPE_KD_STATE_MANIPULATE, 01146 &MessageHeader, 01147 NULL 01148 ); 01149 UNREFERENCED_PARAMETER(Context); 01150 } 01151 01152 VOID 01153 KdpWriteMachineSpecificRegister( 01154 IN PDBGKD_MANIPULATE_STATE m, 01155 IN PSTRING AdditionalData, 01156 IN PCONTEXT Context 01157 ) 01158 01159 /*++ 01160 01161 Routine Description: 01162 01163 This function is called in response of a write of a MSR 01164 manipulation message. Its function is to write to the MSR 01165 01166 Arguments: 01167 01168 m - Supplies the state manipulation message. 01169 01170 AdditionalData - Supplies any additional data for the message. 01171 01172 Context - Supplies the current context. 01173 01174 Return Value: 01175 01176 None. 01177 01178 --*/ 01179 01180 { 01181 PDBGKD_READ_WRITE_MSR a = &m->u.ReadWriteMsr; 01182 STRING MessageHeader; 01183 LARGE_INTEGER l; 01184 01185 MessageHeader.Length = sizeof(*m); 01186 MessageHeader.Buffer = (PCHAR)m; 01187 01188 ASSERT(AdditionalData->Length == 0); 01189 01190 m->ReturnStatus = STATUS_SUCCESS; 01191 01192 l.HighPart = a->DataValueHigh; 01193 l.LowPart = a->DataValueLow; 01194 01195 try { 01196 WRMSR (a->Msr, l.QuadPart); 01197 } except (EXCEPTION_EXECUTE_HANDLER) { 01198 m->ReturnStatus = STATUS_NO_SUCH_DEVICE; 01199 } 01200 01201 KdpSendPacket( 01202 PACKET_TYPE_KD_STATE_MANIPULATE, 01203 &MessageHeader, 01204 NULL 01205 ); 01206 UNREFERENCED_PARAMETER(Context); 01207 } 01208 01209 /*** KdpGetCallNextOffset - compute "next" instruction on a call-like instruction 01210 * 01211 * Purpose: 01212 * Compute how many bytes are in a call-type instruction 01213 * so that a breakpoint can be set upon this instruction's 01214 * return. Treat indirect jmps as if they were call/ret/ret 01215 * 01216 * Returns: 01217 * offset to "next" instruction, or 0 if it wasn't a call instruction. 01218 * 01219 *************************************************************************/ 01220 01221 ULONG 01222 KdpGetCallNextOffset ( 01223 ULONG Pc, 01224 PCONTEXT ContextRecord 01225 ) 01226 { 01227 UCHAR membuf[2]; 01228 UCHAR opcode; 01229 ULONG sib; 01230 ULONG disp; 01231 01232 KdpMoveMemory( membuf, (PVOID)Pc, 2 ); 01233 opcode = membuf[0]; 01234 01235 if ( opcode == 0xe8 ) { // CALL 32 bit disp 01236 return Pc+5; 01237 } else if ( opcode == 0x9a ) { // CALL 16:32 01238 return Pc+7; 01239 } else if ( opcode == 0xff ) { 01240 if ( membuf[1] == 0x25) { // JMP indirect 01241 return KdpGetReturnAddress( ContextRecord ); 01242 } 01243 sib = ((membuf[1] & 0x07) == 0x04) ? 1 : 0; 01244 disp = (membuf[1] & 0xc0) >> 6; 01245 switch (disp) { 01246 case 0: 01247 if ( (membuf[1] & 0x07) == 0x05 ) { 01248 disp = 4; // disp32 alone 01249 } else { 01250 // disp = 0; // no displacement with reg or sib 01251 } 01252 break; 01253 case 1: 01254 // disp = 1; // disp8 with reg or sib 01255 break; 01256 case 2: 01257 disp = 4; // disp32 with reg or sib 01258 break; 01259 case 3: 01260 disp = 0; // direct register addressing (e.g., call esi) 01261 break; 01262 } 01263 return Pc + 2 + sib + disp; 01264 } 01265 01266 return 0; 01267 01268 } // KdpGetCallNextOffset

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