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