506 lines
12 KiB
C
Raw Permalink Normal View History

2001-01-01 00:00:00 +01:00
/*
*
* tldxt.c
*
* Transport layer for the VC debug extension
*
*/
#include "precomp.h"
int
WINAPI
DmDllMain(
HANDLE hModule,
DWORD dwReason,
DWORD dwReserved
);
VOID FAR PASCAL
DMFunc(
DWORD cb,
LPDBB lpdbb
);
XOSD FAR PASCAL
DMInit(
DMTLFUNCTYPE lpfnTl,
LPTSTR lpch
);
BOOL fTlConnected;
BOOL fDMConnected;
LPVOID pvDMBuffer;
DWORD cbDMBuffer;
DWORD ibDMBuffer;
RTL_CRITICAL_SECTION csDMRequest;
RTL_CRITICAL_SECTION csEMRequest;
RTL_CRITICAL_SECTION csPacket;
KEVENT kevtReply;
KEVENT kevtRequest;
KEVENT kevtPacket;
PDM_CMDCONT g_pdmcc;
BYTE rgbSendPacketBuffer[1024];
int ibSendPacketBuffer;
BYTE rgbReceivePacketBuffer[1024];
int ibReceivePacketBuffer;
BOOL fUsingReceivePacketBuffer;
void AcquireSendPacket(void)
{
/* We need to use the global packet buffer. First we wait for its
* availability */
EnterCriticalSection(&csPacket);
KeWaitForSingleObject(&kevtPacket, UserRequest, KernelMode, FALSE,
NULL);
KeResetEvent(&kevtPacket);
LeaveCriticalSection(&csPacket);
}
void FillPacket64(LPSTR sz, BYTE *pb, DWORD cb)
{
WORD w = 0;
int ibit = 0;
while(cb--) {
w |= *pb++ << ibit;
ibit += 8;
while(ibit >= 6) {
*sz++ = (w & 0x3f) + '!';
w >>= 6;
ibit -= 6;
}
}
if(ibit)
*sz++ = (w & 0x3f) + '!';
*sz = 0;
}
int GetPacket64(LPCSTR sz, BYTE *pb, DWORD cb)
{
DWORD ib = 0;
WORD w = 0;
int ibit = 0;
while(*sz) {
w |= (*sz++ - '!') << ibit;
ibit += 6;
while(ibit >= 8) {
if(++ib > cb)
return -1;
*pb++ = w & 0xff;
w >>= 8;
ibit -= 8;
}
}
return ib;
}
XOSD SendTlPacket(char ch, DWORD cb, PVOID pv)
{
XOSD xosd = xosdNone;
if(ch != 'p') {
/* We have an available packet, so set it up */
char sz[512];
sprintf(sz, "msvc!%c ", ch);
if(cb < 256) {
/* Short packets can be translated and sent on the notification
* line */
FillPacket64(sz + 7, pv, cb);
DmSendNotificationString(sz);
} else {
AcquireSendPacket();
if(cb <= sizeof rgbSendPacketBuffer) {
ibSendPacketBuffer = cb;
memcpy(rgbSendPacketBuffer, pv, cb);
sz[6] = 'g';
DmSendNotificationString(sz);
} else
/* Should probably assert here */
xosd = xosdUnknown;
}
} else if(g_pdmcc) {
DPRINT(5, ("dxt: reply\n"));
g_pdmcc->DataSize = cb;
memcpy(g_pdmcc->Buffer, pv, cb);
KeSetEvent(&kevtRequest, EVENT_INCREMENT, FALSE);
} else {
/* What are we replying to? */
assert(FALSE);
}
return xosd;
}
XOSD TLFunc(TLF tlf, HPID hpid, LPARAM wParam, LPARAM lParam)
{
XOSD xosd = xosdNone;
switch(tlf)
{
case tlfSetBuffer:
pvDMBuffer = (LPVOID)lParam;
cbDMBuffer = wParam;
break;
case tlfRequest:
if(!fTlConnected)
xosd = xosdLineNotConnected;
else {
EnterCriticalSection(&csDMRequest);
DPRINT(5, ("dxt: dmrequest\n"));
SendTlPacket('q', wParam, (PVOID)lParam);
KeWaitForSingleObject(&kevtReply, UserRequest, KernelMode, FALSE,
NULL);
DPRINT(5, ("dxt: got dmreply\n"));
LeaveCriticalSection(&csDMRequest);
/* Reply packets come back into the correct buffer, so we just
* need to extract the xosd and we're done */
if(ibDMBuffer == 0)
xosd = xosdInvalidParameter;
}
break;
case tlfReply:
if(!fTlConnected)
xosd = xosdLineNotConnected;
else
xosd = SendTlPacket('p', wParam, (PVOID)lParam);
break;
case tlfDebugPacket:
if(!fTlConnected)
xosd = xosdLineNotConnected;
else
SendTlPacket('d', wParam, (PVOID)lParam);
break;
}
return xosd;
}
HRESULT HrGetPacket(LPCSTR szCommand, PDM_CMDCONT pdmcc)
{
HRESULT hr;
BOOL fAllocated = FALSE;
/* Get a buffer to stick this packet into */
if(szCommand[6] == 'g') {
/* Binary data coming in, so get its length and set things up */
const char *pch = szCommand + 7;
pdmcc->BytesRemaining = 0;
while(*pch)
pdmcc->BytesRemaining = 10 * pdmcc->BytesRemaining +
(*pch++ - '0');
if(!pdmcc->BytesRemaining)
/* No data means no packet */
return E_FAIL;
if(!pdmcc->Buffer) {
if(InterlockedExchange(&fUsingReceivePacketBuffer, TRUE)) {
pdmcc->Buffer = ExAllocatePoolWithTag(PagedPool,
pdmcc->BytesRemaining, 'cvsm');
if(!pdmcc->Buffer)
return E_OUTOFMEMORY;
pdmcc->BufferSize = pdmcc->BytesRemaining;
fAllocated = TRUE;
} else {
pdmcc->Buffer = rgbReceivePacketBuffer;
pdmcc->BufferSize = sizeof rgbReceivePacketBuffer;
}
}
if(pdmcc->BytesRemaining > pdmcc->BufferSize) {
TooBig:
/* Too much data */
ExFreePoolWithTag(pdmcc->Buffer, 'cvsm');
return E_FAIL;
}
pdmcc->CustomData = (PVOID)pdmcc->BytesRemaining;
hr = XBDM_READYFORBIN;
} else {
int ib;
if(!pdmcc->Buffer) {
pdmcc->BufferSize = sizeof rgbReceivePacketBuffer;
if(InterlockedExchange(&fUsingReceivePacketBuffer, TRUE)) {
pdmcc->Buffer = ExAllocatePoolWithTag(PagedPool,
pdmcc->BufferSize, 'cvsm');
if(!pdmcc->Buffer)
return E_OUTOFMEMORY;
fAllocated = TRUE;
} else
pdmcc->Buffer = rgbReceivePacketBuffer;
}
ib = GetPacket64(szCommand + 7, pdmcc->Buffer,
pdmcc->BufferSize);
if(ibReceivePacketBuffer < 0)
goto TooBig;
pdmcc->DataSize = ib;
hr = XBDM_NOERR;
}
return hr;
}
HRESULT SendPacketData(PDM_CMDCONT pdmcc, LPSTR szResp, DWORD cchResp)
{
HRESULT hr;
if(pdmcc->BytesRemaining == 0) {
/* We're done with the send buffer now */
KeSetEvent(&kevtPacket, EVENT_INCREMENT, FALSE);
hr = XBDM_ENDOFLIST;
} else if(pdmcc->Buffer == pdmcc) {
/* We haven't sent anything yet. We need to send the length first */
pdmcc->Buffer = &pdmcc->BytesRemaining;
pdmcc->DataSize = sizeof pdmcc->BytesRemaining;
hr = XBDM_NOERR;
} else {
/* We've sent the length, now send the data */
pdmcc->Buffer = pdmcc->CustomData;
pdmcc->DataSize = pdmcc->BytesRemaining;
pdmcc->BytesRemaining = 0;
hr = XBDM_NOERR;
}
return hr;
}
HRESULT HrDeliverPacket(PDM_CMDCONT pdmcc, LPSTR szResp, DWORD cchResp,
BOOL fCanBinSend)
{
HRESULT hr;
int cbTextMax;
/* Now what do we do with the reply packet? The theory is that anything
* less than 256 bytes is best sent text-encoded in the response, and that
* anything bigger than that should be sent in a binary response. If we
* can't send a binary response, we'll send as text if it will fit into the
* text buffer */
cbTextMax = (cchResp - 8) * 3 / 4;
if(fCanBinSend && cbTextMax > 256)
cbTextMax = 256;
if(pdmcc->DataSize < (DWORD)cbTextMax) {
if(pdmcc->DataSize == 0) {
/* Huh? */
_asm int 3
}
szResp[0] = 'p';
FillPacket64(szResp + 1, pdmcc->Buffer, pdmcc->DataSize);
if(pdmcc->Buffer = rgbSendPacketBuffer)
/* We're done with the send buffer now */
KeSetEvent(&kevtPacket, EVENT_INCREMENT, FALSE);
hr = XBDM_NOERR;
} else if(fCanBinSend) {
/* We're able to send a binary response, so we'll do so */
pdmcc->HandlingFunction = SendPacketData;
pdmcc->BytesRemaining = pdmcc->DataSize;
pdmcc->CustomData = pdmcc->Buffer;
pdmcc->Buffer = pdmcc;
hr = XBDM_BINRESPONSE;
} else {
/* We need to advertise that the response is available as a
* get-packet */
szResp[0] = 'g';
szResp[1] = 0;
hr = XBDM_NOERR;
}
return hr;
}
HRESULT HrDoRequest(PDM_CMDCONT pdmcc, LPSTR szResp, DWORD cchResp,
BOOL fCanBinSend)
{
BYTE *pbRequest = pdmcc->Buffer;
DWORD cbRequest = pdmcc->DataSize;
int cbTextMax;
/* Prepare to receive the reply and do the action */
EnterCriticalSection(&csEMRequest);
g_pdmcc = pdmcc;
AcquireSendPacket();
pdmcc->Buffer = rgbSendPacketBuffer;
pdmcc->BufferSize = sizeof rgbSendPacketBuffer;
pdmcc->DataSize = 0;
DPRINT(5, ("dxt: request\n"));
DMFunc(cbRequest, (LPDBB)pbRequest);
/* Wait for the reply to come through before continuing */
KeWaitForSingleObject(&kevtRequest, UserRequest, KernelMode, FALSE,
NULL);
DPRINT(5, ("dxt: got reply\n"));
g_pdmcc = NULL;
LeaveCriticalSection(&csEMRequest);
/* OK, we have our response data. Send it now if we can, or mark
* it available for later. In either case, we're done with the
* receive buffer so we can accept another request */
if(pbRequest != rgbReceivePacketBuffer)
ExFreePoolWithTag(pbRequest, 'cvsm');
fUsingReceivePacketBuffer = FALSE;
return HrDeliverPacket(pdmcc, szResp, cchResp, fCanBinSend);
}
void DoReply(PDM_CMDCONT pdmcc)
{
ibDMBuffer = pdmcc->DataSize;
DPRINT(5, ("dxt: dmreply\n"));
KeSetEvent(&kevtReply, EVENT_INCREMENT, FALSE);
}
BOOL FHandleIncomingData(PDM_CMDCONT pdmcc)
{
if(!pdmcc->DataSize) {
/* We've lost our socket, so we'll discard what we've got and clean
* up */
pdmcc->Buffer = (LPBYTE)pdmcc->Buffer + pdmcc->BytesRemaining -
(DWORD)pdmcc->CustomData;
if(pdmcc->Buffer != rgbReceivePacketBuffer)
ExFreePoolWithTag(pdmcc->Buffer, 'cvsm');
return FALSE;
}
pdmcc->Buffer = (LPBYTE)pdmcc->Buffer + pdmcc->DataSize;
pdmcc->BytesRemaining -= pdmcc->DataSize;
if(pdmcc->BytesRemaining == 0) {
/* Restore the buffer pointer */
pdmcc->Buffer = (LPBYTE)pdmcc->Buffer - (DWORD)pdmcc->CustomData;
pdmcc->DataSize = (DWORD)pdmcc->CustomData;
}
return TRUE;
}
HRESULT HandleRequest(PDM_CMDCONT pdmcc, LPSTR szResp, DWORD cchResp)
{
if(!FHandleIncomingData(pdmcc) || pdmcc->BytesRemaining != 0)
return XBDM_NOERR;
return HrDoRequest(pdmcc, szResp, cchResp, FALSE);
}
HRESULT HandleReply(PDM_CMDCONT pdmcc, LPSTR szResp, DWORD cchResp)
{
if(!FHandleIncomingData(pdmcc) || pdmcc->BytesRemaining != 0)
return XBDM_NOERR;
DoReply(pdmcc);
return XBDM_NOERR;
}
HRESULT HandleDebugPacket(PDM_CMDCONT pdmcc, LPSTR szResp, DWORD cchResp)
{
if(!FHandleIncomingData(pdmcc) || pdmcc->BytesRemaining != 0)
return XBDM_NOERR;
DMFunc(pdmcc->DataSize, pdmcc->Buffer);
return XBDM_NOERR;
}
HRESULT HrMsvcCmdProcessor(LPCSTR szCommand, LPSTR szResp, DWORD cchResp,
PDM_CMDCONT pdmcc)
{
XOSD xosd;
HRESULT hr;
switch(szCommand[5]) {
case 'c':
/* tlfConnect */
if(fTlConnected)
/* Can't connect twice */
hr = E_FAIL;
else {
fTlConnected = TRUE;
hr = XBDM_DEDICATED;
}
break;
case 'l':
/* tlfLoadDM */
if(!fTlConnected)
xosd = xosdLineNotConnected;
else if(fDMConnected)
xosd = xosdNone;
else
xosd = DMInit(TLFunc, NULL) ? xosdUnknown : xosdNone;
hr = 0;
break;
case 'q':
/* tlfRequest */
if(!fTlConnected) {
sprintf(szResp, "x%d", xosdLineNotConnected);
hr = XBDM_NOERR;
} else {
pdmcc->HandlingFunction = HandleRequest;
pdmcc->Buffer = NULL;
/* First get the incoming packet */
hr = HrGetPacket(szCommand, pdmcc);
if(hr == XBDM_NOERR)
hr = HrDoRequest(pdmcc, szResp, cchResp, TRUE);
}
break;
case 'p':
/* tlfReply */
if(!fTlConnected) {
sprintf(szResp, "x%d", xosdLineNotConnected);
hr = XBDM_NOERR;
} else {
pdmcc->HandlingFunction = HandleReply;
pdmcc->Buffer = pvDMBuffer;
pdmcc->BufferSize = cbDMBuffer;
hr = HrGetPacket(szCommand, pdmcc);
if(hr == XBDM_NOERR)
DoReply(pdmcc);
}
break;
case 'd':
/* tlfDebugPacket */
if(!fTlConnected) {
sprintf(szResp, "x%d", xosdLineNotConnected);
hr = XBDM_NOERR;
} else {
pdmcc->HandlingFunction = HandleDebugPacket;
pdmcc->Buffer = NULL;
hr = HrGetPacket(szCommand, pdmcc);
if(hr == XBDM_NOERR)
DMFunc(pdmcc->DataSize, pdmcc->Buffer);
}
break;
case 'g':
/* not a tlf -- need to get the available debug packet */
if(!fTlConnected) {
sprintf(szResp, "x%d", xosdLineNotConnected);
hr = XBDM_NOERR;
} else if(!kevtPacket.Header.SignalState)
/* No packet available */
hr = E_FAIL;
else {
pdmcc->Buffer = rgbSendPacketBuffer;
pdmcc->DataSize = ibSendPacketBuffer;
hr = HrDeliverPacket(pdmcc, szResp, cchResp, TRUE);
}
break;
default:
hr = XBDM_INVALIDCMD;
break;
}
if(!hr) {
sprintf(szResp, "x%d", xosd);
hr = XBDM_NOERR;
}
return hr;
}
void DxtEntry(ULONG unused1, ULONG unused2, ULONG unused3)
{
/* Set up some things */
InitializeCriticalSection(&csDMRequest);
InitializeCriticalSection(&csEMRequest);
InitializeCriticalSection(&csPacket);
KeInitializeEvent(&kevtReply, SynchronizationEvent, FALSE);
KeInitializeEvent(&kevtRequest, SynchronizationEvent, FALSE);
KeInitializeEvent(&kevtPacket, NotificationEvent, TRUE);
/* Register our command processor */
DmRegisterCommandProcessor("MSVC", HrMsvcCmdProcessor);
/* Send a DLL init to the DM */
DmDllMain(NULL, DLL_PROCESS_ATTACH, 0);
}