cfa94fd4ca8479893c94d7f0f6704788d0d76a1d
[reactos.git] / reactos / ntoskrnl / kd / wrappers / gdbstub.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 <internal/debug.h>
89 #include <internal/ps.h>
90
91 /************************************************************************/
92 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
93 /* at least NUMREGBYTES*2 are needed for register packets */
94 #define BUFMAX 1000
95
96 static BOOLEAN GspInitialized;
97 #if 0
98 static PKINTERRUPT GspInterrupt;
99 #endif
100
101 static BOOLEAN GspRemoteDebug;
102
103 static CONST CHAR HexChars[]="0123456789abcdef";
104
105 static PETHREAD GspRunThread; /* NULL means run all threads */
106 static PETHREAD GspDbgThread;
107 static PETHREAD GspEnumThread;
108
109 extern LIST_ENTRY PsActiveProcessHead;
110 KD_PORT_INFORMATION GdbPortInfo = { 2, 115200, 0 }; /* FIXME hardcoded for COM2, 115200 baud */
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 DWORD Size;
126 DWORD OffsetInTF;
127 DWORD OffsetInContext;
128 BOOLEAN SetInContext;
129 } CPU_REGISTER, *PCPU_REGISTER;
130
131 #define KTRAP_FRAME_X86 KTRAP_FRAME
132
133 #define EIP_REGNO 8
134
135 static CPU_REGISTER GspRegisters[NUMREGS] =
136 {
137 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Eax), FIELD_OFFSET (CONTEXT, Eax), TRUE },
138 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Ecx), FIELD_OFFSET (CONTEXT, Ecx), TRUE },
139 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Edx), FIELD_OFFSET (CONTEXT, Edx), FALSE },
140 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Ebx), FIELD_OFFSET (CONTEXT, Ebx), TRUE },
141 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Esp), FIELD_OFFSET (CONTEXT, Esp), TRUE },
142 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Ebp), FIELD_OFFSET (CONTEXT, Ebp), TRUE },
143 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Esi), FIELD_OFFSET (CONTEXT, Esi), TRUE },
144 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Edi), FIELD_OFFSET (CONTEXT, Edi), TRUE },
145 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Eip), FIELD_OFFSET (CONTEXT, Eip), TRUE },
146 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Eflags), FIELD_OFFSET (CONTEXT, EFlags), TRUE },
147 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Cs), FIELD_OFFSET (CONTEXT, SegCs), TRUE },
148 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Ss), FIELD_OFFSET (CONTEXT, SegSs), TRUE },
149 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Ds), FIELD_OFFSET (CONTEXT, SegDs), TRUE },
150 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Es), FIELD_OFFSET (CONTEXT, SegEs), TRUE },
151 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Fs), FIELD_OFFSET (CONTEXT, SegFs), TRUE },
152 { 4, FIELD_OFFSET (KTRAP_FRAME_X86, Gs), FIELD_OFFSET (CONTEXT, SegGs), TRUE }
153 };
154
155 static PCHAR GspThreadStates[DeferredReady+1] =
156 { "Initialized",
157 "Ready",
158 "Running",
159 "Standby",
160 "Terminated",
161 "Waiting",
162 "Transition",
163 "DeferredReady"
164 };
165
166
167 LONG
168 HexValue (CHAR ch)
169 {
170 if ((ch >= '0') && (ch <= '9')) return (ch - '0');
171 if ((ch >= 'a') && (ch <= 'f')) return (ch - 'a' + 10);
172 if ((ch >= 'A') && (ch <= 'F')) return (ch - 'A' + 10);
173 return (-1);
174 }
175
176 static CHAR GspInBuffer[BUFMAX];
177 static CHAR GspOutBuffer[BUFMAX];
178
179 VOID
180 GdbPutChar(UCHAR Value)
181 {
182 KdPortPutByteEx (&GdbPortInfo, Value);
183 }
184
185 UCHAR
186 GdbGetChar(VOID)
187 {
188 UCHAR Value;
189
190 while (!KdPortGetByteEx (&GdbPortInfo, &Value));
191
192 return Value;
193 }
194
195 /* scan for the sequence $<data>#<Checksum> */
196
197 PCHAR
198 GspGetPacket()
199 {
200 PCHAR Buffer = &GspInBuffer[0];
201 CHAR Checksum;
202 CHAR XmitChecksum;
203 ULONG Count;
204 CHAR ch;
205
206 while (TRUE)
207 {
208 /* wait around for the start character, ignore all other characters */
209 while ((ch = GdbGetChar ()) != '$');
210
211 retry:
212 Checksum = 0;
213 XmitChecksum = -1;
214 Count = 0;
215
216 /* now, read until a # or end of Buffer is found */
217 while (Count < BUFMAX)
218 {
219 ch = GdbGetChar ();
220 if (ch == '$')
221 goto retry;
222 if (ch == '#')
223 break;
224 Checksum = Checksum + ch;
225 Buffer[Count] = ch;
226 Count = Count + 1;
227 }
228 Buffer[Count] = 0;
229
230 if (ch == '#')
231 {
232 ch = GdbGetChar ();
233 XmitChecksum = (CHAR)(HexValue (ch) << 4);
234 ch = GdbGetChar ();
235 XmitChecksum += (CHAR)(HexValue (ch));
236
237 if (Checksum != XmitChecksum)
238 {
239 GdbPutChar ('-'); /* failed checksum */
240 }
241 else
242 {
243 GdbPutChar ('+'); /* successful transfer */
244
245 /* if a sequence char is present, reply the sequence ID */
246 if (Buffer[2] == ':')
247 {
248 GdbPutChar (Buffer[0]);
249 GdbPutChar (Buffer[1]);
250
251 return &Buffer[3];
252 }
253
254 return &Buffer[0];
255 }
256 }
257 }
258 }
259
260 /* send the packet in Buffer. */
261
262 VOID
263 GspPutPacket (PCHAR Buffer)
264 {
265 CHAR Checksum;
266 LONG Count;
267 CHAR ch;
268
269 /* $<packet info>#<Checksum>. */
270 do
271 {
272 GdbPutChar ('$');
273 Checksum = 0;
274 Count = 0;
275
276 while ((ch = Buffer[Count]))
277 {
278 GdbPutChar (ch);
279 Checksum += ch;
280 Count += 1;
281 }
282
283 GdbPutChar ('#');
284 GdbPutChar (HexChars[(Checksum >> 4) & 0xf]);
285 GdbPutChar (HexChars[Checksum & 0xf]);
286 }
287 while (GdbGetChar () != '+');
288 }
289
290
291 VOID
292 GspPutPacketNoWait (PCHAR Buffer)
293 {
294 CHAR Checksum;
295 LONG Count;
296 CHAR ch;
297
298 /* $<packet info>#<Checksum>. */
299 GdbPutChar ('$');
300 Checksum = 0;
301 Count = 0;
302
303 while ((ch = Buffer[Count]))
304 {
305 GdbPutChar (ch);
306 Checksum += ch;
307 Count += 1;
308 }
309
310 GdbPutChar ('#');
311 GdbPutChar (HexChars[(Checksum >> 4) & 0xf]);
312 GdbPutChar (HexChars[Checksum & 0xf]);
313 }
314
315 /* Indicate to caller of GspMem2Hex or GspHex2Mem that there has been an
316 error. */
317 static volatile BOOLEAN GspMemoryError = FALSE;
318 static volatile void *GspAccessLocation = NULL;
319
320
321 /* Convert the memory pointed to by Address into hex, placing result in Buffer */
322 /* Return a pointer to the last char put in Buffer (null) */
323 /* If MayFault is TRUE, then we should set GspMemoryError in response to
324 a fault; if FALSE treat a fault like any other fault in the stub. */
325 PCHAR
326 GspMem2Hex (PCHAR Address,
327 PCHAR Buffer,
328 LONG Count,
329 BOOLEAN MayFault)
330 {
331 ULONG i;
332 CHAR ch;
333
334 if (NULL == Address && MayFault)
335 {
336 GspMemoryError = TRUE;
337 return Buffer;
338 }
339
340 for (i = 0; i < (ULONG) Count; i++)
341 {
342 if (MayFault)
343 GspAccessLocation = Address;
344 ch = *Address;
345 GspAccessLocation = NULL;
346 if (MayFault && GspMemoryError)
347 {
348 return (Buffer);
349 }
350 *Buffer++ = HexChars[(ch >> 4) & 0xf];
351 *Buffer++ = HexChars[ch & 0xf];
352 Address++;
353 }
354 *Buffer = 0;
355 return (Buffer);
356 }
357
358
359 /* Convert the hex array pointed to by Buffer into binary to be placed at Address */
360 /* Return a pointer to the character AFTER the last byte read from Buffer */
361 PCHAR
362 GspHex2Mem (PCHAR Buffer,
363 PCHAR Address,
364 ULONG Count,
365 BOOLEAN MayFault)
366 {
367 PCHAR current;
368 PCHAR page;
369 ULONG countinpage;
370 ULONG i;
371 CHAR ch;
372 ULONG oldprot = 0;
373
374 current = Address;
375 while ( current < Address + Count )
376 {
377 page = (PCHAR)PAGE_ROUND_DOWN (current);
378 if (Address + Count <= page + PAGE_SIZE)
379 {
380 /* Fits in this page */
381 countinpage = Count;
382 }
383 else
384 {
385 /* Flows into next page, handle only current page in this iteration */
386 countinpage = PAGE_SIZE - (Address - page);
387 }
388 if (MayFault)
389 {
390 oldprot = MmGetPageProtect (NULL, Address);
391 MmSetPageProtect (NULL, Address, PAGE_EXECUTE_READWRITE);
392 }
393
394 for (i = 0; i < countinpage && ! GspMemoryError; i++)
395 {
396 ch = (CHAR)(HexValue (*Buffer++) << 4);
397 ch = (CHAR)(ch + HexValue (*Buffer++));
398
399 GspAccessLocation = current;
400 *current = ch;
401 GspAccessLocation = NULL;
402 current++;
403 }
404 if (MayFault)
405 {
406 MmSetPageProtect (NULL, page, oldprot);
407 if (GspMemoryError)
408 {
409 return (Buffer);
410 }
411 }
412 }
413
414 return (Buffer);
415 }
416
417
418 /* This function takes the 386 exception vector and attempts to
419 translate this number into a unix compatible signal value */
420 ULONG
421 GspComputeSignal (NTSTATUS ExceptionCode)
422 {
423 ULONG SigVal;
424
425 switch (ExceptionCode)
426 {
427 case STATUS_INTEGER_DIVIDE_BY_ZERO:
428 SigVal = 8;
429 break; /* divide by zero */
430 case STATUS_SINGLE_STEP:
431 /* debug exception */
432 case STATUS_BREAKPOINT:
433 SigVal = 5;
434 break; /* breakpoint */
435 case STATUS_INTEGER_OVERFLOW:
436 /* into instruction (overflow) */
437 case STATUS_ARRAY_BOUNDS_EXCEEDED:
438 SigVal = 16;
439 break; /* bound instruction */
440 case STATUS_ILLEGAL_INSTRUCTION:
441 SigVal = 4;
442 break; /* Invalid opcode */
443 #if 0
444 case STATUS_FLT_INVALID_OPERATION:
445 SigVal = 8;
446 break; /* coprocessor not available */
447 #endif
448 case STATUS_STACK_OVERFLOW:
449 /* stack exception */
450 case STATUS_DATATYPE_MISALIGNMENT:
451 /* page fault */
452 case STATUS_ACCESS_VIOLATION:
453 SigVal = 11; /* access violation */
454 break;
455 default:
456 SigVal = 7; /* "software generated" */
457 }
458 return (SigVal);
459 }
460
461
462 /**********************************************/
463 /* WHILE WE FIND NICE HEX CHARS, BUILD A LONG */
464 /* RETURN NUMBER OF CHARS PROCESSED */
465 /**********************************************/
466 LONG
467 GspHex2Long (PCHAR *Address,
468 PLONG Value)
469 {
470 LONG NumChars = 0;
471 LONG Hex;
472
473 *Value = 0;
474
475 while (**Address)
476 {
477 Hex = HexValue (**Address);
478 if (Hex >= 0)
479 {
480 *Value = (*Value << 4) | Hex;
481 NumChars++;
482 }
483 else
484 break;
485
486 (*Address)++;
487 }
488
489 return (NumChars);
490 }
491
492
493 VOID
494 GspLong2Hex (PCHAR *Address,
495 LONG Value)
496 {
497 LONG Save;
498
499 Save = (((Value >> 0) & 0xff) << 24) |
500 (((Value >> 8) & 0xff) << 16) |
501 (((Value >> 16) & 0xff) << 8) |
502 (((Value >> 24) & 0xff) << 0);
503 *Address = GspMem2Hex ((PCHAR) &Save, *Address, 4, FALSE);
504 }
505
506
507 /*
508 * When coming from kernel mode, Esp is not stored in the trap frame.
509 * Instead, it was pointing to the location of the TrapFrame Esp member
510 * when the exception occured. When coming from user mode, Esp is just
511 * stored in the TrapFrame Esp member.
512 */
513 static LONG
514 GspGetEspFromTrapFrame(PKTRAP_FRAME TrapFrame)
515 {
516
517 return KeGetPreviousMode() == KernelMode
518 ? (LONG) &TrapFrame->Esp : (LONG)TrapFrame->Esp;
519 }
520
521
522 VOID
523 GspGetRegistersFromTrapFrame(PCHAR Address,
524 PCONTEXT Context,
525 PKTRAP_FRAME TrapFrame)
526 {
527 ULONG Value;
528 PCHAR Buffer;
529 PULONG p;
530 DWORD i;
531
532 Buffer = Address;
533 for (i = 0; i < sizeof (GspRegisters) / sizeof (GspRegisters[0]); i++)
534 {
535 if (TrapFrame)
536 {
537 if (ESP == i)
538 {
539 Value = GspGetEspFromTrapFrame (TrapFrame);
540 }
541 else
542 {
543 p = (PULONG) ((ULONG_PTR) TrapFrame + GspRegisters[i].OffsetInTF);
544 Value = *p;
545 }
546 }
547 else if (i == EIP_REGNO)
548 {
549 /*
550 * This thread has not been sheduled yet so assume it
551 * is still in PsBeginThreadWithContextInternal().
552 */
553 Value = (ULONG)KiThreadStartup;
554 }
555 else
556 {
557 Value = 0;
558 }
559 Buffer = GspMem2Hex ((PCHAR) &Value, Buffer, GspRegisters[i].Size, FALSE);
560 }
561 }
562
563
564 VOID
565 GspSetRegistersInTrapFrame(PCHAR Address,
566 PCONTEXT Context,
567 PKTRAP_FRAME TrapFrame)
568 {
569 ULONG Value;
570 PCHAR Buffer;
571 PULONG p;
572 DWORD i;
573
574 if (!TrapFrame)
575 return;
576
577 Buffer = Address;
578 for (i = 0; i < NUMREGS; i++)
579 {
580 if (GspRegisters[i].SetInContext)
581 p = (PULONG) ((ULONG_PTR) Context + GspRegisters[i].OffsetInContext);
582 else
583 p = (PULONG) ((ULONG_PTR) TrapFrame + GspRegisters[i].OffsetInTF);
584 Value = 0;
585 Buffer = GspHex2Mem (Buffer, (PCHAR) &Value, GspRegisters[i].Size, FALSE);
586 *p = Value;
587 }
588 }
589
590
591 VOID
592 GspSetSingleRegisterInTrapFrame(PCHAR Address,
593 LONG Number,
594 PCONTEXT Context,
595 PKTRAP_FRAME TrapFrame)
596 {
597 ULONG Value;
598 PULONG p;
599
600 if (!TrapFrame)
601 return;
602
603 if (GspRegisters[Number].SetInContext)
604 p = (PULONG) ((ULONG_PTR) Context + GspRegisters[Number].OffsetInContext);
605 else
606 p = (PULONG) ((ULONG_PTR) TrapFrame + GspRegisters[Number].OffsetInTF);
607 Value = 0;
608 GspHex2Mem (Address, (PCHAR) &Value, GspRegisters[Number].Size, FALSE);
609 *p = Value;
610 }
611
612
613 BOOLEAN
614 GspFindThread(PCHAR Data,
615 PETHREAD *Thread)
616 {
617 PETHREAD ThreadInfo = NULL;
618
619 if (strcmp (Data, "-1") == 0)
620 {
621 /* All threads */
622 ThreadInfo = NULL;
623 }
624 else
625 {
626 ULONG uThreadId;
627 HANDLE ThreadId;
628 PCHAR ptr = &Data[0];
629
630 GspHex2Long (&ptr, (PLONG) &uThreadId);
631 ThreadId = (HANDLE)uThreadId;
632
633 if (!NT_SUCCESS (PsLookupThreadByThreadId (ThreadId, &ThreadInfo)))
634 {
635 *Thread = NULL;
636 return FALSE;
637 }
638 }
639 *Thread = ThreadInfo;
640 return TRUE;
641 }
642
643
644 VOID
645 GspSetThread(PCHAR Request)
646 {
647 PETHREAD ThreadInfo;
648 PCHAR ptr = &Request[1];
649
650 switch (Request[0])
651 {
652 case 'c': /* Run thread */
653 if (GspFindThread (ptr, &ThreadInfo))
654 {
655 GspOutBuffer[0] = 'O';
656 GspOutBuffer[1] = 'K';
657
658 if (NULL != GspRunThread)
659 {
660 ObDereferenceObject(GspRunThread);
661 }
662 GspRunThread = ThreadInfo;
663 if (NULL != GspRunThread)
664 {
665 ObReferenceObject(GspRunThread);
666 }
667 }
668 else
669 {
670 GspOutBuffer[0] = 'E';
671 }
672 break;
673 case 'g': /* Debug thread */
674 if (GspFindThread (ptr, &ThreadInfo))
675 {
676 GspOutBuffer[0] = 'O';
677 GspOutBuffer[1] = 'K';
678
679 if(GspDbgThread) ObDereferenceObject(GspDbgThread);
680
681 GspDbgThread = ThreadInfo;
682 }
683 else
684 {
685 GspOutBuffer[0] = 'E';
686 }
687 break;
688 default:
689 break;
690 }
691 }
692
693
694 VOID
695 GspQuery(PCHAR Request)
696 {
697 PCHAR Command;
698 ULONG Value;
699
700 Command = strtok (Request, ",");
701 if (strncmp (Command, "C", 1) == 0)
702 {
703 PCHAR ptr = &GspOutBuffer[2];
704
705 /* Get current thread id */
706 GspOutBuffer[0] = 'Q';
707 GspOutBuffer[1] = 'C';
708 if (NULL != GspDbgThread)
709 {
710 Value = (ULONG) GspDbgThread->Cid.UniqueThread;
711 }
712 else
713 {
714 Value = (ULONG) PsGetCurrentThread()->Cid.UniqueThread;
715 }
716 GspLong2Hex (&ptr, Value);
717 }
718 else if (strncmp (Command, "fThreadInfo", 11) == 0)
719 {
720 PEPROCESS Process;
721 PLIST_ENTRY AThread, AProcess;
722 PCHAR ptr = &GspOutBuffer[1];
723
724 /* Get first thread id */
725 GspEnumThread = NULL;
726 AProcess = PsActiveProcessHead.Flink;
727 while(AProcess != &PsActiveProcessHead)
728 {
729 Process = CONTAINING_RECORD(AProcess, EPROCESS, ActiveProcessLinks);
730 AThread = Process->ThreadListHead.Flink;
731 if(AThread != &Process->ThreadListHead)
732 {
733 GspEnumThread = CONTAINING_RECORD (Process->ThreadListHead.Flink,
734 ETHREAD, ThreadListEntry);
735 break;
736 }
737 AProcess = AProcess->Flink;
738 }
739 if(GspEnumThread != NULL)
740 {
741 GspOutBuffer[0] = 'm';
742 Value = (ULONG) GspEnumThread->Cid.UniqueThread;
743 GspLong2Hex (&ptr, Value);
744 }
745 else
746 {
747 /* FIXME - what to do here? This case should never happen though, there
748 should always be at least one thread on the system... */
749 /* GspOutBuffer[0] = 'l'; */
750 }
751 }
752 else if (strncmp (Command, "sThreadInfo", 11) == 0)
753 {
754 PEPROCESS Process;
755 PLIST_ENTRY AThread, AProcess;
756 PCHAR ptr = &GspOutBuffer[1];
757
758 /* Get next thread id */
759 if (GspEnumThread != NULL)
760 {
761 /* find the next thread */
762 Process = GspEnumThread->ThreadsProcess;
763 if(GspEnumThread->ThreadListEntry.Flink != &Process->ThreadListHead)
764 {
765 GspEnumThread = CONTAINING_RECORD (GspEnumThread->ThreadListEntry.Flink,
766 ETHREAD, ThreadListEntry);
767 }
768 else
769 {
770 PETHREAD Thread = NULL;
771 AProcess = Process->ActiveProcessLinks.Flink;
772 while(AProcess != &PsActiveProcessHead)
773 {
774 Process = CONTAINING_RECORD(AProcess, EPROCESS, ActiveProcessLinks);
775 AThread = Process->ThreadListHead.Flink;
776 if(AThread != &Process->ThreadListHead)
777 {
778 Thread = CONTAINING_RECORD (Process->ThreadListHead.Flink,
779 ETHREAD, ThreadListEntry);
780 break;
781 }
782 AProcess = AProcess->Flink;
783 }
784 GspEnumThread = Thread;
785 }
786
787 if(GspEnumThread != NULL)
788 {
789 /* return the ID */
790 GspOutBuffer[0] = 'm';
791 Value = (ULONG) GspEnumThread->Cid.UniqueThread;
792 GspLong2Hex (&ptr, Value);
793 }
794 else
795 {
796 GspOutBuffer[0] = 'l';
797 }
798 }
799 else
800 {
801 GspOutBuffer[0] = 'l';
802 }
803 }
804 else if (strncmp (Command, "ThreadExtraInfo", 15) == 0)
805 {
806 PETHREAD ThreadInfo;
807 PCHAR ptr = &Command[15];
808
809 /* Get thread information */
810 if (GspFindThread (ptr, &ThreadInfo))
811 {
812 PCHAR String = GspThreadStates[ThreadInfo->Tcb.State];
813
814 ObDereferenceObject(ThreadInfo);
815
816 GspMem2Hex (String, &GspOutBuffer[0], strlen (String), FALSE);
817 }
818 }
819 #if 0
820 else if (strncmp (Command, "L", 1) == 0)
821 {
822 PLIST_ENTRY CurrentEntry;
823 PETHREAD Current;
824 ULONG MaxThreads = 0;
825 ULONG ThreadId = 0;
826 ULONG ThreadCount = 0;
827
828 /* List threads */
829 GspHex2Mem (&Request[1], (PCHAR) &MaxThreads, 2, TRUE);
830 GspHex2Mem (&Request[3], (PCHAR) &Value, 4, TRUE);
831 GspHex2Mem (&Request[11], (PCHAR) &ThreadId, 4, TRUE);
832
833 GspOutBuffer[0] = 'q';
834 GspOutBuffer[1] = 'M';
835 Value = 0;
836 GspMem2Hex ((PCHAR) &Value, &GspOutBuffer[5], 4, TRUE);
837 GspMem2Hex ((PCHAR) &ThreadId, &GspOutBuffer[13], 4, TRUE);
838
839 CurrentEntry = PiThreadListHead.Flink;
840 while ((CurrentEntry != &PiThreadListHead) && (ThreadCount < MaxThreads))
841 {
842 Current = CONTAINING_RECORD (CurrentEntry, ETHREAD, Tcb.ThreadListEntry);
843 Value = 0;
844 GspMem2Hex ((PCHAR) &Value, &GspOutBuffer[21+ThreadCount*16], 4, TRUE);
845 Value = (ULONG) Current->Cid.UniqueThread;
846 GspMem2Hex ((PCHAR) &Value, &GspOutBuffer[21+ThreadCount*16+8], 4, TRUE);
847 CurrentEntry = CurrentEntry->Flink;
848 ThreadCount++;
849 }
850
851 if (CurrentEntry != &PiThreadListHead)
852 {
853 GspOutBuffer[4] = '0';
854 }
855 else
856 {
857 GspOutBuffer[4] = '1';
858 }
859
860 GspMem2Hex ((PCHAR) &ThreadCount, &GspOutBuffer[2], 1, TRUE);
861 }
862 #endif
863 else if (strncmp (Command, "Offsets", 7) == 0)
864 {
865 strcpy (GspOutBuffer, "Text=0;Data=0;Bss=0");
866 }
867 }
868
869 VOID
870 GspQueryThreadStatus(PCHAR Request)
871 {
872 PETHREAD ThreadInfo;
873 PCHAR ptr = &Request[0];
874
875 if (GspFindThread (ptr, &ThreadInfo))
876 {
877 ObDereferenceObject(ThreadInfo);
878
879 GspOutBuffer[0] = 'O';
880 GspOutBuffer[1] = 'K';
881 GspOutBuffer[2] = '\0';
882 }
883 else
884 {
885 GspOutBuffer[0] = 'E';
886 GspOutBuffer[1] = '\0';
887 }
888 }
889
890
891 typedef struct _GsHwBreakPoint
892 {
893 BOOLEAN Enabled;
894 ULONG Type;
895 ULONG Length;
896 ULONG Address;
897 } GsHwBreakPoint;
898
899 #if defined(__GNUC__)
900 GsHwBreakPoint GspBreakpoints[4] =
901 {
902 { Enabled : FALSE },
903 { Enabled : FALSE },
904 { Enabled : FALSE },
905 { Enabled : FALSE }
906 };
907 #else
908 GsHwBreakPoint GspBreakpoints[4] =
909 {
910 { FALSE },
911 { FALSE },
912 { FALSE },
913 { FALSE }
914 };
915 #endif
916
917 VOID
918 GspCorrectHwBreakpoint()
919 {
920 ULONG BreakpointNumber;
921 BOOLEAN CorrectIt;
922 BOOLEAN Bit;
923 ULONG dr7_;
924
925 #if defined(__GNUC__)
926 asm volatile (
927 "movl %%db7, %0\n" : "=r" (dr7_) : );
928 do
929 {
930 ULONG addr0, addr1, addr2, addr3;
931
932 asm volatile (
933 "movl %%db0, %0\n"
934 "movl %%db1, %1\n"
935 "movl %%db2, %2\n"
936 "movl %%db3, %3\n"
937 : "=r" (addr0), "=r" (addr1),
938 "=r" (addr2), "=r" (addr3) : );
939 } while (FALSE);
940 #elif defined(_MSC_VER)
941 __asm
942 {
943 mov eax, dr7; mov dr7_, eax;
944 mov eax, dr0; mov addr0, eax;
945 mov eax, dr1; mov addr1, eax;
946 mov eax, dr2; mov addr2, eax;
947 mov eax, dr3; mov addr3, eax;
948 }
949 #else
950 #error Unknown compiler for inline assembler
951 #endif
952 CorrectIt = FALSE;
953 for (BreakpointNumber = 0; BreakpointNumber < 3; BreakpointNumber++)
954 {
955 Bit = 2 << (BreakpointNumber << 1);
956 if (!(dr7_ & Bit) && GspBreakpoints[BreakpointNumber].Enabled) {
957 CorrectIt = TRUE;
958 dr7_ |= Bit;
959 dr7_ &= ~(0xf0000 << (BreakpointNumber << 2));
960 dr7_ |= (((GspBreakpoints[BreakpointNumber].Length << 2) |
961 GspBreakpoints[BreakpointNumber].Type) << 16) << (BreakpointNumber << 2);
962 switch (BreakpointNumber) {
963 #if defined(__GNUC__)
964 case 0:
965 asm volatile ("movl %0, %%dr0\n"
966 : : "r" (GspBreakpoints[BreakpointNumber].Address) );
967 break;
968
969 case 1:
970 asm volatile ("movl %0, %%dr1\n"
971 : : "r" (GspBreakpoints[BreakpointNumber].Address) );
972 break;
973
974 case 2:
975 asm volatile ("movl %0, %%dr2\n"
976 : : "r" (GspBreakpoints[BreakpointNumber].Address) );
977 break;
978
979 case 3:
980 asm volatile ("movl %0, %%dr3\n"
981 : : "r" (GspBreakpoints[BreakpointNumber].Address) );
982 break;
983 #elif defined(_MSC_VER)
984 case 0:
985 {
986 ULONG addr = GspBreakpoints[BreakpointNumber].Address;
987 __asm mov eax, addr;
988 __asm mov dr0, eax;
989 }
990 break;
991 case 1:
992 {
993 ULONG addr = GspBreakpoints[BreakpointNumber].Address;
994 __asm mov eax, addr;
995 __asm mov dr1, eax;
996 }
997 break;
998 case 2:
999 {
1000 ULONG addr = GspBreakpoints[BreakpointNumber].Address;
1001 __asm mov eax, addr;
1002 __asm mov dr2, eax;
1003 }
1004 break;
1005 case 3:
1006 {
1007 ULONG addr = GspBreakpoints[BreakpointNumber].Address;
1008 __asm mov eax, addr;
1009 __asm mov dr3, eax;
1010 }
1011 break;
1012 #else
1013 #error Unknown compiler for inline assembler
1014 #endif
1015 }
1016 }
1017 else if ((dr7_ & Bit) && !GspBreakpoints[BreakpointNumber].Enabled)
1018 {
1019 CorrectIt = TRUE;
1020 dr7_ &= ~Bit;
1021 dr7_ &= ~(0xf0000 << (BreakpointNumber << 2));
1022 }
1023 }
1024 if (CorrectIt)
1025 {
1026 #if defined(__GNUC__)
1027 asm volatile ( "movl %0, %%db7\n" : : "r" (dr7_));
1028 #elif defined(_MSC_VER)
1029 __asm mov eax, dr7_;
1030 __asm mov dr7, eax;
1031 #else
1032 #error Unknown compiler for inline assembler
1033 #endif
1034 }
1035 }
1036
1037 ULONG
1038 GspRemoveHwBreakpoint(ULONG BreakpointNumber)
1039 {
1040 if (!GspBreakpoints[BreakpointNumber].Enabled)
1041 {
1042 return -1;
1043 }
1044 GspBreakpoints[BreakpointNumber].Enabled = 0;
1045 return 0;
1046 }
1047
1048
1049 ULONG
1050 GspSetHwBreakpoint(ULONG BreakpointNumber,
1051 ULONG Type,
1052 ULONG Length,
1053 ULONG Address)
1054 {
1055 if (GspBreakpoints[BreakpointNumber].Enabled)
1056 {
1057 return -1;
1058 }
1059 GspBreakpoints[BreakpointNumber].Enabled = TRUE;
1060 GspBreakpoints[BreakpointNumber].Type = Type;
1061 GspBreakpoints[BreakpointNumber].Length = Length;
1062 GspBreakpoints[BreakpointNumber].Address = Address;
1063 return 0;
1064 }
1065
1066
1067 /*
1068 * This function does all command procesing for interfacing to gdb.
1069 */
1070 KD_CONTINUE_TYPE
1071 STDCALL
1072 KdpGdbEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
1073 PCONTEXT Context,
1074 PKTRAP_FRAME TrapFrame)
1075 {
1076 BOOLEAN Stepping;
1077 LONG Address;
1078 LONG Length;
1079 LONG SigVal;
1080 LONG NewPC;
1081 PCHAR ptr;
1082 LONG Esp;
1083
1084 /* FIXME: Stop on other CPUs too */
1085 /* Disable hardware debugging while we are inside the stub */
1086 #if defined(__GNUC__)
1087 __asm__("movl %0,%%db7" : /* no output */ : "r" (0));
1088 #elif defined(_MSC_VER)
1089 __asm mov eax, 0 __asm mov dr7, eax
1090 #else
1091 #error Unknown compiler for inline assembler
1092 #endif
1093
1094 if (STATUS_ACCESS_VIOLATION == (NTSTATUS) ExceptionRecord->ExceptionCode &&
1095 NULL != GspAccessLocation &&
1096 (ULONG_PTR) GspAccessLocation ==
1097 (ULONG_PTR) ExceptionRecord->ExceptionInformation[1])
1098 {
1099 GspAccessLocation = NULL;
1100 GspMemoryError = TRUE;
1101 TrapFrame->Eip += 2;
1102 }
1103 else
1104 {
1105 /* Don't switch threads */
1106
1107 /* Always use the current thread when entering the exception handler */
1108 if (NULL != GspDbgThread)
1109 {
1110 ObDereferenceObject(GspDbgThread);
1111 GspDbgThread = NULL;
1112 }
1113
1114 /* reply to host that an exception has occurred */
1115 SigVal = GspComputeSignal (ExceptionRecord->ExceptionCode);
1116
1117 ptr = &GspOutBuffer[0];
1118
1119 *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */
1120 *ptr++ = HexChars[(SigVal >> 4) & 0xf];
1121 *ptr++ = HexChars[SigVal & 0xf];
1122
1123 *ptr++ = HexChars[ESP];
1124 *ptr++ = ':';
1125
1126 Esp = GspGetEspFromTrapFrame (TrapFrame); /* SP */
1127 ptr = GspMem2Hex ((PCHAR) &Esp, ptr, 4, 0);
1128 *ptr++ = ';';
1129
1130 *ptr++ = HexChars[EBP];
1131 *ptr++ = ':';
1132 ptr = GspMem2Hex ((PCHAR) &TrapFrame->Ebp, ptr, 4, 0); /* FP */
1133 *ptr++ = ';';
1134
1135 *ptr++ = HexChars[PC];
1136 *ptr++ = ':';
1137 ptr = GspMem2Hex((PCHAR) &TrapFrame->Eip, ptr, 4, 0); /* PC */
1138 *ptr++ = ';';
1139
1140 *ptr = '\0';
1141
1142 GspPutPacket (&GspOutBuffer[0]);
1143
1144 Stepping = FALSE;
1145
1146 while (TRUE)
1147 {
1148 /* Zero the buffer now so we don't have to worry about the terminating zero character */
1149 memset (GspOutBuffer, 0, sizeof (GspInBuffer));
1150 ptr = GspGetPacket ();
1151
1152 switch (*ptr++)
1153 {
1154 case '?':
1155 GspOutBuffer[0] = 'S';
1156 GspOutBuffer[1] = HexChars[SigVal >> 4];
1157 GspOutBuffer[2] = HexChars[SigVal % 16];
1158 GspOutBuffer[3] = 0;
1159 break;
1160 case 'd':
1161 GspRemoteDebug = !GspRemoteDebug; /* toggle debug flag */
1162 break;
1163 case 'g': /* return the value of the CPU Registers */
1164 if (NULL != GspDbgThread)
1165 {
1166 GspGetRegistersFromTrapFrame (&GspOutBuffer[0], Context, GspDbgThread->Tcb.TrapFrame);
1167 }
1168 else
1169 {
1170 GspGetRegistersFromTrapFrame (&GspOutBuffer[0], Context, TrapFrame);
1171 }
1172 break;
1173 case 'G': /* set the value of the CPU Registers - return OK */
1174 if (NULL != GspDbgThread)
1175 {
1176 GspSetRegistersInTrapFrame (ptr, Context, GspDbgThread->Tcb.TrapFrame);
1177 }
1178 else
1179 {
1180 GspSetRegistersInTrapFrame (ptr, Context, TrapFrame);
1181 }
1182 strcpy (GspOutBuffer, "OK");
1183 break;
1184 case 'P': /* set the value of a single CPU register - return OK */
1185 {
1186 LONG Register;
1187
1188 if ((GspHex2Long (&ptr, &Register)) && (*ptr++ == '='))
1189 if ((Register >= 0) && (Register < NUMREGS))
1190 {
1191 if (GspDbgThread)
1192 {
1193 GspSetSingleRegisterInTrapFrame(ptr, Register,
1194 Context, GspDbgThread->Tcb.TrapFrame);
1195 }
1196 else
1197 {
1198 GspSetSingleRegisterInTrapFrame (ptr, Register, Context, TrapFrame);
1199 }
1200 strcpy (GspOutBuffer, "OK");
1201 break;
1202 }
1203
1204 strcpy (GspOutBuffer, "E01");
1205 break;
1206 }
1207
1208 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
1209 case 'm':
1210 /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
1211 if (GspHex2Long (&ptr, &Address))
1212 if (*(ptr++) == ',')
1213 if (GspHex2Long (&ptr, &Length))
1214 {
1215 ptr = 0;
1216 GspMemoryError = FALSE;
1217 GspMem2Hex ((PCHAR) Address, GspOutBuffer, Length, 1);
1218 if (GspMemoryError)
1219 {
1220 strcpy (GspOutBuffer, "E03");
1221 DPRINT ("Fault during memory read\n");
1222 }
1223 }
1224
1225 if (ptr)
1226 strcpy (GspOutBuffer, "E01");
1227 break;
1228
1229 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
1230 case 'M':
1231 /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
1232 if (GspHex2Long (&ptr, &Address))
1233 if (*(ptr++) == ',')
1234 if (GspHex2Long (&ptr, &Length))
1235 if (*(ptr++) == ':')
1236 {
1237 GspMemoryError = FALSE;
1238 GspHex2Mem (ptr, (PCHAR) Address, Length, TRUE);
1239
1240 if (GspMemoryError)
1241 {
1242 strcpy (GspOutBuffer, "E03");
1243 DPRINT ("Fault during memory write\n");
1244 }
1245 else
1246 {
1247 strcpy (GspOutBuffer, "OK");
1248 }
1249
1250 ptr = NULL;
1251 }
1252 if (ptr)
1253 strcpy (GspOutBuffer, "E02");
1254 break;
1255
1256 /* cAA..AA Continue at address AA..AA(optional) */
1257 /* sAA..AA Step one instruction from AA..AA(optional) */
1258 case 's':
1259 Stepping = TRUE;
1260 case 'c':
1261 {
1262 ULONG BreakpointNumber;
1263 ULONG dr6_;
1264
1265 /* try to read optional parameter, pc unchanged if no parm */
1266 if (GspHex2Long (&ptr, &Address))
1267 Context->Eip = Address;
1268
1269 NewPC = Context->Eip;
1270
1271 /* clear the trace bit */
1272 Context->EFlags &= 0xfffffeff;
1273
1274 /* set the trace bit if we're Stepping */
1275 if (Stepping)
1276 Context->EFlags |= 0x100;
1277
1278 #if defined(__GNUC__)
1279 asm volatile ("movl %%db6, %0\n" : "=r" (dr6_) : );
1280 #elif defined(_MSC_VER)
1281 __asm mov eax, dr6 __asm mov dr6_, eax;
1282 #else
1283 #error Unknown compiler for inline assembler
1284 #endif
1285 if (!(dr6_ & 0x4000))
1286 {
1287 for (BreakpointNumber = 0; BreakpointNumber < 4; ++BreakpointNumber)
1288 {
1289 if (dr6_ & (1 << BreakpointNumber))
1290 {
1291 if (GspBreakpoints[BreakpointNumber].Type == 0)
1292 {
1293 /* Set restore flag */
1294 Context->EFlags |= 0x10000;
1295 break;
1296 }
1297 }
1298 }
1299 }
1300 GspCorrectHwBreakpoint();
1301 #if defined(__GNUC__)
1302 asm volatile ("movl %0, %%db6\n" : : "r" (0));
1303 #elif defined(_MSC_VER)
1304 __asm mov eax, 0 __asm mov dr6, eax;
1305 #else
1306 #error Unknown compiler for inline assembler
1307 #endif
1308
1309 KeContextToTrapFrame(Context, TrapFrame);
1310 return ((SigVal == 5) ? (kdContinue) : (kdHandleException));
1311 break;
1312 }
1313
1314 case 'k': /* kill the program */
1315 strcpy (GspOutBuffer, "OK");
1316 break;
1317 /* kill the program */
1318
1319 case 'H': /* Set thread */
1320 GspSetThread (ptr);
1321 break;
1322
1323 case 'q': /* Query */
1324 GspQuery (ptr);
1325 break;
1326
1327 case 'T': /* Query thread status */
1328 GspQueryThreadStatus (ptr);
1329 break;
1330
1331 case 'Y':
1332 {
1333 LONG Number;
1334 LONG Length;
1335 LONG Type;
1336 LONG Address;
1337
1338 ptr = &GspOutBuffer[1];
1339 GspHex2Long (&ptr, &Number);
1340 ptr++;
1341 GspHex2Long (&ptr, &Type);
1342 ptr++;
1343 GspHex2Long (&ptr, &Length);
1344 ptr++;
1345 GspHex2Long (&ptr, &Address);
1346 if (GspSetHwBreakpoint (Number & 0x3, Type & 0x3 , Length & 0x3, Address) == 0)
1347 {
1348 strcpy (GspOutBuffer, "OK");
1349 }
1350 else
1351 {
1352 strcpy (GspOutBuffer, "E");
1353 }
1354 break;
1355 }
1356
1357 /* Remove hardware breakpoint */
1358 case 'y':
1359 {
1360 LONG Number;
1361
1362 ptr = &GspOutBuffer[1];
1363 GspHex2Long(&ptr, &Number);
1364 if (GspRemoveHwBreakpoint (Number & 0x3) == 0)
1365 {
1366 strcpy (GspOutBuffer, "OK");
1367 }
1368 else
1369 {
1370 strcpy (GspOutBuffer, "E");
1371 }
1372 break;
1373 }
1374
1375 default:
1376 break;
1377 } /* switch */
1378
1379 /* reply to the request */
1380 GspPutPacket (&GspOutBuffer[0]);
1381 }
1382
1383 /* not reached */
1384 ASSERT(0);
1385 }
1386
1387 return kdDoNotHandleException;
1388 }
1389
1390
1391 BOOLEAN
1392 STDCALL
1393 GspBreakIn(PKINTERRUPT Interrupt,
1394 PVOID ServiceContext)
1395 {
1396 PKTRAP_FRAME TrapFrame;
1397 BOOLEAN DoBreakIn;
1398 CONTEXT Context;
1399 KIRQL OldIrql;
1400 UCHAR Value;
1401
1402 DPRINT ("Break In\n");
1403
1404 DoBreakIn = FALSE;
1405 while (KdPortGetByteEx (&GdbPortInfo, &Value))
1406 {
1407 if (Value == 0x03)
1408 DoBreakIn = TRUE;
1409 }
1410
1411 if (!DoBreakIn)
1412 return TRUE;
1413
1414 KeRaiseIrql (HIGH_LEVEL, &OldIrql);
1415
1416 TrapFrame = PsGetCurrentThread()->Tcb.TrapFrame;
1417
1418 KeTrapFrameToContext (TrapFrame, &Context);
1419
1420 KdpGdbEnterDebuggerException (NULL, &Context, TrapFrame);
1421
1422 KeContextToTrapFrame (&Context, TrapFrame);
1423
1424 KeLowerIrql (OldIrql);
1425
1426 return TRUE;
1427 }
1428
1429
1430 extern ULONG KdpPortIrq;
1431
1432
1433 VOID
1434 STDCALL
1435 KdpGdbDebugPrint(PCH Message)
1436 {
1437 #if 0
1438 /* This can be quite annoying! */
1439 if (GspInitialized)
1440 {
1441 ULONG Length;
1442
1443 GspOutBuffer[0] = 'O';
1444 GspOutBuffer[1] = '\0';
1445 strcat (&GspOutBuffer[0], Message);
1446 Length = strlen (Message);
1447 GspOutBuffer[2 + Length] = '\n';
1448 GspOutBuffer[3 + Length] = '\0';
1449 GspPutPacketNoWait (&GspOutBuffer[0]);
1450 }
1451 #endif
1452 }
1453
1454
1455 extern LIST_ENTRY ModuleListHead;
1456
1457 VOID
1458 KdGdbListModules()
1459 {
1460 PLIST_ENTRY CurrentEntry;
1461 PMODULE_OBJECT Current;
1462 ULONG ModuleCount;
1463
1464 DPRINT1("\n");
1465
1466 ModuleCount = 0;
1467
1468 CurrentEntry = ModuleListHead.Flink;
1469 while (CurrentEntry != (&ModuleListHead))
1470 {
1471 Current = CONTAINING_RECORD (CurrentEntry, MODULE_OBJECT, ListEntry);
1472
1473 DbgPrint ("Module %S Base 0x%.08x Length 0x%.08x\n",
1474 Current->BaseName.Buffer, Current->Base, Current->Length);
1475
1476 ModuleCount++;
1477 CurrentEntry = CurrentEntry->Flink;
1478 }
1479
1480 DbgPrint ("%d modules listed\n", ModuleCount);
1481 }
1482
1483 /* Initialize the GDB stub */
1484 VOID
1485 STDCALL
1486 KdpGdbStubInit(PKD_DISPATCH_TABLE WrapperTable,
1487 ULONG BootPhase)
1488 {
1489 if (!KdDebuggerEnabled || !KdpDebugMode.Gdb) return;
1490
1491 if (BootPhase == 0)
1492 {
1493 /* Write out the functions that we support for now */
1494 WrapperTable->KdpInitRoutine = KdpGdbStubInit;
1495 WrapperTable->KdpPrintRoutine = KdpGdbDebugPrint;
1496 WrapperTable->KdpExceptionRoutine = KdpGdbEnterDebuggerException;
1497
1498 /* Initialize the Port */
1499 KdPortInitializeEx(&GdbPortInfo, 0, 0);
1500 }
1501 else if (BootPhase == 1)
1502 {
1503 GspInitialized = TRUE;
1504
1505 GspRunThread = NULL;
1506 GspDbgThread = NULL;
1507 GspEnumThread = NULL;
1508
1509 HalDisplayString("Waiting for GDB to attach\n");
1510 DbgPrint("Module 'hal.dll' loaded at 0x%.08x.\n", LdrHalBase);
1511 DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C);
1512 }
1513 else if (BootPhase == 2)
1514 {
1515 HalDisplayString("\n GDB debugging enabled\n\n");
1516 }
1517 }
1518
1519 /* EOF */