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