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