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