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