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