2002-01-23 23:39:26 +00:00
|
|
|
/****************************************************************************
|
|
|
|
|
|
|
|
THIS SOFTWARE IS NOT COPYRIGHTED
|
|
|
|
|
|
|
|
HP offers the following for use in the public domain. HP makes no
|
|
|
|
warranty with regard to the software or it's performance and the
|
|
|
|
user accepts the software "AS IS" with all faults.
|
|
|
|
|
|
|
|
HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
|
|
|
|
TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
|
|
|
|
*
|
|
|
|
* Module name: remcom.c $
|
|
|
|
* Revision: 1.34 $
|
|
|
|
* Date: 91/03/09 12:29:49 $
|
|
|
|
* Contributor: Lake Stevens Instrument Division$
|
|
|
|
*
|
|
|
|
* Description: low level support for gdb debugger. $
|
|
|
|
*
|
|
|
|
* Considerations: only works on target hardware $
|
|
|
|
*
|
|
|
|
* Written by: Glenn Engel $
|
|
|
|
* ModuleState: Experimental $
|
|
|
|
*
|
|
|
|
* NOTES: See Below $
|
|
|
|
*
|
|
|
|
* Modified for 386 by Jim Kingdon, Cygnus Support.
|
|
|
|
* Modified for ReactOS by Casper S. Hornstrup <chorns@users.sourceforge.net>
|
|
|
|
*
|
|
|
|
* To enable debugger support, two things need to happen. One, setting
|
|
|
|
* up a routine so that it is in the exception path, is necessary in order
|
|
|
|
* to allow any breakpoints or error conditions to be properly intercepted
|
|
|
|
* and reported to gdb.
|
|
|
|
* Two, a breakpoint needs to be generated to begin communication.
|
|
|
|
*
|
|
|
|
* Because gdb will sometimes write to the stack area to execute function
|
|
|
|
* calls, this program cannot rely on using the supervisor stack so it
|
|
|
|
* uses it's own stack area.
|
|
|
|
*
|
|
|
|
*************
|
|
|
|
*
|
|
|
|
* The following gdb commands are supported:
|
|
|
|
*
|
|
|
|
* command function Return value
|
|
|
|
*
|
|
|
|
* g return the value of the CPU Registers hex data or ENN
|
|
|
|
* G set the value of the CPU Registers OK or ENN
|
|
|
|
*
|
|
|
|
* mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
|
|
|
|
* MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
|
|
|
|
*
|
|
|
|
* c Resume at current address SNN ( signal NN)
|
|
|
|
* cAA..AA Continue at address AA..AA SNN
|
|
|
|
*
|
|
|
|
* s Step one instruction SNN
|
|
|
|
* sAA..AA Step one instruction from AA..AA SNN
|
|
|
|
*
|
|
|
|
* k kill
|
|
|
|
*
|
|
|
|
* ? What was the last sigval ? SNN (signal NN)
|
|
|
|
*
|
|
|
|
* All commands and responses are sent with a packet which includes a
|
|
|
|
* Checksum. A packet consists of
|
|
|
|
*
|
|
|
|
* $<packet info>#<Checksum>.
|
|
|
|
*
|
|
|
|
* where
|
|
|
|
* <packet info> :: <characters representing the command or response>
|
|
|
|
* <Checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
|
|
|
|
*
|
|
|
|
* When a packet is received, it is first acknowledged with either '+' or '-'.
|
|
|
|
* '+' indicates a successful transfer. '-' indicates a failed transfer.
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
*
|
|
|
|
* Host: Reply:
|
|
|
|
* $m0,10#2a +$00010203040506070809101112131415#42
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2002-09-08 10:23:54 +00:00
|
|
|
#include <ntddk.h>
|
|
|
|
#include <internal/kd.h>
|
|
|
|
#include <internal/ke.h>
|
|
|
|
#include <internal/ps.h>
|
|
|
|
#include <internal/module.h>
|
|
|
|
#include <internal/ldr.h>
|
2002-01-23 23:39:26 +00:00
|
|
|
|
2003-04-07 23:10:08 +00:00
|
|
|
#define NDEBUG
|
2002-01-23 23:39:26 +00:00
|
|
|
#include <internal/debug.h>
|
|
|
|
|
|
|
|
extern LIST_ENTRY PiThreadListHead;
|
|
|
|
|
|
|
|
|
|
|
|
/************************************************************************/
|
|
|
|
/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
|
|
|
|
/* at least NUMREGBYTES*2 are needed for register packets */
|
|
|
|
#define BUFMAX 1000
|
|
|
|
|
2002-05-13 18:10:41 +00:00
|
|
|
static BOOLEAN GspInitialized;
|
|
|
|
#if 0
|
2002-01-23 23:39:26 +00:00
|
|
|
static PKINTERRUPT GspInterrupt;
|
2002-05-13 18:10:41 +00:00
|
|
|
#endif
|
2002-01-23 23:39:26 +00:00
|
|
|
|
|
|
|
static BOOLEAN GspRemoteDebug;
|
|
|
|
|
|
|
|
static CONST CHAR HexChars[]="0123456789abcdef";
|
|
|
|
|
|
|
|
static PETHREAD GspRunThread; /* NULL means run all threads */
|
|
|
|
static PETHREAD GspDbgThread;
|
|
|
|
static PETHREAD GspEnumThread;
|
|
|
|
|
|
|
|
/* Number of Registers. */
|
|
|
|
#define NUMREGS 16
|
|
|
|
|
|
|
|
enum REGISTER_NAMES
|
|
|
|
{
|
|
|
|
EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
|
|
|
|
PC /* also known as eip */,
|
|
|
|
PS /* also known as eflags */,
|
|
|
|
CS, SS, DS, ES, FS, GS
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct _CPU_REGISTER
|
|
|
|
{
|
|
|
|
DWORD Size;
|
|
|
|
DWORD OffsetInTF;
|
2003-03-06 23:57:03 +00:00
|
|
|
DWORD OffsetInContext;
|
|
|
|
BOOLEAN SetInContext;
|
2002-01-23 23:39:26 +00:00
|
|
|
} CPU_REGISTER, *PCPU_REGISTER;
|
|
|
|
|
|
|
|
#define KTRAP_FRAME_X86 KTRAP_FRAME
|
|
|
|
|
|
|
|
#define EIP_REGNO 8
|
|
|
|
|
|
|
|
static CPU_REGISTER GspRegisters[NUMREGS] =
|
|
|
|
{
|
2003-03-06 23:57:03 +00:00
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Eax), FIELD_OFFSET (CONTEXT, Eax), TRUE },
|
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Ecx), FIELD_OFFSET (CONTEXT, Ecx), TRUE },
|
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Edx), FIELD_OFFSET (CONTEXT, Edx), FALSE },
|
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Ebx), FIELD_OFFSET (CONTEXT, Ebx), TRUE },
|
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Esp), FIELD_OFFSET (CONTEXT, Esp), TRUE },
|
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Ebp), FIELD_OFFSET (CONTEXT, Ebp), TRUE },
|
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Esi), FIELD_OFFSET (CONTEXT, Esi), TRUE },
|
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Edi), FIELD_OFFSET (CONTEXT, Edi), TRUE },
|
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Eip), FIELD_OFFSET (CONTEXT, Eip), TRUE },
|
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Eflags), FIELD_OFFSET (CONTEXT, EFlags), TRUE },
|
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Cs), FIELD_OFFSET (CONTEXT, SegCs), TRUE },
|
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Ss), FIELD_OFFSET (CONTEXT, SegSs), TRUE },
|
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Ds), FIELD_OFFSET (CONTEXT, SegDs), TRUE },
|
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Es), FIELD_OFFSET (CONTEXT, SegEs), TRUE },
|
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Fs), FIELD_OFFSET (CONTEXT, SegFs), TRUE },
|
|
|
|
{ 4, FIELD_OFFSET (KTRAP_FRAME_X86, Gs), FIELD_OFFSET (CONTEXT, SegGs), TRUE }
|
2002-01-23 23:39:26 +00:00
|
|
|
};
|
|
|
|
|
2002-05-05 14:57:45 +00:00
|
|
|
static PCHAR GspThreadStates[THREAD_STATE_MAX] =
|
2002-01-23 23:39:26 +00:00
|
|
|
{
|
2002-07-10 15:15:00 +00:00
|
|
|
"Initialized", /* THREAD_STATE_INITIALIZED */
|
|
|
|
"Ready", /* THREAD_STATE_READY */
|
2002-01-23 23:39:26 +00:00
|
|
|
"Running", /* THREAD_STATE_RUNNING */
|
|
|
|
"Suspended", /* THREAD_STATE_SUSPENDED */
|
|
|
|
"Frozen", /* THREAD_STATE_FROZEN */
|
|
|
|
"Terminated 1", /* THREAD_STATE_TERMINATED_1 */
|
|
|
|
"Terminated 2", /* THREAD_STATE_TERMINATED_2 */
|
|
|
|
"Blocked" /* THREAD_STATE_BLOCKED */
|
|
|
|
};
|
|
|
|
|
|
|
|
char *
|
|
|
|
strtok(char *s, const char *delim)
|
|
|
|
{
|
|
|
|
const char *spanp;
|
|
|
|
int c, sc;
|
|
|
|
char *tok;
|
|
|
|
static char *last;
|
|
|
|
|
|
|
|
|
|
|
|
if (s == NULL && (s = last) == NULL)
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip (span) leading delimiters (s += strspn(s, delim), sort of).
|
|
|
|
*/
|
|
|
|
cont:
|
|
|
|
c = *s++;
|
|
|
|
for (spanp = delim; (sc = *spanp++) != 0;) {
|
|
|
|
if (c == sc)
|
|
|
|
goto cont;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == 0) { /* no non-delimiter characters */
|
|
|
|
last = NULL;
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
tok = s - 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
|
|
|
|
* Note that delim must have one NUL; we stop if we see that, too.
|
|
|
|
*/
|
|
|
|
for (;;) {
|
|
|
|
c = *s++;
|
|
|
|
spanp = delim;
|
|
|
|
do {
|
|
|
|
if ((sc = *spanp++) == c) {
|
|
|
|
if (c == 0)
|
|
|
|
s = NULL;
|
|
|
|
else
|
|
|
|
s[-1] = 0;
|
|
|
|
last = s;
|
|
|
|
return (tok);
|
|
|
|
}
|
|
|
|
} while (sc != 0);
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LONG
|
|
|
|
HexValue (CHAR ch)
|
|
|
|
{
|
|
|
|
if ((ch >= '0') && (ch <= '9')) return (ch - '0');
|
|
|
|
if ((ch >= 'a') && (ch <= 'f')) return (ch - 'a' + 10);
|
|
|
|
if ((ch >= 'A') && (ch <= 'F')) return (ch - 'A' + 10);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static CHAR GspInBuffer[BUFMAX];
|
|
|
|
static CHAR GspOutBuffer[BUFMAX];
|
|
|
|
|
|
|
|
/* scan for the sequence $<data>#<Checksum> */
|
|
|
|
|
|
|
|
PCHAR
|
|
|
|
GspGetPacket()
|
|
|
|
{
|
|
|
|
PCHAR Buffer = &GspInBuffer[0];
|
|
|
|
CHAR Checksum;
|
|
|
|
CHAR XmitChecksum;
|
|
|
|
ULONG Count;
|
|
|
|
CHAR ch;
|
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
/* wait around for the start character, ignore all other characters */
|
|
|
|
while ((ch = KdGetChar ()) != '$');
|
|
|
|
|
|
|
|
retry:
|
|
|
|
Checksum = 0;
|
|
|
|
XmitChecksum = -1;
|
|
|
|
Count = 0;
|
|
|
|
|
|
|
|
/* now, read until a # or end of Buffer is found */
|
|
|
|
while (Count < BUFMAX)
|
|
|
|
{
|
|
|
|
ch = KdGetChar ();
|
|
|
|
if (ch == '$')
|
|
|
|
goto retry;
|
|
|
|
if (ch == '#')
|
|
|
|
break;
|
|
|
|
Checksum = Checksum + ch;
|
|
|
|
Buffer[Count] = ch;
|
|
|
|
Count = Count + 1;
|
|
|
|
}
|
|
|
|
Buffer[Count] = 0;
|
|
|
|
|
|
|
|
if (ch == '#')
|
|
|
|
{
|
|
|
|
ch = KdGetChar ();
|
2003-12-30 18:52:06 +00:00
|
|
|
XmitChecksum = (CHAR)(HexValue (ch) << 4);
|
2002-01-23 23:39:26 +00:00
|
|
|
ch = KdGetChar ();
|
2003-12-30 18:52:06 +00:00
|
|
|
XmitChecksum += (CHAR)(HexValue (ch));
|
2002-01-23 23:39:26 +00:00
|
|
|
|
|
|
|
if (Checksum != XmitChecksum)
|
|
|
|
{
|
|
|
|
KdPutChar ('-'); /* failed checksum */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
KdPutChar ('+'); /* successful transfer */
|
|
|
|
|
|
|
|
/* if a sequence char is present, reply the sequence ID */
|
|
|
|
if (Buffer[2] == ':')
|
|
|
|
{
|
|
|
|
KdPutChar (Buffer[0]);
|
|
|
|
KdPutChar (Buffer[1]);
|
|
|
|
|
|
|
|
return &Buffer[3];
|
|
|
|
}
|
|
|
|
|
|
|
|
return &Buffer[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* send the packet in Buffer. */
|
|
|
|
|
|
|
|
VOID
|
|
|
|
GspPutPacket (PCHAR Buffer)
|
|
|
|
{
|
|
|
|
CHAR Checksum;
|
|
|
|
LONG Count;
|
|
|
|
CHAR ch;
|
|
|
|
|
|
|
|
/* $<packet info>#<Checksum>. */
|
|
|
|
do
|
|
|
|
{
|
|
|
|
KdPutChar ('$');
|
|
|
|
Checksum = 0;
|
|
|
|
Count = 0;
|
|
|
|
|
|
|
|
while ((ch = Buffer[Count]))
|
|
|
|
{
|
|
|
|
KdPutChar (ch);
|
|
|
|
Checksum += ch;
|
|
|
|
Count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
KdPutChar ('#');
|
|
|
|
KdPutChar (HexChars[(Checksum >> 4) & 0xf]);
|
|
|
|
KdPutChar (HexChars[Checksum & 0xf]);
|
|
|
|
}
|
|
|
|
while (KdGetChar () != '+');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
|
|
GspPutPacketNoWait (PCHAR Buffer)
|
|
|
|
{
|
|
|
|
CHAR Checksum;
|
|
|
|
LONG Count;
|
|
|
|
CHAR ch;
|
|
|
|
|
|
|
|
/* $<packet info>#<Checksum>. */
|
|
|
|
KdPutChar ('$');
|
|
|
|
Checksum = 0;
|
|
|
|
Count = 0;
|
|
|
|
|
|
|
|
while ((ch = Buffer[Count]))
|
|
|
|
{
|
|
|
|
KdPutChar (ch);
|
|
|
|
Checksum += ch;
|
|
|
|
Count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
KdPutChar ('#');
|
|
|
|
KdPutChar (HexChars[(Checksum >> 4) & 0xf]);
|
|
|
|
KdPutChar (HexChars[Checksum & 0xf]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Indicate to caller of GspMem2Hex or GspHex2Mem that there has been an
|
|
|
|
error. */
|
|
|
|
static volatile BOOLEAN GspMemoryError = FALSE;
|
2003-04-07 23:10:08 +00:00
|
|
|
static volatile void *GspAccessLocation = NULL;
|
2002-01-23 23:39:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Convert the memory pointed to by Address into hex, placing result in Buffer */
|
|
|
|
/* Return a pointer to the last char put in Buffer (null) */
|
|
|
|
/* If MayFault is TRUE, then we should set GspMemoryError in response to
|
|
|
|
a fault; if FALSE treat a fault like any other fault in the stub. */
|
|
|
|
PCHAR
|
|
|
|
GspMem2Hex (PCHAR Address,
|
|
|
|
PCHAR Buffer,
|
|
|
|
LONG Count,
|
|
|
|
BOOLEAN MayFault)
|
|
|
|
{
|
|
|
|
ULONG i;
|
|
|
|
CHAR ch;
|
|
|
|
|
2003-04-07 23:10:08 +00:00
|
|
|
if (NULL == Address && MayFault)
|
|
|
|
{
|
|
|
|
GspMemoryError = TRUE;
|
|
|
|
return Buffer;
|
|
|
|
}
|
|
|
|
|
2002-11-10 18:17:43 +00:00
|
|
|
for (i = 0; i < (ULONG) Count; i++)
|
2002-01-23 23:39:26 +00:00
|
|
|
{
|
2003-03-06 23:57:03 +00:00
|
|
|
if (MayFault)
|
|
|
|
GspAccessLocation = Address;
|
|
|
|
ch = *Address;
|
|
|
|
GspAccessLocation = NULL;
|
2002-01-23 23:39:26 +00:00
|
|
|
if (MayFault && GspMemoryError)
|
|
|
|
return (Buffer);
|
|
|
|
*Buffer++ = HexChars[(ch >> 4) & 0xf];
|
|
|
|
*Buffer++ = HexChars[ch & 0xf];
|
2003-03-06 23:57:03 +00:00
|
|
|
Address++;
|
2002-01-23 23:39:26 +00:00
|
|
|
}
|
|
|
|
*Buffer = 0;
|
|
|
|
return (Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Convert the hex array pointed to by Buffer into binary to be placed at Address */
|
|
|
|
/* Return a pointer to the character AFTER the last byte read from Buffer */
|
|
|
|
PCHAR
|
|
|
|
GspHex2Mem (PCHAR Buffer,
|
|
|
|
PCHAR Address,
|
|
|
|
ULONG Count,
|
|
|
|
BOOLEAN MayFault)
|
|
|
|
{
|
2003-03-06 23:57:03 +00:00
|
|
|
PCHAR current;
|
|
|
|
PCHAR page;
|
|
|
|
ULONG countinpage;
|
2002-01-23 23:39:26 +00:00
|
|
|
ULONG i;
|
|
|
|
CHAR ch;
|
2003-04-05 22:21:33 +00:00
|
|
|
ULONG oldprot = 0;
|
2002-01-23 23:39:26 +00:00
|
|
|
|
2003-03-06 23:57:03 +00:00
|
|
|
current = Address;
|
|
|
|
while ( current < Address + Count )
|
2002-01-23 23:39:26 +00:00
|
|
|
{
|
2003-03-06 23:57:03 +00:00
|
|
|
page = (PCHAR)PAGE_ROUND_DOWN (current);
|
|
|
|
if (Address + Count <= page + PAGE_SIZE)
|
|
|
|
{
|
|
|
|
/* Fits in this page */
|
|
|
|
countinpage = Count;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Flows into next page, handle only current page in this iteration */
|
|
|
|
countinpage = PAGE_SIZE - (Address - page);
|
|
|
|
}
|
|
|
|
if (MayFault)
|
|
|
|
{
|
|
|
|
oldprot = MmGetPageProtect (NULL, Address);
|
|
|
|
MmSetPageProtect (NULL, Address, PAGE_EXECUTE_READWRITE);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < countinpage && ! GspMemoryError; i++)
|
|
|
|
{
|
2003-12-30 18:52:06 +00:00
|
|
|
ch = (CHAR)(HexValue (*Buffer++) << 4);
|
|
|
|
ch = (CHAR)(ch + HexValue (*Buffer++));
|
2003-03-06 23:57:03 +00:00
|
|
|
|
|
|
|
GspAccessLocation = Address;
|
|
|
|
*current = ch;
|
|
|
|
GspAccessLocation = NULL;
|
|
|
|
current++;
|
|
|
|
}
|
|
|
|
if (MayFault)
|
|
|
|
{
|
|
|
|
MmSetPageProtect (NULL, page, oldprot);
|
|
|
|
if (GspMemoryError)
|
|
|
|
return (Buffer);
|
|
|
|
}
|
2002-01-23 23:39:26 +00:00
|
|
|
}
|
2003-03-06 23:57:03 +00:00
|
|
|
|
2002-01-23 23:39:26 +00:00
|
|
|
return (Buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* This function takes the 386 exception vector and attempts to
|
|
|
|
translate this number into a unix compatible signal value */
|
|
|
|
ULONG
|
|
|
|
GspComputeSignal (NTSTATUS ExceptionCode)
|
|
|
|
{
|
|
|
|
ULONG SigVal;
|
|
|
|
|
|
|
|
switch (ExceptionCode)
|
|
|
|
{
|
|
|
|
case STATUS_INTEGER_DIVIDE_BY_ZERO:
|
|
|
|
SigVal = 8;
|
|
|
|
break; /* divide by zero */
|
|
|
|
case STATUS_SINGLE_STEP:
|
2003-04-07 23:10:08 +00:00
|
|
|
/* debug exception */
|
2002-01-23 23:39:26 +00:00
|
|
|
case STATUS_BREAKPOINT:
|
|
|
|
SigVal = 5;
|
|
|
|
break; /* breakpoint */
|
|
|
|
case STATUS_INTEGER_OVERFLOW:
|
2003-04-07 23:10:08 +00:00
|
|
|
/* into instruction (overflow) */
|
2002-01-23 23:39:26 +00:00
|
|
|
case STATUS_ARRAY_BOUNDS_EXCEEDED:
|
|
|
|
SigVal = 16;
|
|
|
|
break; /* bound instruction */
|
|
|
|
case STATUS_ILLEGAL_INSTRUCTION:
|
|
|
|
SigVal = 4;
|
|
|
|
break; /* Invalid opcode */
|
|
|
|
#if 0
|
|
|
|
case STATUS_FLT_INVALID_OPERATION:
|
|
|
|
SigVal = 8;
|
|
|
|
break; /* coprocessor not available */
|
|
|
|
#endif
|
|
|
|
case STATUS_STACK_OVERFLOW:
|
2003-04-07 23:10:08 +00:00
|
|
|
/* stack exception */
|
2002-01-23 23:39:26 +00:00
|
|
|
case STATUS_DATATYPE_MISALIGNMENT:
|
2003-04-07 23:10:08 +00:00
|
|
|
/* page fault */
|
|
|
|
case STATUS_ACCESS_VIOLATION:
|
|
|
|
SigVal = 11; /* access violation */
|
|
|
|
break;
|
2002-01-23 23:39:26 +00:00
|
|
|
default:
|
|
|
|
SigVal = 7; /* "software generated" */
|
|
|
|
}
|
|
|
|
return (SigVal);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************/
|
|
|
|
/* WHILE WE FIND NICE HEX CHARS, BUILD A LONG */
|
|
|
|
/* RETURN NUMBER OF CHARS PROCESSED */
|
|
|
|
/**********************************************/
|
|
|
|
LONG
|
|
|
|
GspHex2Long (PCHAR *Address,
|
|
|
|
PLONG Value)
|
|
|
|
{
|
|
|
|
LONG NumChars = 0;
|
|
|
|
LONG Hex;
|
|
|
|
|
|
|
|
*Value = 0;
|
|
|
|
|
|
|
|
while (**Address)
|
|
|
|
{
|
|
|
|
Hex = HexValue (**Address);
|
|
|
|
if (Hex >= 0)
|
|
|
|
{
|
|
|
|
*Value = (*Value << 4) | Hex;
|
|
|
|
NumChars++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
|
|
|
|
(*Address)++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NumChars);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
|
|
GspLong2Hex (PCHAR *Address,
|
|
|
|
LONG Value)
|
|
|
|
{
|
|
|
|
LONG Save;
|
|
|
|
|
2003-03-06 23:57:03 +00:00
|
|
|
Save = (((Value >> 0) & 0xff) << 24) |
|
|
|
|
(((Value >> 8) & 0xff) << 16) |
|
|
|
|
(((Value >> 16) & 0xff) << 8) |
|
|
|
|
(((Value >> 24) & 0xff) << 0);
|
2002-01-23 23:39:26 +00:00
|
|
|
*Address = GspMem2Hex ((PCHAR) &Save, *Address, 4, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-03-06 23:57:03 +00:00
|
|
|
/*
|
2003-11-27 22:58:24 +00:00
|
|
|
* When coming from kernel mode, Esp is not stored in the trap frame.
|
|
|
|
* Instead, it was pointing to the location of the TrapFrame Esp member
|
|
|
|
* when the exception occured. When coming from user mode, Esp is just
|
|
|
|
* stored in the TrapFrame Esp member.
|
2003-03-06 23:57:03 +00:00
|
|
|
*/
|
|
|
|
static LONG
|
|
|
|
GspGetEspFromTrapFrame(PKTRAP_FRAME TrapFrame)
|
|
|
|
{
|
2003-11-27 22:58:24 +00:00
|
|
|
|
|
|
|
return KeGetPreviousMode() == KernelMode
|
|
|
|
? (LONG) &TrapFrame->Esp : TrapFrame->Esp;
|
2003-03-06 23:57:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-01-23 23:39:26 +00:00
|
|
|
VOID
|
|
|
|
GspGetRegistersFromTrapFrame(PCHAR Address,
|
2003-03-06 23:57:03 +00:00
|
|
|
PCONTEXT Context,
|
2002-01-23 23:39:26 +00:00
|
|
|
PKTRAP_FRAME TrapFrame)
|
|
|
|
{
|
|
|
|
ULONG Value;
|
|
|
|
PCHAR Buffer;
|
|
|
|
PULONG p;
|
|
|
|
DWORD i;
|
|
|
|
|
|
|
|
Buffer = Address;
|
2003-03-06 23:57:03 +00:00
|
|
|
for (i = 0; i < sizeof (GspRegisters) / sizeof (GspRegisters[0]); i++)
|
2002-01-23 23:39:26 +00:00
|
|
|
{
|
|
|
|
if (TrapFrame)
|
|
|
|
{
|
2003-03-06 23:57:03 +00:00
|
|
|
if (ESP == i)
|
|
|
|
{
|
|
|
|
Value = GspGetEspFromTrapFrame (TrapFrame);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
p = (PULONG) ((ULONG_PTR) TrapFrame + GspRegisters[i].OffsetInTF);
|
|
|
|
Value = *p;
|
|
|
|
}
|
2002-01-23 23:39:26 +00:00
|
|
|
}
|
|
|
|
else if (i == EIP_REGNO)
|
2003-03-06 23:57:03 +00:00
|
|
|
{
|
2002-01-23 23:39:26 +00:00
|
|
|
/*
|
|
|
|
* This thread has not been sheduled yet so assume it
|
|
|
|
* is still in PsBeginThreadWithContextInternal().
|
|
|
|
*/
|
|
|
|
Value = (ULONG) PsBeginThreadWithContextInternal;
|
2003-03-06 23:57:03 +00:00
|
|
|
}
|
2002-01-23 23:39:26 +00:00
|
|
|
else
|
2003-03-06 23:57:03 +00:00
|
|
|
{
|
2002-01-23 23:39:26 +00:00
|
|
|
Value = 0;
|
|
|
|
}
|
2003-03-06 23:57:03 +00:00
|
|
|
Buffer = GspMem2Hex ((PCHAR) &Value, Buffer, GspRegisters[i].Size, FALSE);
|
2002-01-23 23:39:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
|
|
GspSetRegistersInTrapFrame(PCHAR Address,
|
2003-03-06 23:57:03 +00:00
|
|
|
PCONTEXT Context,
|
2002-01-23 23:39:26 +00:00
|
|
|
PKTRAP_FRAME TrapFrame)
|
|
|
|
{
|
|
|
|
ULONG Value;
|
|
|
|
PCHAR Buffer;
|
|
|
|
PULONG p;
|
|
|
|
DWORD i;
|
|
|
|
|
|
|
|
if (!TrapFrame)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Buffer = Address;
|
|
|
|
for (i = 0; i < NUMREGS; i++)
|
|
|
|
{
|
2003-03-06 23:57:03 +00:00
|
|
|
if (GspRegisters[i].SetInContext)
|
|
|
|
p = (PULONG) ((ULONG_PTR) Context + GspRegisters[i].OffsetInContext);
|
|
|
|
else
|
|
|
|
p = (PULONG) ((ULONG_PTR) TrapFrame + GspRegisters[i].OffsetInTF);
|
2002-01-23 23:39:26 +00:00
|
|
|
Value = 0;
|
2003-03-06 23:57:03 +00:00
|
|
|
Buffer = GspHex2Mem (Buffer, (PCHAR) &Value, GspRegisters[i].Size, FALSE);
|
2002-01-23 23:39:26 +00:00
|
|
|
*p = Value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
|
|
GspSetSingleRegisterInTrapFrame(PCHAR Address,
|
|
|
|
LONG Number,
|
2003-03-06 23:57:03 +00:00
|
|
|
PCONTEXT Context,
|
2002-01-23 23:39:26 +00:00
|
|
|
PKTRAP_FRAME TrapFrame)
|
|
|
|
{
|
|
|
|
ULONG Value;
|
|
|
|
PULONG p;
|
|
|
|
|
|
|
|
if (!TrapFrame)
|
|
|
|
return;
|
|
|
|
|
2003-03-06 23:57:03 +00:00
|
|
|
if (GspRegisters[Number].SetInContext)
|
|
|
|
p = (PULONG) ((ULONG_PTR) Context + GspRegisters[Number].OffsetInContext);
|
|
|
|
else
|
|
|
|
p = (PULONG) ((ULONG_PTR) TrapFrame + GspRegisters[Number].OffsetInTF);
|
2002-01-23 23:39:26 +00:00
|
|
|
Value = 0;
|
|
|
|
GspHex2Mem (Address, (PCHAR) &Value, GspRegisters[Number].Size, FALSE);
|
|
|
|
*p = Value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
GspFindThread(PCHAR Data,
|
|
|
|
PETHREAD *Thread)
|
|
|
|
{
|
|
|
|
PETHREAD ThreadInfo = NULL;
|
|
|
|
|
|
|
|
if (strcmp (Data, "-1") == 0)
|
|
|
|
{
|
|
|
|
/* All threads */
|
|
|
|
ThreadInfo = NULL;
|
|
|
|
}
|
|
|
|
else if (strcmp (Data, "0") == 0)
|
|
|
|
{
|
|
|
|
/* Pick any thread, pick the first thread,
|
|
|
|
* which is what most people are interested in
|
|
|
|
*/
|
|
|
|
ThreadInfo = CONTAINING_RECORD (PiThreadListHead.Flink,
|
|
|
|
ETHREAD, Tcb.ThreadListEntry);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ULONG ThreadId;
|
|
|
|
PCHAR ptr = &Data[0];
|
|
|
|
|
|
|
|
GspHex2Long (&ptr, (PLONG) &ThreadId);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS (PsLookupThreadByThreadId ((PVOID) ThreadId, &ThreadInfo)))
|
|
|
|
{
|
|
|
|
*Thread = NULL;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*Thread = ThreadInfo;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
|
|
GspSetThread(PCHAR Request)
|
|
|
|
{
|
|
|
|
PETHREAD ThreadInfo;
|
|
|
|
PCHAR ptr = &Request[1];
|
|
|
|
|
|
|
|
switch (Request[0])
|
|
|
|
{
|
|
|
|
case 'c': /* Run thread */
|
|
|
|
if (GspFindThread (ptr, &ThreadInfo))
|
|
|
|
{
|
|
|
|
GspOutBuffer[0] = 'O';
|
|
|
|
GspOutBuffer[1] = 'K';
|
2003-04-11 02:25:24 +00:00
|
|
|
|
|
|
|
if(GspRunThread) ObDereferenceObject(GspRunThread);
|
|
|
|
|
|
|
|
GspRunThread = ThreadInfo;
|
2004-02-08 22:12:53 +00:00
|
|
|
if (GspRunThread) ObReferenceObject(GspRunThread);
|
2002-01-23 23:39:26 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GspOutBuffer[0] = 'E';
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'g': /* Debug thread */
|
|
|
|
if (GspFindThread (ptr, &ThreadInfo))
|
|
|
|
{
|
|
|
|
GspOutBuffer[0] = 'O';
|
|
|
|
GspOutBuffer[1] = 'K';
|
2003-04-11 02:25:24 +00:00
|
|
|
|
|
|
|
if(GspDbgThread) ObDereferenceObject(GspDbgThread);
|
|
|
|
|
|
|
|
GspDbgThread = ThreadInfo;
|
2002-01-23 23:39:26 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GspOutBuffer[0] = 'E';
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
|
|
GspQuery(PCHAR Request)
|
|
|
|
{
|
|
|
|
PCHAR Command;
|
|
|
|
ULONG Value;
|
|
|
|
|
|
|
|
Command = strtok (Request, ",");
|
|
|
|
if (strncmp (Command, "C", 1) == 0)
|
|
|
|
{
|
|
|
|
PCHAR ptr = &GspOutBuffer[2];
|
|
|
|
|
|
|
|
/* Get current thread id */
|
|
|
|
GspOutBuffer[0] = 'Q';
|
|
|
|
GspOutBuffer[1] = 'C';
|
2003-03-06 23:57:03 +00:00
|
|
|
if (NULL != GspDbgThread)
|
|
|
|
{
|
|
|
|
Value = (ULONG) GspDbgThread->Cid.UniqueThread;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Value = (ULONG) PsGetCurrentThread()->Cid.UniqueThread;
|
|
|
|
}
|
2002-01-23 23:39:26 +00:00
|
|
|
GspLong2Hex (&ptr, Value);
|
|
|
|
}
|
|
|
|
else if (strncmp (Command, "fThreadInfo", 11) == 0)
|
|
|
|
{
|
|
|
|
PCHAR ptr = &GspOutBuffer[1];
|
|
|
|
|
|
|
|
/* Get first thread id */
|
|
|
|
GspOutBuffer[0] = 'm';
|
|
|
|
GspEnumThread = CONTAINING_RECORD (PiThreadListHead.Flink,
|
|
|
|
ETHREAD, Tcb.ThreadListEntry);
|
|
|
|
Value = (ULONG) GspEnumThread->Cid.UniqueThread;
|
|
|
|
GspLong2Hex (&ptr, Value);
|
|
|
|
}
|
|
|
|
else if (strncmp (Command, "sThreadInfo", 11) == 0)
|
|
|
|
{
|
|
|
|
PCHAR ptr = &GspOutBuffer[1];
|
|
|
|
|
|
|
|
/* Get next thread id */
|
|
|
|
if ((GspEnumThread) && (GspEnumThread->Tcb.ThreadListEntry.Flink != PiThreadListHead.Flink))
|
|
|
|
{
|
|
|
|
GspEnumThread = CONTAINING_RECORD (GspEnumThread->Tcb.ThreadListEntry.Flink,
|
|
|
|
ETHREAD, Tcb.ThreadListEntry);
|
|
|
|
GspOutBuffer[0] = 'm';
|
|
|
|
Value = (ULONG) GspEnumThread->Cid.UniqueThread;
|
|
|
|
GspLong2Hex (&ptr, Value);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-03-06 23:57:03 +00:00
|
|
|
GspOutBuffer[0] = 'l';
|
2002-01-23 23:39:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (strncmp (Command, "ThreadExtraInfo", 15) == 0)
|
|
|
|
{
|
|
|
|
PETHREAD ThreadInfo;
|
|
|
|
PCHAR ptr = &Command[15];
|
|
|
|
|
|
|
|
/* Get thread information */
|
|
|
|
if (GspFindThread (ptr, &ThreadInfo))
|
|
|
|
{
|
2003-04-11 02:25:24 +00:00
|
|
|
PCHAR String = GspThreadStates[ThreadInfo->Tcb.State];
|
|
|
|
|
|
|
|
ObDereferenceObject(ThreadInfo);
|
|
|
|
|
|
|
|
GspMem2Hex (String, &GspOutBuffer[0], strlen (String), FALSE);
|
2002-01-23 23:39:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
else if (strncmp (Command, "L", 1) == 0)
|
|
|
|
{
|
|
|
|
PLIST_ENTRY CurrentEntry;
|
|
|
|
PETHREAD Current;
|
|
|
|
ULONG MaxThreads = 0;
|
|
|
|
ULONG ThreadId = 0;
|
|
|
|
ULONG ThreadCount = 0;
|
|
|
|
|
|
|
|
/* List threads */
|
|
|
|
GspHex2Mem (&Request[1], (PCHAR) &MaxThreads, 2, TRUE);
|
|
|
|
GspHex2Mem (&Request[3], (PCHAR) &Value, 4, TRUE);
|
|
|
|
GspHex2Mem (&Request[11], (PCHAR) &ThreadId, 4, TRUE);
|
|
|
|
|
|
|
|
GspOutBuffer[0] = 'q';
|
|
|
|
GspOutBuffer[1] = 'M';
|
|
|
|
Value = 0;
|
|
|
|
GspMem2Hex ((PCHAR) &Value, &GspOutBuffer[5], 4, TRUE);
|
|
|
|
GspMem2Hex ((PCHAR) &ThreadId, &GspOutBuffer[13], 4, TRUE);
|
|
|
|
|
|
|
|
CurrentEntry = PiThreadListHead.Flink;
|
|
|
|
while ((CurrentEntry != &PiThreadListHead) && (ThreadCount < MaxThreads))
|
|
|
|
{
|
|
|
|
Current = CONTAINING_RECORD (CurrentEntry, ETHREAD, Tcb.ThreadListEntry);
|
|
|
|
Value = 0;
|
|
|
|
GspMem2Hex ((PCHAR) &Value, &GspOutBuffer[21+ThreadCount*16], 4, TRUE);
|
|
|
|
Value = (ULONG) Current->Cid.UniqueThread;
|
|
|
|
GspMem2Hex ((PCHAR) &Value, &GspOutBuffer[21+ThreadCount*16+8], 4, TRUE);
|
|
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
|
|
ThreadCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CurrentEntry != &PiThreadListHead)
|
|
|
|
{
|
|
|
|
GspOutBuffer[4] = '0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GspOutBuffer[4] = '1';
|
|
|
|
}
|
|
|
|
|
|
|
|
GspMem2Hex ((PCHAR) &ThreadCount, &GspOutBuffer[2], 1, TRUE);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else if (strncmp (Command, "Offsets", 7) == 0)
|
|
|
|
{
|
|
|
|
strcpy (GspOutBuffer, "Text=0;Data=0;Bss=0");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
GspQueryThreadStatus(PCHAR Request)
|
|
|
|
{
|
|
|
|
PETHREAD ThreadInfo;
|
|
|
|
PCHAR ptr = &Request[0];
|
|
|
|
|
|
|
|
if (GspFindThread (ptr, &ThreadInfo))
|
|
|
|
{
|
2003-04-11 02:25:24 +00:00
|
|
|
ObDereferenceObject(ThreadInfo);
|
|
|
|
|
2002-01-23 23:39:26 +00:00
|
|
|
GspOutBuffer[0] = 'O';
|
|
|
|
GspOutBuffer[1] = 'K';
|
|
|
|
GspOutBuffer[2] = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GspOutBuffer[0] = 'E';
|
|
|
|
GspOutBuffer[1] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct _GsHwBreakPoint
|
|
|
|
{
|
|
|
|
BOOLEAN Enabled;
|
|
|
|
ULONG Type;
|
|
|
|
ULONG Length;
|
|
|
|
ULONG Address;
|
|
|
|
} GsHwBreakPoint;
|
|
|
|
|
2003-12-30 18:52:06 +00:00
|
|
|
#if defined(__GNUC__)
|
2002-01-23 23:39:26 +00:00
|
|
|
GsHwBreakPoint GspBreakpoints[4] =
|
|
|
|
{
|
|
|
|
{ Enabled : FALSE },
|
|
|
|
{ Enabled : FALSE },
|
|
|
|
{ Enabled : FALSE },
|
|
|
|
{ Enabled : FALSE }
|
|
|
|
};
|
2003-12-30 18:52:06 +00:00
|
|
|
#else
|
|
|
|
GsHwBreakPoint GspBreakpoints[4] =
|
|
|
|
{
|
|
|
|
{ FALSE },
|
|
|
|
{ FALSE },
|
|
|
|
{ FALSE },
|
|
|
|
{ FALSE }
|
|
|
|
};
|
|
|
|
#endif
|
2002-01-23 23:39:26 +00:00
|
|
|
|
|
|
|
VOID
|
|
|
|
GspCorrectHwBreakpoint()
|
|
|
|
{
|
|
|
|
ULONG BreakpointNumber;
|
|
|
|
BOOLEAN CorrectIt;
|
|
|
|
BOOLEAN Bit;
|
2003-12-30 18:52:06 +00:00
|
|
|
ULONG dr7_;
|
2002-01-23 23:39:26 +00:00
|
|
|
|
2003-12-30 18:52:06 +00:00
|
|
|
#if defined(__GNUC__)
|
2002-01-23 23:39:26 +00:00
|
|
|
asm volatile (
|
2003-12-30 18:52:06 +00:00
|
|
|
"movl %%db7, %0\n" : "=r" (dr7_) : );
|
2002-01-23 23:39:26 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
ULONG addr0, addr1, addr2, addr3;
|
|
|
|
|
|
|
|
asm volatile (
|
|
|
|
"movl %%db0, %0\n"
|
|
|
|
"movl %%db1, %1\n"
|
|
|
|
"movl %%db2, %2\n"
|
|
|
|
"movl %%db3, %3\n"
|
|
|
|
: "=r" (addr0), "=r" (addr1),
|
|
|
|
"=r" (addr2), "=r" (addr3) : );
|
|
|
|
} while (FALSE);
|
2003-12-30 18:52:06 +00:00
|
|
|
#elif defined(_MSC_VER)
|
|
|
|
__asm
|
|
|
|
{
|
|
|
|
mov eax, dr7; mov dr7_, eax;
|
|
|
|
mov eax, dr0; mov addr0, eax;
|
|
|
|
mov eax, dr1; mov addr1, eax;
|
|
|
|
mov eax, dr2; mov addr2, eax;
|
|
|
|
mov eax, dr3; mov addr3, eax;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#error Unknown compiler for inline assembler
|
|
|
|
#endif
|
2002-01-23 23:39:26 +00:00
|
|
|
CorrectIt = FALSE;
|
|
|
|
for (BreakpointNumber = 0; BreakpointNumber < 3; BreakpointNumber++)
|
|
|
|
{
|
|
|
|
Bit = 2 << (BreakpointNumber << 1);
|
2003-12-30 18:52:06 +00:00
|
|
|
if (!(dr7_ & Bit) && GspBreakpoints[BreakpointNumber].Enabled) {
|
2002-01-23 23:39:26 +00:00
|
|
|
CorrectIt = TRUE;
|
2003-12-30 18:52:06 +00:00
|
|
|
dr7_ |= Bit;
|
|
|
|
dr7_ &= ~(0xf0000 << (BreakpointNumber << 2));
|
|
|
|
dr7_ |= (((GspBreakpoints[BreakpointNumber].Length << 2) |
|
2002-01-23 23:39:26 +00:00
|
|
|
GspBreakpoints[BreakpointNumber].Type) << 16) << (BreakpointNumber << 2);
|
|
|
|
switch (BreakpointNumber) {
|
2003-12-30 18:52:06 +00:00
|
|
|
#if defined(__GNUC__)
|
2002-01-23 23:39:26 +00:00
|
|
|
case 0:
|
|
|
|
asm volatile ("movl %0, %%dr0\n"
|
|
|
|
: : "r" (GspBreakpoints[BreakpointNumber].Address) );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
asm volatile ("movl %0, %%dr1\n"
|
|
|
|
: : "r" (GspBreakpoints[BreakpointNumber].Address) );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
asm volatile ("movl %0, %%dr2\n"
|
|
|
|
: : "r" (GspBreakpoints[BreakpointNumber].Address) );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
asm volatile ("movl %0, %%dr3\n"
|
|
|
|
: : "r" (GspBreakpoints[BreakpointNumber].Address) );
|
|
|
|
break;
|
2003-12-30 18:52:06 +00:00
|
|
|
#elif defined(_MSC_VER)
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
ULONG addr = GspBreakpoints[BreakpointNumber].Address;
|
|
|
|
__asm mov eax, addr;
|
|
|
|
__asm mov dr0, eax;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
ULONG addr = GspBreakpoints[BreakpointNumber].Address;
|
|
|
|
__asm mov eax, addr;
|
|
|
|
__asm mov dr1, eax;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
ULONG addr = GspBreakpoints[BreakpointNumber].Address;
|
|
|
|
__asm mov eax, addr;
|
|
|
|
__asm mov dr2, eax;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
{
|
|
|
|
ULONG addr = GspBreakpoints[BreakpointNumber].Address;
|
|
|
|
__asm mov eax, addr;
|
|
|
|
__asm mov dr3, eax;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#else
|
|
|
|
#error Unknown compiler for inline assembler
|
|
|
|
#endif
|
2002-01-23 23:39:26 +00:00
|
|
|
}
|
|
|
|
}
|
2003-12-30 18:52:06 +00:00
|
|
|
else if ((dr7_ & Bit) && !GspBreakpoints[BreakpointNumber].Enabled)
|
2002-01-23 23:39:26 +00:00
|
|
|
{
|
|
|
|
CorrectIt = TRUE;
|
2003-12-30 18:52:06 +00:00
|
|
|
dr7_ &= ~Bit;
|
|
|
|
dr7_ &= ~(0xf0000 << (BreakpointNumber << 2));
|
2002-01-23 23:39:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (CorrectIt)
|
|
|
|
{
|
2003-12-30 18:52:06 +00:00
|
|
|
#if defined(__GNUC__)
|
|
|
|
asm volatile ( "movl %0, %%db7\n" : : "r" (dr7_));
|
|
|
|
#elif defined(_MSC_VER)
|
|
|
|
__asm mov eax, dr7_;
|
|
|
|
__asm mov dr7, eax;
|
|
|
|
#else
|
|
|
|
#error Unknown compiler for inline assembler
|
|
|
|
#endif
|
2002-01-23 23:39:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
|
|
GspRemoveHwBreakpoint(ULONG BreakpointNumber)
|
|
|
|
{
|
|
|
|
if (!GspBreakpoints[BreakpointNumber].Enabled)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
GspBreakpoints[BreakpointNumber].Enabled = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ULONG
|
|
|
|
GspSetHwBreakpoint(ULONG BreakpointNumber,
|
|
|
|
ULONG Type,
|
|
|
|
ULONG Length,
|
|
|
|
ULONG Address)
|
|
|
|
{
|
|
|
|
if (GspBreakpoints[BreakpointNumber].Enabled)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
GspBreakpoints[BreakpointNumber].Enabled = TRUE;
|
|
|
|
GspBreakpoints[BreakpointNumber].Type = Type;
|
|
|
|
GspBreakpoints[BreakpointNumber].Length = Length;
|
|
|
|
GspBreakpoints[BreakpointNumber].Address = Address;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function does all command procesing for interfacing to gdb.
|
|
|
|
*/
|
|
|
|
KD_CONTINUE_TYPE
|
|
|
|
KdEnterDebuggerException(PEXCEPTION_RECORD ExceptionRecord,
|
2002-08-08 17:54:16 +00:00
|
|
|
PCONTEXT Context,
|
|
|
|
PKTRAP_FRAME TrapFrame)
|
2002-01-23 23:39:26 +00:00
|
|
|
{
|
|
|
|
BOOLEAN Stepping;
|
|
|
|
LONG Address;
|
|
|
|
LONG Length;
|
|
|
|
LONG SigVal;
|
|
|
|
LONG NewPC;
|
|
|
|
PCHAR ptr;
|
2003-03-06 23:57:03 +00:00
|
|
|
LONG Esp;
|
2004-02-08 22:12:53 +00:00
|
|
|
KIRQL OldIrql;
|
2002-01-23 23:39:26 +00:00
|
|
|
|
|
|
|
/* FIXME: Stop on other CPUs too */
|
|
|
|
/* Disable hardware debugging while we are inside the stub */
|
2003-12-30 18:52:06 +00:00
|
|
|
#if defined(__GNUC__)
|
2002-01-23 23:39:26 +00:00
|
|
|
__asm__("movl %0,%%db7" : /* no output */ : "r" (0));
|
2003-12-30 18:52:06 +00:00
|
|
|
#elif defined(_MSC_VER)
|
|
|
|
__asm mov eax, 0 __asm mov dr7, eax
|
|
|
|
#else
|
|
|
|
#error Unknown compiler for inline assembler
|
|
|
|
#endif
|
2002-01-23 23:39:26 +00:00
|
|
|
|
2003-04-13 17:38:27 +00:00
|
|
|
if (STATUS_ACCESS_VIOLATION == (NTSTATUS) ExceptionRecord->ExceptionCode &&
|
2003-04-07 23:10:08 +00:00
|
|
|
NULL != GspAccessLocation &&
|
2003-03-06 23:57:03 +00:00
|
|
|
(ULONG_PTR) GspAccessLocation ==
|
|
|
|
(ULONG_PTR) ExceptionRecord->ExceptionInformation[1])
|
2002-01-23 23:39:26 +00:00
|
|
|
{
|
2003-03-06 23:57:03 +00:00
|
|
|
GspAccessLocation = NULL;
|
|
|
|
GspMemoryError = TRUE;
|
2003-08-22 18:46:40 +00:00
|
|
|
Context->Eip += 2;
|
2003-03-06 23:57:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-02-08 22:12:53 +00:00
|
|
|
/* Don't switch threads */
|
|
|
|
OldIrql = KeGetCurrentIrql();
|
|
|
|
if (OldIrql < DISPATCH_LEVEL)
|
|
|
|
{
|
|
|
|
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Always use the current thread when entering the exception handler */
|
|
|
|
if (NULL != GspDbgThread)
|
|
|
|
{
|
|
|
|
ObDereferenceObject(GspDbgThread);
|
|
|
|
GspDbgThread = NULL;
|
|
|
|
}
|
|
|
|
|
2003-03-06 23:57:03 +00:00
|
|
|
/* reply to host that an exception has occurred */
|
|
|
|
SigVal = GspComputeSignal (ExceptionRecord->ExceptionCode);
|
2002-01-23 23:39:26 +00:00
|
|
|
|
2003-03-06 23:57:03 +00:00
|
|
|
ptr = &GspOutBuffer[0];
|
2002-01-23 23:39:26 +00:00
|
|
|
|
2003-03-06 23:57:03 +00:00
|
|
|
*ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */
|
|
|
|
*ptr++ = HexChars[(SigVal >> 4) & 0xf];
|
|
|
|
*ptr++ = HexChars[SigVal & 0xf];
|
2002-01-23 23:39:26 +00:00
|
|
|
|
2003-03-06 23:57:03 +00:00
|
|
|
*ptr++ = HexChars[ESP];
|
|
|
|
*ptr++ = ':';
|
2002-01-23 23:39:26 +00:00
|
|
|
|
2003-03-06 23:57:03 +00:00
|
|
|
Esp = GspGetEspFromTrapFrame (TrapFrame); /* SP */
|
|
|
|
ptr = GspMem2Hex ((PCHAR) &Esp, ptr, 4, 0);
|
|
|
|
*ptr++ = ';';
|
2002-01-23 23:39:26 +00:00
|
|
|
|
2003-03-06 23:57:03 +00:00
|
|
|
*ptr++ = HexChars[EBP];
|
|
|
|
*ptr++ = ':';
|
|
|
|
ptr = GspMem2Hex ((PCHAR) &TrapFrame->Ebp, ptr, 4, 0); /* FP */
|
|
|
|
*ptr++ = ';';
|
2002-01-23 23:39:26 +00:00
|
|
|
|
2003-03-06 23:57:03 +00:00
|
|
|
*ptr++ = HexChars[PC];
|
|
|
|
*ptr++ = ':';
|
|
|
|
ptr = GspMem2Hex((PCHAR) &TrapFrame->Eip, ptr, 4, 0); /* PC */
|
|
|
|
*ptr++ = ';';
|
2002-01-23 23:39:26 +00:00
|
|
|
|
2003-03-06 23:57:03 +00:00
|
|
|
*ptr = '\0';
|
2002-01-23 23:39:26 +00:00
|
|
|
|
|
|
|
GspPutPacket (&GspOutBuffer[0]);
|
2003-03-06 23:57:03 +00:00
|
|
|
|
|
|
|
Stepping = FALSE;
|
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
/* Zero the buffer now so we don't have to worry about the terminating zero character */
|
|
|
|
memset (GspOutBuffer, 0, sizeof (GspInBuffer));
|
|
|
|
ptr = GspGetPacket ();
|
|
|
|
|
|
|
|
switch (*ptr++)
|
|
|
|
{
|
|
|
|
case '?':
|
|
|
|
GspOutBuffer[0] = 'S';
|
|
|
|
GspOutBuffer[1] = HexChars[SigVal >> 4];
|
|
|
|
GspOutBuffer[2] = HexChars[SigVal % 16];
|
|
|
|
GspOutBuffer[3] = 0;
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
GspRemoteDebug = !GspRemoteDebug; /* toggle debug flag */
|
|
|
|
break;
|
|
|
|
case 'g': /* return the value of the CPU Registers */
|
2004-02-08 22:12:53 +00:00
|
|
|
if (NULL != GspDbgThread)
|
|
|
|
{
|
|
|
|
GspGetRegistersFromTrapFrame (&GspOutBuffer[0], Context, GspDbgThread->Tcb.TrapFrame);
|
|
|
|
}
|
2003-03-06 23:57:03 +00:00
|
|
|
else
|
2004-02-08 22:12:53 +00:00
|
|
|
{
|
|
|
|
GspGetRegistersFromTrapFrame (&GspOutBuffer[0], Context, TrapFrame);
|
|
|
|
}
|
2003-03-06 23:57:03 +00:00
|
|
|
break;
|
|
|
|
case 'G': /* set the value of the CPU Registers - return OK */
|
2004-02-08 22:12:53 +00:00
|
|
|
if (NULL != GspDbgThread)
|
|
|
|
{
|
|
|
|
GspSetRegistersInTrapFrame (ptr, Context, GspDbgThread->Tcb.TrapFrame);
|
|
|
|
}
|
2003-03-06 23:57:03 +00:00
|
|
|
else
|
2004-02-08 22:12:53 +00:00
|
|
|
{
|
|
|
|
GspSetRegistersInTrapFrame (ptr, Context, TrapFrame);
|
|
|
|
}
|
2003-03-06 23:57:03 +00:00
|
|
|
strcpy (GspOutBuffer, "OK");
|
|
|
|
break;
|
|
|
|
case 'P': /* set the value of a single CPU register - return OK */
|
|
|
|
{
|
|
|
|
LONG Register;
|
|
|
|
|
|
|
|
if ((GspHex2Long (&ptr, &Register)) && (*ptr++ == '='))
|
|
|
|
if ((Register >= 0) && (Register < NUMREGS))
|
|
|
|
{
|
|
|
|
if (GspDbgThread)
|
2004-02-08 22:12:53 +00:00
|
|
|
{
|
|
|
|
GspSetSingleRegisterInTrapFrame(ptr, Register,
|
|
|
|
Context, GspDbgThread->Tcb.TrapFrame);
|
|
|
|
}
|
2003-03-06 23:57:03 +00:00
|
|
|
else
|
2004-02-08 22:12:53 +00:00
|
|
|
{
|
|
|
|
GspSetSingleRegisterInTrapFrame (ptr, Register, Context, TrapFrame);
|
|
|
|
}
|
2003-03-06 23:57:03 +00:00
|
|
|
strcpy (GspOutBuffer, "OK");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy (GspOutBuffer, "E01");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
|
|
|
|
case 'm':
|
|
|
|
/* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
|
|
|
|
if (GspHex2Long (&ptr, &Address))
|
|
|
|
if (*(ptr++) == ',')
|
|
|
|
if (GspHex2Long (&ptr, &Length))
|
|
|
|
{
|
|
|
|
ptr = 0;
|
|
|
|
GspMemoryError = FALSE;
|
|
|
|
GspMem2Hex ((PCHAR) Address, GspOutBuffer, Length, 1);
|
|
|
|
if (GspMemoryError)
|
|
|
|
{
|
|
|
|
strcpy (GspOutBuffer, "E03");
|
|
|
|
DPRINT ("Fault during memory read\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
strcpy (GspOutBuffer, "E01");
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
|
|
|
|
case 'M':
|
|
|
|
/* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
|
|
|
|
if (GspHex2Long (&ptr, &Address))
|
|
|
|
if (*(ptr++) == ',')
|
|
|
|
if (GspHex2Long (&ptr, &Length))
|
|
|
|
if (*(ptr++) == ':')
|
|
|
|
{
|
|
|
|
GspMemoryError = FALSE;
|
|
|
|
GspHex2Mem (ptr, (PCHAR) Address, Length, TRUE);
|
|
|
|
|
|
|
|
if (GspMemoryError)
|
|
|
|
{
|
|
|
|
strcpy (GspOutBuffer, "E03");
|
|
|
|
DPRINT ("Fault during memory write\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy (GspOutBuffer, "OK");
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = NULL;
|
|
|
|
}
|
|
|
|
if (ptr)
|
|
|
|
strcpy (GspOutBuffer, "E02");
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* cAA..AA Continue at address AA..AA(optional) */
|
|
|
|
/* sAA..AA Step one instruction from AA..AA(optional) */
|
|
|
|
case 's':
|
|
|
|
Stepping = TRUE;
|
|
|
|
case 'c':
|
|
|
|
{
|
|
|
|
ULONG BreakpointNumber;
|
2003-12-30 18:52:06 +00:00
|
|
|
ULONG dr6_;
|
2003-03-06 23:57:03 +00:00
|
|
|
|
|
|
|
/* try to read optional parameter, pc unchanged if no parm */
|
|
|
|
if (GspHex2Long (&ptr, &Address))
|
2004-02-08 22:12:53 +00:00
|
|
|
Context->Eip = Address;
|
2003-03-06 23:57:03 +00:00
|
|
|
|
|
|
|
NewPC = Context->Eip;
|
|
|
|
|
|
|
|
/* clear the trace bit */
|
|
|
|
Context->EFlags &= 0xfffffeff;
|
|
|
|
|
|
|
|
/* set the trace bit if we're Stepping */
|
|
|
|
if (Stepping)
|
|
|
|
Context->EFlags |= 0x100;
|
|
|
|
|
2003-12-30 18:52:06 +00:00
|
|
|
#if defined(__GNUC__)
|
|
|
|
asm volatile ("movl %%db6, %0\n" : "=r" (dr6_) : );
|
|
|
|
#elif defined(_MSC_VER)
|
|
|
|
__asm mov eax, dr6 __asm mov dr6_, eax;
|
|
|
|
#else
|
|
|
|
#error Unknown compiler for inline assembler
|
|
|
|
#endif
|
|
|
|
if (!(dr6_ & 0x4000))
|
2003-03-06 23:57:03 +00:00
|
|
|
{
|
|
|
|
for (BreakpointNumber = 0; BreakpointNumber < 4; ++BreakpointNumber)
|
|
|
|
{
|
2003-12-30 18:52:06 +00:00
|
|
|
if (dr6_ & (1 << BreakpointNumber))
|
2003-03-06 23:57:03 +00:00
|
|
|
{
|
|
|
|
if (GspBreakpoints[BreakpointNumber].Type == 0)
|
|
|
|
{
|
|
|
|
/* Set restore flag */
|
|
|
|
Context->EFlags |= 0x10000;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
GspCorrectHwBreakpoint();
|
2003-12-30 18:52:06 +00:00
|
|
|
#if defined(__GNUC__)
|
2003-03-06 23:57:03 +00:00
|
|
|
asm volatile ("movl %0, %%db6\n" : : "r" (0));
|
2003-12-30 18:52:06 +00:00
|
|
|
#elif defined(_MSC_VER)
|
|
|
|
__asm mov eax, 0 __asm mov dr6, eax;
|
|
|
|
#else
|
|
|
|
#error Unknown compiler for inline assembler
|
|
|
|
#endif
|
2004-02-08 22:12:53 +00:00
|
|
|
if (OldIrql < DISPATCH_LEVEL)
|
|
|
|
{
|
|
|
|
KeLowerIrql(OldIrql);
|
|
|
|
}
|
2003-03-06 23:57:03 +00:00
|
|
|
|
|
|
|
return kdHandleException;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 'k': /* kill the program */
|
|
|
|
strcpy (GspOutBuffer, "OK");
|
|
|
|
break;
|
|
|
|
/* kill the program */
|
|
|
|
|
|
|
|
case 'H': /* Set thread */
|
|
|
|
GspSetThread (ptr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'q': /* Query */
|
|
|
|
GspQuery (ptr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'T': /* Query thread status */
|
|
|
|
GspQueryThreadStatus (ptr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'Y':
|
|
|
|
{
|
My biggest commit so far (everything compiles and apparently runs fine):
- replaced DWORD with ULONG in a couple of places
- replaced some ULONGs with LONGs in the KD GDB stub
- replaced INITIAL_TEB with USER_STACK, as per Nebbet's book, to support both fixed size and expandable stacks
- added InterlockedExchangePointer
- added the ASM_BREAKPOINT macro as the architecture-dependent assembler code to raise a breakpoint exception
- corrected definitions of INT, LONG, DWORD, UINT, ULONG and ULONG32
- corrected IoSetCancelRoutine to use InterlockedExchangePointer
- corrected definition of NtCurrentTeb and NtCurrentPeb
- corrected DbgBreakPoint and DbgUserBreakPoint not to set up a stack frame (temporary fix with inline assembler - why doesn't GCC understand __declspec(naked)?)
- corrected various calls to Interlocked* functions to cast OUT operands to LONG *
- corrected various printf format strings
- corrected DbgUiIssueRemoteBreakin to use the smallest possible stack (this is what started everything)
- removed a DPRINT that accessed pageable memory at non-PASSIVE_LEVEL IRQL
- beautified CreateProcessA (another temporary fix - all the new functions will be isolated in the upcoming stand-alone RTL)
- prefixed LdrInitializeThunk with a nop that can be overwritten with a breakpoint for debugging purposes (temporary debugging aid until we have user-mode debugger support). Will add support for this to the breakin utility soon
- thread creation code rewritten from scratch (some glitches documented inline, but works fine)
- thread creation code now duplicated just twice, as opposed to five times (temporary fix - three new, non standard functions have been exported from NTDLL.DLL, will fix later)
svn path=/trunk/; revision=4595
2003-04-26 23:13:33 +00:00
|
|
|
LONG Number;
|
|
|
|
LONG Length;
|
|
|
|
LONG Type;
|
|
|
|
LONG Address;
|
2003-03-06 23:57:03 +00:00
|
|
|
|
|
|
|
ptr = &GspOutBuffer[1];
|
|
|
|
GspHex2Long (&ptr, &Number);
|
|
|
|
ptr++;
|
|
|
|
GspHex2Long (&ptr, &Type);
|
|
|
|
ptr++;
|
|
|
|
GspHex2Long (&ptr, &Length);
|
|
|
|
ptr++;
|
|
|
|
GspHex2Long (&ptr, &Address);
|
|
|
|
if (GspSetHwBreakpoint (Number & 0x3, Type & 0x3 , Length & 0x3, Address) == 0)
|
|
|
|
{
|
|
|
|
strcpy (GspOutBuffer, "OK");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy (GspOutBuffer, "E");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove hardware breakpoint */
|
|
|
|
case 'y':
|
|
|
|
{
|
My biggest commit so far (everything compiles and apparently runs fine):
- replaced DWORD with ULONG in a couple of places
- replaced some ULONGs with LONGs in the KD GDB stub
- replaced INITIAL_TEB with USER_STACK, as per Nebbet's book, to support both fixed size and expandable stacks
- added InterlockedExchangePointer
- added the ASM_BREAKPOINT macro as the architecture-dependent assembler code to raise a breakpoint exception
- corrected definitions of INT, LONG, DWORD, UINT, ULONG and ULONG32
- corrected IoSetCancelRoutine to use InterlockedExchangePointer
- corrected definition of NtCurrentTeb and NtCurrentPeb
- corrected DbgBreakPoint and DbgUserBreakPoint not to set up a stack frame (temporary fix with inline assembler - why doesn't GCC understand __declspec(naked)?)
- corrected various calls to Interlocked* functions to cast OUT operands to LONG *
- corrected various printf format strings
- corrected DbgUiIssueRemoteBreakin to use the smallest possible stack (this is what started everything)
- removed a DPRINT that accessed pageable memory at non-PASSIVE_LEVEL IRQL
- beautified CreateProcessA (another temporary fix - all the new functions will be isolated in the upcoming stand-alone RTL)
- prefixed LdrInitializeThunk with a nop that can be overwritten with a breakpoint for debugging purposes (temporary debugging aid until we have user-mode debugger support). Will add support for this to the breakin utility soon
- thread creation code rewritten from scratch (some glitches documented inline, but works fine)
- thread creation code now duplicated just twice, as opposed to five times (temporary fix - three new, non standard functions have been exported from NTDLL.DLL, will fix later)
svn path=/trunk/; revision=4595
2003-04-26 23:13:33 +00:00
|
|
|
LONG Number;
|
2003-03-06 23:57:03 +00:00
|
|
|
|
|
|
|
ptr = &GspOutBuffer[1];
|
|
|
|
GspHex2Long(&ptr, &Number);
|
|
|
|
if (GspRemoveHwBreakpoint (Number & 0x3) == 0)
|
|
|
|
{
|
|
|
|
strcpy (GspOutBuffer, "OK");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy (GspOutBuffer, "E");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
} /* switch */
|
|
|
|
|
|
|
|
/* reply to the request */
|
|
|
|
GspPutPacket (&GspOutBuffer[0]);
|
|
|
|
}
|
2002-01-23 23:39:26 +00:00
|
|
|
}
|
|
|
|
|
2003-08-22 18:46:40 +00:00
|
|
|
return kdHandleException;
|
2002-01-23 23:39:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
STDCALL
|
|
|
|
GspBreakIn(PKINTERRUPT Interrupt,
|
|
|
|
PVOID ServiceContext)
|
|
|
|
{
|
|
|
|
PKTRAP_FRAME TrapFrame;
|
|
|
|
BOOLEAN DoBreakIn;
|
|
|
|
CONTEXT Context;
|
|
|
|
KIRQL OldIrql;
|
|
|
|
CHAR Value;
|
|
|
|
|
|
|
|
DPRINT ("Break In\n");
|
|
|
|
|
|
|
|
DoBreakIn = FALSE;
|
2002-05-08 17:05:32 +00:00
|
|
|
while (KdPortGetByteEx (&GdbPortInfo, &Value))
|
2002-01-23 23:39:26 +00:00
|
|
|
{
|
|
|
|
if (Value == 0x03)
|
|
|
|
DoBreakIn = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!DoBreakIn)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
KeRaiseIrql (HIGH_LEVEL, &OldIrql);
|
|
|
|
|
|
|
|
TrapFrame = PsGetCurrentThread()->Tcb.TrapFrame;
|
|
|
|
|
|
|
|
KeTrapFrameToContext (TrapFrame, &Context);
|
|
|
|
|
|
|
|
KdEnterDebuggerException (NULL, &Context, TrapFrame);
|
|
|
|
|
|
|
|
KeContextToTrapFrame (&Context, TrapFrame);
|
|
|
|
|
|
|
|
KeLowerIrql (OldIrql);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
extern ULONG KdpPortIrq;
|
|
|
|
|
|
|
|
/* Initialize the GDB stub */
|
2003-10-12 17:05:50 +00:00
|
|
|
VOID INIT_FUNCTION
|
2002-01-23 23:39:26 +00:00
|
|
|
KdGdbStubInit(ULONG Phase)
|
|
|
|
{
|
2002-05-13 18:10:41 +00:00
|
|
|
#if 0
|
2002-01-23 23:39:26 +00:00
|
|
|
KAFFINITY Affinity;
|
|
|
|
NTSTATUS Status;
|
|
|
|
ULONG MappedIrq;
|
|
|
|
KIRQL Dirql;
|
2002-05-13 18:10:41 +00:00
|
|
|
#endif
|
2002-01-23 23:39:26 +00:00
|
|
|
|
|
|
|
if (Phase == 0)
|
|
|
|
{
|
2002-05-08 17:05:32 +00:00
|
|
|
DbgPrint("Module 'hal.dll' loaded at 0x%.08x.\n", LdrHalBase);
|
|
|
|
|
2002-01-23 23:39:26 +00:00
|
|
|
GspInitialized = TRUE;
|
|
|
|
GspRunThread = PsGetCurrentThread();
|
2003-04-11 02:25:24 +00:00
|
|
|
|
|
|
|
ObReferenceObject(GspRunThread);
|
|
|
|
|
2003-03-06 23:57:03 +00:00
|
|
|
/* GspDbgThread = PsGetCurrentThread(); */
|
2003-04-11 02:25:24 +00:00
|
|
|
GspDbgThread = NULL;
|
2002-01-23 23:39:26 +00:00
|
|
|
GspEnumThread = NULL;
|
2002-05-13 18:10:41 +00:00
|
|
|
|
|
|
|
DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C);
|
2002-01-23 23:39:26 +00:00
|
|
|
}
|
|
|
|
else if (Phase == 1)
|
|
|
|
{
|
2002-05-13 18:10:41 +00:00
|
|
|
#if 0
|
2002-01-23 23:39:26 +00:00
|
|
|
/* Hook an interrupt handler to allow the debugger to break into
|
|
|
|
the system */
|
|
|
|
MappedIrq = HalGetInterruptVector (Internal,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
KdpPortIrq,
|
|
|
|
&Dirql,
|
|
|
|
&Affinity);
|
|
|
|
|
|
|
|
Status = IoConnectInterrupt(&GspInterrupt,
|
|
|
|
GspBreakIn,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
MappedIrq,
|
|
|
|
Dirql,
|
|
|
|
Dirql,
|
|
|
|
0,
|
|
|
|
FALSE,
|
|
|
|
Affinity,
|
|
|
|
FALSE);
|
|
|
|
if (!NT_SUCCESS (Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Could not connect to IRQ line %d (0x%x)\n",
|
|
|
|
KdpPortIrq, Status);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KdPortEnableInterrupts();
|
2002-02-09 18:41:24 +00:00
|
|
|
|
|
|
|
DbgBreakPointWithStatus (DBG_STATUS_CONTROL_C);
|
2002-05-13 18:10:41 +00:00
|
|
|
#endif
|
2002-01-23 23:39:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
2002-05-13 18:10:41 +00:00
|
|
|
KdGdbDebugPrint(LPSTR Message)
|
2002-01-23 23:39:26 +00:00
|
|
|
{
|
|
|
|
#if 0
|
2002-05-13 18:10:41 +00:00
|
|
|
/* This can be quite annoying! */
|
2002-01-23 23:39:26 +00:00
|
|
|
if (GspInitialized)
|
2002-05-13 18:10:41 +00:00
|
|
|
{
|
|
|
|
ULONG Length;
|
|
|
|
|
|
|
|
GspOutBuffer[0] = 'O';
|
|
|
|
GspOutBuffer[1] = '\0';
|
|
|
|
strcat (&GspOutBuffer[0], Message);
|
|
|
|
Length = strlen (Message);
|
|
|
|
GspOutBuffer[2 + Length] = '\n';
|
|
|
|
GspOutBuffer[3 + Length] = '\0';
|
|
|
|
GspPutPacketNoWait (&GspOutBuffer[0]);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
HalDisplayString(Message);
|
2002-01-23 23:39:26 +00:00
|
|
|
#endif
|
|
|
|
}
|
2002-05-13 18:10:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
extern LIST_ENTRY ModuleListHead;
|
|
|
|
|
|
|
|
VOID
|
|
|
|
KdGdbListModules()
|
|
|
|
{
|
|
|
|
PLIST_ENTRY CurrentEntry;
|
|
|
|
PMODULE_OBJECT Current;
|
|
|
|
ULONG ModuleCount;
|
|
|
|
|
|
|
|
DPRINT1("\n");
|
|
|
|
|
|
|
|
ModuleCount = 0;
|
|
|
|
|
|
|
|
CurrentEntry = ModuleListHead.Flink;
|
|
|
|
while (CurrentEntry != (&ModuleListHead))
|
|
|
|
{
|
|
|
|
Current = CONTAINING_RECORD (CurrentEntry, MODULE_OBJECT, ListEntry);
|
|
|
|
|
|
|
|
DbgPrint ("Module %S Base 0x%.08x Length 0x%.08x\n",
|
|
|
|
Current->BaseName.Buffer, Current->Base, Current->Length);
|
|
|
|
|
|
|
|
ModuleCount++;
|
|
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
|
|
}
|
|
|
|
|
|
|
|
DbgPrint ("%d modules listed\n", ModuleCount);
|
|
|
|
}
|