1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/kd64/kdapi.c
5 * PURPOSE: KD64 Public Routines and Internal Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Stefan Ginsberg (stefan.ginsberg@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13
14 #ifdef KDBG
15 #include <kdbg/kdb.h>
16 #endif
17
18 #define NDEBUG
19 #include <debug.h>
20
21 VOID NTAPI PspDumpThreads(BOOLEAN SystemThreads);
22
23 /* PRIVATE FUNCTIONS *********************************************************/
24
25 VOID
26 NTAPI
KdpMoveMemory(_In_ PVOID Destination,_In_ PVOID Source,_In_ SIZE_T Length)27 KdpMoveMemory(
28 _In_ PVOID Destination,
29 _In_ PVOID Source,
30 _In_ SIZE_T Length)
31 {
32 PCHAR DestinationBytes, SourceBytes;
33
34 /* Copy the buffers 1 byte at a time */
35 DestinationBytes = Destination;
36 SourceBytes = Source;
37 while (Length--) *DestinationBytes++ = *SourceBytes++;
38 }
39
40 VOID
41 NTAPI
KdpZeroMemory(_In_ PVOID Destination,_In_ SIZE_T Length)42 KdpZeroMemory(
43 _In_ PVOID Destination,
44 _In_ SIZE_T Length)
45 {
46 PCHAR DestinationBytes;
47
48 /* Zero the buffer 1 byte at a time */
49 DestinationBytes = Destination;
50 while (Length--) *DestinationBytes++ = 0;
51 }
52
53 NTSTATUS
54 NTAPI
KdpCopyMemoryChunks(_In_ ULONG64 Address,_In_ PVOID Buffer,_In_ ULONG TotalSize,_In_ ULONG ChunkSize,_In_ ULONG Flags,_Out_opt_ PULONG ActualSize)55 KdpCopyMemoryChunks(
56 _In_ ULONG64 Address,
57 _In_ PVOID Buffer,
58 _In_ ULONG TotalSize,
59 _In_ ULONG ChunkSize,
60 _In_ ULONG Flags,
61 _Out_opt_ PULONG ActualSize)
62 {
63 NTSTATUS Status;
64 ULONG RemainingLength, CopyChunk;
65
66 /* Check if we didn't get a chunk size or if it is too big */
67 if (ChunkSize == 0)
68 {
69 /* Default to 4 byte chunks */
70 ChunkSize = 4;
71 }
72 else if (ChunkSize > MMDBG_COPY_MAX_SIZE)
73 {
74 /* Normalize to maximum size */
75 ChunkSize = MMDBG_COPY_MAX_SIZE;
76 }
77
78 /* Copy the whole range in aligned chunks */
79 RemainingLength = TotalSize;
80 CopyChunk = 1;
81 while (RemainingLength > 0)
82 {
83 /*
84 * Determine the best chunk size for this round.
85 * The ideal size is aligned, isn't larger than the
86 * the remaining length and respects the chunk limit.
87 */
88 while (((CopyChunk * 2) <= RemainingLength) &&
89 (CopyChunk < ChunkSize) &&
90 ((Address & ((CopyChunk * 2) - 1)) == 0))
91 {
92 /* Increase it */
93 CopyChunk *= 2;
94 }
95
96 /*
97 * The chunk size can be larger than the remaining size if this
98 * isn't the first round, so check if we need to shrink it back.
99 */
100 while (CopyChunk > RemainingLength)
101 {
102 /* Shrink it */
103 CopyChunk /= 2;
104 }
105
106 /* Do the copy */
107 Status = MmDbgCopyMemory(Address, Buffer, CopyChunk, Flags);
108 if (!NT_SUCCESS(Status))
109 {
110 /* Copy failed, break out */
111 break;
112 }
113
114 /* Update pointers and length for the next run */
115 Address = Address + CopyChunk;
116 Buffer = (PVOID)((ULONG_PTR)Buffer + CopyChunk);
117 RemainingLength = RemainingLength - CopyChunk;
118 }
119
120 /* We may have modified executable code, flush the instruction cache */
121 KeSweepICache((PVOID)(ULONG_PTR)Address, TotalSize);
122
123 /*
124 * Return the size we managed to copy and return
125 * success if we could copy the whole range.
126 */
127 if (ActualSize) *ActualSize = TotalSize - RemainingLength;
128 return RemainingLength == 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
129 }
130
131 VOID
132 NTAPI
KdpQueryMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PCONTEXT Context)133 KdpQueryMemory(IN PDBGKD_MANIPULATE_STATE64 State,
134 IN PCONTEXT Context)
135 {
136 PDBGKD_QUERY_MEMORY Memory = &State->u.QueryMemory;
137 STRING Header;
138 NTSTATUS Status = STATUS_SUCCESS;
139
140 /* Validate the address space */
141 if (Memory->AddressSpace == DBGKD_QUERY_MEMORY_VIRTUAL)
142 {
143 /* Check if this is process memory */
144 if ((PVOID)(ULONG_PTR)Memory->Address < MmHighestUserAddress)
145 {
146 /* It is */
147 Memory->AddressSpace = DBGKD_QUERY_MEMORY_PROCESS;
148 }
149 else
150 {
151 /* Check if it's session space */
152 if (MmIsSessionAddress((PVOID)(ULONG_PTR)Memory->Address))
153 {
154 /* It is */
155 Memory->AddressSpace = DBGKD_QUERY_MEMORY_SESSION;
156 }
157 else
158 {
159 /* Not session space but some other kernel memory */
160 Memory->AddressSpace = DBGKD_QUERY_MEMORY_KERNEL;
161 }
162 }
163
164 /* Set flags */
165 Memory->Flags = DBGKD_QUERY_MEMORY_READ |
166 DBGKD_QUERY_MEMORY_WRITE |
167 DBGKD_QUERY_MEMORY_EXECUTE;
168 }
169 else
170 {
171 /* Invalid */
172 Status = STATUS_INVALID_PARAMETER;
173 }
174
175 /* Return structure */
176 State->ReturnStatus = Status;
177 Memory->Reserved = 0;
178
179 /* Build header */
180 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
181 Header.Buffer = (PCHAR)State;
182
183 /* Send the packet */
184 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
185 &Header,
186 NULL,
187 &KdpContext);
188 }
189
190 VOID
191 NTAPI
KdpSearchMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)192 KdpSearchMemory(IN PDBGKD_MANIPULATE_STATE64 State,
193 IN PSTRING Data,
194 IN PCONTEXT Context)
195 {
196 //PDBGKD_SEARCH_MEMORY SearchMemory = &State->u.SearchMemory;
197 STRING Header;
198
199 /* TODO */
200 KdpDprintf("Memory Search support is unimplemented!\n");
201
202 /* Send a failure packet */
203 State->ReturnStatus = STATUS_UNSUCCESSFUL;
204 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
205 Header.Buffer = (PCHAR)State;
206 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
207 &Header,
208 NULL,
209 &KdpContext);
210 }
211
212 VOID
213 NTAPI
KdpFillMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)214 KdpFillMemory(IN PDBGKD_MANIPULATE_STATE64 State,
215 IN PSTRING Data,
216 IN PCONTEXT Context)
217 {
218 //PDBGKD_FILL_MEMORY FillMemory = &State->u.FillMemory;
219 STRING Header;
220
221 /* TODO */
222 KdpDprintf("Memory Fill support is unimplemented!\n");
223
224 /* Send a failure packet */
225 State->ReturnStatus = STATUS_UNSUCCESSFUL;
226 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
227 Header.Buffer = (PCHAR)State;
228 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
229 &Header,
230 NULL,
231 &KdpContext);
232 }
233
234 VOID
235 NTAPI
KdpWriteBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)236 KdpWriteBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,
237 IN PSTRING Data,
238 IN PCONTEXT Context)
239 {
240 PDBGKD_WRITE_BREAKPOINT64 Breakpoint = &State->u.WriteBreakPoint;
241 STRING Header;
242
243 /* Build header */
244 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
245 Header.Buffer = (PCHAR)State;
246 ASSERT(Data->Length == 0);
247
248 /* Create the breakpoint */
249 Breakpoint->BreakPointHandle =
250 KdpAddBreakpoint((PVOID)(ULONG_PTR)Breakpoint->BreakPointAddress);
251 if (!Breakpoint->BreakPointHandle)
252 {
253 /* We failed */
254 State->ReturnStatus = STATUS_UNSUCCESSFUL;
255 }
256 else
257 {
258 /* Success! */
259 State->ReturnStatus = STATUS_SUCCESS;
260 }
261
262 /* Send the packet */
263 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
264 &Header,
265 NULL,
266 &KdpContext);
267 }
268
269 VOID
270 NTAPI
KdpRestoreBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)271 KdpRestoreBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,
272 IN PSTRING Data,
273 IN PCONTEXT Context)
274 {
275 PDBGKD_RESTORE_BREAKPOINT RestoreBp = &State->u.RestoreBreakPoint;
276 STRING Header;
277
278 /* Fill out the header */
279 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
280 Header.Buffer = (PCHAR)State;
281 ASSERT(Data->Length == 0);
282
283 /* Get the version block */
284 if (KdpDeleteBreakpoint(RestoreBp->BreakPointHandle))
285 {
286 /* We're all good */
287 State->ReturnStatus = STATUS_SUCCESS;
288 }
289 else
290 {
291 /* We failed */
292 State->ReturnStatus = STATUS_UNSUCCESSFUL;
293 }
294
295 /* Send the packet */
296 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
297 &Header,
298 NULL,
299 &KdpContext);
300 }
301
302 NTSTATUS
303 NTAPI
KdpWriteBreakPointEx(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)304 KdpWriteBreakPointEx(IN PDBGKD_MANIPULATE_STATE64 State,
305 IN PSTRING Data,
306 IN PCONTEXT Context)
307 {
308 //PDBGKD_BREAKPOINTEX = &State->u.BreakPointEx;
309 STRING Header;
310
311 /* TODO */
312 KdpDprintf("Extended Breakpoint Write support is unimplemented!\n");
313
314 /* Send a failure packet */
315 State->ReturnStatus = STATUS_UNSUCCESSFUL;
316 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
317 Header.Buffer = (PCHAR)State;
318 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
319 &Header,
320 Data,
321 &KdpContext);
322 return STATUS_UNSUCCESSFUL;
323 }
324
325 VOID
326 NTAPI
KdpRestoreBreakPointEx(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)327 KdpRestoreBreakPointEx(IN PDBGKD_MANIPULATE_STATE64 State,
328 IN PSTRING Data,
329 IN PCONTEXT Context)
330 {
331 //PDBGKD_BREAKPOINTEX = &State->u.BreakPointEx;
332 STRING Header;
333
334 /* TODO */
335 KdpDprintf("Extended Breakpoint Restore support is unimplemented!\n");
336
337 /* Send a failure packet */
338 State->ReturnStatus = STATUS_UNSUCCESSFUL;
339 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
340 Header.Buffer = (PCHAR)State;
341 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
342 &Header,
343 Data,
344 &KdpContext);
345 }
346
347 VOID
348 NTAPI
KdpWriteCustomBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)349 KdpWriteCustomBreakpoint(IN PDBGKD_MANIPULATE_STATE64 State,
350 IN PSTRING Data,
351 IN PCONTEXT Context)
352 {
353 //PDBGKD_WRITE_CUSTOM_BREAKPOINT = &State->u.WriteCustomBreakpoint;
354 STRING Header;
355
356 /* Not supported */
357 KdpDprintf("Custom Breakpoint Write is unimplemented\n");
358
359 /* Send a failure packet */
360 State->ReturnStatus = STATUS_UNSUCCESSFUL;
361 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
362 Header.Buffer = (PCHAR)State;
363 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
364 &Header,
365 NULL,
366 &KdpContext);
367 }
368
369 VOID
370 NTAPI
DumpTraceData(IN PSTRING TraceData)371 DumpTraceData(IN PSTRING TraceData)
372 {
373 /* Update the buffer */
374 TraceDataBuffer[0] = TraceDataBufferPosition;
375
376 /* Setup the trace data */
377 TraceData->Length = (USHORT)(TraceDataBufferPosition * sizeof(ULONG));
378 TraceData->Buffer = (PCHAR)TraceDataBuffer;
379
380 /* Reset the buffer location */
381 TraceDataBufferPosition = 1;
382 }
383
384 VOID
385 NTAPI
KdpSetCommonState(IN ULONG NewState,IN PCONTEXT Context,IN PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange)386 KdpSetCommonState(IN ULONG NewState,
387 IN PCONTEXT Context,
388 IN PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange)
389 {
390 ULONG InstructionCount;
391 BOOLEAN HadBreakpoints;
392
393 /* Setup common stuff available for all CPU architectures */
394 WaitStateChange->NewState = NewState;
395 WaitStateChange->ProcessorLevel = KeProcessorLevel;
396 WaitStateChange->Processor = (USHORT)KeGetCurrentPrcb()->Number;
397 WaitStateChange->NumberProcessors = (ULONG)KeNumberProcessors;
398 WaitStateChange->Thread = (ULONG64)(LONG_PTR)KeGetCurrentThread();
399 WaitStateChange->ProgramCounter = (ULONG64)(LONG_PTR)KeGetContextPc(Context);
400
401 /* Zero out the entire Control Report */
402 KdpZeroMemory(&WaitStateChange->AnyControlReport,
403 sizeof(DBGKD_ANY_CONTROL_REPORT));
404
405 /* Now copy the instruction stream and set the count */
406 KdpCopyMemoryChunks((ULONG_PTR)WaitStateChange->ProgramCounter,
407 &WaitStateChange->ControlReport.InstructionStream[0],
408 DBGKD_MAXSTREAM,
409 0,
410 MMDBG_COPY_UNSAFE,
411 &InstructionCount);
412 WaitStateChange->ControlReport.InstructionCount = (USHORT)InstructionCount;
413
414 /* Clear all the breakpoints in this region */
415 HadBreakpoints =
416 KdpDeleteBreakpointRange((PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter,
417 (PVOID)((ULONG_PTR)WaitStateChange->ProgramCounter +
418 WaitStateChange->ControlReport.InstructionCount - 1));
419 if (HadBreakpoints)
420 {
421 /* Copy the instruction stream again, this time without breakpoints */
422 KdpCopyMemoryChunks((ULONG_PTR)WaitStateChange->ProgramCounter,
423 &WaitStateChange->ControlReport.InstructionStream[0],
424 InstructionCount,
425 0,
426 MMDBG_COPY_UNSAFE,
427 NULL);
428 }
429 }
430
431 VOID
432 NTAPI
KdpSysGetVersion(IN PDBGKD_GET_VERSION64 Version)433 KdpSysGetVersion(IN PDBGKD_GET_VERSION64 Version)
434 {
435 /* Copy the version block */
436 KdpMoveMemory(Version,
437 &KdVersionBlock,
438 sizeof(DBGKD_GET_VERSION64));
439 }
440
441 VOID
442 NTAPI
KdpGetVersion(IN PDBGKD_MANIPULATE_STATE64 State)443 KdpGetVersion(IN PDBGKD_MANIPULATE_STATE64 State)
444 {
445 STRING Header;
446
447 /* Fill out the header */
448 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
449 Header.Buffer = (PCHAR)State;
450
451 /* Get the version block */
452 KdpSysGetVersion(&State->u.GetVersion64);
453
454 /* Fill out the state */
455 State->ApiNumber = DbgKdGetVersionApi;
456 State->ReturnStatus = STATUS_SUCCESS;
457
458 /* Send the packet */
459 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
460 &Header,
461 NULL,
462 &KdpContext);
463 }
464
465 VOID
466 NTAPI
KdpReadVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)467 KdpReadVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,
468 IN PSTRING Data,
469 IN PCONTEXT Context)
470 {
471 PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
472 STRING Header;
473 ULONG Length = ReadMemory->TransferCount;
474
475 /* Setup the header */
476 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
477 Header.Buffer = (PCHAR)State;
478 ASSERT(Data->Length == 0);
479
480 /* Validate length */
481 if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
482 {
483 /* Overflow, set it to maximum possible */
484 Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
485 }
486
487 /* Do the read */
488 State->ReturnStatus = KdpCopyMemoryChunks(ReadMemory->TargetBaseAddress,
489 Data->Buffer,
490 Length,
491 0,
492 MMDBG_COPY_UNSAFE,
493 &Length);
494
495 /* Return the actual length read */
496 ReadMemory->ActualBytesRead = Length;
497 Data->Length = (USHORT)Length;
498
499 /* Send the packet */
500 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
501 &Header,
502 Data,
503 &KdpContext);
504 }
505
506 VOID
507 NTAPI
KdpWriteVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)508 KdpWriteVirtualMemory(IN PDBGKD_MANIPULATE_STATE64 State,
509 IN PSTRING Data,
510 IN PCONTEXT Context)
511 {
512 PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
513 STRING Header;
514
515 /* Setup the header */
516 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
517 Header.Buffer = (PCHAR)State;
518
519 /* Do the write */
520 State->ReturnStatus = KdpCopyMemoryChunks(WriteMemory->TargetBaseAddress,
521 Data->Buffer,
522 Data->Length,
523 0,
524 MMDBG_COPY_UNSAFE |
525 MMDBG_COPY_WRITE,
526 &WriteMemory->ActualBytesWritten);
527
528 /* Send the packet */
529 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
530 &Header,
531 NULL,
532 &KdpContext);
533 }
534
535 VOID
536 NTAPI
KdpReadPhysicalMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)537 KdpReadPhysicalMemory(IN PDBGKD_MANIPULATE_STATE64 State,
538 IN PSTRING Data,
539 IN PCONTEXT Context)
540 {
541 PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
542 STRING Header;
543 ULONG Length = ReadMemory->TransferCount;
544 ULONG Flags, CacheFlags;
545
546 /* Setup the header */
547 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
548 Header.Buffer = (PCHAR)State;
549 ASSERT(Data->Length == 0);
550
551 /* Validate length */
552 if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
553 {
554 /* Overflow, set it to maximum possible */
555 Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
556 }
557
558 /* Start with the default flags */
559 Flags = MMDBG_COPY_UNSAFE | MMDBG_COPY_PHYSICAL;
560
561 /* Get the caching flags and check if a type is specified */
562 CacheFlags = ReadMemory->ActualBytesRead;
563 if (CacheFlags == DBGKD_CACHING_CACHED)
564 {
565 /* Cached */
566 Flags |= MMDBG_COPY_CACHED;
567 }
568 else if (CacheFlags == DBGKD_CACHING_UNCACHED)
569 {
570 /* Uncached */
571 Flags |= MMDBG_COPY_UNCACHED;
572 }
573 else if (CacheFlags == DBGKD_CACHING_WRITE_COMBINED)
574 {
575 /* Write Combined */
576 Flags |= MMDBG_COPY_WRITE_COMBINED;
577 }
578
579 /* Do the read */
580 State->ReturnStatus = KdpCopyMemoryChunks(ReadMemory->TargetBaseAddress,
581 Data->Buffer,
582 Length,
583 0,
584 Flags,
585 &Length);
586
587 /* Return the actual length read */
588 ReadMemory->ActualBytesRead = Length;
589 Data->Length = (USHORT)Length;
590
591 /* Send the packet */
592 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
593 &Header,
594 Data,
595 &KdpContext);
596 }
597
598 VOID
599 NTAPI
KdpWritePhysicalMemory(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)600 KdpWritePhysicalMemory(IN PDBGKD_MANIPULATE_STATE64 State,
601 IN PSTRING Data,
602 IN PCONTEXT Context)
603 {
604 PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
605 STRING Header;
606 ULONG Flags, CacheFlags;
607
608 /* Setup the header */
609 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
610 Header.Buffer = (PCHAR)State;
611
612 /* Start with the default flags */
613 Flags = MMDBG_COPY_UNSAFE | MMDBG_COPY_WRITE | MMDBG_COPY_PHYSICAL;
614
615 /* Get the caching flags and check if a type is specified */
616 CacheFlags = WriteMemory->ActualBytesWritten;
617 if (CacheFlags == DBGKD_CACHING_CACHED)
618 {
619 /* Cached */
620 Flags |= MMDBG_COPY_CACHED;
621 }
622 else if (CacheFlags == DBGKD_CACHING_UNCACHED)
623 {
624 /* Uncached */
625 Flags |= MMDBG_COPY_UNCACHED;
626 }
627 else if (CacheFlags == DBGKD_CACHING_WRITE_COMBINED)
628 {
629 /* Write Combined */
630 Flags |= MMDBG_COPY_WRITE_COMBINED;
631 }
632
633 /* Do the write */
634 State->ReturnStatus = KdpCopyMemoryChunks(WriteMemory->TargetBaseAddress,
635 Data->Buffer,
636 Data->Length,
637 0,
638 Flags,
639 &WriteMemory->ActualBytesWritten);
640
641 /* Send the packet */
642 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
643 &Header,
644 NULL,
645 &KdpContext);
646 }
647
648 VOID
649 NTAPI
KdpReadControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)650 KdpReadControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,
651 IN PSTRING Data,
652 IN PCONTEXT Context)
653 {
654 PDBGKD_READ_MEMORY64 ReadMemory = &State->u.ReadMemory;
655 STRING Header;
656 ULONG Length;
657
658 /* Setup the header */
659 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
660 Header.Buffer = (PCHAR)State;
661 ASSERT(Data->Length == 0);
662
663 /* Check the length requested */
664 Length = ReadMemory->TransferCount;
665 if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
666 {
667 /* Use maximum allowed */
668 Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
669 }
670
671 /* Call the internal routine */
672 State->ReturnStatus = KdpSysReadControlSpace(State->Processor,
673 ReadMemory->TargetBaseAddress,
674 Data->Buffer,
675 Length,
676 &Length);
677
678 /* Return the actual length read */
679 ReadMemory->ActualBytesRead = Length;
680 Data->Length = (USHORT)Length;
681
682 /* Send the reply */
683 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
684 &Header,
685 Data,
686 &KdpContext);
687 }
688
689 VOID
690 NTAPI
KdpWriteControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)691 KdpWriteControlSpace(IN PDBGKD_MANIPULATE_STATE64 State,
692 IN PSTRING Data,
693 IN PCONTEXT Context)
694 {
695 PDBGKD_WRITE_MEMORY64 WriteMemory = &State->u.WriteMemory;
696 STRING Header;
697
698 /* Setup the header */
699 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
700 Header.Buffer = (PCHAR)State;
701
702 /* Call the internal routine */
703 State->ReturnStatus = KdpSysWriteControlSpace(State->Processor,
704 WriteMemory->TargetBaseAddress,
705 Data->Buffer,
706 Data->Length,
707 &WriteMemory->ActualBytesWritten);
708
709 /* Send the reply */
710 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
711 &Header,
712 Data,
713 &KdpContext);
714 }
715
716 VOID
717 NTAPI
KdpGetContext(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)718 KdpGetContext(IN PDBGKD_MANIPULATE_STATE64 State,
719 IN PSTRING Data,
720 IN PCONTEXT Context)
721 {
722 STRING Header;
723 PCONTEXT TargetContext;
724
725 /* Setup the header */
726 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
727 Header.Buffer = (PCHAR)State;
728 ASSERT(Data->Length == 0);
729
730 /* Make sure that this is a valid request */
731 if (State->Processor < KeNumberProcessors)
732 {
733 /* Check if the request is for this CPU */
734 if (State->Processor == KeGetCurrentPrcb()->Number)
735 {
736 /* We're just copying our own context */
737 TargetContext = Context;
738 }
739 else
740 {
741 /* Get the context from the PRCB array */
742 TargetContext = &KiProcessorBlock[State->Processor]->
743 ProcessorState.ContextFrame;
744 }
745
746 /* Copy it over to the debugger */
747 KdpMoveMemory(Data->Buffer,
748 TargetContext,
749 sizeof(CONTEXT));
750 Data->Length = sizeof(CONTEXT);
751
752 /* Let the debugger set the context now */
753 KdpContextSent = TRUE;
754
755 /* Finish up */
756 State->ReturnStatus = STATUS_SUCCESS;
757 }
758 else
759 {
760 /* Invalid request */
761 State->ReturnStatus = STATUS_UNSUCCESSFUL;
762 }
763
764 /* Send the reply */
765 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
766 &Header,
767 Data,
768 &KdpContext);
769 }
770
771 VOID
772 NTAPI
KdpSetContext(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)773 KdpSetContext(IN PDBGKD_MANIPULATE_STATE64 State,
774 IN PSTRING Data,
775 IN PCONTEXT Context)
776 {
777 STRING Header;
778 PCONTEXT TargetContext;
779
780 /* Setup the header */
781 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
782 Header.Buffer = (PCHAR)State;
783 ASSERT(Data->Length == sizeof(CONTEXT));
784
785 /* Make sure that this is a valid request */
786 if ((State->Processor < KeNumberProcessors) &&
787 (KdpContextSent))
788 {
789 /* Check if the request is for this CPU */
790 if (State->Processor == KeGetCurrentPrcb()->Number)
791 {
792 /* We're just copying our own context */
793 TargetContext = Context;
794 }
795 else
796 {
797 /* Get the context from the PRCB array */
798 TargetContext = &KiProcessorBlock[State->Processor]->
799 ProcessorState.ContextFrame;
800 }
801
802 /* Copy the new context to it */
803 KdpMoveMemory(TargetContext,
804 Data->Buffer,
805 sizeof(CONTEXT));
806
807 /* Finish up */
808 State->ReturnStatus = STATUS_SUCCESS;
809 }
810 else
811 {
812 /* Invalid request */
813 State->ReturnStatus = STATUS_UNSUCCESSFUL;
814 }
815
816 /* Send the reply */
817 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
818 &Header,
819 NULL,
820 &KdpContext);
821 }
822
823 VOID
824 NTAPI
KdpGetContextEx(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)825 KdpGetContextEx(IN PDBGKD_MANIPULATE_STATE64 State,
826 IN PSTRING Data,
827 IN PCONTEXT Context)
828 {
829 STRING Header;
830 PDBGKD_CONTEXT_EX ContextEx;
831 PCONTEXT TargetContext;
832 ASSERT(Data->Length == 0);
833
834 /* Get our struct */
835 ContextEx = &State->u.ContextEx;
836
837 /* Set up the header */
838 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
839 Header.Buffer = (PCHAR)State;
840
841 /* Make sure that this is a valid request */
842 if ((State->Processor < KeNumberProcessors) &&
843 (ContextEx->Offset + ContextEx->ByteCount) <= sizeof(CONTEXT))
844 {
845 /* Check if the request is for this CPU */
846 if (State->Processor == KeGetCurrentPrcb()->Number)
847 {
848 /* We're just copying our own context */
849 TargetContext = Context;
850 }
851 else
852 {
853 /* Get the context from the PRCB array */
854 TargetContext = &KiProcessorBlock[State->Processor]->
855 ProcessorState.ContextFrame;
856 }
857
858 /* Copy what is requested */
859 KdpMoveMemory(Data->Buffer,
860 (PVOID)((ULONG_PTR)TargetContext + ContextEx->Offset),
861 ContextEx->ByteCount);
862
863 /* KD copies all */
864 Data->Length = ContextEx->BytesCopied = ContextEx->ByteCount;
865
866 /* Let the debugger set the context now */
867 KdpContextSent = TRUE;
868
869 /* Finish up */
870 State->ReturnStatus = STATUS_SUCCESS;
871 }
872 else
873 {
874 /* Invalid request */
875 ContextEx->BytesCopied = 0;
876 State->ReturnStatus = STATUS_UNSUCCESSFUL;
877 }
878
879 /* Send the reply */
880 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
881 &Header,
882 Data,
883 &KdpContext);
884 }
885
886 VOID
887 NTAPI
KdpSetContextEx(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)888 KdpSetContextEx(IN PDBGKD_MANIPULATE_STATE64 State,
889 IN PSTRING Data,
890 IN PCONTEXT Context)
891 {
892 STRING Header;
893 PDBGKD_CONTEXT_EX ContextEx;
894 PCONTEXT TargetContext;
895
896 /* Get our struct */
897 ContextEx = &State->u.ContextEx;
898 ASSERT(Data->Length == ContextEx->ByteCount);
899
900 /* Set up the header */
901 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
902 Header.Buffer = (PCHAR)State;
903
904 /* Make sure that this is a valid request */
905 if ((State->Processor < KeNumberProcessors) &&
906 ((ContextEx->Offset + ContextEx->ByteCount) <= sizeof(CONTEXT)) &&
907 (KdpContextSent))
908 {
909 /* Check if the request is for this CPU */
910 if (State->Processor == KeGetCurrentPrcb()->Number)
911 {
912 /* We're just copying our own context */
913 TargetContext = Context;
914 }
915 else
916 {
917 /* Get the context from the PRCB array */
918 TargetContext = &KiProcessorBlock[State->Processor]->
919 ProcessorState.ContextFrame;
920 }
921
922 /* Copy what is requested */
923 KdpMoveMemory((PVOID)((ULONG_PTR)TargetContext + ContextEx->Offset),
924 Data->Buffer,
925 ContextEx->ByteCount);
926
927 /* KD copies all */
928 ContextEx->BytesCopied = ContextEx->ByteCount;
929
930 /* Finish up */
931 State->ReturnStatus = STATUS_SUCCESS;
932 }
933 else
934 {
935 /* Invalid request */
936 ContextEx->BytesCopied = 0;
937 State->ReturnStatus = STATUS_UNSUCCESSFUL;
938 }
939
940 /* Send the reply */
941 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
942 &Header,
943 NULL,
944 &KdpContext);
945 }
946
947 VOID
948 NTAPI
KdpCauseBugCheck(IN PDBGKD_MANIPULATE_STATE64 State)949 KdpCauseBugCheck(IN PDBGKD_MANIPULATE_STATE64 State)
950 {
951 /* Crash with the special code */
952 KeBugCheck(MANUALLY_INITIATED_CRASH);
953 }
954
955 VOID
956 NTAPI
KdpReadMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)957 KdpReadMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State,
958 IN PSTRING Data,
959 IN PCONTEXT Context)
960 {
961 STRING Header;
962 PDBGKD_READ_WRITE_MSR ReadMsr = &State->u.ReadWriteMsr;
963 LARGE_INTEGER MsrValue;
964
965 /* Setup the header */
966 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
967 Header.Buffer = (PCHAR)State;
968 ASSERT(Data->Length == 0);
969
970 /* Call the internal routine */
971 State->ReturnStatus = KdpSysReadMsr(ReadMsr->Msr,
972 &MsrValue);
973
974 /* Return the data */
975 ReadMsr->DataValueLow = MsrValue.LowPart;
976 ReadMsr->DataValueHigh = MsrValue.HighPart;
977
978 /* Send the reply */
979 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
980 &Header,
981 NULL,
982 &KdpContext);
983 }
984
985 VOID
986 NTAPI
KdpWriteMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)987 KdpWriteMachineSpecificRegister(IN PDBGKD_MANIPULATE_STATE64 State,
988 IN PSTRING Data,
989 IN PCONTEXT Context)
990 {
991 STRING Header;
992 PDBGKD_READ_WRITE_MSR WriteMsr = &State->u.ReadWriteMsr;
993 LARGE_INTEGER MsrValue;
994
995 /* Setup the header */
996 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
997 Header.Buffer = (PCHAR)State;
998 ASSERT(Data->Length == 0);
999
1000 /* Call the internal routine */
1001 MsrValue.LowPart = WriteMsr->DataValueLow;
1002 MsrValue.HighPart = WriteMsr->DataValueHigh;
1003 State->ReturnStatus = KdpSysWriteMsr(WriteMsr->Msr,
1004 &MsrValue);
1005
1006 /* Send the reply */
1007 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1008 &Header,
1009 NULL,
1010 &KdpContext);
1011 }
1012
1013 VOID
1014 NTAPI
KdpGetBusData(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)1015 KdpGetBusData(IN PDBGKD_MANIPULATE_STATE64 State,
1016 IN PSTRING Data,
1017 IN PCONTEXT Context)
1018 {
1019 STRING Header;
1020 PDBGKD_GET_SET_BUS_DATA GetBusData = &State->u.GetSetBusData;
1021 ULONG Length;
1022
1023 /* Setup the header */
1024 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1025 Header.Buffer = (PCHAR)State;
1026 ASSERT(Data->Length == 0);
1027
1028 /* Check the length requested */
1029 Length = GetBusData->Length;
1030 if (Length > (PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64)))
1031 {
1032 /* Use maximum allowed */
1033 Length = PACKET_MAX_SIZE - sizeof(DBGKD_MANIPULATE_STATE64);
1034 }
1035
1036 /* Call the internal routine */
1037 State->ReturnStatus = KdpSysReadBusData(GetBusData->BusDataType,
1038 GetBusData->BusNumber,
1039 GetBusData->SlotNumber,
1040 GetBusData->Offset,
1041 Data->Buffer,
1042 Length,
1043 &Length);
1044
1045 /* Return the actual length read */
1046 GetBusData->Length = Length;
1047 Data->Length = (USHORT)Length;
1048
1049 /* Send the reply */
1050 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1051 &Header,
1052 Data,
1053 &KdpContext);
1054 }
1055
1056 VOID
1057 NTAPI
KdpSetBusData(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)1058 KdpSetBusData(IN PDBGKD_MANIPULATE_STATE64 State,
1059 IN PSTRING Data,
1060 IN PCONTEXT Context)
1061 {
1062 STRING Header;
1063 PDBGKD_GET_SET_BUS_DATA SetBusData = &State->u.GetSetBusData;
1064 ULONG Length;
1065
1066 /* Setup the header */
1067 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1068 Header.Buffer = (PCHAR)State;
1069
1070 /* Call the internal routine */
1071 State->ReturnStatus = KdpSysWriteBusData(SetBusData->BusDataType,
1072 SetBusData->BusNumber,
1073 SetBusData->SlotNumber,
1074 SetBusData->Offset,
1075 Data->Buffer,
1076 SetBusData->Length,
1077 &Length);
1078
1079 /* Return the actual length written */
1080 SetBusData->Length = Length;
1081
1082 /* Send the reply */
1083 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1084 &Header,
1085 NULL,
1086 &KdpContext);
1087 }
1088
1089 VOID
1090 NTAPI
KdpReadIoSpace(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)1091 KdpReadIoSpace(IN PDBGKD_MANIPULATE_STATE64 State,
1092 IN PSTRING Data,
1093 IN PCONTEXT Context)
1094 {
1095 STRING Header;
1096 PDBGKD_READ_WRITE_IO64 ReadIo = &State->u.ReadWriteIo;
1097
1098 /* Setup the header */
1099 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1100 Header.Buffer = (PCHAR)State;
1101 ASSERT(Data->Length == 0);
1102
1103 /*
1104 * Clear the value so 1 or 2 byte reads
1105 * don't leave the higher bits unmodified
1106 */
1107 ReadIo->DataValue = 0;
1108
1109 /* Call the internal routine */
1110 State->ReturnStatus = KdpSysReadIoSpace(Isa,
1111 0,
1112 1,
1113 ReadIo->IoAddress,
1114 &ReadIo->DataValue,
1115 ReadIo->DataSize,
1116 &ReadIo->DataSize);
1117
1118 /* Send the reply */
1119 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1120 &Header,
1121 NULL,
1122 &KdpContext);
1123 }
1124
1125 VOID
1126 NTAPI
KdpWriteIoSpace(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)1127 KdpWriteIoSpace(IN PDBGKD_MANIPULATE_STATE64 State,
1128 IN PSTRING Data,
1129 IN PCONTEXT Context)
1130 {
1131 STRING Header;
1132 PDBGKD_READ_WRITE_IO64 WriteIo = &State->u.ReadWriteIo;
1133
1134 /* Setup the header */
1135 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1136 Header.Buffer = (PCHAR)State;
1137 ASSERT(Data->Length == 0);
1138
1139 /* Call the internal routine */
1140 State->ReturnStatus = KdpSysWriteIoSpace(Isa,
1141 0,
1142 1,
1143 WriteIo->IoAddress,
1144 &WriteIo->DataValue,
1145 WriteIo->DataSize,
1146 &WriteIo->DataSize);
1147
1148 /* Send the reply */
1149 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1150 &Header,
1151 NULL,
1152 &KdpContext);
1153 }
1154
1155 VOID
1156 NTAPI
KdpReadIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)1157 KdpReadIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State,
1158 IN PSTRING Data,
1159 IN PCONTEXT Context)
1160 {
1161 STRING Header;
1162 PDBGKD_READ_WRITE_IO_EXTENDED64 ReadIoExtended = &State->u.
1163 ReadWriteIoExtended;
1164
1165 /* Setup the header */
1166 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1167 Header.Buffer = (PCHAR)State;
1168 ASSERT(Data->Length == 0);
1169
1170 /*
1171 * Clear the value so 1 or 2 byte reads
1172 * don't leave the higher bits unmodified
1173 */
1174 ReadIoExtended->DataValue = 0;
1175
1176 /* Call the internal routine */
1177 State->ReturnStatus = KdpSysReadIoSpace(ReadIoExtended->InterfaceType,
1178 ReadIoExtended->BusNumber,
1179 ReadIoExtended->AddressSpace,
1180 ReadIoExtended->IoAddress,
1181 &ReadIoExtended->DataValue,
1182 ReadIoExtended->DataSize,
1183 &ReadIoExtended->DataSize);
1184
1185 /* Send the reply */
1186 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1187 &Header,
1188 NULL,
1189 &KdpContext);
1190 }
1191
1192 VOID
1193 NTAPI
KdpWriteIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State,IN PSTRING Data,IN PCONTEXT Context)1194 KdpWriteIoSpaceExtended(IN PDBGKD_MANIPULATE_STATE64 State,
1195 IN PSTRING Data,
1196 IN PCONTEXT Context)
1197 {
1198 STRING Header;
1199 PDBGKD_READ_WRITE_IO_EXTENDED64 WriteIoExtended = &State->u.
1200 ReadWriteIoExtended;
1201
1202 /* Setup the header */
1203 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1204 Header.Buffer = (PCHAR)State;
1205 ASSERT(Data->Length == 0);
1206
1207 /* Call the internal routine */
1208 State->ReturnStatus = KdpSysWriteIoSpace(WriteIoExtended->InterfaceType,
1209 WriteIoExtended->BusNumber,
1210 WriteIoExtended->AddressSpace,
1211 WriteIoExtended->IoAddress,
1212 &WriteIoExtended->DataValue,
1213 WriteIoExtended->DataSize,
1214 &WriteIoExtended->DataSize);
1215
1216 /* Send the reply */
1217 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1218 &Header,
1219 NULL,
1220 &KdpContext);
1221 }
1222
1223 VOID
1224 NTAPI
KdpCheckLowMemory(IN PDBGKD_MANIPULATE_STATE64 State)1225 KdpCheckLowMemory(IN PDBGKD_MANIPULATE_STATE64 State)
1226 {
1227 STRING Header;
1228
1229 /* Setup the header */
1230 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1231 Header.Buffer = (PCHAR)State;
1232
1233 /* Call the internal routine */
1234 State->ReturnStatus = KdpSysCheckLowMemory(MMDBG_COPY_UNSAFE);
1235
1236 /* Send the reply */
1237 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1238 &Header,
1239 NULL,
1240 &KdpContext);
1241 }
1242
1243 VOID
1244 NTAPI
KdpNotSupported(IN PDBGKD_MANIPULATE_STATE64 State)1245 KdpNotSupported(IN PDBGKD_MANIPULATE_STATE64 State)
1246 {
1247 STRING Header;
1248
1249 /* Set failure */
1250 State->ReturnStatus = STATUS_UNSUCCESSFUL;
1251
1252 /* Setup the packet */
1253 Header.Length = sizeof(DBGKD_MANIPULATE_STATE64);
1254 Header.Buffer = (PCHAR)State;
1255
1256 /* Send it */
1257 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1258 &Header,
1259 NULL,
1260 &KdpContext);
1261 }
1262
1263 static
1264 KCONTINUE_STATUS
KdpSwitchProcessor(_In_ USHORT ProcessorIndex)1265 KdpSwitchProcessor(
1266 _In_ USHORT ProcessorIndex)
1267 {
1268 /* Make sure that the processor index is valid */
1269 if (ProcessorIndex >= KeNumberProcessors)
1270 {
1271 KdpDprintf("%u is not a valid processor number\n", ProcessorIndex);
1272 return ContinueProcessorReselected;
1273 }
1274
1275 /* If the new processor is the current one, there is nothing to do */
1276 if (ProcessorIndex == KeGetCurrentProcessorNumber())
1277 {
1278 return ContinueProcessorReselected;
1279 }
1280
1281 /* Call the architecture specific Ke routine */
1282 return KxSwitchKdProcessor(ProcessorIndex);
1283 }
1284
1285 KCONTINUE_STATUS
1286 NTAPI
KdpSendWaitContinue(IN ULONG PacketType,IN PSTRING SendHeader,IN PSTRING SendData OPTIONAL,IN OUT PCONTEXT Context)1287 KdpSendWaitContinue(IN ULONG PacketType,
1288 IN PSTRING SendHeader,
1289 IN PSTRING SendData OPTIONAL,
1290 IN OUT PCONTEXT Context)
1291 {
1292 STRING Data, Header;
1293 DBGKD_MANIPULATE_STATE64 ManipulateState;
1294 ULONG Length;
1295 KDSTATUS RecvCode;
1296
1297 /* Setup the Manipulate State structure */
1298 Header.MaximumLength = sizeof(DBGKD_MANIPULATE_STATE64);
1299 Header.Buffer = (PCHAR)&ManipulateState;
1300 Data.MaximumLength = sizeof(KdpMessageBuffer);
1301 Data.Buffer = KdpMessageBuffer;
1302
1303 /*
1304 * Reset the context state to ensure the debugger has received
1305 * the current context before it sets it.
1306 */
1307 KdpContextSent = FALSE;
1308
1309 SendPacket:
1310 /* Send the Packet */
1311 KdSendPacket(PacketType, SendHeader, SendData, &KdpContext);
1312
1313 /* If the debugger isn't present anymore, just return success */
1314 if (KdDebuggerNotPresent) return ContinueSuccess;
1315
1316 /* Main processing Loop */
1317 for (;;)
1318 {
1319 /* Receive Loop */
1320 do
1321 {
1322 /* Wait to get a reply to our packet */
1323 RecvCode = KdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1324 &Header,
1325 &Data,
1326 &Length,
1327 &KdpContext);
1328
1329 /* If we got a resend request, do it */
1330 if (RecvCode == KdPacketNeedsResend) goto SendPacket;
1331 } while (RecvCode == KdPacketTimedOut);
1332
1333 /* Now check what API we got */
1334 switch (ManipulateState.ApiNumber)
1335 {
1336 case DbgKdReadVirtualMemoryApi:
1337
1338 /* Read virtual memory */
1339 KdpReadVirtualMemory(&ManipulateState, &Data, Context);
1340 break;
1341
1342 case DbgKdWriteVirtualMemoryApi:
1343
1344 /* Write virtual memory */
1345 KdpWriteVirtualMemory(&ManipulateState, &Data, Context);
1346 break;
1347
1348 case DbgKdGetContextApi:
1349
1350 /* Get the current context */
1351 KdpGetContext(&ManipulateState, &Data, Context);
1352 break;
1353
1354 case DbgKdSetContextApi:
1355
1356 /* Set a new context */
1357 KdpSetContext(&ManipulateState, &Data, Context);
1358 break;
1359
1360 case DbgKdWriteBreakPointApi:
1361
1362 /* Write the breakpoint */
1363 KdpWriteBreakpoint(&ManipulateState, &Data, Context);
1364 break;
1365
1366 case DbgKdRestoreBreakPointApi:
1367
1368 /* Restore the breakpoint */
1369 KdpRestoreBreakpoint(&ManipulateState, &Data, Context);
1370 break;
1371
1372 case DbgKdContinueApi:
1373
1374 /* Simply continue */
1375 return NT_SUCCESS(ManipulateState.u.Continue.ContinueStatus);
1376
1377 case DbgKdReadControlSpaceApi:
1378
1379 /* Read control space */
1380 KdpReadControlSpace(&ManipulateState, &Data, Context);
1381 break;
1382
1383 case DbgKdWriteControlSpaceApi:
1384
1385 /* Write control space */
1386 KdpWriteControlSpace(&ManipulateState, &Data, Context);
1387 break;
1388
1389 case DbgKdReadIoSpaceApi:
1390
1391 /* Read I/O Space */
1392 KdpReadIoSpace(&ManipulateState, &Data, Context);
1393 break;
1394
1395 case DbgKdWriteIoSpaceApi:
1396
1397 /* Write I/O Space */
1398 KdpWriteIoSpace(&ManipulateState, &Data, Context);
1399 break;
1400
1401 case DbgKdRebootApi:
1402
1403 /* Reboot the system */
1404 HalReturnToFirmware(HalRebootRoutine);
1405 break;
1406
1407 case DbgKdContinueApi2:
1408
1409 /* Check if caller reports success */
1410 if (NT_SUCCESS(ManipulateState.u.Continue2.ContinueStatus))
1411 {
1412 /* Update the state */
1413 KdpGetStateChange(&ManipulateState, Context);
1414 return ContinueSuccess;
1415 }
1416 else
1417 {
1418 /* Return an error */
1419 return ContinueError;
1420 }
1421
1422 case DbgKdReadPhysicalMemoryApi:
1423
1424 /* Read physical memory */
1425 KdpReadPhysicalMemory(&ManipulateState, &Data, Context);
1426 break;
1427
1428 case DbgKdWritePhysicalMemoryApi:
1429
1430 /* Write physical memory */
1431 KdpWritePhysicalMemory(&ManipulateState, &Data, Context);
1432 break;
1433
1434 case DbgKdQuerySpecialCallsApi:
1435 case DbgKdSetSpecialCallApi:
1436 case DbgKdClearSpecialCallsApi:
1437
1438 /* TODO */
1439 KdpDprintf("Special Call support is unimplemented!\n");
1440 KdpNotSupported(&ManipulateState);
1441 break;
1442
1443 case DbgKdSetInternalBreakPointApi:
1444 case DbgKdGetInternalBreakPointApi:
1445
1446 /* TODO */
1447 KdpDprintf("Internal Breakpoint support is unimplemented!\n");
1448 KdpNotSupported(&ManipulateState);
1449 break;
1450
1451 case DbgKdReadIoSpaceExtendedApi:
1452
1453 /* Read I/O Space */
1454 KdpReadIoSpaceExtended(&ManipulateState, &Data, Context);
1455 break;
1456
1457 case DbgKdWriteIoSpaceExtendedApi:
1458
1459 /* Write I/O Space */
1460 KdpWriteIoSpaceExtended(&ManipulateState, &Data, Context);
1461 break;
1462
1463 case DbgKdGetVersionApi:
1464
1465 /* Get version data */
1466 KdpGetVersion(&ManipulateState);
1467 break;
1468
1469 case DbgKdWriteBreakPointExApi:
1470
1471 /* Write the breakpoint and check if it failed */
1472 if (!NT_SUCCESS(KdpWriteBreakPointEx(&ManipulateState,
1473 &Data,
1474 Context)))
1475 {
1476 /* Return an error */
1477 return ContinueError;
1478 }
1479 break;
1480
1481 case DbgKdRestoreBreakPointExApi:
1482
1483 /* Restore the breakpoint */
1484 KdpRestoreBreakPointEx(&ManipulateState, &Data, Context);
1485 break;
1486
1487 case DbgKdCauseBugCheckApi:
1488
1489 /* Crash the system */
1490 KdpCauseBugCheck(&ManipulateState);
1491 break;
1492
1493 case DbgKdSwitchProcessor:
1494
1495 /* Switch the processor and return */
1496 return KdpSwitchProcessor(ManipulateState.Processor);
1497
1498 case DbgKdPageInApi:
1499
1500 /* This API, introduced in NT4, has been obsoleted in NT5. It is
1501 * replaced by ExpDebuggerPageIn support in ExpDebuggerWorker(). */
1502 KdpDprintf("DbgKdPageInApi is obsolete!\n");
1503 KdpNotSupported(&ManipulateState);
1504 break;
1505
1506 case DbgKdReadMachineSpecificRegister:
1507
1508 /* Read from the specified MSR */
1509 KdpReadMachineSpecificRegister(&ManipulateState, &Data, Context);
1510 break;
1511
1512 case DbgKdWriteMachineSpecificRegister:
1513
1514 /* Write to the specified MSR */
1515 KdpWriteMachineSpecificRegister(&ManipulateState, &Data, Context);
1516 break;
1517
1518 case DbgKdSearchMemoryApi:
1519
1520 /* Search memory */
1521 KdpSearchMemory(&ManipulateState, &Data, Context);
1522 break;
1523
1524 case DbgKdGetBusDataApi:
1525
1526 /* Read from the bus */
1527 KdpGetBusData(&ManipulateState, &Data, Context);
1528 break;
1529
1530 case DbgKdSetBusDataApi:
1531
1532 /* Write to the bus */
1533 KdpSetBusData(&ManipulateState, &Data, Context);
1534 break;
1535
1536 case DbgKdCheckLowMemoryApi:
1537
1538 /* Check for memory corruption in the lower 4 GB */
1539 KdpCheckLowMemory(&ManipulateState);
1540 break;
1541
1542 case DbgKdClearAllInternalBreakpointsApi:
1543
1544 /* Just clear the counter */
1545 KdpNumInternalBreakpoints = 0;
1546 break;
1547
1548 case DbgKdFillMemoryApi:
1549
1550 /* Fill memory */
1551 KdpFillMemory(&ManipulateState, &Data, Context);
1552 break;
1553
1554 case DbgKdQueryMemoryApi:
1555
1556 /* Query memory */
1557 KdpQueryMemory(&ManipulateState, Context);
1558 break;
1559
1560 case DbgKdSwitchPartition:
1561
1562 /* TODO */
1563 KdpDprintf("Partition Switch support is unimplemented!\n");
1564 KdpNotSupported(&ManipulateState);
1565 break;
1566
1567 case DbgKdWriteCustomBreakpointApi:
1568
1569 /* Write the customized breakpoint */
1570 KdpWriteCustomBreakpoint(&ManipulateState, &Data, Context);
1571 break;
1572
1573 case DbgKdGetContextExApi:
1574
1575 /* Extended Context Get */
1576 KdpGetContextEx(&ManipulateState, &Data, Context);
1577 break;
1578
1579 case DbgKdSetContextExApi:
1580
1581 /* Extended Context Set */
1582 KdpSetContextEx(&ManipulateState, &Data, Context);
1583 break;
1584
1585 /* Unsupported Messages */
1586 default:
1587
1588 /* Send warning */
1589 KdpDprintf("Received Unrecognized API 0x%lx\n", ManipulateState.ApiNumber);
1590
1591 /* Setup an empty message, with failure */
1592 Data.Length = 0;
1593 ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
1594
1595 /* Send it */
1596 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
1597 &Header,
1598 &Data,
1599 &KdpContext);
1600 break;
1601 }
1602 }
1603 }
1604
1605 VOID
1606 NTAPI
KdpReportLoadSymbolsStateChange(IN PSTRING PathName,IN PKD_SYMBOLS_INFO SymbolInfo,IN BOOLEAN Unload,IN OUT PCONTEXT Context)1607 KdpReportLoadSymbolsStateChange(IN PSTRING PathName,
1608 IN PKD_SYMBOLS_INFO SymbolInfo,
1609 IN BOOLEAN Unload,
1610 IN OUT PCONTEXT Context)
1611 {
1612 PSTRING ExtraData;
1613 STRING Data, Header;
1614 DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
1615 ULONG PathNameLength;
1616 KCONTINUE_STATUS Status;
1617
1618 /* Start wait loop */
1619 do
1620 {
1621 /* Build the architecture common parts of the message */
1622 KdpSetCommonState(DbgKdLoadSymbolsStateChange,
1623 Context,
1624 &WaitStateChange);
1625
1626 /* Now finish creating the structure */
1627 KdpSetContextState(&WaitStateChange, Context);
1628
1629 /* Fill out load data */
1630 WaitStateChange.u.LoadSymbols.UnloadSymbols = Unload;
1631 WaitStateChange.u.LoadSymbols.BaseOfDll = (ULONG64)(LONG_PTR)SymbolInfo->BaseOfDll;
1632 WaitStateChange.u.LoadSymbols.ProcessId = SymbolInfo->ProcessId;
1633 WaitStateChange.u.LoadSymbols.CheckSum = SymbolInfo->CheckSum;
1634 WaitStateChange.u.LoadSymbols.SizeOfImage = SymbolInfo->SizeOfImage;
1635
1636 /* Check if we have a path name */
1637 if (PathName)
1638 {
1639 /* Copy it to the path buffer */
1640 KdpCopyMemoryChunks((ULONG_PTR)PathName->Buffer,
1641 KdpPathBuffer,
1642 PathName->Length,
1643 0,
1644 MMDBG_COPY_UNSAFE,
1645 &PathNameLength);
1646
1647 /* Null terminate */
1648 KdpPathBuffer[PathNameLength++] = ANSI_NULL;
1649
1650 /* Set the path length */
1651 WaitStateChange.u.LoadSymbols.PathNameLength = PathNameLength;
1652
1653 /* Set up the data */
1654 Data.Buffer = KdpPathBuffer;
1655 Data.Length = (USHORT)PathNameLength;
1656 ExtraData = &Data;
1657 }
1658 else
1659 {
1660 /* No name */
1661 WaitStateChange.u.LoadSymbols.PathNameLength = 0;
1662 ExtraData = NULL;
1663 }
1664
1665 /* Setup the header */
1666 Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
1667 Header.Buffer = (PCHAR)&WaitStateChange;
1668
1669 /* Send the packet */
1670 Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1671 &Header,
1672 ExtraData,
1673 Context);
1674 } while (Status == ContinueProcessorReselected);
1675 }
1676
1677 VOID
1678 NTAPI
KdpReportCommandStringStateChange(IN PSTRING NameString,IN PSTRING CommandString,IN OUT PCONTEXT Context)1679 KdpReportCommandStringStateChange(IN PSTRING NameString,
1680 IN PSTRING CommandString,
1681 IN OUT PCONTEXT Context)
1682 {
1683 STRING Header, Data;
1684 DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
1685 ULONG Length, ActualLength, TotalLength;
1686 KCONTINUE_STATUS Status;
1687
1688 /* Start wait loop */
1689 do
1690 {
1691 /* Build the architecture common parts of the message */
1692 KdpSetCommonState(DbgKdCommandStringStateChange,
1693 Context,
1694 &WaitStateChange);
1695
1696 /* Set the context */
1697 KdpSetContextState(&WaitStateChange, Context);
1698
1699 /* Clear the command string structure */
1700 KdpZeroMemory(&WaitStateChange.u.CommandString,
1701 sizeof(DBGKD_COMMAND_STRING));
1702
1703 /* Normalize name string to max */
1704 Length = min(128 - 1, NameString->Length);
1705
1706 /* Copy it to the message buffer */
1707 KdpCopyMemoryChunks((ULONG_PTR)NameString->Buffer,
1708 KdpMessageBuffer,
1709 Length,
1710 0,
1711 MMDBG_COPY_UNSAFE,
1712 &ActualLength);
1713
1714 /* Null terminate and calculate the total length */
1715 TotalLength = ActualLength;
1716 KdpMessageBuffer[TotalLength++] = ANSI_NULL;
1717
1718 /* Check if the command string is too long */
1719 Length = CommandString->Length;
1720 if (Length > (PACKET_MAX_SIZE -
1721 sizeof(DBGKD_ANY_WAIT_STATE_CHANGE) - TotalLength))
1722 {
1723 /* Use maximum possible size */
1724 Length = (PACKET_MAX_SIZE -
1725 sizeof(DBGKD_ANY_WAIT_STATE_CHANGE) - TotalLength);
1726 }
1727
1728 /* Copy it to the message buffer */
1729 KdpCopyMemoryChunks((ULONG_PTR)CommandString->Buffer,
1730 KdpMessageBuffer + TotalLength,
1731 Length,
1732 0,
1733 MMDBG_COPY_UNSAFE,
1734 &ActualLength);
1735
1736 /* Null terminate and calculate the total length */
1737 TotalLength += ActualLength;
1738 KdpMessageBuffer[TotalLength++] = ANSI_NULL;
1739
1740 /* Now set up the header and the data */
1741 Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
1742 Header.Buffer = (PCHAR)&WaitStateChange;
1743 Data.Length = (USHORT)TotalLength;
1744 Data.Buffer = KdpMessageBuffer;
1745
1746 /* Send State Change packet and wait for a reply */
1747 Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1748 &Header,
1749 &Data,
1750 Context);
1751 } while (Status == ContinueProcessorReselected);
1752 }
1753
1754 BOOLEAN
1755 NTAPI
KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,IN OUT PCONTEXT Context,IN BOOLEAN SecondChanceException)1756 KdpReportExceptionStateChange(IN PEXCEPTION_RECORD ExceptionRecord,
1757 IN OUT PCONTEXT Context,
1758 IN BOOLEAN SecondChanceException)
1759 {
1760 STRING Header, Data;
1761 DBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange;
1762 KCONTINUE_STATUS Status;
1763
1764 /* Start report loop */
1765 do
1766 {
1767 /* Build the architecture common parts of the message */
1768 KdpSetCommonState(DbgKdExceptionStateChange, Context, &WaitStateChange);
1769
1770 #if !defined(_WIN64)
1771
1772 /* Convert it and copy it over */
1773 ExceptionRecord32To64((PEXCEPTION_RECORD32)ExceptionRecord,
1774 &WaitStateChange.u.Exception.ExceptionRecord);
1775
1776 #else
1777
1778 /* Just copy it directly, no need to convert */
1779 KdpMoveMemory(&WaitStateChange.u.Exception.ExceptionRecord,
1780 ExceptionRecord,
1781 sizeof(EXCEPTION_RECORD));
1782
1783 #endif
1784
1785 /* Set the First Chance flag */
1786 WaitStateChange.u.Exception.FirstChance = !SecondChanceException;
1787
1788 /* Now finish creating the structure */
1789 KdpSetContextState(&WaitStateChange, Context);
1790
1791 /* Setup the actual header to send to KD */
1792 Header.Length = sizeof(DBGKD_ANY_WAIT_STATE_CHANGE);
1793 Header.Buffer = (PCHAR)&WaitStateChange;
1794
1795 /* Setup the trace data */
1796 DumpTraceData(&Data);
1797
1798 /* Send State Change packet and wait for a reply */
1799 Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
1800 &Header,
1801 &Data,
1802 Context);
1803 } while (Status == ContinueProcessorReselected);
1804
1805 /* Return */
1806 return Status;
1807 }
1808
1809 KCONTINUE_STATUS
1810 NTAPI
KdReportProcessorChange(VOID)1811 KdReportProcessorChange(
1812 VOID)
1813 {
1814 PKPRCB CurrentPrcb = KeGetCurrentPrcb();
1815 PCONTEXT ContextRecord = &CurrentPrcb->ProcessorState.ContextFrame;
1816 EXCEPTION_RECORD ExceptionRecord = {0};
1817 KCONTINUE_STATUS Status;
1818
1819 /* Save the port data */
1820 KdSave(FALSE);
1821
1822 ExceptionRecord.ExceptionAddress = (PVOID)KeGetContextPc(ContextRecord);
1823 ExceptionRecord.ExceptionCode = STATUS_WAKE_SYSTEM_DEBUGGER;
1824
1825 /* Report the new state */
1826 Status = KdpReportExceptionStateChange(&ExceptionRecord,
1827 ContextRecord,
1828 FALSE);
1829
1830 /* Restore the port data */
1831 KdRestore(FALSE);
1832
1833 return Status;
1834 }
1835
1836 VOID
1837 NTAPI
KdpTimeSlipDpcRoutine(IN PKDPC Dpc,IN PVOID DeferredContext,IN PVOID SystemArgument1,IN PVOID SystemArgument2)1838 KdpTimeSlipDpcRoutine(IN PKDPC Dpc,
1839 IN PVOID DeferredContext,
1840 IN PVOID SystemArgument1,
1841 IN PVOID SystemArgument2)
1842 {
1843 LONG OldSlip, NewSlip, PendingSlip;
1844
1845 /* Get the current pending slip */
1846 PendingSlip = KdpTimeSlipPending;
1847 do
1848 {
1849 /* Save the old value and either disable or enable it now. */
1850 OldSlip = PendingSlip;
1851 NewSlip = OldSlip > 1 ? 1 : 0;
1852
1853 /* Try to change the value */
1854 } while (InterlockedCompareExchange(&KdpTimeSlipPending,
1855 NewSlip,
1856 OldSlip) != OldSlip);
1857
1858 /* If the New Slip value is 1, then do the Time Slipping */
1859 if (NewSlip) ExQueueWorkItem(&KdpTimeSlipWorkItem, DelayedWorkQueue);
1860 }
1861
1862 VOID
1863 NTAPI
KdpTimeSlipWork(IN PVOID Context)1864 KdpTimeSlipWork(IN PVOID Context)
1865 {
1866 KIRQL OldIrql;
1867 LARGE_INTEGER DueTime;
1868
1869 /* Update the System time from the CMOS */
1870 ExAcquireTimeRefreshLock(FALSE);
1871 ExUpdateSystemTimeFromCmos(FALSE, 0);
1872 ExReleaseTimeRefreshLock();
1873
1874 /* Check if we have a registered Time Slip Event and signal it */
1875 KeAcquireSpinLock(&KdpTimeSlipEventLock, &OldIrql);
1876 if (KdpTimeSlipEvent) KeSetEvent(KdpTimeSlipEvent, 0, FALSE);
1877 KeReleaseSpinLock(&KdpTimeSlipEventLock, OldIrql);
1878
1879 /* Delay the DPC until it runs next time */
1880 DueTime.QuadPart = -1800000000;
1881 KeSetTimer(&KdpTimeSlipTimer, DueTime, &KdpTimeSlipDpc);
1882 }
1883
1884 LARGE_INTEGER
1885 NTAPI
KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)1886 KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)
1887 {
1888 LARGE_INTEGER Null = {{0}};
1889
1890 /* Check if interrupts were disabled */
1891 if (!KeGetTrapFrameInterruptState(TrapFrame))
1892 {
1893 /* Nothing to return */
1894 return Null;
1895 }
1896
1897 /* Otherwise, do the call */
1898 return KeQueryPerformanceCounter(NULL);
1899 }
1900
1901 BOOLEAN
1902 NTAPI
KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,IN PKEXCEPTION_FRAME ExceptionFrame)1903 KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,
1904 IN PKEXCEPTION_FRAME ExceptionFrame)
1905 {
1906 BOOLEAN Enable;
1907
1908 /* Check if we have a trap frame */
1909 if (TrapFrame)
1910 {
1911 /* Calculate the time difference for the enter */
1912 KdTimerStop = KdpQueryPerformanceCounter(TrapFrame);
1913 KdTimerDifference.QuadPart = KdTimerStop.QuadPart -
1914 KdTimerStart.QuadPart;
1915 }
1916 else
1917 {
1918 /* No trap frame, so can't calculate */
1919 KdTimerStop.QuadPart = 0;
1920 }
1921
1922 /* Save the current IRQL */
1923 KeGetCurrentPrcb()->DebuggerSavedIRQL = KeGetCurrentIrql();
1924
1925 /* Freeze all CPUs, raising also the IRQL to HIGH_LEVEL */
1926 Enable = KeFreezeExecution(TrapFrame, ExceptionFrame);
1927
1928 /* Lock the port, save the state and set debugger entered */
1929 KdpPortLocked = KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock);
1930 KdSave(FALSE);
1931 KdEnteredDebugger = TRUE;
1932
1933 /* Check freeze flag */
1934 if (KiFreezeFlag & 1)
1935 {
1936 /* Print out errror */
1937 KdpDprintf("FreezeLock was jammed! Backup SpinLock was used!\n");
1938 }
1939
1940 /* Check processor state */
1941 if (KiFreezeFlag & 2)
1942 {
1943 /* Print out errror */
1944 KdpDprintf("Some processors not frozen in debugger!\n");
1945 }
1946
1947 /* Make sure we acquired the port */
1948 if (!KdpPortLocked) KdpDprintf("Port lock was not acquired!\n");
1949
1950 /* Return if interrupts needs to be re-enabled */
1951 return Enable;
1952 }
1953
1954 VOID
1955 NTAPI
KdExitDebugger(IN BOOLEAN Enable)1956 KdExitDebugger(IN BOOLEAN Enable)
1957 {
1958 ULONG TimeSlip;
1959
1960 /* Restore the state and unlock the port */
1961 KdRestore(FALSE);
1962 if (KdpPortLocked) KdpPortUnlock();
1963
1964 /* Unfreeze the CPUs, restoring also the IRQL */
1965 KeThawExecution(Enable);
1966
1967 /* Compare time with the one from KdEnterDebugger */
1968 if (!KdTimerStop.QuadPart)
1969 {
1970 /* We didn't get a trap frame earlier in so never got the time */
1971 KdTimerStart = KdTimerStop;
1972 }
1973 else
1974 {
1975 /* Query the timer */
1976 KdTimerStart = KeQueryPerformanceCounter(NULL);
1977 }
1978
1979 /* Check if a Time Slip was on queue */
1980 TimeSlip = InterlockedIncrement(&KdpTimeSlipPending);
1981 if (TimeSlip == 1)
1982 {
1983 /* Queue a DPC for the time slip */
1984 InterlockedIncrement(&KdpTimeSlipPending);
1985 KeInsertQueueDpc(&KdpTimeSlipDpc, NULL, NULL); // FIXME: this can trigger context switches!
1986 }
1987 }
1988
1989 NTSTATUS
1990 NTAPI
KdEnableDebuggerWithLock(IN BOOLEAN NeedLock)1991 KdEnableDebuggerWithLock(IN BOOLEAN NeedLock)
1992 {
1993 KIRQL OldIrql;
1994
1995 #if defined(__GNUC__)
1996 /* Make gcc happy */
1997 OldIrql = PASSIVE_LEVEL;
1998 #endif
1999
2000 /* Check if enabling the debugger is blocked */
2001 if (KdBlockEnable)
2002 {
2003 /* It is, fail the enable */
2004 return STATUS_ACCESS_DENIED;
2005 }
2006
2007 /* Check if we need to acquire the lock */
2008 if (NeedLock)
2009 {
2010 /* Lock the port */
2011 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
2012 KdpPortLock();
2013 }
2014
2015 /* Check if we're not disabled */
2016 if (!KdDisableCount)
2017 {
2018 /* Check if we had locked the port before */
2019 if (NeedLock)
2020 {
2021 /* Do the unlock */
2022 KdpPortUnlock();
2023 KeLowerIrql(OldIrql);
2024
2025 /* Fail: We're already enabled */
2026 return STATUS_INVALID_PARAMETER;
2027 }
2028 else
2029 {
2030 /*
2031 * This can only happen if we are called from a bugcheck
2032 * and were never initialized, so initialize the debugger now.
2033 */
2034 KdInitSystem(0, NULL);
2035
2036 /* Return success since we initialized */
2037 return STATUS_SUCCESS;
2038 }
2039 }
2040
2041 /* Decrease the disable count */
2042 if (!(--KdDisableCount))
2043 {
2044 /* We're now enabled again! Were we enabled before, too? */
2045 if (KdPreviouslyEnabled)
2046 {
2047 /* Reinitialize the Debugger */
2048 KdInitSystem(0, NULL);
2049 KdpRestoreAllBreakpoints();
2050 }
2051 }
2052
2053 /* Check if we had locked the port before */
2054 if (NeedLock)
2055 {
2056 /* Yes, now unlock it */
2057 KdpPortUnlock();
2058 KeLowerIrql(OldIrql);
2059 }
2060
2061 /* We're done */
2062 return STATUS_SUCCESS;
2063 }
2064
2065 NTSTATUS
2066 NTAPI
KdDisableDebuggerWithLock(IN BOOLEAN NeedLock)2067 KdDisableDebuggerWithLock(IN BOOLEAN NeedLock)
2068 {
2069 KIRQL OldIrql;
2070 NTSTATUS Status;
2071
2072 #if defined(__GNUC__)
2073 /* Make gcc happy */
2074 OldIrql = PASSIVE_LEVEL;
2075 #endif
2076
2077 /*
2078 * If enabling the debugger is blocked
2079 * then there is nothing to disable (duh)
2080 */
2081 if (KdBlockEnable)
2082 {
2083 /* Fail */
2084 return STATUS_ACCESS_DENIED;
2085 }
2086
2087 /* Check if we need to acquire the lock */
2088 if (NeedLock)
2089 {
2090 /* Lock the port */
2091 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
2092 KdpPortLock();
2093 }
2094
2095 /* Check if we're not disabled */
2096 if (!KdDisableCount)
2097 {
2098 /* Check if the debugger was never actually initialized */
2099 if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
2100 {
2101 /* It wasn't, so don't re-enable it later */
2102 KdPreviouslyEnabled = FALSE;
2103 }
2104 else
2105 {
2106 /* It was, so we will re-enable it later */
2107 KdPreviouslyEnabled = TRUE;
2108 }
2109
2110 /* Check if we were called from the exported API and are enabled */
2111 if ((NeedLock) && (KdPreviouslyEnabled))
2112 {
2113 /* Check if it is safe to disable the debugger */
2114 Status = KdpAllowDisable();
2115 if (!NT_SUCCESS(Status))
2116 {
2117 /* Release the lock and fail */
2118 KdpPortUnlock();
2119 KeLowerIrql(OldIrql);
2120 return Status;
2121 }
2122 }
2123
2124 /* Only disable the debugger if it is enabled */
2125 if (KdDebuggerEnabled)
2126 {
2127 /*
2128 * Disable the debugger; suspend breakpoints
2129 * and reset the debug stub
2130 */
2131 KdpSuspendAllBreakPoints();
2132 KiDebugRoutine = KdpStub;
2133
2134 /* We are disabled now */
2135 KdDebuggerEnabled = FALSE;
2136 SharedUserData->KdDebuggerEnabled = FALSE;
2137 }
2138 }
2139
2140 /* Increment the disable count */
2141 KdDisableCount++;
2142
2143 /* Check if we had locked the port before */
2144 if (NeedLock)
2145 {
2146 /* Yes, now unlock it */
2147 KdpPortUnlock();
2148 KeLowerIrql(OldIrql);
2149 }
2150
2151 /* We're done */
2152 return STATUS_SUCCESS;
2153 }
2154
2155 /* PUBLIC FUNCTIONS **********************************************************/
2156
2157 /*
2158 * @implemented
2159 */
2160 NTSTATUS
2161 NTAPI
KdEnableDebugger(VOID)2162 KdEnableDebugger(VOID)
2163 {
2164 /* Use the internal routine */
2165 return KdEnableDebuggerWithLock(TRUE);
2166 }
2167
2168 /*
2169 * @implemented
2170 */
2171 NTSTATUS
2172 NTAPI
KdDisableDebugger(VOID)2173 KdDisableDebugger(VOID)
2174 {
2175 /* Use the internal routine */
2176 return KdDisableDebuggerWithLock(TRUE);
2177 }
2178
2179 /*
2180 * @unimplemented
2181 */
2182 NTSTATUS
2183 NTAPI
KdSystemDebugControl(_In_ SYSDBG_COMMAND Command,_In_ PVOID InputBuffer,_In_ ULONG InputBufferLength,_Out_ PVOID OutputBuffer,_In_ ULONG OutputBufferLength,_Inout_ PULONG ReturnLength,_In_ KPROCESSOR_MODE PreviousMode)2184 KdSystemDebugControl(
2185 _In_ SYSDBG_COMMAND Command,
2186 _In_ PVOID InputBuffer,
2187 _In_ ULONG InputBufferLength,
2188 _Out_ PVOID OutputBuffer,
2189 _In_ ULONG OutputBufferLength,
2190 _Inout_ PULONG ReturnLength,
2191 _In_ KPROCESSOR_MODE PreviousMode)
2192 {
2193 /* Handle some internal commands */
2194 switch ((ULONG)Command)
2195 {
2196 #if DBG
2197 case ' soR': /* ROS-INTERNAL */
2198 {
2199 switch ((ULONG_PTR)InputBuffer)
2200 {
2201 case 0x21: // DumpAllThreads:
2202 PspDumpThreads(TRUE);
2203 break;
2204
2205 case 0x22: // DumpUserThreads:
2206 PspDumpThreads(FALSE);
2207 break;
2208
2209 case 0x24: // KdSpare3:
2210 MmDumpArmPfnDatabase(FALSE);
2211 break;
2212
2213 default:
2214 break;
2215 }
2216 return STATUS_SUCCESS;
2217 }
2218
2219 #if defined(_M_IX86) && !defined(_WINKD_) // See ke/i386/traphdlr.c
2220 /* Register a debug callback */
2221 case 'CsoR':
2222 {
2223 switch (InputBufferLength)
2224 {
2225 case ID_Win32PreServiceHook:
2226 KeWin32PreServiceHook = InputBuffer;
2227 break;
2228
2229 case ID_Win32PostServiceHook:
2230 KeWin32PostServiceHook = InputBuffer;
2231 break;
2232
2233 }
2234 break;
2235 }
2236 #endif
2237
2238 /* Special case for stack frame dumps */
2239 case 'DsoR':
2240 {
2241 KeRosDumpStackFrames((PULONG_PTR)InputBuffer, InputBufferLength);
2242 break;
2243 }
2244 #ifdef KDBG
2245 /* Register KDBG CLI callback */
2246 case 'RbdK':
2247 {
2248 return KdbRegisterCliCallback(InputBuffer, InputBufferLength);
2249 }
2250 #endif // KDBG
2251 #endif
2252 default:
2253 break;
2254 }
2255
2256 /* Local kernel debugging is not yet supported */
2257 DbgPrint("KdSystemDebugControl is unimplemented!\n");
2258 return STATUS_NOT_IMPLEMENTED;
2259 }
2260
2261 /*
2262 * @implemented
2263 */
2264 NTSTATUS
2265 NTAPI
KdChangeOption(IN KD_OPTION Option,IN ULONG InBufferBytes OPTIONAL,IN PVOID InBuffer,IN ULONG OutBufferBytes OPTIONAL,OUT PVOID OutBuffer,OUT PULONG OutBufferNeeded OPTIONAL)2266 KdChangeOption(IN KD_OPTION Option,
2267 IN ULONG InBufferBytes OPTIONAL,
2268 IN PVOID InBuffer,
2269 IN ULONG OutBufferBytes OPTIONAL,
2270 OUT PVOID OutBuffer,
2271 OUT PULONG OutBufferNeeded OPTIONAL)
2272 {
2273 /* Fail if there is no debugger */
2274 if (KdPitchDebugger)
2275 {
2276 /* No debugger, no options */
2277 return STATUS_DEBUGGER_INACTIVE;
2278 }
2279
2280 /* Do we recognize this option? */
2281 if (Option != KD_OPTION_SET_BLOCK_ENABLE)
2282 {
2283 /* We don't, clear the output length and fail */
2284 if (OutBufferNeeded) *OutBufferNeeded = 0;
2285 return STATUS_INVALID_INFO_CLASS;
2286 }
2287
2288 /* Verify parameters */
2289 if ((InBufferBytes != sizeof(BOOLEAN)) ||
2290 (OutBufferBytes != 0) ||
2291 (OutBuffer != NULL))
2292 {
2293 /* Invalid parameters for this option, fail */
2294 return STATUS_INVALID_PARAMETER;
2295 }
2296
2297 /*
2298 * Check if the high bit is set, meaning we don't
2299 * allow the debugger to be enabled
2300 */
2301 if (KdBlockEnable & 0x80)
2302 {
2303 /* Fail regardless of what state the caller tried to set */
2304 return STATUS_ACCESS_VIOLATION;
2305 }
2306
2307 /* Set the new block enable state */
2308 KdBlockEnable = *(PBOOLEAN)InBuffer;
2309
2310 /* No output buffer required for this option */
2311 if (OutBufferNeeded) *OutBufferNeeded = 0;
2312
2313 /* We are done */
2314 return STATUS_SUCCESS;
2315 }
2316
2317 /*
2318 * @implemented
2319 */
2320 NTSTATUS
2321 NTAPI
KdPowerTransition(IN DEVICE_POWER_STATE NewState)2322 KdPowerTransition(IN DEVICE_POWER_STATE NewState)
2323 {
2324 /* Check what power state this is */
2325 if (NewState == PowerDeviceD0)
2326 {
2327 /* Wake up the debug port */
2328 KdD0Transition();
2329 return STATUS_SUCCESS;
2330 }
2331 else if ((NewState == PowerDeviceD1) ||
2332 (NewState == PowerDeviceD2) ||
2333 (NewState == PowerDeviceD3))
2334 {
2335 /* Power down the debug port */
2336 KdD3Transition();
2337 return STATUS_SUCCESS;
2338 }
2339 else
2340 {
2341 /* Invalid state! */
2342 return STATUS_INVALID_PARAMETER_1;
2343 }
2344 }
2345
2346 /*
2347 * @implemented
2348 */
2349 BOOLEAN
2350 NTAPI
KdRefreshDebuggerNotPresent(VOID)2351 KdRefreshDebuggerNotPresent(VOID)
2352 {
2353 BOOLEAN Enable, DebuggerNotPresent;
2354
2355 /* Check if the debugger is completely disabled */
2356 if (KdPitchDebugger)
2357 {
2358 /* Don't try to refresh then, fail early */
2359 return TRUE;
2360 }
2361
2362 /* Enter the debugger */
2363 Enable = KdEnterDebugger(NULL, NULL);
2364
2365 /*
2366 * Attempt to send a string to the debugger
2367 * to refresh the connection state.
2368 */
2369 KdpDprintf("KDTARGET: Refreshing KD connection\n");
2370
2371 /* Save the state while we are holding the lock */
2372 DebuggerNotPresent = KdDebuggerNotPresent;
2373
2374 /* Exit the debugger and return the state */
2375 KdExitDebugger(Enable);
2376 return DebuggerNotPresent;
2377 }
2378
2379 /*
2380 * @implemented
2381 */
2382 NTSTATUS
2383 NTAPI
NtQueryDebugFilterState(_In_ ULONG ComponentId,_In_ ULONG Level)2384 NtQueryDebugFilterState(
2385 _In_ ULONG ComponentId,
2386 _In_ ULONG Level)
2387 {
2388 PULONG Mask;
2389
2390 /* Check if the ID fits in the component table */
2391 if (ComponentId < KdComponentTableSize)
2392 {
2393 /* It does, so get the mask from there */
2394 Mask = KdComponentTable[ComponentId];
2395 }
2396 else if (ComponentId == MAXULONG)
2397 {
2398 /*
2399 * This is the internal ID used for DbgPrint messages without ID
2400 * and Level. Use the system-wide mask for those.
2401 */
2402 Mask = &Kd_WIN2000_Mask;
2403 }
2404 else
2405 {
2406 #if (NTDDI_VERSION >= NTDDI_VISTA)
2407 /* Use the default component ID */
2408 Mask = &Kd_DEFAULT_Mask;
2409 // Level = DPFLTR_INFO_LEVEL; // Override the Level.
2410 #else
2411 /* Invalid ID, fail */
2412 return STATUS_INVALID_PARAMETER_1;
2413 #endif
2414 }
2415
2416 /* Convert Level to bit field if required */
2417 if (Level < 32) Level = 1 << Level;
2418 Level &= ~DPFLTR_MASK;
2419
2420 /* Determine if this Level is filtered out */
2421 if ((Kd_WIN2000_Mask & Level) || (*Mask & Level))
2422 {
2423 /* This mask will get through to the debugger */
2424 return (NTSTATUS)TRUE;
2425 }
2426 else
2427 {
2428 /* This mask is filtered out */
2429 return (NTSTATUS)FALSE;
2430 }
2431 }
2432
2433 /*
2434 * @implemented
2435 */
2436 NTSTATUS
2437 NTAPI
NtSetDebugFilterState(_In_ ULONG ComponentId,_In_ ULONG Level,_In_ BOOLEAN State)2438 NtSetDebugFilterState(
2439 _In_ ULONG ComponentId,
2440 _In_ ULONG Level,
2441 _In_ BOOLEAN State)
2442 {
2443 PULONG Mask;
2444
2445 /* Modifying debug filters requires the debug privilege */
2446 if (!SeSinglePrivilegeCheck(SeDebugPrivilege, ExGetPreviousMode()))
2447 {
2448 /* Fail */
2449 return STATUS_ACCESS_DENIED;
2450 }
2451
2452 /* Check if the ID fits in the component table */
2453 if (ComponentId < KdComponentTableSize)
2454 {
2455 /* It does, so get the mask from there */
2456 Mask = KdComponentTable[ComponentId];
2457 }
2458 else if (ComponentId == MAXULONG)
2459 {
2460 /*
2461 * This is the internal ID used for DbgPrint messages without ID
2462 * and Level. Use the system-wide mask for those.
2463 */
2464 Mask = &Kd_WIN2000_Mask;
2465 }
2466 else
2467 {
2468 #if (NTDDI_VERSION >= NTDDI_VISTA)
2469 /* Use the default component ID */
2470 Mask = &Kd_DEFAULT_Mask;
2471 #else
2472 /* Invalid ID, fail */
2473 return STATUS_INVALID_PARAMETER_1;
2474 #endif
2475 }
2476
2477 /* Convert Level to bit field if required */
2478 if (Level < 32) Level = 1 << Level;
2479 Level &= ~DPFLTR_MASK;
2480
2481 /* Set or remove the Level */
2482 if (State)
2483 *Mask |= Level;
2484 else
2485 *Mask &= ~Level;
2486
2487 return STATUS_SUCCESS;
2488 }
2489