test: kdcpuapi.c Source File

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