- We now tell WinDBG to load kernel symbols and WinDBG replies (!) with DbgKdGetVersi...
[reactos.git] / reactos / ntoskrnl / kd64 / kdapi.c
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 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* PRIVATE FUNCTIONS *********************************************************/
16
17 VOID
18 NTAPI
19 KdpSetCommonState(IN ULONG NewState,
20 IN PCONTEXT Context,
21 IN PDBGKD_WAIT_STATE_CHANGE64 WaitStateChange)
22 {
23 USHORT InstructionCount;
24 BOOLEAN HadBreakpoints;
25
26 /* Setup common stuff available for all CPU architectures */
27 WaitStateChange->NewState = NewState;
28 WaitStateChange->ProcessorLevel = KeProcessorLevel;
29 WaitStateChange->Processor = (USHORT)KeGetCurrentPrcb()->Number;
30 WaitStateChange->NumberProcessors = (ULONG)KeNumberProcessors;
31 WaitStateChange->Thread = (ULONG)KeGetCurrentThread();
32 WaitStateChange->ProgramCounter = (ULONG64)Context->Eip;
33
34 /* Zero out the Control Report */
35 RtlZeroMemory(&WaitStateChange->ControlReport,
36 sizeof(DBGKD_CONTROL_REPORT));
37
38 /* Now copy the instruction stream and set the count */
39 RtlCopyMemory(&WaitStateChange->ControlReport.InstructionStream[0],
40 (PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter,
41 DBGKD_MAXSTREAM);
42 InstructionCount = DBGKD_MAXSTREAM;
43 WaitStateChange->ControlReport.InstructionCount = InstructionCount;
44
45 /* Clear all the breakpoints in this region */
46 HadBreakpoints = FALSE;
47 #if 0
48 KdpDeleteBreakpointRange((PVOID)WaitStateChange->ProgramCounter,
49 (PVOID)(WaitStateChange->ProgramCounter +
50 WaitStateChange->ControlReport.
51 InstructionCount - 1));
52 #endif
53 if (HadBreakpoints)
54 {
55 /* Copy the instruction stream again, this time without breakpoints */
56 RtlCopyMemory(&WaitStateChange->ControlReport.InstructionStream[0],
57 (PVOID)(ULONG_PTR)WaitStateChange->ProgramCounter,
58 WaitStateChange->ControlReport.InstructionCount);
59 }
60 }
61
62 VOID
63 NTAPI
64 KdpSetContextState(IN PDBGKD_WAIT_STATE_CHANGE64 WaitStateChange,
65 IN PCONTEXT Context)
66 {
67 PKPRCB Prcb = KeGetCurrentPrcb();
68
69 /* Copy i386 specific debug registers */
70 WaitStateChange->ControlReport.Dr6 = Prcb->ProcessorState.SpecialRegisters.
71 KernelDr6;
72 WaitStateChange->ControlReport.Dr7 = Prcb->ProcessorState.SpecialRegisters.
73 KernelDr7;
74
75 /* Copy i386 specific segments */
76 WaitStateChange->ControlReport.SegCs = (USHORT)Context->SegCs;
77 WaitStateChange->ControlReport.SegDs = (USHORT)Context->SegDs;
78 WaitStateChange->ControlReport.SegEs = (USHORT)Context->SegEs;
79 WaitStateChange->ControlReport.SegFs = (USHORT)Context->SegFs;
80
81 /* Copy EFlags */
82 WaitStateChange->ControlReport.EFlags = Context->EFlags;
83
84 /* Set Report Flags */
85 WaitStateChange->ControlReport.ReportFlags = REPORT_INCLUDES_SEGS;
86 if (WaitStateChange->ControlReport.SegCs == KGDT_R0_CODE)
87 {
88 WaitStateChange->ControlReport.ReportFlags = REPORT_INCLUDES_CS;
89 }
90 }
91
92 BOOLEAN
93 NTAPI
94 KdpSendWaitContinue(IN ULONG PacketType,
95 IN PSTRING SendHeader,
96 IN PSTRING SendData OPTIONAL,
97 IN OUT PCONTEXT ContextRecord)
98 {
99 STRING Data, Header;
100 DBGKD_MANIPULATE_STATE64 ManipulateState;
101 ULONG Length;
102 KDSTATUS RecvCode;
103
104 /* Setup the Manipulate State structure */
105 Header.MaximumLength = sizeof(DBGKD_MANIPULATE_STATE64);
106 Header.Buffer = (PCHAR)&ManipulateState;
107 Data.MaximumLength = sizeof(KdpMessageBuffer);
108 Data.Buffer = KdpMessageBuffer;
109 //KdpContextSent = FALSE;
110
111 SendPacket:
112 /* Send the Packet */
113 KdSendPacket(PacketType, SendHeader, SendData, &KdpContext);
114
115 /* If the debugger isn't present anymore, just return success */
116 if (KdDebuggerNotPresent) return TRUE;
117
118 /* Main processing Loop */
119 for (;;)
120 {
121 /* Receive Loop */
122 do
123 {
124 /* Wait to get a reply to our packet */
125 ManipulateState.ApiNumber = 0xFFFFFFFF;
126 RecvCode = KdReceivePacket(PACKET_TYPE_KD_STATE_MANIPULATE,
127 &Header,
128 &Data,
129 &Length,
130 &KdpContext);
131
132 /* If we got a resend request, do it */
133 if (RecvCode == KdPacketNeedsResend) goto SendPacket;
134 } while (RecvCode == KdPacketTimedOut);
135
136 /* Now check what API we got */
137 switch (ManipulateState.ApiNumber)
138 {
139 case DbgKdReadVirtualMemoryApi:
140
141 /* FIXME: TODO */
142 Ke386SetCr2(DbgKdReadVirtualMemoryApi);
143 while (TRUE);
144 break;
145
146 case DbgKdWriteVirtualMemoryApi:
147
148 /* FIXME: TODO */
149 Ke386SetCr2(DbgKdWriteVirtualMemoryApi);
150 while (TRUE);
151 break;
152
153 case DbgKdGetContextApi:
154
155 /* FIXME: TODO */
156 Ke386SetCr2(DbgKdGetContextApi);
157 while (TRUE);
158 break;
159
160 case DbgKdSetContextApi:
161
162 /* FIXME: TODO */
163 Ke386SetCr2(DbgKdSetContextApi);
164 while (TRUE);
165 break;
166
167 case DbgKdWriteBreakPointApi:
168
169 /* FIXME: TODO */
170 Ke386SetCr2(DbgKdWriteBreakPointApi);
171 while (TRUE);
172 break;
173
174 case DbgKdRestoreBreakPointApi:
175
176 /* FIXME: TODO */
177 Ke386SetCr2(DbgKdRestoreBreakPointApi);
178 while (TRUE);
179 break;
180
181 case DbgKdContinueApi:
182
183 /* FIXME: TODO */
184 Ke386SetCr2(DbgKdContinueApi);
185 while (TRUE);
186 break;
187
188 case DbgKdReadControlSpaceApi:
189
190 /* FIXME: TODO */
191 Ke386SetCr2(DbgKdReadControlSpaceApi);
192 while (TRUE);
193 break;
194
195 case DbgKdWriteControlSpaceApi:
196
197 /* FIXME: TODO */
198 Ke386SetCr2(DbgKdWriteControlSpaceApi);
199 while (TRUE);
200 break;
201
202 case DbgKdReadIoSpaceApi:
203
204 /* FIXME: TODO */
205 Ke386SetCr2(DbgKdReadIoSpaceApi);
206 while (TRUE);
207 break;
208
209 case DbgKdWriteIoSpaceApi:
210
211 /* FIXME: TODO */
212 Ke386SetCr2(DbgKdWriteIoSpaceApi);
213 while (TRUE);
214 break;
215
216 case DbgKdRebootApi:
217
218 /* FIXME: TODO */
219 Ke386SetCr2(DbgKdRebootApi);
220 while (TRUE);
221 break;
222
223 case DbgKdContinueApi2:
224
225 /* FIXME: TODO */
226 Ke386SetCr2(DbgKdContinueApi2);
227 while (TRUE);
228 break;
229
230 case DbgKdReadPhysicalMemoryApi:
231
232 /* FIXME: TODO */
233 Ke386SetCr2(DbgKdReadPhysicalMemoryApi);
234 while (TRUE);
235 break;
236
237 case DbgKdWritePhysicalMemoryApi:
238
239 /* FIXME: TODO */
240 Ke386SetCr2(DbgKdWritePhysicalMemoryApi);
241 while (TRUE);
242 break;
243
244 case DbgKdQuerySpecialCallsApi:
245
246 /* FIXME: TODO */
247 Ke386SetCr2(DbgKdQuerySpecialCallsApi);
248 while (TRUE);
249 break;
250
251 case DbgKdSetSpecialCallApi:
252
253 /* FIXME: TODO */
254 Ke386SetCr2(DbgKdSetSpecialCallApi);
255 while (TRUE);
256 break;
257
258 case DbgKdClearSpecialCallsApi:
259
260 /* FIXME: TODO */
261 Ke386SetCr2(DbgKdClearSpecialCallsApi);
262 while (TRUE);
263 break;
264
265 case DbgKdSetInternalBreakPointApi:
266
267 /* FIXME: TODO */
268 Ke386SetCr2(DbgKdSetInternalBreakPointApi);
269 while (TRUE);
270 break;
271
272 case DbgKdGetInternalBreakPointApi:
273
274 /* FIXME: TODO */
275 Ke386SetCr2(DbgKdGetInternalBreakPointApi);
276 while (TRUE);
277 break;
278
279 case DbgKdReadIoSpaceExtendedApi:
280
281 /* FIXME: TODO */
282 Ke386SetCr2(DbgKdReadIoSpaceExtendedApi);
283 while (TRUE);
284 break;
285
286 case DbgKdWriteIoSpaceExtendedApi:
287
288 /* FIXME: TODO */
289 Ke386SetCr2(DbgKdWriteIoSpaceExtendedApi);
290 while (TRUE);
291 break;
292
293 case DbgKdGetVersionApi:
294
295 /* FIXME: TODO */
296 Ke386SetCr2(DbgKdGetVersionApi);
297 while (TRUE);
298 break;
299
300 case DbgKdWriteBreakPointExApi:
301
302 /* FIXME: TODO */
303 Ke386SetCr2(DbgKdWriteBreakPointExApi);
304 while (TRUE);
305 break;
306
307 case DbgKdRestoreBreakPointExApi:
308
309 /* FIXME: TODO */
310 Ke386SetCr2(DbgKdRestoreBreakPointExApi);
311 while (TRUE);
312 break;
313
314 case DbgKdCauseBugCheckApi:
315
316 /* FIXME: TODO */
317 Ke386SetCr2(DbgKdCauseBugCheckApi);
318 while (TRUE);
319 break;
320
321 case DbgKdSwitchProcessor:
322
323 /* FIXME: TODO */
324 Ke386SetCr2(DbgKdSwitchProcessor);
325 while (TRUE);
326 break;
327
328 case DbgKdPageInApi:
329
330 /* FIXME: TODO */
331 Ke386SetCr2(DbgKdPageInApi);
332 while (TRUE);
333 break;
334
335 case DbgKdReadMachineSpecificRegister:
336
337 /* FIXME: TODO */
338 Ke386SetCr2(DbgKdReadMachineSpecificRegister);
339 while (TRUE);
340 break;
341
342 case DbgKdWriteMachineSpecificRegister:
343
344 /* FIXME: TODO */
345 Ke386SetCr2(DbgKdWriteMachineSpecificRegister);
346 while (TRUE);
347 break;
348
349 case OldVlm1:
350
351 /* FIXME: TODO */
352 Ke386SetCr2(OldVlm1);
353 while (TRUE);
354 break;
355
356 case OldVlm2:
357
358 /* FIXME: TODO */
359 Ke386SetCr2(OldVlm2);
360 while (TRUE);
361 break;
362
363 case DbgKdSearchMemoryApi:
364
365 /* FIXME: TODO */
366 Ke386SetCr2(DbgKdSearchMemoryApi);
367 while (TRUE);
368 break;
369
370 case DbgKdGetBusDataApi:
371
372 /* FIXME: TODO */
373 Ke386SetCr2(DbgKdGetBusDataApi);
374 while (TRUE);
375 break;
376
377 case DbgKdSetBusDataApi:
378
379 /* FIXME: TODO */
380 Ke386SetCr2(DbgKdSetBusDataApi);
381 while (TRUE);
382 break;
383
384 case DbgKdCheckLowMemoryApi:
385
386 /* FIXME: TODO */
387 Ke386SetCr2(DbgKdCheckLowMemoryApi);
388 while (TRUE);
389 break;
390
391 case DbgKdClearAllInternalBreakpointsApi:
392
393 /* FIXME: TODO */
394 Ke386SetCr2(DbgKdClearAllInternalBreakpointsApi);
395 while (TRUE);
396 break;
397
398 case DbgKdFillMemoryApi:
399
400 /* FIXME: TODO */
401 Ke386SetCr2(DbgKdFillMemoryApi);
402 while (TRUE);
403 break;
404
405 case DbgKdQueryMemoryApi:
406
407 /* FIXME: TODO */
408 Ke386SetCr2(DbgKdQueryMemoryApi);
409 while (TRUE);
410 break;
411
412 case DbgKdSwitchPartition:
413
414 /* FIXME: TODO */
415 Ke386SetCr2(DbgKdSwitchPartition);
416 while (TRUE);
417 break;
418
419 /* Unsupported Message */
420 default:
421
422 /* Setup an empty message, with failure */
423 while (TRUE);
424 Data.Length = 0;
425 ManipulateState.ReturnStatus = STATUS_UNSUCCESSFUL;
426
427 /* Send it */
428 KdSendPacket(PACKET_TYPE_KD_STATE_MANIPULATE,
429 &Header,
430 &Data,
431 &KdpContext);
432 break;
433 }
434 }
435 }
436
437 BOOLEAN
438 NTAPI
439 KdpReportLoadSymbolsStateChange(IN PSTRING PathName,
440 IN PKD_SYMBOLS_INFO SymbolInfo,
441 IN BOOLEAN Unload,
442 IN OUT PCONTEXT Context)
443 {
444 PSTRING ExtraData;
445 STRING Data, Header;
446 DBGKD_WAIT_STATE_CHANGE64 WaitStateChange;
447 KCONTINUE_STATUS Status;
448
449 /* Start wait loop */
450 do
451 {
452 /* Build the architecture common parts of the message */
453 KdpSetCommonState(DbgKdLoadSymbolsStateChange,
454 Context,
455 &WaitStateChange);
456
457 /* Now finish creating the structure */
458 KdpSetContextState(&WaitStateChange, Context);
459
460 /* Fill out load data */
461 WaitStateChange.u.LoadSymbols.UnloadSymbols = Unload;
462 WaitStateChange.u.LoadSymbols.BaseOfDll = (ULONG)SymbolInfo->BaseOfDll;
463 WaitStateChange.u.LoadSymbols.ProcessId = SymbolInfo->ProcessId;
464 WaitStateChange.u.LoadSymbols.CheckSum = SymbolInfo->CheckSum;
465 WaitStateChange.u.LoadSymbols.SizeOfImage = SymbolInfo->SizeOfImage;
466
467 /* Check if we have a symbol name */
468 if (PathName)
469 {
470 /* Setup the information */
471 WaitStateChange.u.LoadSymbols.PathNameLength = PathName->Length;
472 Data.Buffer = KdpPathBuffer;
473 Data.Length = WaitStateChange.u.LoadSymbols.PathNameLength;
474 ExtraData = &Data;
475 }
476 else
477 {
478 /* No name */
479 WaitStateChange.u.LoadSymbols.PathNameLength = 0;
480 ExtraData = NULL;
481 }
482
483 /* Setup the header */
484 Header.Length = sizeof(DBGKD_WAIT_STATE_CHANGE64);
485 Header.Buffer = (PCHAR)&WaitStateChange;
486
487 /* Send the packet */
488 Status = KdpSendWaitContinue(PACKET_TYPE_KD_STATE_CHANGE64,
489 &Header,
490 ExtraData,
491 Context);
492 } while(Status == ContinueProcessorReselected);
493
494 /* Return status */
495 while (TRUE);
496 return Status;
497 }
498
499 VOID
500 NTAPI
501 KdpTimeSlipDpcRoutine(IN PKDPC Dpc,
502 IN PVOID DeferredContext,
503 IN PVOID SystemArgument1,
504 IN PVOID SystemArgument2)
505 {
506 LONG OldSlip, NewSlip, PendingSlip;
507
508 /* Get the current pending slip */
509 PendingSlip = KdpTimeSlipPending;
510 do
511 {
512 /* Save the old value and either disable or enable it now. */
513 OldSlip = PendingSlip;
514 NewSlip = OldSlip > 1 ? 1 : 0;
515
516 /* Try to change the value */
517 } while (InterlockedCompareExchange(&KdpTimeSlipPending,
518 NewSlip,
519 OldSlip) != OldSlip);
520
521 /* If the New Slip value is 1, then do the Time Slipping */
522 if (NewSlip) ExQueueWorkItem(&KdpTimeSlipWorkItem, DelayedWorkQueue);
523 }
524
525 VOID
526 NTAPI
527 KdpTimeSlipWork(IN PVOID Context)
528 {
529 KIRQL OldIrql;
530 LARGE_INTEGER DueTime;
531
532 /* Update the System time from the CMOS */
533 ExAcquireTimeRefreshLock(FALSE);
534 ExUpdateSystemTimeFromCmos(FALSE, 0);
535 ExReleaseTimeRefreshLock();
536
537 /* Check if we have a registered Time Slip Event and signal it */
538 KeAcquireSpinLock(&KdpTimeSlipEventLock, &OldIrql);
539 if (KdpTimeSlipEvent) KeSetEvent(KdpTimeSlipEvent, 0, FALSE);
540 KeReleaseSpinLock(&KdpTimeSlipEventLock, OldIrql);
541
542 /* Delay the DPC until it runs next time */
543 DueTime.QuadPart = -1800000000;
544 KeSetTimer(&KdpTimeSlipTimer, DueTime, &KdpTimeSlipDpc);
545 }
546
547 BOOLEAN
548 NTAPI
549 KdpSwitchProcessor(IN PEXCEPTION_RECORD ExceptionRecord,
550 IN OUT PCONTEXT ContextRecord,
551 IN BOOLEAN SecondChanceException)
552 {
553 BOOLEAN Status;
554
555 /* Save the port data */
556 KdSave(FALSE);
557
558 /* Report a state change */
559 #if 0
560 Status = KdpReportExceptionStateChange(ExceptionRecord,
561 ContextRecord,
562 SecondChanceException);
563 #else
564 Status = FALSE;
565 #endif
566
567 /* Restore the port data and return */
568 KdRestore(FALSE);
569 return Status;
570 }
571
572 LARGE_INTEGER
573 NTAPI
574 KdpQueryPerformanceCounter(IN PKTRAP_FRAME TrapFrame)
575 {
576 LARGE_INTEGER Null = {{0}};
577
578 /* Check if interrupts were disabled */
579 if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
580 {
581 /* Nothing to return */
582 return Null;
583 }
584
585 /* Otherwise, do the call */
586 return KeQueryPerformanceCounter(NULL);
587 }
588
589 BOOLEAN
590 NTAPI
591 KdEnterDebugger(IN PKTRAP_FRAME TrapFrame,
592 IN PKEXCEPTION_FRAME ExceptionFrame)
593 {
594 BOOLEAN Entered;
595
596 /* Check if we have a trap frame */
597 if (TrapFrame)
598 {
599 /* Calculate the time difference for the enter */
600 KdTimerStop = KdpQueryPerformanceCounter(TrapFrame);
601 KdTimerDifference.QuadPart = KdTimerStop.QuadPart -
602 KdTimerStart.QuadPart;
603 }
604 else
605 {
606 /* No trap frame, so can't calculate */
607 KdTimerStop.QuadPart = 0;
608 }
609
610 /* Save the current IRQL */
611 KeGetCurrentPrcb()->DebuggerSavedIRQL = KeGetCurrentIrql();
612
613 /* Freeze all CPUs */
614 Entered = KeFreezeExecution(TrapFrame, ExceptionFrame);
615
616 /* Lock the port, save the state and set debugger entered */
617 KdpPortLocked = KeTryToAcquireSpinLockAtDpcLevel(&KdpDebuggerLock);
618 KdSave(FALSE);
619 KdEnteredDebugger = TRUE;
620
621 /* Check freeze flag */
622 if (KiFreezeFlag & 1)
623 {
624 /* Print out errror */
625 DbgPrint("FreezeLock was jammed! Backup SpinLock was used!\n");
626 }
627
628 /* Check processor state */
629 if (KiFreezeFlag & 2)
630 {
631 /* Print out errror */
632 DbgPrint("Some processors not frozen in debugger!\n");
633 }
634
635 /* Make sure we acquired the port */
636 if (!KdpPortLocked) DbgPrint("Port lock was not acquired!\n");
637
638 /* Return enter state */
639 return Entered;
640 }
641
642 VOID
643 NTAPI
644 KdExitDebugger(IN BOOLEAN Entered)
645 {
646 ULONG TimeSlip;
647
648 /* Restore the state and unlock the port */
649 KdRestore(FALSE);
650 if (KdpPortLocked) KdpPortUnlock();
651
652 /* Unfreeze the CPUs */
653 KeThawExecution(Entered);
654
655 /* Compare time with the one from KdEnterDebugger */
656 if (!KdTimerStop.QuadPart)
657 {
658 /* We didn't get a trap frame earlier in so never got the time */
659 KdTimerStart = KdTimerStop;
660 }
661 else
662 {
663 /* Query the timer */
664 KdTimerStart = KeQueryPerformanceCounter(NULL);
665 }
666
667 /* Check if a Time Slip was on queue */
668 TimeSlip = InterlockedIncrement(&KdpTimeSlipPending);
669 if (TimeSlip == 1)
670 {
671 /* Queue a DPC for the time slip */
672 InterlockedIncrement(&KdpTimeSlipPending);
673 KeInsertQueueDpc(&KdpTimeSlipDpc, NULL, NULL);
674 }
675 }
676
677 NTSTATUS
678 NTAPI
679 KdEnableDebuggerWithLock(BOOLEAN NeedLock)
680 {
681 KIRQL OldIrql;
682
683 /* Check if we need to acquire the lock */
684 if (NeedLock)
685 {
686 /* Lock the port */
687 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
688 KdpPortLock();
689 }
690
691 /* Check if we're not disabled */
692 if (!KdDisableCount)
693 {
694 /* Check if we had locked the port before */
695 if (NeedLock)
696 {
697 /* Do the unlock */
698 KeLowerIrql(OldIrql);
699 KdpPortUnlock();
700 }
701
702 /* Fail: We're already enabled */
703 return STATUS_INVALID_PARAMETER;
704 }
705
706 /* Decrease the disable count */
707 if (!(--KdDisableCount))
708 {
709 /* We're now enabled again! Were we enabled before, too? */
710 if (KdPreviouslyEnabled)
711 {
712 /* Reinitialize the Debugger */
713 KdInitSystem(0, NULL) ;
714 //KdpRestoreAllBreakpoints();
715 }
716 }
717
718 /* Check if we had locked the port before */
719 if (NeedLock)
720 {
721 /* Yes, now unlock it */
722 KeLowerIrql(OldIrql);
723 KdpPortUnlock();
724 }
725
726 /* We're done */
727 return STATUS_SUCCESS;
728 }
729
730 /* PUBLIC FUNCTIONS **********************************************************/
731
732 /*
733 * @implemented
734 */
735 NTSTATUS
736 NTAPI
737 KdEnableDebugger(VOID)
738 {
739 /* Use the internal routine */
740 while (TRUE);
741 return KdEnableDebuggerWithLock(TRUE);
742 }
743