[NTOSKRNL] Don't keep the spin lock hold too long when we lost the BCB race
[reactos.git] / ntoskrnl / kd / wrappers / gdbstub_powerpc.c
1 /****************************************************************************
2
3 THIS SOFTWARE IS NOT COPYRIGHTED
4
5 HP offers the following for use in the public domain. HP makes no
6 warranty with regard to the software or it's performance and the
7 user accepts the software "AS IS" with all faults.
8
9 HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
10 TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
11 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12
13 ****************************************************************************/
14
15 /****************************************************************************
16 * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
17 *
18 * Module name: remcom.c $
19 * Revision: 1.34 $
20 * Date: 91/03/09 12:29:49 $
21 * Contributor: Lake Stevens Instrument Division$
22 *
23 * Description: low level support for gdb debugger. $
24 *
25 * Considerations: only works on target hardware $
26 *
27 * Written by: Glenn Engel $
28 * ModuleState: Experimental $
29 *
30 * NOTES: See Below $
31 *
32 * Modified for 386 by Jim Kingdon, Cygnus Support.
33 * Modified for ReactOS by Casper S. Hornstrup <chorns@users.sourceforge.net>
34 *
35 * To enable debugger support, two things need to happen. One, setting
36 * up a routine so that it is in the exception path, is necessary in order
37 * to allow any breakpoints or error conditions to be properly intercepted
38 * and reported to gdb.
39 * Two, a breakpoint needs to be generated to begin communication.
40 *
41 * Because gdb will sometimes write to the stack area to execute function
42 * calls, this program cannot rely on using the supervisor stack so it
43 * uses it's own stack area.
44 *
45 *************
46 *
47 * The following gdb commands are supported:
48 *
49 * command function Return value
50 *
51 * g return the value of the CPU Registers hex data or ENN
52 * G set the value of the CPU Registers OK or ENN
53 *
54 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
55 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
56 *
57 * c Resume at current address SNN ( signal NN)
58 * cAA..AA Continue at address AA..AA SNN
59 *
60 * s Step one instruction SNN
61 * sAA..AA Step one instruction from AA..AA SNN
62 *
63 * k kill
64 *
65 * ? What was the last sigval ? SNN (signal NN)
66 *
67 * All commands and responses are sent with a packet which includes a
68 * Checksum. A packet consists of
69 *
70 * $<packet info>#<Checksum>.
71 *
72 * where
73 * <packet info> :: <characters representing the command or response>
74 * <Checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
75 *
76 * When a packet is received, it is first acknowledged with either '+' or '-'.
77 * '+' indicates a successful transfer. '-' indicates a failed transfer.
78 *
79 * Example:
80 *
81 * Host: Reply:
82 * $m0,10#2a +$00010203040506070809101112131415#42
83 *
84 ****************************************************************************/
85
86 #include <ntoskrnl.h>
87 #define NDEBUG
88 #include <debug.h>
89
90 /************************************************************************/
91
92 static BOOLEAN GspInitialized;
93 static BOOLEAN GspRemoteDebug;
94
95 static CONST CHAR HexChars[]="0123456789abcdef";
96
97 static PETHREAD GspRunThread; /* NULL means run all threads */
98 static PETHREAD GspDbgThread;
99 static PETHREAD GspEnumThread;
100
101 static FAST_MUTEX GspLock;
102
103 extern LIST_ENTRY PsActiveProcessHead;
104
105 /* FIXME hardcoded for COM2, 115200 baud */
106 ULONG GdbPortNumber = DEFAULT_DEBUG_PORT;
107 CPPORT GdbPortInfo = {0, DEFAULT_DEBUG_BAUD_RATE, 0};
108
109 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
110 /* at least NUMREGBYTES*2 are needed for register packets */
111 #define BUFMAX 1000
112 static CHAR GspInBuffer[BUFMAX];
113 static CHAR GspOutBuffer[BUFMAX];
114
115 /* Number of Registers. */
116 #define NUMREGS 16
117
118 enum REGISTER_NAMES
119 {
120 EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
121 PC /* also known as eip */,
122 PS /* also known as eflags */,
123 CS, SS, DS, ES, FS, GS
124 };
125
126 typedef struct _CPU_REGISTER
127 {
128 ULONG Size;
129 ULONG OffsetInTF;
130 ULONG OffsetInContext;
131 BOOLEAN SetInContext;
132 } CPU_REGISTER, *PCPU_REGISTER;
133
134 static CPU_REGISTER GspRegisters[NUMREGS] =
135 {
136 };
137
138 static PCHAR GspThreadStates[DeferredReady+1] =
139 {
140 "Initialized",
141 "Ready",
142 "Running",
143 "Standby",
144 "Terminated",
145 "Waiting",
146 "Transition",
147 "DeferredReady"
148 };
149
150
151 LONG
152 HexValue(CHAR ch)
153 {
154 if ((ch >= '0') && (ch <= '9'))
155 return (ch - '0');
156
157 if ((ch >= 'a') && (ch <= 'f'))
158 return (ch - 'a' + 10);
159
160 if ((ch >= 'A') && (ch <= 'F'))
161 return (ch - 'A' + 10);
162
163 return -1;
164 }
165
166 VOID
167 GdbPutChar(UCHAR Value)
168 {
169 KdPortPutByteEx(&GdbPortInfo, Value);
170 }
171
172 UCHAR
173 GdbGetChar(VOID)
174 {
175 UCHAR Value;
176
177 while (!KdPortGetByteEx(&GdbPortInfo, &Value)) ;
178 return Value;
179 }
180
181 /* scan for the sequence $<data>#<Checksum> */
182
183 PCHAR
184 GspGetPacket(VOID)
185 {
186 PCHAR Buffer = &GspInBuffer[0];
187 CHAR Checksum;
188 CHAR XmitChecksum;
189 ULONG Count;
190 CHAR ch;
191
192 while (TRUE)
193 {
194 /* wait around for the start character, ignore all other characters */
195 while ((ch = GdbGetChar ()) != '$') ;
196
197 retry:
198 Checksum = 0;
199 XmitChecksum = -1;
200 Count = 0;
201
202 /* now, read until a # or end of Buffer is found */
203 while (Count < BUFMAX)
204 {
205 ch = GdbGetChar();
206 if (ch == '$')
207 goto retry;
208
209 if (ch == '#')
210 break;
211
212 Checksum = Checksum + ch;
213 Buffer[Count] = ch;
214 Count = Count + 1;
215 }
216 Buffer[Count] = 0;
217
218 if (ch == '#')
219 {
220 ch = GdbGetChar();
221 XmitChecksum = (CHAR)(HexValue(ch) << 4);
222 ch = GdbGetChar();
223 XmitChecksum += (CHAR)(HexValue(ch));
224
225 if (Checksum != XmitChecksum)
226 {
227 GdbPutChar('-'); /* failed checksum */
228 }
229 else
230 {
231 GdbPutChar('+'); /* successful transfer */
232 return &Buffer[0];
233 }
234 }
235 }
236 }
237
238 /* send the packet in Buffer. */
239
240 VOID
241 GspPutPacket(PCHAR Buffer)
242 {
243 CHAR Checksum;
244 LONG Count;
245 CHAR ch;
246
247 /* $<packet info>#<Checksum>. */
248 do
249 {
250 GdbPutChar('$');
251 Checksum = 0;
252 Count = 0;
253
254 while ((ch = Buffer[Count]))
255 {
256 GdbPutChar(ch);
257 Checksum += ch;
258 Count += 1;
259 }
260
261 GdbPutChar('#');
262 GdbPutChar(HexChars[(Checksum >> 4) & 0xf]);
263 GdbPutChar(HexChars[Checksum & 0xf]);
264 }
265 while (GdbGetChar() != '+');
266 }
267
268
269 VOID
270 GspPutPacketNoWait(PCHAR Buffer)
271 {
272 CHAR Checksum;
273 LONG Count;
274 CHAR ch;
275
276 /* $<packet info>#<Checksum>. */
277 GdbPutChar('$');
278 Checksum = 0;
279 Count = 0;
280
281 while ((ch = Buffer[Count]))
282 {
283 GdbPutChar(ch);
284 Checksum += ch;
285 Count += 1;
286 }
287
288 GdbPutChar('#');
289 GdbPutChar(HexChars[(Checksum >> 4) & 0xf]);
290 GdbPutChar(HexChars[Checksum & 0xf]);
291 }
292
293 /* Indicate to caller of GspMem2Hex or GspHex2Mem that there has been an
294 error. */
295 static volatile BOOLEAN GspMemoryError = FALSE;
296 static volatile void *GspAccessLocation = NULL;
297
298 static CHAR
299 GspReadMemSafe(PCHAR Address)
300 {
301 CHAR ch;
302
303 if (NULL == Address)
304 {
305 GspMemoryError = TRUE;
306 return '\0';
307 }
308
309 GspAccessLocation = Address;
310 ch = *Address;
311 GspAccessLocation = NULL;
312
313 return ch;
314 }
315
316 static CHAR
317 GspWriteMemSafeGetContent(PVOID Context, ULONG Offset)
318 {
319 ASSERT(0 == Offset);
320 return *((PCHAR) Context);
321 }
322
323 static void
324 GspWriteMemSafe(PCHAR Address,
325 CHAR Ch)
326 {
327 GspWriteMem(Address, 1, TRUE, GspWriteMemSafeGetContent, &Ch);
328 }
329
330 /* Convert the memory pointed to by Address into hex, placing result in Buffer */
331 /* Return a pointer to the last char put in Buffer (null) */
332 /* If MayFault is TRUE, then we should set GspMemoryError in response to
333 a fault; if FALSE treat a fault like any other fault in the stub. */
334 static PCHAR
335 GspMem2Hex(PCHAR Address,
336 PCHAR Buffer,
337 LONG Count,
338 BOOLEAN MayFault)
339 {
340 ULONG i;
341 CHAR ch;
342
343 for (i = 0; i < (ULONG) Count; i++)
344 {
345 if (MayFault)
346 {
347 ch = GspReadMemSafe(Address);
348 if (GspMemoryError)
349 return Buffer;
350 }
351 else
352 {
353 ch = *Address;
354 }
355 *Buffer++ = HexChars[(ch >> 4) & 0xf];
356 *Buffer++ = HexChars[ch & 0xf];
357 Address++;
358 }
359
360 *Buffer = 0;
361 return Buffer;
362 }
363
364 static ULONG
365 GspWriteMem(PCHAR Address,
366 ULONG Count,
367 BOOLEAN MayFault,
368 CHAR (*GetContent)(PVOID Context, ULONG Offset),
369 PVOID Context)
370 {
371 PCHAR Current;
372 PCHAR Page;
373 ULONG CountInPage;
374 ULONG i;
375 CHAR ch;
376 ULONG OldProt = 0;
377
378 Current = Address;
379 while (Current < Address + Count)
380 {
381 Page = (PCHAR)PAGE_ROUND_DOWN(Current);
382 if (Address + Count <= Page + PAGE_SIZE)
383 {
384 /* Fits in this page */
385 CountInPage = Count;
386 }
387 else
388 {
389 /* Flows into next page, handle only current page in this iteration */
390 CountInPage = PAGE_SIZE - (Address - Page);
391 }
392 if (MayFault)
393 {
394 OldProt = MmGetPageProtect(NULL, Address);
395 MmSetPageProtect(NULL, Address, PAGE_EXECUTE_READWRITE);
396 }
397
398 for (i = 0; i < CountInPage && ! GspMemoryError; i++)
399 {
400 ch = (*GetContent)(Context, Current - Address);
401
402 if (MayFault)
403 GspAccessLocation = Current;
404
405 *Current = ch;
406
407 if (MayFault)
408 GspAccessLocation = NULL;
409
410 Current++;
411 }
412 if (MayFault)
413 {
414 MmSetPageProtect(NULL, Page, OldProt);
415 if (GspMemoryError)
416 return Current - Address;
417 }
418 }
419
420 return Current - Address;
421 }
422
423 static CHAR
424 GspHex2MemGetContent(PVOID Context, ULONG Offset)
425 {
426 return (CHAR)((HexValue(*((PCHAR) Context + 2 * Offset)) << 4) +
427 HexValue(*((PCHAR) Context + 2 * Offset + 1)));
428 }
429
430 /* Convert the hex array pointed to by Buffer into binary to be placed at Address */
431 /* Return a pointer to the character AFTER the last byte read from Buffer */
432 static PCHAR
433 GspHex2Mem(PCHAR Buffer,
434 PCHAR Address,
435 ULONG Count,
436 BOOLEAN MayFault)
437 {
438 Count = GspWriteMem(Address, Count, MayFault, GspHex2MemGetContent, Buffer);
439 return Buffer + 2 * Count;
440 }
441
442
443 /* This function takes the 386 exception vector and attempts to
444 translate this number into a unix compatible signal value */
445 ULONG
446 GspComputeSignal(NTSTATUS ExceptionCode)
447 {
448 ULONG SigVal;
449
450 switch (ExceptionCode)
451 {
452 case STATUS_INTEGER_DIVIDE_BY_ZERO:
453 SigVal = 8; /* divide by zero */
454 break;
455
456 case STATUS_SINGLE_STEP:
457 case STATUS_BREAKPOINT:
458 SigVal = 5; /* breakpoint */
459 break;
460
461 case STATUS_INTEGER_OVERFLOW:
462 case STATUS_ARRAY_BOUNDS_EXCEEDED:
463 SigVal = 16; /* bound instruction */
464 break;
465
466 case STATUS_ILLEGAL_INSTRUCTION:
467 SigVal = 4; /* Invalid opcode */
468 break;
469
470 case STATUS_STACK_OVERFLOW:
471 case STATUS_DATATYPE_MISALIGNMENT:
472 case STATUS_ACCESS_VIOLATION:
473 SigVal = 11; /* access violation */
474 break;
475
476 default:
477 SigVal = 7; /* "software generated" */
478 }
479 return SigVal;
480 }
481
482
483 /**********************************************/
484 /* WHILE WE FIND NICE HEX CHARS, BUILD A LONG */
485 /* RETURN NUMBER OF CHARS PROCESSED */
486 /**********************************************/
487 LONG
488 GspHex2Long(PCHAR *Address,
489 PLONG Value)
490 {
491 LONG NumChars = 0;
492 LONG Hex;
493
494 *Value = 0;
495
496 while (**Address)
497 {
498 Hex = HexValue(**Address);
499 if (Hex >= 0)
500 {
501 *Value = (*Value << 4) | Hex;
502 NumChars++;
503 }
504 else
505 {
506 break;
507 }
508
509 (*Address)++;
510 }
511
512 return NumChars;
513 }
514
515
516 VOID
517 GspLong2Hex(PCHAR *Address,
518 LONG Value)
519 {
520 LONG Save;
521
522 Save = (((Value >> 0) & 0xff) << 24) |
523 (((Value >> 8) & 0xff) << 16) |
524 (((Value >> 16) & 0xff) << 8) |
525 (((Value >> 24) & 0xff) << 0);
526 *Address = GspMem2Hex((PCHAR) &Save, *Address, 4, FALSE);
527 }
528
529
530 /*
531 * When coming from kernel mode, Esp is not stored in the trap frame.
532 * Instead, it was pointing to the location of the TrapFrame Esp member
533 * when the exception occured. When coming from user mode, Esp is just
534 * stored in the TrapFrame Esp member.
535 */
536 static LONG
537 GspGetEspFromTrapFrame(PKTRAP_FRAME TrapFrame)
538 {
539 return KeGetPreviousMode() == KernelMode
540 ? (LONG) &TrapFrame->Gpr1 : (LONG)TrapFrame->Gpr1;
541 }
542
543
544 static VOID
545 GspGetRegisters(PCHAR Address,
546 PKTRAP_FRAME TrapFrame)
547 {
548 ULONG_PTR Value;
549 PULONG p;
550 ULONG i;
551 PETHREAD Thread;
552 ULONG_PTR *KernelStack;
553
554 if (NULL == GspDbgThread)
555 {
556 Thread = PsGetCurrentThread();
557 }
558 else
559 {
560 TrapFrame = GspDbgThread->Tcb.TrapFrame;
561 Thread = GspDbgThread;
562 }
563
564 if (Waiting == Thread->Tcb.State)
565 {
566 KernelStack = Thread->Tcb.KernelStack;
567 for (i = 0; i < sizeof(GspRegisters) / sizeof(GspRegisters[0]); i++)
568 {
569 switch(i)
570 {
571 }
572 Address = GspMem2Hex((PCHAR) &Value, Address, GspRegisters[i].Size,
573 FALSE);
574 }
575 }
576 else
577 {
578 for (i = 0; i < sizeof(GspRegisters) / sizeof(GspRegisters[0]); i++)
579 {
580 if (TrapFrame)
581 {
582 if (ESP == i)
583 {
584 Value = GspGetEspFromTrapFrame(TrapFrame);
585 }
586 else
587 {
588 p = (PULONG)((ULONG_PTR) TrapFrame +
589 GspRegisters[i].OffsetInTF);
590 Value = *p;
591 }
592 }
593 else if (i == PC)
594 {
595 /*
596 * This thread has not been sheduled yet so assume it
597 * is still in PsBeginThreadWithContextInternal().
598 */
599 Value = (ULONG)KiThreadStartup;
600 }
601 else
602 {
603 Value = 0;
604 }
605 Address = GspMem2Hex((PCHAR) &Value, Address,
606 GspRegisters[i].Size, FALSE);
607 }
608 }
609 }
610
611
612 VOID
613 GspSetRegistersInTrapFrame(PCHAR Address,
614 PCONTEXT Context,
615 PKTRAP_FRAME TrapFrame)
616 {
617 ULONG Value;
618 PCHAR Buffer;
619 PULONG p;
620 ULONG i;
621
622 if (!TrapFrame)
623 {
624 return;
625 }
626
627 Buffer = Address;
628 for (i = 0; i < NUMREGS; i++)
629 {
630 if (GspRegisters[i].SetInContext)
631 {
632 p = (PULONG) ((ULONG_PTR) Context + GspRegisters[i].OffsetInContext);
633 }
634 else
635 {
636 p = (PULONG) ((ULONG_PTR) TrapFrame + GspRegisters[i].OffsetInTF);
637 }
638 Value = 0;
639 Buffer = GspHex2Mem(Buffer, (PCHAR) &Value, GspRegisters[i].Size, FALSE);
640 *p = Value;
641 }
642 }
643
644
645 VOID
646 GspSetSingleRegisterInTrapFrame(PCHAR Address,
647 LONG Number,
648 PCONTEXT Context,
649 PKTRAP_FRAME TrapFrame)
650 {
651 ULONG Value;
652 PULONG p;
653
654 if (!TrapFrame)
655 {
656 return;
657 }
658
659 if (GspRegisters[Number].SetInContext)
660 {
661 p = (PULONG) ((ULONG_PTR) Context + GspRegisters[Number].OffsetInContext);
662 }
663 else
664 {
665 p = (PULONG) ((ULONG_PTR) TrapFrame + GspRegisters[Number].OffsetInTF);
666 }
667 Value = 0;
668 GspHex2Mem(Address, (PCHAR) &Value, GspRegisters[Number].Size, FALSE);
669 *p = Value;
670 }
671
672
673 BOOLEAN
674 GspFindThread(PCHAR Data,
675 PETHREAD *Thread)
676 {
677 PETHREAD ThreadInfo = NULL;
678
679 if (strcmp (Data, "-1") == 0)
680 {
681 /* All threads */
682 ThreadInfo = NULL;
683 }
684 else
685 {
686 ULONG uThreadId;
687 HANDLE ThreadId;
688 PCHAR ptr = &Data[0];
689
690 GspHex2Long(&ptr, (PLONG) &uThreadId);
691 ThreadId = (HANDLE)uThreadId;
692
693 if (!NT_SUCCESS(PsLookupThreadByThreadId(ThreadId, &ThreadInfo)))
694 {
695 *Thread = NULL;
696 return FALSE;
697 }
698 }
699 *Thread = ThreadInfo;
700 return TRUE;
701 }
702
703
704 VOID
705 GspSetThread(PCHAR Request)
706 {
707 PETHREAD ThreadInfo;
708 PCHAR ptr = &Request[1];
709
710 switch (Request[0])
711 {
712 case 'c': /* Run thread */
713 if (GspFindThread(ptr, &ThreadInfo))
714 {
715 GspOutBuffer[0] = 'O';
716 GspOutBuffer[1] = 'K';
717
718 if (NULL != GspRunThread)
719 {
720 ObDereferenceObject(GspRunThread);
721 }
722 GspRunThread = ThreadInfo;
723 if (NULL != GspRunThread)
724 {
725 ObReferenceObject(GspRunThread);
726 }
727 }
728 else
729 {
730 GspOutBuffer[0] = 'E';
731 }
732 break;
733 case 'g': /* Debug thread */
734 if (GspFindThread(ptr, &ThreadInfo))
735 {
736 GspOutBuffer[0] = 'O';
737 GspOutBuffer[1] = 'K';
738
739 if (NULL != GspDbgThread)
740 {
741 ObDereferenceObject(GspDbgThread);
742 }
743
744 if (ThreadInfo == PsGetCurrentThread())
745 {
746 GspDbgThread = NULL;
747 ObDereferenceObject(ThreadInfo);
748 }
749 else
750 {
751 GspDbgThread = ThreadInfo;
752 }
753 }
754 else
755 {
756 GspOutBuffer[0] = 'E';
757 }
758 break;
759 default:
760 break;
761 }
762 }
763
764
765 VOID
766 GspQuery(PCHAR Request)
767 {
768 ULONG Value;
769
770 if (strncmp(Request, "C", 1) == 0)
771 {
772 PCHAR ptr = &GspOutBuffer[2];
773
774 /* Get current thread id */
775 GspOutBuffer[0] = 'Q';
776 GspOutBuffer[1] = 'C';
777 if (NULL != GspDbgThread)
778 {
779 Value = (ULONG) GspDbgThread->Cid.UniqueThread;
780 }
781 else
782 {
783 Value = (ULONG) PsGetCurrentThread()->Cid.UniqueThread;
784 }
785 GspLong2Hex(&ptr, Value);
786 }
787 else if (strncmp(Request, "fThreadInfo", 11) == 0)
788 {
789 PEPROCESS Process;
790 PLIST_ENTRY AThread, AProcess;
791 PCHAR ptr = &GspOutBuffer[1];
792
793 /* Get first thread id */
794 GspEnumThread = NULL;
795 AProcess = PsActiveProcessHead.Flink;
796 while(AProcess != &PsActiveProcessHead)
797 {
798 Process = CONTAINING_RECORD(AProcess, EPROCESS, ActiveProcessLinks);
799 AThread = Process->ThreadListHead.Flink;
800 if (AThread != &Process->ThreadListHead)
801 {
802 GspEnumThread = CONTAINING_RECORD(Process->ThreadListHead.Flink,
803 ETHREAD, ThreadListEntry);
804 break;
805 }
806 AProcess = AProcess->Flink;
807 }
808 if(GspEnumThread != NULL)
809 {
810 GspOutBuffer[0] = 'm';
811 Value = (ULONG) GspEnumThread->Cid.UniqueThread;
812 GspLong2Hex(&ptr, Value);
813 }
814 else
815 {
816 /* FIXME - what to do here? This case should never happen though, there
817 should always be at least one thread on the system... */
818 /* GspOutBuffer[0] = 'l'; */
819 }
820 }
821 else if (strncmp(Request, "sThreadInfo", 11) == 0)
822 {
823 PEPROCESS Process;
824 PLIST_ENTRY AThread, AProcess;
825 PCHAR ptr = &GspOutBuffer[1];
826
827 /* Get next thread id */
828 if (GspEnumThread != NULL)
829 {
830 /* find the next thread */
831 Process = GspEnumThread->ThreadsProcess;
832 if(GspEnumThread->ThreadListEntry.Flink != &Process->ThreadListHead)
833 {
834 GspEnumThread = CONTAINING_RECORD(GspEnumThread->ThreadListEntry.Flink,
835 ETHREAD, ThreadListEntry);
836 }
837 else
838 {
839 PETHREAD Thread = NULL;
840 AProcess = Process->ActiveProcessLinks.Flink;
841 while(AProcess != &PsActiveProcessHead)
842 {
843 Process = CONTAINING_RECORD(AProcess, EPROCESS, ActiveProcessLinks);
844 AThread = Process->ThreadListHead.Flink;
845 if (AThread != &Process->ThreadListHead)
846 {
847 Thread = CONTAINING_RECORD(Process->ThreadListHead.Flink,
848 ETHREAD, ThreadListEntry);
849 break;
850 }
851 AProcess = AProcess->Flink;
852 }
853 GspEnumThread = Thread;
854 }
855
856 if (GspEnumThread != NULL)
857 {
858 /* return the ID */
859 GspOutBuffer[0] = 'm';
860 Value = (ULONG) GspEnumThread->Cid.UniqueThread;
861 GspLong2Hex(&ptr, Value);
862 }
863 else
864 {
865 GspOutBuffer[0] = 'l';
866 }
867 }
868 else
869 {
870 GspOutBuffer[0] = 'l';
871 }
872 }
873 else if (strncmp(Request, "ThreadExtraInfo", 15) == 0)
874 {
875 PETHREAD ThreadInfo;
876
877 /* Get thread information */
878 if (GspFindThread(Request + 16, &ThreadInfo))
879 {
880 char Buffer[64];
881 PEPROCESS Proc;
882
883 Proc = (PEPROCESS) ThreadInfo->ThreadsProcess;
884
885 Buffer[0] = '\0';
886 if (NULL != Proc )
887 {
888 sprintf(Buffer, "%s [%d:0x%x], ", Proc->ImageFileName,
889 (int) Proc->UniqueProcessId,
890 (int) ThreadInfo->Cid.UniqueThread);
891 }
892 strcpy(Buffer + strlen(Buffer),
893 GspThreadStates[ThreadInfo->Tcb.State]);
894
895 ObDereferenceObject(ThreadInfo);
896
897 GspMem2Hex(Buffer, &GspOutBuffer[0], strlen(Buffer), FALSE);
898 }
899 }
900 }
901
902 VOID
903 GspQueryThreadStatus(PCHAR Request)
904 {
905 PETHREAD ThreadInfo;
906 PCHAR ptr = &Request[0];
907
908 if (GspFindThread(ptr, &ThreadInfo))
909 {
910 ObDereferenceObject(ThreadInfo);
911
912 GspOutBuffer[0] = 'O';
913 GspOutBuffer[1] = 'K';
914 GspOutBuffer[2] = '\0';
915 }
916 else
917 {
918 GspOutBuffer[0] = 'E';
919 GspOutBuffer[1] = '\0';
920 }
921 }
922
923 #define DR7_L0 0x00000001 /* Local breakpoint 0 enable */
924 #define DR7_G0 0x00000002 /* Global breakpoint 0 enable */
925 #define DR7_L1 0x00000004 /* Local breakpoint 1 enable */
926 #define DR7_G1 0x00000008 /* Global breakpoint 1 enable */
927 #define DR7_L2 0x00000010 /* Local breakpoint 2 enable */
928 #define DR7_G2 0x00000020 /* Global breakpoint 2 enable */
929 #define DR7_L3 0x00000040 /* Local breakpoint 3 enable */
930 #define DR7_G3 0x00000080 /* Global breakpoint 3 enable */
931 #define DR7_LE 0x00000100 /* Local exact breakpoint enable (old) */
932 #define DR7_GE 0x00000200 /* Global exact breakpoint enable (old) */
933 #define DR7_GD 0x00002000 /* General detect enable */
934 #define DR7_TYPE0_MASK 0x00030000 /* Breakpoint 0 condition */
935 #define DR7_LEN0_MASK 0x000c0000 /* Breakpoint 0 length */
936 #define DR7_TYPE1_MASK 0x00300000 /* Breakpoint 1 condition */
937 #define DR7_LEN1_MASK 0x00c00000 /* Breakpoint 1 length */
938 #define DR7_TYPE2_MASK 0x03000000 /* Breakpoint 2 condition */
939 #define DR7_LEN2_MASK 0x0c000000 /* Breakpoint 2 length */
940 #define DR7_TYPE3_MASK 0x30000000 /* Breakpoint 3 condition */
941 #define DR7_LEN3_MASK 0xc0000000 /* Breakpoint 3 length */
942 #define DR7_GLOBAL_ENABLE(Bp) (2 << (2 * (Bp)))
943 #define DR7_TYPE(Bp, Type) ((Type) << (16 + 4 * (Bp)))
944 #define DR7_LEN(Bp, Len) ((Len) << (18 + 4 * (Bp)))
945
946 #define I386_BP_TYPE_EXECUTE 0
947 #define I386_BP_TYPE_DATA_WRITE 1
948 #define I386_BP_TYPE_DATA_READWRITE 3
949
950 #define I386_OPCODE_INT3 0xcc
951
952 #define GDB_ZTYPE_MEMORY_BREAKPOINT 0
953 #define GDB_ZTYPE_HARDWARE_BREAKPOINT 1
954 #define GDB_ZTYPE_WRITE_WATCHPOINT 2
955 #define GDB_ZTYPE_READ_WATCHPOINT 3
956 #define GDB_ZTYPE_ACCESS_WATCHPOINT 4
957
958 typedef struct _GSPHWBREAKPOINT
959 {
960 ULONG Type;
961 ULONG_PTR Address;
962 ULONG Length;
963 } GSPHWBREAKPOINT;
964
965 #define MAX_HW_BREAKPOINTS 4
966 static unsigned GspHwBreakpointCount = 0;
967 static GSPHWBREAKPOINT GspHwBreakpoints[MAX_HW_BREAKPOINTS];
968
969 typedef struct _GSPSWBREAKPOINT
970 {
971 ULONG_PTR Address;
972 CHAR PrevContent;
973 BOOLEAN Active;
974 } GSPSWBREAKPOINT;
975
976 #define MAX_SW_BREAKPOINTS 64
977 static unsigned GspSwBreakpointCount = 0;
978 static GSPSWBREAKPOINT GspSwBreakpoints[MAX_SW_BREAKPOINTS];
979
980 static void
981 GspSetHwBreakpoint(ULONG Type, ULONG_PTR Address, ULONG Length)
982 {
983 DPRINT("GspSetHwBreakpoint(%lu, 0x%p, %lu)\n", Type, Address, Length);
984
985 if (GDB_ZTYPE_READ_WATCHPOINT == Type)
986 {
987 DPRINT1("Read watchpoint not supported\n");
988 strcpy(GspOutBuffer, "E22");
989 }
990 else if (GDB_ZTYPE_HARDWARE_BREAKPOINT == Type && 1 != Length)
991 {
992 DPRINT1("Invalid length %lu for hardware breakpoint\n", Length);
993 strcpy(GspOutBuffer, "E22");
994 }
995 else if (1 != Length && 2 != Length && 4 != Length)
996 {
997 DPRINT1("Invalid length %lu for GDB Z type %lu\n", Length, Type);
998 strcpy(GspOutBuffer, "E22");
999 }
1000 else if (0 != (Address & (Length - 1)))
1001 {
1002 DPRINT1("Invalid alignment for address 0x%p and length %d\n",
1003 Address, Length);
1004 strcpy(GspOutBuffer, "E22");
1005 }
1006 else if (MAX_HW_BREAKPOINTS == GspHwBreakpointCount)
1007 {
1008 DPRINT1("Trying to set too many hardware breakpoints\n");
1009 strcpy(GspOutBuffer, "E22");
1010 }
1011 else
1012 {
1013 DPRINT("Stored at index %u\n", GspHwBreakpointCount);
1014 GspHwBreakpoints[GspHwBreakpointCount].Type = Type;
1015 GspHwBreakpoints[GspHwBreakpointCount].Address = Address;
1016 GspHwBreakpoints[GspHwBreakpointCount].Length = Length;
1017 GspHwBreakpointCount++;
1018 strcpy(GspOutBuffer, "OK");
1019 }
1020 }
1021
1022 static void
1023 GspRemoveHwBreakpoint(ULONG Type, ULONG_PTR Address, ULONG Length)
1024 {
1025 unsigned Index;
1026
1027 DPRINT("GspRemoveHwBreakpoint(%lu, 0x%p, %lu)\n", Type, Address, Length);
1028 for (Index = 0; Index < GspHwBreakpointCount; Index++)
1029 {
1030 if (GspHwBreakpoints[Index].Type == Type &&
1031 GspHwBreakpoints[Index].Address == Address &&
1032 GspHwBreakpoints[Index].Length == Length)
1033 {
1034 DPRINT("Found match at index %u\n", Index);
1035 if (Index + 1 < GspHwBreakpointCount)
1036 {
1037 memmove(GspHwBreakpoints + Index,
1038 GspHwBreakpoints + (Index + 1),
1039 (GspHwBreakpointCount - Index - 1) *
1040 sizeof(GSPHWBREAKPOINT));
1041 }
1042 GspHwBreakpointCount--;
1043 strcpy(GspOutBuffer, "OK");
1044 return;
1045 }
1046 }
1047
1048 DPRINT1("Not found\n");
1049 strcpy(GspOutBuffer, "E22");
1050 }
1051
1052 static void
1053 GspSetSwBreakpoint(ULONG_PTR Address)
1054 {
1055 DPRINT("GspSetSwBreakpoint(0x%p)\n", Address);
1056
1057 if (MAX_SW_BREAKPOINTS == GspSwBreakpointCount)
1058 {
1059 DPRINT1("Trying to set too many software breakpoints\n");
1060 strcpy(GspOutBuffer, "E22");
1061 }
1062 else
1063 {
1064 DPRINT("Stored at index %u\n", GspSwBreakpointCount);
1065 GspSwBreakpoints[GspSwBreakpointCount].Address = Address;
1066 GspSwBreakpoints[GspSwBreakpointCount].Active = FALSE;
1067 GspSwBreakpointCount++;
1068 strcpy(GspOutBuffer, "OK");
1069 }
1070 }
1071
1072 static void
1073 GspRemoveSwBreakpoint(ULONG_PTR Address)
1074 {
1075 unsigned Index;
1076
1077 DPRINT("GspRemoveSwBreakpoint(0x%p)\n", Address);
1078 for (Index = 0; Index < GspSwBreakpointCount; Index++)
1079 {
1080 if (GspSwBreakpoints[Index].Address == Address)
1081 {
1082 DPRINT("Found match at index %u\n", Index);
1083 ASSERT(! GspSwBreakpoints[Index].Active);
1084 if (Index + 1 < GspSwBreakpointCount)
1085 {
1086 memmove(GspSwBreakpoints + Index,
1087 GspSwBreakpoints + (Index + 1),
1088 (GspSwBreakpointCount - Index - 1) *
1089 sizeof(GSPSWBREAKPOINT));
1090 }
1091 GspSwBreakpointCount--;
1092 strcpy(GspOutBuffer, "OK");
1093 return;
1094 }
1095 }
1096
1097 DPRINT1("Not found\n");
1098 strcpy(GspOutBuffer, "E22");
1099 }
1100
1101 static void
1102 GspLoadHwBreakpoint(PKTRAP_FRAME TrapFrame,
1103 unsigned BpIndex,
1104 ULONG_PTR Address,
1105 ULONG Length,
1106 ULONG Type)
1107 {
1108 DPRINT("GspLoadHwBreakpoint(0x%p, %d, 0x%p, %d)\n", TrapFrame, BpIndex,
1109 Address, Type);
1110
1111 /* Set the DR7_Gx bit to globally enable the breakpoint */
1112 TrapFrame->Dr7 |= DR7_GLOBAL_ENABLE(BpIndex) |
1113 DR7_LEN(BpIndex, Length) |
1114 DR7_TYPE(BpIndex, Type);
1115
1116 switch (BpIndex)
1117 {
1118 case 0:
1119 DPRINT("Setting DR0 to 0x%p\n", Address);
1120 TrapFrame->Dr0 = Address;
1121 break;
1122
1123 case 1:
1124 DPRINT("Setting DR1 to 0x%p\n", Address);
1125 TrapFrame->Dr1 = Address;
1126 break;
1127
1128 case 2:
1129 DPRINT("Setting DR2 to 0x%p\n", Address);
1130 TrapFrame->Dr2 = Address;
1131 break;
1132
1133 case 3:
1134 DPRINT("Setting DR3 to 0x%p\n", Address);
1135 TrapFrame->Dr3 = Address;
1136 break;
1137 }
1138 }
1139
1140 static void
1141 GspLoadBreakpoints(PKTRAP_FRAME TrapFrame)
1142 {
1143 unsigned Index;
1144 ULONG i386Type;
1145
1146 DPRINT("GspLoadBreakpoints\n");
1147 DPRINT("DR7 on entry: 0x%08x\n", TrapFrame->Dr7);
1148 /* Remove all breakpoints */
1149 TrapFrame->Dr7 &= ~(DR7_L0 | DR7_L1 | DR7_L2 | DR7_L3 |
1150 DR7_G0 | DR7_G1 | DR7_G2 | DR7_G3 |
1151 DR7_TYPE0_MASK | DR7_LEN0_MASK |
1152 DR7_TYPE1_MASK | DR7_LEN1_MASK |
1153 DR7_TYPE2_MASK | DR7_LEN2_MASK |
1154 DR7_TYPE3_MASK | DR7_LEN3_MASK);
1155
1156 for (Index = 0; Index < GspHwBreakpointCount; Index++)
1157 {
1158 switch(GspHwBreakpoints[Index].Type)
1159 {
1160 case GDB_ZTYPE_HARDWARE_BREAKPOINT:
1161 i386Type = I386_BP_TYPE_EXECUTE;
1162 break;
1163 case GDB_ZTYPE_WRITE_WATCHPOINT:
1164 i386Type = I386_BP_TYPE_DATA_WRITE;
1165 break;
1166 case GDB_ZTYPE_ACCESS_WATCHPOINT:
1167 i386Type = I386_BP_TYPE_DATA_READWRITE;
1168 break;
1169 default:
1170 ASSERT(FALSE);
1171 i386Type = I386_BP_TYPE_EXECUTE;
1172 break;
1173 }
1174
1175 GspLoadHwBreakpoint(TrapFrame, Index, GspHwBreakpoints[Index].Address,
1176 GspHwBreakpoints[Index].Length - 1, i386Type);
1177 }
1178
1179 for (Index = 0; Index < GspSwBreakpointCount; Index++)
1180 {
1181 if (GspHwBreakpointCount + Index < MAX_HW_BREAKPOINTS)
1182 {
1183 DPRINT("Implementing software interrupt using hardware register\n");
1184 GspLoadHwBreakpoint(TrapFrame, GspHwBreakpointCount + Index,
1185 GspSwBreakpoints[Index].Address, 0,
1186 I386_BP_TYPE_EXECUTE);
1187 GspSwBreakpoints[Index].Active = FALSE;
1188 }
1189 else
1190 {
1191 DPRINT("Using real software breakpoint\n");
1192 GspMemoryError = FALSE;
1193 GspSwBreakpoints[Index].PrevContent = GspReadMemSafe((PCHAR) GspSwBreakpoints[Index].Address);
1194 if (! GspMemoryError)
1195 {
1196 GspWriteMemSafe((PCHAR) GspSwBreakpoints[Index].Address, I386_OPCODE_INT3);
1197 }
1198 GspSwBreakpoints[Index].Active = ! GspMemoryError;
1199 if (GspMemoryError)
1200 {
1201 DPRINT1("Failed to set software breakpoint at 0x%p\n",
1202 GspSwBreakpoints[Index].Address);
1203 }
1204 else
1205 {
1206 DPRINT("Successfully set software breakpoint at 0x%p\n",
1207 GspSwBreakpoints[Index].Address);
1208 DPRINT1("Successfully set software breakpoint at 0x%p\n", GspSwBreakpoints[Index].Address);
1209 }
1210 }
1211 }
1212
1213 DPRINT("Final DR7 value 0x%08x\n", TrapFrame->Dr7);
1214 }
1215
1216 static void
1217 GspUnloadBreakpoints(PKTRAP_FRAME TrapFrame)
1218 {
1219 unsigned Index;
1220
1221 DPRINT("GspUnloadHwBreakpoints\n");
1222
1223 for (Index = 0; Index < GspSwBreakpointCount; Index++)
1224 {
1225 if (GspSwBreakpoints[Index].Active)
1226 {
1227 GspMemoryError = FALSE;
1228 GspWriteMemSafe((PCHAR) GspSwBreakpoints[Index].Address,
1229 GspSwBreakpoints[Index].PrevContent);
1230 GspSwBreakpoints[Index].Active = FALSE;
1231 if (GspMemoryError)
1232 {
1233 DPRINT1("Failed to remove software breakpoint from 0x%p\n",
1234 GspSwBreakpoints[Index].Address);
1235 }
1236 else
1237 {
1238 DPRINT("Successfully removed software breakpoint from 0x%p\n",
1239 GspSwBreakpoints[Index].Address);
1240 }
1241 }
1242 }
1243 }
1244
1245 static BOOLEAN gdb_attached_yet = FALSE;
1246 /*
1247 * This function does all command procesing for interfacing to gdb.
1248 */
1249 KD_CONTINUE_TYPE
1250 NTAPI
1251 KdpGdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
1252 PCONTEXT Context,
1253 PKTRAP_FRAME TrapFrame)
1254 {
1255 BOOLEAN Stepping;
1256 LONG Address;
1257 LONG Length;
1258 LONG SigVal = 0;
1259 //LONG NewPC;
1260 PCHAR ptr;
1261
1262 /* FIXME: Stop on other CPUs too */
1263
1264 if (STATUS_ACCESS_VIOLATION == (NTSTATUS) ExceptionRecord->ExceptionCode &&
1265 NULL != GspAccessLocation &&
1266 (ULONG_PTR) GspAccessLocation ==
1267 (ULONG_PTR) ExceptionRecord->ExceptionInformation[1])
1268 {
1269 GspAccessLocation = NULL;
1270 GspMemoryError = TRUE;
1271 //Context->Eip += 3;
1272 }
1273 else
1274 {
1275 DPRINT("Thread %p entering stub\n", PsGetCurrentThread());
1276 /* Can only debug 1 thread at a time... */
1277 ExAcquireFastMutex(&GspLock);
1278 DPRINT("Thread %p acquired mutex\n", PsGetCurrentThread());
1279
1280 /* Disable hardware debugging while we are inside the stub */
1281 //Ke386SetDr7(0);
1282 GspUnloadBreakpoints(TrapFrame);
1283
1284 /* Make sure we're debugging the current thread. */
1285 if (NULL != GspDbgThread)
1286 {
1287 DPRINT1("Internal error: entering stub with non-NULL GspDbgThread\n");
1288 ObDereferenceObject(GspDbgThread);
1289 GspDbgThread = NULL;
1290 }
1291
1292 /* ugly hack to avoid attempting to send status at the very
1293 * beginning, right when GDB is trying to query the stub */
1294 if (gdb_attached_yet)
1295 {
1296 LONG Esp;
1297
1298 stop_reply:
1299 /* reply to host that an exception has occurred */
1300 SigVal = GspComputeSignal(ExceptionRecord->ExceptionCode);
1301
1302 ptr = GspOutBuffer;
1303
1304 *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */
1305 *ptr++ = HexChars[(SigVal >> 4) & 0xf];
1306 *ptr++ = HexChars[SigVal & 0xf];
1307
1308 *ptr++ = HexChars[ESP];
1309 *ptr++ = ':';
1310
1311 Esp = GspGetEspFromTrapFrame(TrapFrame); /* SP */
1312 ptr = GspMem2Hex((PCHAR) &Esp, ptr, 4, 0);
1313 *ptr++ = ';';
1314
1315 *ptr++ = HexChars[EBP];
1316 *ptr++ = ':';
1317 //ptr = GspMem2Hex((PCHAR) &TrapFrame->Ebp, ptr, 4, 0); /* FP */
1318 *ptr++ = ';';
1319
1320 *ptr++ = HexChars[PC];
1321 *ptr++ = ':';
1322 //ptr = GspMem2Hex((PCHAR) &TrapFrame->Eip, ptr, 4, 0); /* PC */
1323 *ptr++ = ';';
1324
1325 *ptr = '\0';
1326
1327 GspPutPacket(&GspOutBuffer[0]);
1328 }
1329 else
1330 {
1331 gdb_attached_yet = 1;
1332 }
1333
1334 Stepping = FALSE;
1335
1336 while (TRUE)
1337 {
1338 /* Zero the buffer now so we don't have to worry about the terminating zero character */
1339 memset(GspOutBuffer, 0, sizeof(GspInBuffer));
1340 ptr = GspGetPacket();
1341
1342 switch(*ptr++)
1343 {
1344 case '?':
1345 /* a little hack to send more complete status information */
1346 goto stop_reply;
1347 GspOutBuffer[0] = 'S';
1348 GspOutBuffer[1] = HexChars[SigVal >> 4];
1349 GspOutBuffer[2] = HexChars[SigVal % 16];
1350 GspOutBuffer[3] = 0;
1351 break;
1352 case 'd':
1353 GspRemoteDebug = !GspRemoteDebug; /* toggle debug flag */
1354 break;
1355 case 'g': /* return the value of the CPU Registers */
1356 GspGetRegisters(GspOutBuffer, TrapFrame);
1357 break;
1358 case 'G': /* set the value of the CPU Registers - return OK */
1359 if (NULL != GspDbgThread)
1360 {
1361 GspSetRegistersInTrapFrame(ptr, Context, GspDbgThread->Tcb.TrapFrame);
1362 }
1363 else
1364 {
1365 GspSetRegistersInTrapFrame(ptr, Context, TrapFrame);
1366 }
1367 strcpy(GspOutBuffer, "OK");
1368 break;
1369 case 'P': /* set the value of a single CPU register - return OK */
1370 {
1371 LONG Register;
1372
1373 if ((GspHex2Long(&ptr, &Register)) && (*ptr++ == '='))
1374 {
1375 if ((Register >= 0) && (Register < NUMREGS))
1376 {
1377 if (GspDbgThread)
1378 {
1379 GspSetSingleRegisterInTrapFrame(ptr, Register,
1380 Context,
1381 GspDbgThread->Tcb.TrapFrame);
1382 }
1383 else
1384 {
1385 GspSetSingleRegisterInTrapFrame(ptr, Register,
1386 Context, TrapFrame);
1387 }
1388 strcpy(GspOutBuffer, "OK");
1389 break;
1390 }
1391 }
1392
1393 strcpy(GspOutBuffer, "E01");
1394 break;
1395 }
1396
1397 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
1398 case 'm':
1399 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
1400 if (GspHex2Long(&ptr, &Address) &&
1401 *(ptr++) == ',' &&
1402 GspHex2Long(&ptr, &Length))
1403 {
1404 PEPROCESS DbgProcess = NULL;
1405
1406 ptr = NULL;
1407 if (NULL != GspDbgThread &&
1408 PsGetCurrentProcess() != GspDbgThread->ThreadsProcess)
1409 {
1410 DbgProcess = GspDbgThread->ThreadsProcess;
1411 KeAttachProcess(&DbgProcess->Pcb);
1412 }
1413 GspMemoryError = FALSE;
1414 GspMem2Hex((PCHAR) Address, GspOutBuffer, Length, 1);
1415 if (NULL != DbgProcess)
1416 {
1417 KeDetachProcess();
1418 }
1419 if (GspMemoryError)
1420 {
1421 strcpy(GspOutBuffer, "E03");
1422 DPRINT("Fault during memory read\n");
1423 }
1424 }
1425
1426 if (NULL != ptr)
1427 {
1428 strcpy(GspOutBuffer, "E01");
1429 }
1430 break;
1431
1432 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
1433 case 'M':
1434 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
1435 if (GspHex2Long(&ptr, &Address))
1436 {
1437 if (*(ptr++) == ',' &&
1438 GspHex2Long(&ptr, &Length) &&
1439 *(ptr++) == ':')
1440 {
1441 PEPROCESS DbgProcess = NULL;
1442
1443 if (NULL != GspDbgThread &&
1444 PsGetCurrentProcess() != GspDbgThread->ThreadsProcess)
1445 {
1446 DbgProcess = GspDbgThread->ThreadsProcess;
1447 KeAttachProcess(&DbgProcess->Pcb);
1448 }
1449 GspMemoryError = FALSE;
1450 GspHex2Mem(ptr, (PCHAR) Address, Length, TRUE);
1451 if (NULL != DbgProcess)
1452 {
1453 KeDetachProcess();
1454 }
1455 if (GspMemoryError)
1456 {
1457 strcpy(GspOutBuffer, "E03");
1458 DPRINT("Fault during memory write\n");
1459 }
1460 else
1461 {
1462 strcpy(GspOutBuffer, "OK");
1463 }
1464 ptr = NULL;
1465 }
1466 }
1467
1468 if (NULL != ptr)
1469 {
1470 strcpy(GspOutBuffer, "E02");
1471 }
1472 break;
1473
1474 /* cAA..AA Continue at address AA..AA(optional) */
1475 /* sAA..AA Step one instruction from AA..AA(optional) */
1476 case 's':
1477 Stepping = TRUE;
1478 case 'c':
1479 {
1480 ULONG BreakpointNumber;
1481 ULONG dr6_ = 0;
1482
1483 /* try to read optional parameter, pc unchanged if no parm */
1484 if (GspHex2Long (&ptr, &Address))
1485 {
1486 //Context->Eip = Address;
1487 }
1488
1489 //NewPC = Context->Eip;
1490
1491 /* clear the trace bit */
1492 //Context->EFlags &= 0xfffffeff;
1493
1494 /* set the trace bit if we're Stepping */
1495 if (Stepping)
1496 {
1497 //Context->EFlags |= 0x100;
1498 }
1499
1500 // XXX arty load dr6
1501 if (!(dr6_ & 0x4000))
1502 {
1503 for (BreakpointNumber = 0; BreakpointNumber < 4; ++BreakpointNumber)
1504 {
1505 if (dr6_ & (1 << BreakpointNumber))
1506 {
1507 if (GspHwBreakpoints[BreakpointNumber].Type == 0)
1508 {
1509 /* Set restore flag */
1510 //Context->EFlags |= 0x10000;
1511 break;
1512 }
1513 }
1514 }
1515 }
1516 GspLoadBreakpoints(TrapFrame);
1517 // XXX load dr6
1518 if (NULL != GspDbgThread)
1519 {
1520 ObDereferenceObject(GspDbgThread);
1521 GspDbgThread = NULL;
1522 }
1523
1524 DPRINT("Thread %p releasing mutex\n", PsGetCurrentThread());
1525 ExReleaseFastMutex(&GspLock);
1526 DPRINT("Thread %p leaving stub\n", PsGetCurrentThread());
1527 return kdContinue;
1528 break;
1529 }
1530
1531 case 'k': /* kill the program */
1532 strcpy(GspOutBuffer, "OK");
1533 break;
1534 /* kill the program */
1535
1536 case 'H': /* Set thread */
1537 GspSetThread(ptr);
1538 break;
1539
1540 case 'q': /* Query */
1541 GspQuery(ptr);
1542 break;
1543
1544 case 'T': /* Query thread status */
1545 GspQueryThreadStatus(ptr);
1546 break;
1547
1548 case 'Z':
1549 {
1550 LONG Type;
1551 LONG Address;
1552 LONG Length;
1553
1554 GspHex2Long(&ptr, &Type);
1555 ptr++;
1556 GspHex2Long(&ptr, &Address);
1557 ptr++;
1558 GspHex2Long(&ptr, &Length);
1559 if (0 == Type)
1560 {
1561 GspSetSwBreakpoint((ULONG_PTR) Address);
1562 }
1563 else
1564 {
1565 GspSetHwBreakpoint(Type, (ULONG_PTR) Address, Length);
1566 }
1567 break;
1568 }
1569
1570 case 'z':
1571 {
1572 LONG Type;
1573 LONG Address;
1574 LONG Length;
1575
1576 GspHex2Long(&ptr, &Type);
1577 ptr++;
1578 GspHex2Long(&ptr, &Address);
1579 ptr++;
1580 GspHex2Long(&ptr, &Length);
1581 if (0 == Type)
1582 {
1583 GspRemoveSwBreakpoint((ULONG_PTR) Address);
1584 }
1585 else
1586 {
1587 GspRemoveHwBreakpoint(Type, (ULONG_PTR) Address, Length);
1588 }
1589 break;
1590 }
1591
1592 default:
1593 break;
1594 }
1595
1596 /* reply to the request */
1597 GspPutPacket(GspOutBuffer);
1598 }
1599
1600 /* not reached */
1601 ASSERT(0);
1602 }
1603
1604 if (NULL != GspDbgThread)
1605 {
1606 ObDereferenceObject(GspDbgThread);
1607 GspDbgThread = NULL;
1608 }
1609
1610 return kdContinue;
1611 }
1612
1613
1614 BOOLEAN
1615 NTAPI
1616 GspBreakIn(PKINTERRUPT Interrupt,
1617 PVOID ServiceContext)
1618 {
1619 PKTRAP_FRAME TrapFrame;
1620 BOOLEAN DoBreakIn;
1621 CONTEXT Context;
1622 KIRQL OldIrql;
1623 UCHAR Value;
1624
1625 DPRINT("Break In\n");
1626
1627 DoBreakIn = FALSE;
1628 while (KdPortGetByteEx(&GdbPortInfo, &Value))
1629 {
1630 if (Value == 0x03)
1631 DoBreakIn = TRUE;
1632 }
1633
1634 if (!DoBreakIn)
1635 return TRUE;
1636
1637 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1638
1639 TrapFrame = PsGetCurrentThread()->Tcb.TrapFrame;
1640
1641 KeTrapFrameToContext(TrapFrame, NULL, &Context);
1642
1643 KdpGdbEnterDebuggerException(NULL, &Context, TrapFrame);
1644
1645 KeContextToTrapFrame(&Context, NULL, TrapFrame, Context.ContextFlags, KernelMode);
1646
1647 KeLowerIrql(OldIrql);
1648
1649 return TRUE;
1650 }
1651
1652 VOID
1653 NTAPI
1654 KdpGdbDebugPrint(PCH Message, ULONG Length)
1655 {
1656 }
1657
1658 /* Initialize the GDB stub */
1659 VOID
1660 NTAPI
1661 KdpGdbStubInit(PKD_DISPATCH_TABLE WrapperTable,
1662 ULONG BootPhase)
1663 {
1664 if (!KdDebuggerEnabled || !KdpDebugMode.Gdb)
1665 return;
1666
1667 if (BootPhase == 0)
1668 {
1669 ExInitializeFastMutex(&GspLock);
1670
1671 /* Write out the functions that we support for now */
1672 WrapperTable->KdpInitRoutine = KdpGdbStubInit;
1673 WrapperTable->KdpPrintRoutine = KdpGdbDebugPrint;
1674 WrapperTable->KdpExceptionRoutine = KdpGdbEnterDebuggerException;
1675
1676 /* Initialize the Port */
1677 KdPortInitializeEx(&GdbPortInfo, GdbPortNumber);
1678 // KdpPort = GdbPortInfo.ComPort;
1679 }
1680 else if (BootPhase == 1)
1681 {
1682 GspInitialized = TRUE;
1683
1684 GspRunThread = NULL;
1685 GspDbgThread = NULL;
1686 GspEnumThread = NULL;
1687
1688 HalDisplayString("Waiting for GDB to attach\r\n");
1689 DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
1690 }
1691 else if (BootPhase == 2)
1692 {
1693 HalDisplayString("\r\n GDB debugging enabled\r\n\r\n");
1694 }
1695 }
1696
1697 /* EOF */