Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817/* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory * FILE: ntoskrnl/kd64/kdapi.c * PURPOSE: KD64 Public Routines and Internal Support * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) * Stefan Ginsberg (stefan.ginsberg@reactos.org) */
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#ifdef KDBG#include <kdbg/kdb.h>#endif
#define NDEBUG#include <debug.h>
VOID NTAPI PspDumpThreads(BOOLEAN SystemThreads);
/* PRIVATE FUNCTIONS *********************************************************/
VOIDNTAPIKdpMoveMemory( _In_ PVOID Destination, _In_ PVOID Source, _In_ SIZE_T Length){ PCHAR DestinationBytes, SourceBytes;
/* Copy the buffers 1 byte at a time */ DestinationBytes = Destination; SourceBytes = Source; while (Length--) *DestinationBytes++ = *SourceBytes++;}
VOIDNTAPIKdpZeroMemory( _In_ PVOID Destination, _In_ SIZE_T Length){ PCHAR DestinationBytes;
/* Zero the buffer 1 byte at a time */ DestinationBytes = Destination; while (Length--) *DestinationBytes++ = 0;}
NTSTATUSNTAPIKdpCopyMemoryChunks( _In_ ULONG64 Address, _In_ PVOID Buffer, _In_ ULONG TotalSize, _In_ ULONG ChunkSize, _In_ ULONG Flags, _Out_opt_ PULONG ActualSize){ NTSTATUS Status; ULONG RemainingLength, CopyChunk;
/* Check if we didn't get a chunk size or if it is too big */ if (ChunkSize == 0) { /* Default to 4 byte chunks */ ChunkSize = 4; } else if (ChunkSize > MMDBG_COPY_MAX_SIZE) { /* Normalize to maximum size */ ChunkSize = MMDBG_COPY_MAX_SIZE; }
/* Copy the whole range in aligned chunks */ RemainingLength = TotalSize; CopyChunk = 1; while (RemainingLength > 0) { /* * Determine the best chunk size for this round. * The ideal size is aligned, isn't larger than the * the remaining length and respects the chunk limit. */ while (((CopyChunk * 2) <= RemainingLength) && (CopyChunk < ChunkSize) && ((Address & ((CopyChunk * 2) - 1)) == 0)) { /* Increase it */ CopyChunk *= 2; }
/* * The chunk size can be larger than the remaining size if this * isn't the first round, so check if we need to shrink it back. */ while (CopyChunk > RemainingLength) { /* Shrink it */ CopyChunk /= 2; }
/* Do the copy */ Status = MmDbgCopyMemory(Address, Buffer, CopyChunk, Flags); if (!NT_SUCCESS(Status)) { /* Copy failed, break out */ break; }
/* Update pointers and length for the next run */ Address = Address + CopyChunk; Buffer = (PVOID)((ULONG_PTR)Buffer + CopyChunk); RemainingLength = RemainingLength - CopyChunk; }
/* We may have modified executable code, flush the instruction cache */ KeSweepICache((PVOID)(ULONG_PTR)Address, TotalSize);
/* * Return the size we managed to copy and return * success if we could copy the whole range. */ if (ActualSize) *ActualSize = TotalSize - RemainingLength; return RemainingLength == 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;}
VOIDNTAPIKdpQueryMemory(IN PDBGKD_MANIPULATE_STATE64 State, IN PCONTEXT Context){ PDBGKD_QUERY_MEMORY Memory = &State->u.QueryMemory; STRING Header; NTSTATUS Status = STATUS_SUCCESS;
/* Validate the address space */ if (Memory->AddressSpace == DBGKD_QUERY_MEMORY_VIRTUAL) { /* Check if this is process memory */ if ((PVOID)(ULONG_PTR)Memory->Address < MmHighestUserAddress) { /* It is */ Memory->AddressSpace = DBGKD_QUERY_MEMORY_PROCESS; } else { /* Check if it's session space */ if (MmIsSessionAddress((PVOID)(ULONG_PTR)Memory->Address)) { /* It is */ Memory->AddressSpace = DBGKD_QUERY_MEMORY_SESSION; } else { /* Not session space but some other kernel memory */ Memory->AddressSpace = DBGKD_QUERY_MEMORY_KERNEL; } }
/* Set flags */ Memory->Flags = DBGKD_QUERY_MEMORY_READ | DBGKD_QUERY_MEMORY_WRITE | DBGKD_QUERY_MEMORY_EXECUTE; } else { /* Invalid */ Status = STATUS_INVALID_PARAMETER; }
/* Return structure */ State->ReturnStatus = Status; Memory->Reserved = 0;
/* Build header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State;
/* Send the packet */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpSearchMemory(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ //PDBGKD_SEARCH_MEMORY SearchMemory = &State->u.SearchMemory; STRING Header;
/* TODO */ KdpDprintf("Memory Search support is unimplemented!\n");
/* Send a failure packet */ State->ReturnStatus = STATUS_UNSUCCESSFUL; Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpFillMemory(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ //PDBGKD_FILL_MEMORY FillMemory = &State->u.FillMemory; STRING Header;
/* TODO */ KdpDprintf("Memory Fill support is unimplemented!\n");
/* Send a failure packet */ State->ReturnStatus = STATUS_UNSUCCESSFUL; Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpWriteBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ PDBGKD_WRITE_BREAKPOINT64 Breakpoint = &State->u.WriteBreakPoint; STRING Header;
/* Build header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; ASSERT(Data->Length == 0);
/* Create the breakpoint */ Breakpoint->BreakPointHandle = KdpAddBreakpoint((PVOID)(ULONG_PTR)Breakpoint->BreakPointAddress); if (!Breakpoint->BreakPointHandle) { /* We failed */ State->ReturnStatus = STATUS_UNSUCCESSFUL; } else { /* Success! */ State->ReturnStatus = STATUS_SUCCESS; }
/* Send the packet */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpRestoreBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ PDBGKD_RESTORE_BREAKPOINT RestoreBp = &State->u.RestoreBreakPoint; STRING Header;
/* Fill out the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; ASSERT(Data->Length == 0);
/* Get the version block */ if (KdpDeleteBreakpoint(RestoreBp->BreakPointHandle)) { /* We're all good */ State->ReturnStatus = STATUS_SUCCESS; } else { /* We failed */ State->ReturnStatus = STATUS_UNSUCCESSFUL; }
/* Send the packet */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
NTSTATUSNTAPIKdpWriteBreakPointEx(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ //PDBGKD_BREAKPOINTEX = &State->u.BreakPointEx; STRING Header;
/* TODO */ KdpDprintf("Extended Breakpoint Write support is unimplemented!\n");
/* Send a failure packet */ State->ReturnStatus = STATUS_UNSUCCESSFUL; Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, Data, &KdpContext); return STATUS_UNSUCCESSFUL;}
VOIDNTAPIKdpRestoreBreakPointEx(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ //PDBGKD_BREAKPOINTEX = &State->u.BreakPointEx; STRING Header;
/* TODO */ KdpDprintf("Extended Breakpoint Restore support is unimplemented!\n");
/* Send a failure packet */ State->ReturnStatus = STATUS_UNSUCCESSFUL; Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, Data, &KdpContext);}
VOIDNTAPIKdpWriteCustomBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ //PDBGKD_WRITE_CUSTOM_BREAKPOINT = &State->u.WriteCustomBreakpoint; STRING Header;
/* Not supported */ KdpDprintf("Custom Breakpoint Write is unimplemented\n");
/* Send a failure packet */ State->ReturnStatus = STATUS_UNSUCCESSFUL; Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIDumpTraceData(IN PSTRING TraceData){ /* Update the buffer */ TraceDataBuffer[0] = TraceDataBufferPosition;
/* Setup the trace data */ TraceData->Length = (USHORT)(TraceDataBufferPosition * sizeof(ULONG)); TraceData->Buffer = (PCHAR)TraceDataBuffer;
/* Reset the buffer location */ TraceDataBufferPosition = 1;}
VOIDNTAPIKdpSetCommonState(IN ULONG NewState, IN PCONTEXT Context, IN PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange){ ULONG InstructionCount; BOOLEAN HadBreakpoints;
/* Setup common stuff available for all CPU architectures */ WaitStateChange->NewState = NewState; WaitStateChange->ProcessorLevel = KeProcessorLevel; WaitStateChange->Processor = (USHORT)KeGetCurrentPrcb()->Number; WaitStateChange->NumberProcessors = (ULONG)KeNumberProcessors; WaitStateChange->Thread = (ULONG64)(LONG_PTR)KeGetCurrentThread(); WaitStateChange->ProgramCounter = (ULONG64)(LONG_PTR)KeGetContextPc(Context);
/* Zero out the entire Control Report */ KdpZeroMemory(&WaitStateChange->AnyControlReport, sizeof(DBGKD_ANY_CONTROL_REPORT));
/* Now copy the instruction stream and set the count */ KdpCopyMemoryChunks((ULONG_PTR)WaitStateChange->ProgramCounter, &WaitStateChange->ControlReport.InstructionStream[0], DBGKD_MAXSTREAM, 0, MMDBG_COPY_UNSAFE, &InstructionCount); WaitStateChange->ControlReport.InstructionCount = (USHORT)InstructionCount;
/* Clear all the breakpoints in this region */ HadBreakpoints = KdpDeleteBreakpointRange((PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter, (PVOID)((ULONG_PTR)WaitStateChange->ProgramCounter + WaitStateChange->ControlReport.InstructionCount - 1)); if (HadBreakpoints) { /* Copy the instruction stream again, this time without breakpoints */ KdpCopyMemoryChunks((ULONG_PTR)WaitStateChange->ProgramCounter, &WaitStateChange->ControlReport.InstructionStream[0], InstructionCount, 0, MMDBG_COPY_UNSAFE, NULL); }}
VOIDNTAPIKdpSysGetVersion( _Out_ PDBGKD_GET_VERSION64 Version){ /* Copy the version block */ KdpMoveMemory(Version, &KdVersionBlock, sizeof(DBGKD_GET_VERSION64));}
VOIDNTAPIKdpGetVersion(IN PDBGKD_MANIPULATE_STATE64 State){ STRING Header;
/* Fill out the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State;
/* Get the version block */ KdpSysGetVersion(&State->u.GetVersion64);
/* Fill out the state */ State->ApiNumber = DbgKdGetVersionApi; State->ReturnStatus = STATUS_SUCCESS;
/* Send the packet */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpReadVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory; STRING Header; ULONG Length = ReadMemory->TransferCount;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; ASSERT(Data->Length == 0);
/* Validate length */ if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64))) { /* Overflow, set it to maximum possible */ Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64); }
/* Do the read */ State->ReturnStatus = KdpCopyMemoryChunks(ReadMemory->TargetBaseAddress, Data->Buffer, Length, 0, MMDBG_COPY_UNSAFE, &Length);
/* Return the actual length read */ ReadMemory->ActualBytesRead = Length; Data->Length = (USHORT)Length;
/* Send the packet */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, Data, &KdpContext);}
VOIDNTAPIKdpWriteVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory; STRING Header;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State;
/* Do the write */ State->ReturnStatus = KdpCopyMemoryChunks(WriteMemory->TargetBaseAddress, Data->Buffer, Data->Length, 0, MMDBG_COPY_UNSAFE | MMDBG_COPY_WRITE, &WriteMemory->ActualBytesWritten);
/* Send the packet */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpReadPhysicalMemory(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory; STRING Header; ULONG Length = ReadMemory->TransferCount; ULONG Flags, CacheFlags;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; ASSERT(Data->Length == 0);
/* Validate length */ if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64))) { /* Overflow, set it to maximum possible */ Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64); }
/* Start with the default flags */ Flags = MMDBG_COPY_UNSAFE | MMDBG_COPY_PHYSICAL;
/* Get the caching flags and check if a type is specified */ CacheFlags = ReadMemory->ActualBytesRead; if (CacheFlags == DBGKD_CACHING_CACHED) { /* Cached */ Flags |= MMDBG_COPY_CACHED; } else if (CacheFlags == DBGKD_CACHING_UNCACHED) { /* Uncached */ Flags |= MMDBG_COPY_UNCACHED; } else if (CacheFlags == DBGKD_CACHING_WRITE_COMBINED) { /* Write Combined */ Flags |= MMDBG_COPY_WRITE_COMBINED; }
/* Do the read */ State->ReturnStatus = KdpCopyMemoryChunks(ReadMemory->TargetBaseAddress, Data->Buffer, Length, 0, Flags, &Length);
/* Return the actual length read */ ReadMemory->ActualBytesRead = Length; Data->Length = (USHORT)Length;
/* Send the packet */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, Data, &KdpContext);}
VOIDNTAPIKdpWritePhysicalMemory(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory; STRING Header; ULONG Flags, CacheFlags;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State;
/* Start with the default flags */ Flags = MMDBG_COPY_UNSAFE | MMDBG_COPY_WRITE | MMDBG_COPY_PHYSICAL;
/* Get the caching flags and check if a type is specified */ CacheFlags = WriteMemory->ActualBytesWritten; if (CacheFlags == DBGKD_CACHING_CACHED) { /* Cached */ Flags |= MMDBG_COPY_CACHED; } else if (CacheFlags == DBGKD_CACHING_UNCACHED) { /* Uncached */ Flags |= MMDBG_COPY_UNCACHED; } else if (CacheFlags == DBGKD_CACHING_WRITE_COMBINED) { /* Write Combined */ Flags |= MMDBG_COPY_WRITE_COMBINED; }
/* Do the write */ State->ReturnStatus = KdpCopyMemoryChunks(WriteMemory->TargetBaseAddress, Data->Buffer, Data->Length, 0, Flags, &WriteMemory->ActualBytesWritten);
/* Send the packet */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpReadControlSpace(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory; STRING Header; ULONG Length;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; ASSERT(Data->Length == 0);
/* Check the length requested */ Length = ReadMemory->TransferCount; if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64))) { /* Use maximum allowed */ Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64); }
/* Call the internal routine */ State->ReturnStatus = KdpSysReadControlSpace(State->Processor, ReadMemory->TargetBaseAddress, Data->Buffer, Length, &Length);
/* Return the actual length read */ ReadMemory->ActualBytesRead = Length; Data->Length = (USHORT)Length;
/* Send the reply */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, Data, &KdpContext);}
VOIDNTAPIKdpWriteControlSpace(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory; STRING Header;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State;
/* Call the internal routine */ State->ReturnStatus = KdpSysWriteControlSpace(State->Processor, WriteMemory->TargetBaseAddress, Data->Buffer, Data->Length, &WriteMemory->ActualBytesWritten);
/* Send the reply */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, Data, &KdpContext);}
VOIDNTAPIKdpGetContext(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ STRING Header; PCONTEXT TargetContext;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; ASSERT(Data->Length == 0);
/* Make sure that this is a valid request */ if (State->Processor < KeNumberProcessors) { /* Check if the request is for this CPU */ if (State->Processor == KeGetCurrentPrcb()->Number) { /* We're just copying our own context */ TargetContext = Context; } else { /* Get the context from the PRCB array */ TargetContext = &KiProcessorBlock[State->Processor]-> ProcessorState.ContextFrame; }
/* Copy it over to the debugger */ KdpMoveMemory(Data->Buffer, TargetContext, sizeof(CONTEXT)); Data->Length = sizeof(CONTEXT);
/* Let the debugger set the context now */ KdpContextSent = TRUE;
/* Finish up */ State->ReturnStatus = STATUS_SUCCESS; } else { /* Invalid request */ State->ReturnStatus = STATUS_UNSUCCESSFUL; }
/* Send the reply */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, Data, &KdpContext);}
VOIDNTAPIKdpSetContext(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ STRING Header; PCONTEXT TargetContext;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; ASSERT(Data->Length == sizeof(CONTEXT));
/* Make sure that this is a valid request */ if ((State->Processor < KeNumberProcessors) && (KdpContextSent)) { /* Check if the request is for this CPU */ if (State->Processor == KeGetCurrentPrcb()->Number) { /* We're just copying our own context */ TargetContext = Context; } else { /* Get the context from the PRCB array */ TargetContext = &KiProcessorBlock[State->Processor]-> ProcessorState.ContextFrame; }
/* Copy the new context to it */ KdpMoveMemory(TargetContext, Data->Buffer, sizeof(CONTEXT));
/* Finish up */ State->ReturnStatus = STATUS_SUCCESS; } else { /* Invalid request */ State->ReturnStatus = STATUS_UNSUCCESSFUL; }
/* Send the reply */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpGetContextEx(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ STRING Header; PDBGKD_CONTEXT_EX ContextEx; PCONTEXT TargetContext; ASSERT(Data->Length == 0);
/* Get our struct */ ContextEx = &State->u.ContextEx;
/* Set up the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State;
/* Make sure that this is a valid request */ if ((State->Processor < KeNumberProcessors) && (ContextEx->Offset + ContextEx->ByteCount) <= sizeof(CONTEXT)) { /* Check if the request is for this CPU */ if (State->Processor == KeGetCurrentPrcb()->Number) { /* We're just copying our own context */ TargetContext = Context; } else { /* Get the context from the PRCB array */ TargetContext = &KiProcessorBlock[State->Processor]-> ProcessorState.ContextFrame; }
/* Copy what is requested */ KdpMoveMemory(Data->Buffer, (PVOID)((ULONG_PTR)TargetContext + ContextEx->Offset), ContextEx->ByteCount);
/* KD copies all */ Data->Length = ContextEx->BytesCopied = ContextEx->ByteCount;
/* Let the debugger set the context now */ KdpContextSent = TRUE;
/* Finish up */ State->ReturnStatus = STATUS_SUCCESS; } else { /* Invalid request */ ContextEx->BytesCopied = 0; State->ReturnStatus = STATUS_UNSUCCESSFUL; }
/* Send the reply */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, Data, &KdpContext);}
VOIDNTAPIKdpSetContextEx(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ STRING Header; PDBGKD_CONTEXT_EX ContextEx; PCONTEXT TargetContext;
/* Get our struct */ ContextEx = &State->u.ContextEx; ASSERT(Data->Length == ContextEx->ByteCount);
/* Set up the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State;
/* Make sure that this is a valid request */ if ((State->Processor < KeNumberProcessors) && ((ContextEx->Offset + ContextEx->ByteCount) <= sizeof(CONTEXT)) && (KdpContextSent)) { /* Check if the request is for this CPU */ if (State->Processor == KeGetCurrentPrcb()->Number) { /* We're just copying our own context */ TargetContext = Context; } else { /* Get the context from the PRCB array */ TargetContext = &KiProcessorBlock[State->Processor]-> ProcessorState.ContextFrame; }
/* Copy what is requested */ KdpMoveMemory((PVOID)((ULONG_PTR)TargetContext + ContextEx->Offset), Data->Buffer, ContextEx->ByteCount);
/* KD copies all */ ContextEx->BytesCopied = ContextEx->ByteCount;
/* Finish up */ State->ReturnStatus = STATUS_SUCCESS; } else { /* Invalid request */ ContextEx->BytesCopied = 0; State->ReturnStatus = STATUS_UNSUCCESSFUL; }
/* Send the reply */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpCauseBugCheck(IN PDBGKD_MANIPULATE_STATE64 State){ /* Crash with the special code */ KeBugCheck(MANUALLY_INITIATED_CRASH);}
VOIDNTAPIKdpReadMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ STRING Header; PDBGKD_READ_WRITE_MSR ReadMsr = &State->u.ReadWriteMsr; ULARGE_INTEGER MsrValue;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; ASSERT(Data->Length == 0);
/* Call the internal routine */ State->ReturnStatus = KdpSysReadMsr(ReadMsr->Msr, &MsrValue.QuadPart);
/* Return the data */ ReadMsr->DataValueLow = MsrValue.LowPart; ReadMsr->DataValueHigh = MsrValue.HighPart;
/* Send the reply */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpWriteMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ STRING Header; PDBGKD_READ_WRITE_MSR WriteMsr = &State->u.ReadWriteMsr; ULARGE_INTEGER MsrValue;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; ASSERT(Data->Length == 0);
/* Call the internal routine */ MsrValue.LowPart = WriteMsr->DataValueLow; MsrValue.HighPart = WriteMsr->DataValueHigh; State->ReturnStatus = KdpSysWriteMsr(WriteMsr->Msr, &MsrValue.QuadPart);
/* Send the reply */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpGetBusData(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ STRING Header; PDBGKD_GET_SET_BUS_DATA GetBusData = &State->u.GetSetBusData; ULONG Length;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; ASSERT(Data->Length == 0);
/* Check the length requested */ Length = GetBusData->Length; if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64))) { /* Use maximum allowed */ Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64); }
/* Call the internal routine */ State->ReturnStatus = KdpSysReadBusData(GetBusData->BusDataType, GetBusData->BusNumber, GetBusData->SlotNumber, GetBusData->Offset, Data->Buffer, Length, &Length);
/* Return the actual length read */ GetBusData->Length = Length; Data->Length = (USHORT)Length;
/* Send the reply */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, Data, &KdpContext);}
VOIDNTAPIKdpSetBusData(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ STRING Header; PDBGKD_GET_SET_BUS_DATA SetBusData = &State->u.GetSetBusData;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State;
/* Call the internal routine */ State->ReturnStatus = KdpSysWriteBusData(SetBusData->BusDataType, SetBusData->BusNumber, SetBusData->SlotNumber, SetBusData->Offset, Data->Buffer, SetBusData->Length, &SetBusData->Length);
/* Send the reply */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpReadIoSpace(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ STRING Header; PDBGKD_READ_WRITE_IO64 ReadIo = &State->u.ReadWriteIo;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; ASSERT(Data->Length == 0);
/* * Clear the value so 1 or 2 byte reads * don't leave the higher bits unmodified */ ReadIo->DataValue = 0;
/* Call the internal routine */ State->ReturnStatus = KdpSysReadIoSpace(Isa, 0, 1, ReadIo->IoAddress, &ReadIo->DataValue, ReadIo->DataSize, &ReadIo->DataSize);
/* Send the reply */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpWriteIoSpace(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ STRING Header; PDBGKD_READ_WRITE_IO64 WriteIo = &State->u.ReadWriteIo;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; ASSERT(Data->Length == 0);
/* Call the internal routine */ State->ReturnStatus = KdpSysWriteIoSpace(Isa, 0, 1, WriteIo->IoAddress, &WriteIo->DataValue, WriteIo->DataSize, &WriteIo->DataSize);
/* Send the reply */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpReadIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ STRING Header; PDBGKD_READ_WRITE_IO_EXTENDED64 ReadIoExtended = &State->u. ReadWriteIoExtended;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; ASSERT(Data->Length == 0);
/* * Clear the value so 1 or 2 byte reads * don't leave the higher bits unmodified */ ReadIoExtended->DataValue = 0;
/* Call the internal routine */ State->ReturnStatus = KdpSysReadIoSpace(ReadIoExtended->InterfaceType, ReadIoExtended->BusNumber, ReadIoExtended->AddressSpace, ReadIoExtended->IoAddress, &ReadIoExtended->DataValue, ReadIoExtended->DataSize, &ReadIoExtended->DataSize);
/* Send the reply */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpWriteIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State, IN PSTRING Data, IN PCONTEXT Context){ STRING Header; PDBGKD_READ_WRITE_IO_EXTENDED64 WriteIoExtended = &State->u. ReadWriteIoExtended;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State; ASSERT(Data->Length == 0);
/* Call the internal routine */ State->ReturnStatus = KdpSysWriteIoSpace(WriteIoExtended->InterfaceType, WriteIoExtended->BusNumber, WriteIoExtended->AddressSpace, WriteIoExtended->IoAddress, &WriteIoExtended->DataValue, WriteIoExtended->DataSize, &WriteIoExtended->DataSize);
/* Send the reply */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpCheckLowMemory(IN PDBGKD_MANIPULATE_STATE64 State){ STRING Header;
/* Setup the header */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State;
/* Call the internal routine */ State->ReturnStatus = KdpSysCheckLowMemory(MMDBG_COPY_UNSAFE);
/* Send the reply */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
VOIDNTAPIKdpNotSupported(IN PDBGKD_MANIPULATE_STATE64 State){ STRING Header;
/* Set failure */ State->ReturnStatus = STATUS_UNSUCCESSFUL;
/* Setup the packet */ Header.Length = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)State;
/* Send it */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, NULL, &KdpContext);}
staticKCONTINUE_STATUSKdpSwitchProcessor( _In_ USHORT ProcessorIndex){ /* Make sure that the processor index is valid */ if (ProcessorIndex >= KeNumberProcessors) { KdpDprintf("%u is not a valid processor number\n", ProcessorIndex); return ContinueProcessorReselected; }
/* If the new processor is the current one, there is nothing to do */ if (ProcessorIndex == KeGetCurrentProcessorNumber()) { return ContinueProcessorReselected; }
/* Call the architecture specific Ke routine */ return KxSwitchKdProcessor(ProcessorIndex);}
KCONTINUE_STATUSNTAPIKdpSendWaitContinue(IN ULONG PacketType, IN PSTRING SendHeader, IN PSTRING SendData OPTIONAL, IN OUT PCONTEXT Context){ STRING Data, Header; DBGKD_MANIPULATE_STATE64 ManipulateState; ULONG Length; KDSTATUS RecvCode;
/* Setup the Manipulate State structure */ Header.MaximumLength = sizeof(DBGKD_MANIPULATE_STATE64); Header.Buffer = (PCHAR)&ManipulateState; Data.MaximumLength = sizeof(KdpMessageBuffer); Data.Buffer = KdpMessageBuffer;
/* * Reset the context state to ensure the debugger has received * the current context before it sets it. */ KdpContextSent = FALSE;
SendPacket: /* Send the Packet */ KdSendPacket(PacketType, SendHeader, SendData, &KdpContext);
/* If the debugger isn't present anymore, just return success */ if (KdDebuggerNotPresent) return ContinueSuccess;
/* Main processing Loop */ for (;;) { /* Receive Loop */ do { /* Wait to get a reply to our packet */ RecvCode = KdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, &Data, &Length, &KdpContext);
/* If we got a resend request, do it */ if (RecvCode == KdPacketNeedsResend) goto SendPacket; } while (RecvCode == KdPacketTimedOut);
/* Now check what API we got */ switch (ManipulateState.ApiNumber) { case DbgKdReadVirtualMemoryApi:
/* Read virtual memory */ KdpReadVirtualMemory(&ManipulateState, &Data, Context); break;
case DbgKdWriteVirtualMemoryApi:
/* Write virtual memory */ KdpWriteVirtualMemory(&ManipulateState, &Data, Context); break;
case DbgKdGetContextApi:
/* Get the current context */ KdpGetContext(&ManipulateState, &Data, Context); break;
case DbgKdSetContextApi:
/* Set a new context */ KdpSetContext(&ManipulateState, &Data, Context); break;
case DbgKdWriteBreakPointApi:
/* Write the breakpoint */ KdpWriteBreakpoint(&ManipulateState, &Data, Context); break;
case DbgKdRestoreBreakPointApi:
/* Restore the breakpoint */ KdpRestoreBreakpoint(&ManipulateState, &Data, Context); break;
case DbgKdContinueApi:
/* Simply continue */ return NT_SUCCESS(ManipulateState.u.Continue.ContinueStatus);
case DbgKdReadControlSpaceApi:
/* Read control space */ KdpReadControlSpace(&ManipulateState, &Data, Context); break;
case DbgKdWriteControlSpaceApi:
/* Write control space */ KdpWriteControlSpace(&ManipulateState, &Data, Context); break;
case DbgKdReadIoSpaceApi:
/* Read I/O Space */ KdpReadIoSpace(&ManipulateState, &Data, Context); break;
case DbgKdWriteIoSpaceApi:
/* Write I/O Space */ KdpWriteIoSpace(&ManipulateState, &Data, Context); break;
case DbgKdRebootApi:
/* Reboot the system */ HalReturnToFirmware(HalRebootRoutine); break;
case DbgKdContinueApi2:
/* Check if caller reports success */ if (NT_SUCCESS(ManipulateState.u.Continue2.ContinueStatus)) { /* Update the state */ KdpGetStateChange(&ManipulateState, Context); return ContinueSuccess; } else { /* Return an error */ return ContinueError; }
case DbgKdReadPhysicalMemoryApi:
/* Read physical memory */ KdpReadPhysicalMemory(&ManipulateState, &Data, Context); break;
case DbgKdWritePhysicalMemoryApi:
/* Write physical memory */ KdpWritePhysicalMemory(&ManipulateState, &Data, Context); break;
case DbgKdQuerySpecialCallsApi: case DbgKdSetSpecialCallApi: case DbgKdClearSpecialCallsApi:
/* TODO */ KdpDprintf("Special Call support is unimplemented!\n"); KdpNotSupported(&ManipulateState); break;
case DbgKdSetInternalBreakPointApi: case DbgKdGetInternalBreakPointApi:
/* TODO */ KdpDprintf("Internal Breakpoint support is unimplemented!\n"); KdpNotSupported(&ManipulateState); break;
case DbgKdReadIoSpaceExtendedApi:
/* Read I/O Space */ KdpReadIoSpaceExtended(&ManipulateState, &Data, Context); break;
case DbgKdWriteIoSpaceExtendedApi:
/* Write I/O Space */ KdpWriteIoSpaceExtended(&ManipulateState, &Data, Context); break;
case DbgKdGetVersionApi:
/* Get version data */ KdpGetVersion(&ManipulateState); break;
case DbgKdWriteBreakPointExApi:
/* Write the breakpoint and check if it failed */ if (!NT_SUCCESS(KdpWriteBreakPointEx(&ManipulateState, &Data, Context))) { /* Return an error */ return ContinueError; } break;
case DbgKdRestoreBreakPointExApi:
/* Restore the breakpoint */ KdpRestoreBreakPointEx(&ManipulateState, &Data, Context); break;
case DbgKdCauseBugCheckApi:
/* Crash the system */ KdpCauseBugCheck(&ManipulateState); break;
case DbgKdSwitchProcessor:
/* Switch the processor and return */ return KdpSwitchProcessor(ManipulateState.Processor);
case DbgKdPageInApi:
/* This API, introduced in NT4, has been obsoleted in NT5. It is * replaced by ExpDebuggerPageIn support in ExpDebuggerWorker(). */ KdpDprintf("DbgKdPageInApi is obsolete!\n"); KdpNotSupported(&ManipulateState); break;
case DbgKdReadMachineSpecificRegister:
/* Read from the specified MSR */ KdpReadMachineSpecificRegister(&ManipulateState, &Data, Context); break;
case DbgKdWriteMachineSpecificRegister:
/* Write to the specified MSR */ KdpWriteMachineSpecificRegister(&ManipulateState, &Data, Context); break;
case DbgKdSearchMemoryApi:
/* Search memory */ KdpSearchMemory(&ManipulateState, &Data, Context); break;
case DbgKdGetBusDataApi:
/* Read from the bus */ KdpGetBusData(&ManipulateState, &Data, Context); break;
case DbgKdSetBusDataApi:
/* Write to the bus */ KdpSetBusData(&ManipulateState, &Data, Context); break;
case DbgKdCheckLowMemoryApi:
/* Check for memory corruption in the lower 4 GB */ KdpCheckLowMemory(&ManipulateState); break;
case DbgKdClearAllInternalBreakpointsApi:
/* Just clear the counter */ KdpNumInternalBreakpoints = 0; break;
case DbgKdFillMemoryApi:
/* Fill memory */ KdpFillMemory(&ManipulateState, &Data, Context); break;
case DbgKdQueryMemoryApi:
/* Query memory */ KdpQueryMemory(&ManipulateState, Context); break;
case DbgKdSwitchPartition:
/* TODO */ KdpDprintf("Partition Switch support is unimplemented!\n"); KdpNotSupported(&ManipulateState); break;
case DbgKdWriteCustomBreakpointApi:
/* Write the customized breakpoint */ KdpWriteCustomBreakpoint(&ManipulateState, &Data, Context); break;
case DbgKdGetContextExApi:
/* Extended Context Get */ KdpGetContextEx(&ManipulateState, &Data, Context); break;
case DbgKdSetContextExApi:
/* Extended Context Set */ KdpSetContextEx(&ManipulateState, &Data, Context); break;
/* Unsupported Messages */ default:
/* Send warning */ KdpDprintf("Received Unrecognized API 0x%lx\n", ManipulateState.ApiNumber);
/* Setup an empty message, with failure */ Data.Length = 0; ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
/* Send it */ KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE, &Header, &Data, &KdpContext); break; } }}
VOIDNTAPIKdpReportLoadSymbolsStateChange(IN PSTRING PathName, IN PKD_SYMBOLS_INFO SymbolInfo, IN BOOLEAN Unload, IN OUT PCONTEXT Context){ PSTRING ExtraData; STRING Data, Header; DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange; ULONG PathNameLength; KCONTINUE_STATUS Status;
/* Start wait loop */ do { /* Build the architecture common parts of the message */ KdpSetCommonState(DbgKdLoadSymbolsStateChange, Context, &WaitStateChange);
/* Now finish creating the structure */ KdpSetContextState(&WaitStateChange, Context);
/* Fill out load data */ WaitStateChange.u.LoadSymbols.UnloadSymbols = Unload; WaitStateChange.u.LoadSymbols.BaseOfDll = (ULONG64)(LONG_PTR)SymbolInfo->BaseOfDll; WaitStateChange.u.LoadSymbols.ProcessId = SymbolInfo->ProcessId; WaitStateChange.u.LoadSymbols.CheckSum = SymbolInfo->CheckSum; WaitStateChange.u.LoadSymbols.SizeOfImage = SymbolInfo->SizeOfImage;
/* Check if we have a path name */ if (PathName) { /* Copy it to the path buffer */ KdpCopyMemoryChunks((ULONG_PTR)PathName->Buffer, KdpPathBuffer, PathName->Length, 0, MMDBG_COPY_UNSAFE, &PathNameLength);
/* Null terminate */ KdpPathBuffer[PathNameLength++] = ANSI_NULL;
/* Set the path length */ WaitStateChange.u.LoadSymbols.PathNameLength = PathNameLength;
/* Set up the data */ Data.Buffer = KdpPathBuffer; Data.Length = (USHORT)PathNameLength; ExtraData = &Data; } else { /* No name */ WaitStateChange.u.LoadSymbols.PathNameLength = 0; ExtraData = NULL; }
/* Setup the header */ Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE); Header.Buffer = (PCHAR)&WaitStateChange;
/* Send the packet */ Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64, &Header, ExtraData, Context); } while (Status == ContinueProcessorReselected);}
VOIDNTAPIKdpReportCommandStringStateChange(IN PSTRING NameString, IN PSTRING CommandString, IN OUT PCONTEXT Context){ STRING Header, Data; DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange; ULONG Length, ActualLength, TotalLength; KCONTINUE_STATUS Status;
/* Start wait loop */ do { /* Build the architecture common parts of the message */ KdpSetCommonState(DbgKdCommandStringStateChange, Context, &WaitStateChange);
/* Set the context */ KdpSetContextState(&WaitStateChange, Context);
/* Clear the command string structure */ KdpZeroMemory(&WaitStateChange.u.CommandString, sizeof(DBGKD_COMMAND_STRING));
/* Normalize name string to max */ Length = min(128 - 1, NameString->Length);
/* Copy it to the message buffer */ KdpCopyMemoryChunks((ULONG_PTR)NameString->Buffer, KdpMessageBuffer, Length, 0, MMDBG_COPY_UNSAFE, &ActualLength);
/* Null terminate and calculate the total length */ TotalLength = ActualLength; KdpMessageBuffer[TotalLength++] = ANSI_NULL;
/* Check if the command string is too long */ Length = CommandString->Length; if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_ANY_WAIT_STATE_CHANGE) - TotalLength)) { /* Use maximum possible size */ Length = (PACKET_MAX_SIZE - sizeof(DBGKD_ANY_WAIT_STATE_CHANGE) - TotalLength); }
/* Copy it to the message buffer */ KdpCopyMemoryChunks((ULONG_PTR)CommandString->Buffer, KdpMessageBuffer + TotalLength, Length, 0, MMDBG_COPY_UNSAFE, &ActualLength);
/* Null terminate and calculate the total length */ TotalLength += ActualLength; KdpMessageBuffer[TotalLength++] = ANSI_NULL;
/* Now set up the header and the data */ Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE); Header.Buffer = (PCHAR)&WaitStateChange; Data.Length = (USHORT)TotalLength; Data.Buffer = KdpMessageBuffer;
/* Send State Change packet and wait for a reply */ Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64, &Header, &Data, Context); } while (Status == ContinueProcessorReselected);}
BOOLEANNTAPIKdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord, IN OUT PCONTEXT Context, IN BOOLEAN SecondChanceException){ STRING Header, Data; DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange; KCONTINUE_STATUS Status;
/* Start report loop */ do { /* Build the architecture common parts of the message */ KdpSetCommonState(DbgKdExceptionStateChange, Context, &WaitStateChange);
#if !defined(_WIN64)
/* Convert it and copy it over */ ExceptionRecord32To64((PEXCEPTION_RECORD32)ExceptionRecord, &WaitStateChange.u.Exception.ExceptionRecord);
#else
/* Just copy it directly, no need to convert */ KdpMoveMemory(&WaitStateChange.u.Exception.ExceptionRecord, ExceptionRecord, sizeof(EXCEPTION_RECORD));
#endif
/* Set the First Chance flag */ WaitStateChange.u.Exception.FirstChance = !SecondChanceException;
/* Now finish creating the structure */ KdpSetContextState(&WaitStateChange, Context);
/* Setup the actual header to send to KD */ Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE); Header.Buffer = (PCHAR)&WaitStateChange;
/* Setup the trace data */ DumpTraceData(&Data);
/* Send State Change packet and wait for a reply */ Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64, &Header, &Data, Context); } while (Status == ContinueProcessorReselected);
/* Return */ return Status;}
KCONTINUE_STATUSNTAPIKdReportProcessorChange( VOID){ PKPRCB CurrentPrcb = KeGetCurrentPrcb(); PCONTEXT ContextRecord = &CurrentPrcb->ProcessorState.ContextFrame; EXCEPTION_RECORD ExceptionRecord = {0}; KCONTINUE_STATUS Status;
/* Save the port data */ KdSave(FALSE);
ExceptionRecord.ExceptionAddress = (PVOID)KeGetContextPc(ContextRecord); ExceptionRecord.ExceptionCode = STATUS_WAKE_SYSTEM_DEBUGGER;
/* Report the new state */ Status = KdpReportExceptionStateChange(&ExceptionRecord, ContextRecord, FALSE);
/* Restore the port data */ KdRestore(FALSE);
return Status;}
VOIDNTAPIKdpTimeSlipDpcRoutine(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2){ LONG OldSlip, NewSlip, PendingSlip;
/* Get the current pending slip */ PendingSlip = KdpTimeSlipPending; do { /* Save the old value and either disable or enable it now. */ OldSlip = PendingSlip; NewSlip = OldSlip > 1 ? 1 : 0;
/* Try to change the value */ } while (InterlockedCompareExchange(&KdpTimeSlipPending, NewSlip, OldSlip) != OldSlip);
/* If the New Slip value is 1, then do the Time Slipping */ if (NewSlip) ExQueueWorkItem(&KdpTimeSlipWorkItem, DelayedWorkQueue);}
VOIDNTAPIKdpTimeSlipWork(IN PVOID Context){ KIRQL OldIrql; LARGE_INTEGER DueTime;
/* Update the System time from the CMOS */ ExAcquireTimeRefreshLock(FALSE); ExUpdateSystemTimeFromCmos(FALSE, 0); ExReleaseTimeRefreshLock();
/* Check if we have a registered Time Slip Event and signal it */ KeAcquireSpinLock(&KdpTimeSlipEventLock, &OldIrql); if (KdpTimeSlipEvent) KeSetEvent(KdpTimeSlipEvent, 0, FALSE); KeReleaseSpinLock(&KdpTimeSlipEventLock, OldIrql);
/* Delay the DPC until it runs next time */ DueTime.QuadPart = -1800000000; KeSetTimer(&KdpTimeSlipTimer, DueTime, &KdpTimeSlipDpc);}
LARGE_INTEGERNTAPIKdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame){ LARGE_INTEGER Null = {{0}};
/* Check if interrupts were disabled */ if (!KeGetTrapFrameInterruptState(TrapFrame)) { /* Nothing to return */ return Null; }
/* Otherwise, do the call */ return KeQueryPerformanceCounter(NULL);}
BOOLEANNTAPIKdEnterDebugger(IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame){ BOOLEAN Enable;
/* Check if we have a trap frame */ if (TrapFrame) { /* Calculate the time difference for the enter */ KdTimerStop = KdpQueryPerformanceCounter(TrapFrame); KdTimerDifference.QuadPart = KdTimerStop.QuadPart - KdTimerStart.QuadPart; } else { /* No trap frame, so can't calculate */ KdTimerStop.QuadPart = 0; }
/* Save the current IRQL */ KeGetCurrentPrcb()->DebuggerSavedIRQL = KeGetCurrentIrql();
/* Freeze all CPUs, raising also the IRQL to HIGH_LEVEL */ Enable = KeFreezeExecution(TrapFrame, ExceptionFrame);
/* Lock the port, save its state and set the debugger entered flag */ KdpPortLocked = KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock); KdSave(FALSE); KdEnteredDebugger = TRUE;
/* Check freeze flag */ if (KiFreezeFlag & 1) { /* Print out errror */ KdpDprintf("FreezeLock was jammed! Backup SpinLock was used!\n"); }
/* Check processor state */ if (KiFreezeFlag & 2) { /* Print out errror */ KdpDprintf("Some processors not frozen in debugger!\n"); }
/* Make sure we acquired the port */ if (!KdpPortLocked) KdpDprintf("Port lock was not acquired!\n");
/* Return if interrupts needs to be re-enabled */ return Enable;}
VOIDNTAPIKdExitDebugger(IN BOOLEAN Enable){ ULONG TimeSlip;
/* Reset the debugger entered flag, restore the port state and unlock it */ KdEnteredDebugger = FALSE; KdRestore(FALSE); if (KdpPortLocked) KdpPortUnlock();
/* Unfreeze the CPUs, restoring also the IRQL */ KeThawExecution(Enable);
/* Compare time with the one from KdEnterDebugger */ if (!KdTimerStop.QuadPart) { /* We didn't get a trap frame earlier in so never got the time */ KdTimerStart = KdTimerStop; } else { /* Query the timer */ KdTimerStart = KeQueryPerformanceCounter(NULL); }
/* Check if a Time Slip was on queue */ TimeSlip = InterlockedIncrement(&KdpTimeSlipPending); if (TimeSlip == 1) { /* Queue a DPC for the time slip */ InterlockedIncrement(&KdpTimeSlipPending); KeInsertQueueDpc(&KdpTimeSlipDpc, NULL, NULL); // FIXME: this can trigger context switches! }}
NTSTATUSNTAPIKdEnableDebuggerWithLock(IN BOOLEAN NeedLock){ KIRQL OldIrql;
#if defined(__GNUC__) /* Make gcc happy */ OldIrql = PASSIVE_LEVEL;#endif
/* Check if enabling the debugger is blocked */ if (KdBlockEnable) { /* It is, fail the enable */ return STATUS_ACCESS_DENIED; }
/* Check if we need to acquire the lock */ if (NeedLock) { /* Lock the port */ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); KdpPortLock(); }
/* Check if we're not disabled */ if (!KdDisableCount) { /* Check if we had locked the port before */ if (NeedLock) { /* Do the unlock */ KdpPortUnlock(); KeLowerIrql(OldIrql);
/* Fail: We're already enabled */ return STATUS_INVALID_PARAMETER; } else { /* * This can only happen if we are called from a bugcheck * and were never initialized, so initialize the debugger now. */ KdInitSystem(0, NULL);
/* Return success since we initialized */ return STATUS_SUCCESS; } }
/* Decrease the disable count */ if (!(--KdDisableCount)) { /* We're now enabled again! Were we enabled before, too? */ if (KdPreviouslyEnabled) { /* Reinitialize the Debugger */ KdInitSystem(0, NULL); KdpRestoreAllBreakpoints(); } }
/* Check if we had locked the port before */ if (NeedLock) { /* Yes, now unlock it */ KdpPortUnlock(); KeLowerIrql(OldIrql); }
/* We're done */ return STATUS_SUCCESS;}
NTSTATUSNTAPIKdDisableDebuggerWithLock(IN BOOLEAN NeedLock){ KIRQL OldIrql; NTSTATUS Status;
#if defined(__GNUC__) /* Make gcc happy */ OldIrql = PASSIVE_LEVEL;#endif
/* * If enabling the debugger is blocked * then there is nothing to disable (duh) */ if (KdBlockEnable) { /* Fail */ return STATUS_ACCESS_DENIED; }
/* Check if we need to acquire the lock */ if (NeedLock) { /* Lock the port */ KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); KdpPortLock(); }
/* Check if we're not disabled */ if (!KdDisableCount) { /* Check if the debugger was never actually initialized */ if (!(KdDebuggerEnabled) && !(KdPitchDebugger)) { /* It wasn't, so don't re-enable it later */ KdPreviouslyEnabled = FALSE; } else { /* It was, so we will re-enable it later */ KdPreviouslyEnabled = TRUE; }
/* Check if we were called from the exported API and are enabled */ if ((NeedLock) && (KdPreviouslyEnabled)) { /* Check if it is safe to disable the debugger */ Status = KdpAllowDisable(); if (!NT_SUCCESS(Status)) { /* Release the lock and fail */ KdpPortUnlock(); KeLowerIrql(OldIrql); return Status; } }
/* Only disable the debugger if it is enabled */ if (KdDebuggerEnabled) { /* * Disable the debugger; suspend breakpoints * and reset the debug stub */ KdpSuspendAllBreakPoints(); KiDebugRoutine = KdpStub;
/* We are disabled now */ KdDebuggerEnabled = FALSE; SharedUserData->KdDebuggerEnabled = FALSE; } }
/* Increment the disable count */ KdDisableCount++;
/* Check if we had locked the port before */ if (NeedLock) { /* Yes, now unlock it */ KdpPortUnlock(); KeLowerIrql(OldIrql); }
/* We're done */ return STATUS_SUCCESS;}
/* PUBLIC FUNCTIONS **********************************************************/
/* * @implemented */NTSTATUSNTAPIKdEnableDebugger(VOID){ /* Use the internal routine */ return KdEnableDebuggerWithLock(TRUE);}
/* * @implemented */NTSTATUSNTAPIKdDisableDebugger(VOID){ /* Use the internal routine */ return KdDisableDebuggerWithLock(TRUE);}
/** * @brief * Perform various queries to the kernel debugger. * * @param[in] Command * A SYSDBG_COMMAND value describing the kernel debugger command to perform. * * @param[in] InputBuffer * Pointer to a user-provided input command-specific buffer, whose length * is given by InputBufferLength. * * @param[in] InputBufferLength * The size (in bytes) of the buffer pointed by InputBuffer. * * @param[out] OutputBuffer * Pointer to a user-provided command-specific output buffer, whose length * is given by OutputBufferLength. * * @param[in] OutputBufferLength * The size (in bytes) of the buffer pointed by OutputBuffer. * * @param[out] ReturnLength * Optional pointer to a ULONG variable that receives the actual length of * data written written in the output buffer. It is always zero, except for * the live dump commands where an actual non-zero length is returned. * * @param[in] PreviousMode * The processor mode (KernelMode or UserMode) in which the command is being executed. * * @return * STATUS_SUCCESS in case of success, or a proper error code otherwise. * * @remarks * - This is a kernel-mode function, accessible only by kernel-mode drivers. * * @note * See: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2004-2339 * * @see NtSystemDebugControl() **/NTSTATUSNTAPIKdSystemDebugControl( _In_ SYSDBG_COMMAND Command, _In_reads_bytes_(InputBufferLength) PVOID InputBuffer, _In_ ULONG InputBufferLength, _Out_writes_bytes_(OutputBufferLength) PVOID OutputBuffer, _In_ ULONG OutputBufferLength, _Out_opt_ PULONG ReturnLength, _In_ KPROCESSOR_MODE PreviousMode){ NTSTATUS Status; ULONG Length = 0;
/* Handle some internal commands */ switch ((ULONG)Command) {#if DBG case ' soR': /* ROS-INTERNAL */ { switch ((ULONG_PTR)InputBuffer) { case 0x21: // DumpAllThreads: PspDumpThreads(TRUE); break;
case 0x22: // DumpUserThreads: PspDumpThreads(FALSE); break;
case 0x24: // KdSpare3: MmDumpArmPfnDatabase(FALSE); break;
default: break; } return STATUS_SUCCESS; }
#if defined(_M_IX86) && !defined(_WINKD_) // See ke/i386/traphdlr.c /* Register a debug callback */ case 'CsoR': { switch (InputBufferLength) { case ID_Win32PreServiceHook: KeWin32PreServiceHook = InputBuffer; break;
case ID_Win32PostServiceHook: KeWin32PostServiceHook = InputBuffer; break;
} break; }#endif
/* Special case for stack frame dumps */ case 'DsoR': { KeRosDumpStackFrames((PULONG_PTR)InputBuffer, InputBufferLength); break; }#ifdef KDBG /* Register KDBG CLI callback */ case 'RbdK': { return KdbRegisterCliCallback(InputBuffer, InputBufferLength); }#endif // KDBG#endif default: break; }
switch (Command) { case SysDbgQueryVersion: if (OutputBufferLength != sizeof(DBGKD_GET_VERSION64)) { Status = STATUS_INFO_LENGTH_MISMATCH; } else { KdpSysGetVersion((PDBGKD_GET_VERSION64)OutputBuffer); Status = STATUS_SUCCESS; } break;
case SysDbgReadVirtual: case SysDbgWriteVirtual: if (InputBufferLength != sizeof(SYSDBG_VIRTUAL)) { Status = STATUS_INFO_LENGTH_MISMATCH; } else { SYSDBG_VIRTUAL Request = *(PSYSDBG_VIRTUAL)InputBuffer; PVOID LockedBuffer; PMDL LockVariable;
Status = ExLockUserBuffer(Request.Buffer, Request.Request, PreviousMode, Command == SysDbgReadVirtual ? IoWriteAccess : IoReadAccess, &LockedBuffer, &LockVariable); if (NT_SUCCESS(Status)) { Status = KdpCopyMemoryChunks((ULONG64)(ULONG_PTR)Request.Address, Request.Buffer, Request.Request, 0, Command == SysDbgReadVirtual ? 0 : MMDBG_COPY_WRITE, &Length); ExUnlockUserBuffer(LockVariable); } } break;
case SysDbgReadPhysical: case SysDbgWritePhysical: if (InputBufferLength != sizeof(SYSDBG_PHYSICAL)) { Status = STATUS_INFO_LENGTH_MISMATCH; } else { SYSDBG_PHYSICAL Request = *(PSYSDBG_PHYSICAL)InputBuffer; PVOID LockedBuffer; PMDL LockVariable;
Status = ExLockUserBuffer(Request.Buffer, Request.Request, PreviousMode, Command == SysDbgReadVirtual ? IoWriteAccess : IoReadAccess, &LockedBuffer, &LockVariable); if (NT_SUCCESS(Status)) { Status = KdpCopyMemoryChunks(Request.Address.QuadPart, Request.Buffer, Request.Request, 0, MMDBG_COPY_PHYSICAL | (Command == SysDbgReadVirtual ? 0 : MMDBG_COPY_WRITE), &Length); ExUnlockUserBuffer(LockVariable); } } break;
case SysDbgReadControlSpace: if (InputBufferLength != sizeof(SYSDBG_CONTROL_SPACE)) { Status = STATUS_INFO_LENGTH_MISMATCH; } else { SYSDBG_CONTROL_SPACE Request = *(PSYSDBG_CONTROL_SPACE)InputBuffer; PVOID LockedBuffer; PMDL LockVariable;
Status = ExLockUserBuffer(Request.Buffer, Request.Request, PreviousMode, IoWriteAccess, &LockedBuffer, &LockVariable); if (NT_SUCCESS(Status)) { Status = KdpSysReadControlSpace(Request.Processor, Request.Address, LockedBuffer, Request.Request, &Length); ExUnlockUserBuffer(LockVariable); } } break;
case SysDbgWriteControlSpace: if (InputBufferLength != sizeof(SYSDBG_CONTROL_SPACE)) { Status = STATUS_INFO_LENGTH_MISMATCH; } else { SYSDBG_CONTROL_SPACE Request = *(PSYSDBG_CONTROL_SPACE)InputBuffer; PVOID LockedBuffer; PMDL LockVariable;
Status = ExLockUserBuffer(Request.Buffer, Request.Request, PreviousMode, IoReadAccess, &LockedBuffer, &LockVariable); if (NT_SUCCESS(Status)) { Status = KdpSysWriteControlSpace(Request.Processor, Request.Address, LockedBuffer, Request.Request, &Length); ExUnlockUserBuffer(LockVariable); } } break;
case SysDbgReadIoSpace: if (InputBufferLength != sizeof(SYSDBG_IO_SPACE)) { Status = STATUS_INFO_LENGTH_MISMATCH; } else { SYSDBG_IO_SPACE Request = *(PSYSDBG_IO_SPACE)InputBuffer; PVOID LockedBuffer; PMDL LockVariable;
Status = ExLockUserBuffer(Request.Buffer, Request.Request, PreviousMode, IoWriteAccess, &LockedBuffer, &LockVariable); if (NT_SUCCESS(Status)) { Status = KdpSysReadIoSpace(Request.InterfaceType, Request.BusNumber, Request.AddressSpace, Request.Address, LockedBuffer, Request.Request, &Length); ExUnlockUserBuffer(LockVariable); } } break;
case SysDbgWriteIoSpace: if (InputBufferLength != sizeof(SYSDBG_IO_SPACE)) { Status = STATUS_INFO_LENGTH_MISMATCH; } else { SYSDBG_IO_SPACE Request = *(PSYSDBG_IO_SPACE)InputBuffer; PVOID LockedBuffer; PMDL LockVariable;
Status = ExLockUserBuffer(Request.Buffer, Request.Request, PreviousMode, IoReadAccess, &LockedBuffer, &LockVariable); if (NT_SUCCESS(Status)) { Status = KdpSysWriteIoSpace(Request.InterfaceType, Request.BusNumber, Request.AddressSpace, Request.Address, LockedBuffer, Request.Request, &Length); ExUnlockUserBuffer(LockVariable); } } break;
case SysDbgReadMsr: if (InputBufferLength != sizeof(SYSDBG_MSR)) { Status = STATUS_INFO_LENGTH_MISMATCH; } else { PSYSDBG_MSR Request = (PSYSDBG_MSR)InputBuffer; Status = KdpSysReadMsr(Request->Address, &Request->Data); } break;
case SysDbgWriteMsr: if (InputBufferLength != sizeof(SYSDBG_MSR)) { Status = STATUS_INFO_LENGTH_MISMATCH; } else { PSYSDBG_MSR Request = (PSYSDBG_MSR)InputBuffer; Status = KdpSysWriteMsr(Request->Address, &Request->Data); } break;
case SysDbgReadBusData: if (InputBufferLength != sizeof(SYSDBG_BUS_DATA)) { Status = STATUS_INFO_LENGTH_MISMATCH; } else { SYSDBG_BUS_DATA Request = *(PSYSDBG_BUS_DATA)InputBuffer; PVOID LockedBuffer; PMDL LockVariable;
Status = ExLockUserBuffer(Request.Buffer, Request.Request, PreviousMode, IoWriteAccess, &LockedBuffer, &LockVariable); if (NT_SUCCESS(Status)) { Status = KdpSysReadBusData(Request.BusDataType, Request.BusNumber, Request.SlotNumber, Request.Address, LockedBuffer, Request.Request, &Length); ExUnlockUserBuffer(LockVariable); } } break;
case SysDbgWriteBusData: if (InputBufferLength != sizeof(SYSDBG_BUS_DATA)) { Status = STATUS_INFO_LENGTH_MISMATCH; } else { SYSDBG_BUS_DATA Request = *(PSYSDBG_BUS_DATA)InputBuffer; PVOID LockedBuffer; PMDL LockVariable;
Status = ExLockUserBuffer(Request.Buffer, Request.Request, PreviousMode, IoReadAccess, &LockedBuffer, &LockVariable); if (NT_SUCCESS(Status)) { Status = KdpSysWriteBusData(Request.BusDataType, Request.BusNumber, Request.SlotNumber, Request.Address, LockedBuffer, Request.Request, &Length); ExUnlockUserBuffer(LockVariable); } } break;
case SysDbgCheckLowMemory: Status = KdpSysCheckLowMemory(0); break;
default: Status = STATUS_INVALID_INFO_CLASS; break; }
if (ReturnLength) *ReturnLength = Length;
return Status;}
/* * @implemented */NTSTATUSNTAPIKdChangeOption(IN KD_OPTION Option, IN ULONG InBufferBytes OPTIONAL, IN PVOID InBuffer, IN ULONG OutBufferBytes OPTIONAL, OUT PVOID OutBuffer, OUT PULONG OutBufferNeeded OPTIONAL){ /* Fail if there is no debugger */ if (KdPitchDebugger) { /* No debugger, no options */ return STATUS_DEBUGGER_INACTIVE; }
/* Do we recognize this option? */ if (Option != KD_OPTION_SET_BLOCK_ENABLE) { /* We don't, clear the output length and fail */ if (OutBufferNeeded) *OutBufferNeeded = 0; return STATUS_INVALID_INFO_CLASS; }
/* Verify parameters */ if ((InBufferBytes != sizeof(BOOLEAN)) || (OutBufferBytes != 0) || (OutBuffer != NULL)) { /* Invalid parameters for this option, fail */ return STATUS_INVALID_PARAMETER; }
/* * Check if the high bit is set, meaning we don't * allow the debugger to be enabled */ if (KdBlockEnable & 0x80) { /* Fail regardless of what state the caller tried to set */ return STATUS_ACCESS_VIOLATION; }
/* Set the new block enable state */ KdBlockEnable = *(PBOOLEAN)InBuffer;
/* No output buffer required for this option */ if (OutBufferNeeded) *OutBufferNeeded = 0;
/* We are done */ return STATUS_SUCCESS;}
/* * @implemented */NTSTATUSNTAPIKdPowerTransition(IN DEVICE_POWER_STATE NewState){ /* Check what power state this is */ if (NewState == PowerDeviceD0) { /* Wake up the debug port */ KdD0Transition(); return STATUS_SUCCESS; } else if ((NewState == PowerDeviceD1) || (NewState == PowerDeviceD2) || (NewState == PowerDeviceD3)) { /* Power down the debug port */ KdD3Transition(); return STATUS_SUCCESS; } else { /* Invalid state! */ return STATUS_INVALID_PARAMETER_1; }}
/* * @implemented */BOOLEANNTAPIKdRefreshDebuggerNotPresent(VOID){ BOOLEAN Enable, DebuggerNotPresent;
/* Check if the debugger is completely disabled */ if (KdPitchDebugger) { /* Don't try to refresh then, fail early */ return TRUE; }
/* Enter the debugger */ Enable = KdEnterDebugger(NULL, NULL);
/* * Attempt to send a string to the debugger * to refresh the connection state. */ KdpDprintf("KDTARGET: Refreshing KD connection\n");
/* Save the state while we are holding the lock */ DebuggerNotPresent = KdDebuggerNotPresent;
/* Exit the debugger and return the state */ KdExitDebugger(Enable); return DebuggerNotPresent;}
/* * @implemented */NTSTATUSNTAPINtQueryDebugFilterState( _In_ ULONG ComponentId, _In_ ULONG Level){ PULONG Mask;
/* Check if the ID fits in the component table */ if (ComponentId < KdComponentTableSize) { /* It does, so get the mask from there */ Mask = KdComponentTable[ComponentId]; } else if (ComponentId == MAXULONG) { /* * This is the internal ID used for DbgPrint messages without ID * and Level. Use the system-wide mask for those. */ Mask = &Kd_WIN2000_Mask; } else {#if (NTDDI_VERSION >= NTDDI_VISTA) /* Use the default component ID */ Mask = &Kd_DEFAULT_Mask; // Level = DPFLTR_INFO_LEVEL; // Override the Level.#else /* Invalid ID, fail */ return STATUS_INVALID_PARAMETER_1;#endif }
/* Convert Level to bit field if required */ if (Level < 32) Level = 1 << Level; Level &= ~DPFLTR_MASK;
/* Determine if this Level is filtered out */ if ((Kd_WIN2000_Mask & Level) || (*Mask & Level)) { /* This mask will get through to the debugger */ return (NTSTATUS)TRUE; } else { /* This mask is filtered out */ return (NTSTATUS)FALSE; }}
/* * @implemented */NTSTATUSNTAPINtSetDebugFilterState( _In_ ULONG ComponentId, _In_ ULONG Level, _In_ BOOLEAN State){ PULONG Mask;
/* Modifying debug filters requires the debug privilege */ if (!SeSinglePrivilegeCheck(SeDebugPrivilege, ExGetPreviousMode())) { /* Fail */ return STATUS_ACCESS_DENIED; }
/* Check if the ID fits in the component table */ if (ComponentId < KdComponentTableSize) { /* It does, so get the mask from there */ Mask = KdComponentTable[ComponentId]; } else if (ComponentId == MAXULONG) { /* * This is the internal ID used for DbgPrint messages without ID * and Level. Use the system-wide mask for those. */ Mask = &Kd_WIN2000_Mask; } else {#if (NTDDI_VERSION >= NTDDI_VISTA) /* Use the default component ID */ Mask = &Kd_DEFAULT_Mask;#else /* Invalid ID, fail */ return STATUS_INVALID_PARAMETER_1;#endif }
/* Convert Level to bit field if required */ if (Level < 32) Level = 1 << Level; Level &= ~DPFLTR_MASK;
/* Set or remove the Level */ if (State) *Mask |= Level; else *Mask &= ~Level;
return STATUS_SUCCESS;}