570 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			570 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  Detours Test Program (tracebld.cpp of tracebld.exe)
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  Microsoft Research Detours Package
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//  Copyright (c) Microsoft Corporation.  All rights reserved.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								#include <windows.h>
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#include <stddef.h>
							 | 
						||
| 
								 | 
							
								#pragma warning(push)
							 | 
						||
| 
								 | 
							
								#if _MSC_VER > 1400
							 | 
						||
| 
								 | 
							
								#pragma warning(disable:6102 6103) // /analyze warnings
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								#include <strsafe.h>
							 | 
						||
| 
								 | 
							
								#pragma warning(pop)
							 | 
						||
| 
								 | 
							
								#include <detours.h>
							 | 
						||
| 
								 | 
							
								#include "tracebld.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if (_MSC_VER < 1299)
							 | 
						||
| 
								 | 
							
								typedef ULONG * PULONG_PTR;
							 | 
						||
| 
								 | 
							
								typedef ULONG ULONG_PTR;
							 | 
						||
| 
								 | 
							
								typedef LONG * PLONG_PTR;
							 | 
						||
| 
								 | 
							
								typedef LONG LONG_PTR;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								#pragma warning(disable:4127)   // Many of our asserts are constants.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define ASSERT_ALWAYS(x)   \
							 | 
						||
| 
								 | 
							
								    do {                                                        \
							 | 
						||
| 
								 | 
							
								    if (!(x)) {                                                 \
							 | 
						||
| 
								 | 
							
								            AssertMessage(#x, __FILE__, __LINE__);              \
							 | 
						||
| 
								 | 
							
								            DebugBreak();                                       \
							 | 
						||
| 
								 | 
							
								    }                                                           \
							 | 
						||
| 
								 | 
							
								    } while (0)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef NDEBUG
							 | 
						||
| 
								 | 
							
								#define ASSERT(x)           ASSERT_ALWAYS(x)
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#define ASSERT(x)
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define UNUSED(c)       (c) = (c)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								enum {
							 | 
						||
| 
								 | 
							
								    CLIENT_AWAITING_PIPE_ACCEPT = 0x21,
							 | 
						||
| 
								 | 
							
								    CLIENT_AWAITING_PIPE_DATA   = 0x22,
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								typedef struct _CLIENT : OVERLAPPED
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    HANDLE          hPipe;
							 | 
						||
| 
								 | 
							
								    LONG            nClient;
							 | 
						||
| 
								 | 
							
								    HANDLE          hFile;
							 | 
						||
| 
								 | 
							
								    BOOL            fAwaitingAccept;
							 | 
						||
| 
								 | 
							
								    PVOID           Zero;
							 | 
						||
| 
								 | 
							
								    TBLOG_MESSAGE   Message;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    BOOL LogMessage(PTBLOG_MESSAGE pMessage, DWORD nBytes);
							 | 
						||
| 
								 | 
							
								    BOOL LogMessageV(PCHAR pszMsg, ...);
							 | 
						||
| 
								 | 
							
								} CLIENT, *PCLIENT;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								CHAR        s_szLogFile[MAX_PATH];
							 | 
						||
| 
								 | 
							
								CHAR        s_szPipe[MAX_PATH];
							 | 
						||
| 
								 | 
							
								LONG        s_nActiveClients = 0;
							 | 
						||
| 
								 | 
							
								LONG        s_nTotalClients = 0;
							 | 
						||
| 
								 | 
							
								LONGLONG    s_llStartTime;
							 | 
						||
| 
								 | 
							
								BOOL        s_fVerbose = FALSE;
							 | 
						||
| 
								 | 
							
								TBLOG_PAYLOAD s_Payload;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								VOID MyErrExit(PCSTR pszMsg)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    DWORD error = GetLastError();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    fprintf(stderr, "TRACEBLD: Error %ld in %s.\n", error, pszMsg);
							 | 
						||
| 
								 | 
							
								    fflush(stderr);
							 | 
						||
| 
								 | 
							
								    exit(1);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								BOOL CLIENT::LogMessageV(PCHAR pszMsg, ...)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    DWORD cbWritten = 0;
							 | 
						||
| 
								 | 
							
								    CHAR szBuf[1024];
							 | 
						||
| 
								 | 
							
								    PCHAR pcchEnd = szBuf + ARRAYSIZE(szBuf) - 2;
							 | 
						||
| 
								 | 
							
								    PCHAR pcchCur = szBuf;
							 | 
						||
| 
								 | 
							
								    HRESULT hr;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    va_list args;
							 | 
						||
| 
								 | 
							
								    va_start(args, pszMsg);
							 | 
						||
| 
								 | 
							
								    hr = StringCchVPrintfExA(pcchCur, pcchEnd - pcchCur,
							 | 
						||
| 
								 | 
							
								                             &pcchCur, NULL, STRSAFE_NULL_ON_FAILURE,
							 | 
						||
| 
								 | 
							
								                             pszMsg, args);
							 | 
						||
| 
								 | 
							
								    va_end(args);
							 | 
						||
| 
								 | 
							
								    if (FAILED(hr)) {
							 | 
						||
| 
								 | 
							
								        goto cleanup;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    hr = StringCchPrintfExA(pcchCur, szBuf + (ARRAYSIZE(szBuf)) - pcchCur,
							 | 
						||
| 
								 | 
							
								                            &pcchCur, NULL, STRSAFE_NULL_ON_FAILURE,
							 | 
						||
| 
								 | 
							
								                            "\n");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  cleanup:
							 | 
						||
| 
								 | 
							
								    WriteFile(hFile, szBuf, (DWORD)(pcchCur - szBuf), &cbWritten, NULL);
							 | 
						||
| 
								 | 
							
								    return TRUE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								BOOL CLIENT::LogMessage(PTBLOG_MESSAGE pMessage, DWORD nBytes)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    // Sanity check the size of the message.
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    if (nBytes > pMessage->nBytes) {
							 | 
						||
| 
								 | 
							
								        nBytes = pMessage->nBytes;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (nBytes >= sizeof(*pMessage)) {
							 | 
						||
| 
								 | 
							
								        nBytes = sizeof(*pMessage) - 1;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Don't log message if there isn't and message text.
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    DWORD cbWrite = nBytes - offsetof(TBLOG_MESSAGE, szMessage);
							 | 
						||
| 
								 | 
							
								    if (cbWrite <= 0 ) {
							 | 
						||
| 
								 | 
							
								        return TRUE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (s_fVerbose) {
							 | 
						||
| 
								 | 
							
								        printf("[%s]", pMessage->szMessage);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    DWORD cbWritten = 0;
							 | 
						||
| 
								 | 
							
								    WriteFile(hFile, pMessage->szMessage, cbWrite, &cbWritten, NULL);
							 | 
						||
| 
								 | 
							
								    return TRUE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								BOOL CloseConnection(PCLIENT pClient)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    InterlockedDecrement(&s_nActiveClients);
							 | 
						||
| 
								 | 
							
								    if (pClient != NULL) {
							 | 
						||
| 
								 | 
							
								        if (pClient->hPipe != INVALID_HANDLE_VALUE) {
							 | 
						||
| 
								 | 
							
								            //FlushFileBuffers(pClient->hPipe);
							 | 
						||
| 
								 | 
							
								            if (!DisconnectNamedPipe(pClient->hPipe)) {
							 | 
						||
| 
								 | 
							
								                DWORD error = GetLastError();
							 | 
						||
| 
								 | 
							
								                pClient->LogMessageV("<!-- Error %d in DisconnectNamedPipe. -->\n", error);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            CloseHandle(pClient->hPipe);
							 | 
						||
| 
								 | 
							
								            pClient->hPipe = INVALID_HANDLE_VALUE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (pClient->hFile != INVALID_HANDLE_VALUE) {
							 | 
						||
| 
								 | 
							
								            CloseHandle(pClient->hFile);
							 | 
						||
| 
								 | 
							
								            pClient->hFile = INVALID_HANDLE_VALUE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        GlobalFree(pClient);
							 | 
						||
| 
								 | 
							
								        pClient = NULL;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return TRUE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Creates a pipe instance and initiate an accept request.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								PCLIENT CreatePipeConnection(HANDLE hCompletionPort, LONG nClient)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    HANDLE hPipe = CreateNamedPipeA(s_szPipe,                   // pipe name
							 | 
						||
| 
								 | 
							
								                                    PIPE_ACCESS_INBOUND |       // read-only access
							 | 
						||
| 
								 | 
							
								                                    FILE_FLAG_OVERLAPPED,       // overlapped mode
							 | 
						||
| 
								 | 
							
								                                    PIPE_TYPE_MESSAGE |         // message-type pipe
							 | 
						||
| 
								 | 
							
								                                    PIPE_READMODE_MESSAGE |     // message read mode
							 | 
						||
| 
								 | 
							
								                                    PIPE_WAIT,                  // blocking mode
							 | 
						||
| 
								 | 
							
								                                    PIPE_UNLIMITED_INSTANCES,   // unlimited instances
							 | 
						||
| 
								 | 
							
								                                    0,                          // output buffer size
							 | 
						||
| 
								 | 
							
								                                    0,                          // input buffer size
							 | 
						||
| 
								 | 
							
								                                    20000,                      // client time-out
							 | 
						||
| 
								 | 
							
								                                    NULL);                      // no security attributes
							 | 
						||
| 
								 | 
							
								    if (hPipe == INVALID_HANDLE_VALUE) {
							 | 
						||
| 
								 | 
							
								        MyErrExit("CreateNamedPipe");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Allocate the client data structure.
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    PCLIENT pClient = (PCLIENT) GlobalAlloc(GPTR, sizeof(CLIENT));
							 | 
						||
| 
								 | 
							
								    if (pClient == NULL) {
							 | 
						||
| 
								 | 
							
								        MyErrExit("GlobalAlloc pClient");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    CHAR szLogFile[MAX_PATH];
							 | 
						||
| 
								 | 
							
								    StringCchPrintfA(szLogFile, ARRAYSIZE(szLogFile), "%s.%08d.xml", s_szLogFile, nClient);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ZeroMemory(pClient, sizeof(*pClient));
							 | 
						||
| 
								 | 
							
								    pClient->hPipe = hPipe;
							 | 
						||
| 
								 | 
							
								    pClient->nClient = nClient;
							 | 
						||
| 
								 | 
							
								    pClient->fAwaitingAccept = TRUE;
							 | 
						||
| 
								 | 
							
								    pClient->hFile = CreateFileA(szLogFile,
							 | 
						||
| 
								 | 
							
								                                 GENERIC_WRITE,
							 | 
						||
| 
								 | 
							
								                                 FILE_SHARE_READ,
							 | 
						||
| 
								 | 
							
								                                 NULL,
							 | 
						||
| 
								 | 
							
								                                 CREATE_ALWAYS,
							 | 
						||
| 
								 | 
							
								                                 FILE_ATTRIBUTE_NORMAL |
							 | 
						||
| 
								 | 
							
								                                 FILE_FLAG_SEQUENTIAL_SCAN,
							 | 
						||
| 
								 | 
							
								                                 NULL);
							 | 
						||
| 
								 | 
							
								    if (pClient->hFile == INVALID_HANDLE_VALUE) {
							 | 
						||
| 
								 | 
							
								        fprintf(stderr, "TRACEBLD: Error opening output file: %s: %ld\n\n",
							 | 
						||
| 
								 | 
							
								                szLogFile, GetLastError());
							 | 
						||
| 
								 | 
							
								        fflush(stderr);
							 | 
						||
| 
								 | 
							
								        MyErrExit("CreateFile");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Associate file with our complietion port.
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    if (!CreateIoCompletionPort(pClient->hPipe, hCompletionPort, (ULONG_PTR)pClient, 0)) {
							 | 
						||
| 
								 | 
							
								        MyErrExit("CreateIoComplietionPort pClient");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!ConnectNamedPipe(hPipe, pClient)) {
							 | 
						||
| 
								 | 
							
								        DWORD error = GetLastError();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (error == ERROR_IO_PENDING) {
							 | 
						||
| 
								 | 
							
								            return NULL;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (error == ERROR_PIPE_CONNECTED) {
							 | 
						||
| 
								 | 
							
								#if 0
							 | 
						||
| 
								 | 
							
								            pClient->LogMessageV("<!-- ConnectNamedPipe client already connected. -->");
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								            pClient->fAwaitingAccept = FALSE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else if (error != ERROR_IO_PENDING &&
							 | 
						||
| 
								 | 
							
								                 error != ERROR_PIPE_LISTENING) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            MyErrExit("ConnectNamedPipe");
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else {
							 | 
						||
| 
								 | 
							
								        fprintf(stderr, "*** ConnectNamedPipe accepted immediately.\n");
							 | 
						||
| 
								 | 
							
								#if 0
							 | 
						||
| 
								 | 
							
								        pClient->LogMessageV("<!-- ConnectNamedPipe accepted immediately. -->");
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								        pClient->fAwaitingAccept = FALSE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return pClient;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								BOOL DoRead(PCLIENT pClient)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    SetLastError(NO_ERROR);
							 | 
						||
| 
								 | 
							
								    DWORD nBytes = 0;
							 | 
						||
| 
								 | 
							
								    BOOL b = ReadFile(pClient->hPipe, &pClient->Message, sizeof(pClient->Message),
							 | 
						||
| 
								 | 
							
								                      &nBytes, pClient);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    DWORD error = GetLastError();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (b && error == NO_ERROR) {
							 | 
						||
| 
								 | 
							
								        return TRUE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (error == ERROR_BROKEN_PIPE) {
							 | 
						||
| 
								 | 
							
								        pClient->LogMessageV("<!-- **** ReadFile 002 *** ERROR_BROKEN_PIPE [%d] -->\n", nBytes);
							 | 
						||
| 
								 | 
							
								        CloseConnection(pClient);
							 | 
						||
| 
								 | 
							
								        return TRUE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else if (error == ERROR_INVALID_HANDLE) {
							 | 
						||
| 
								 | 
							
								        // ?
							 | 
						||
| 
								 | 
							
								        pClient->LogMessageV("<!-- **** ReadFile 002 *** ERROR_INVALID_HANDLE -->\n");
							 | 
						||
| 
								 | 
							
								        // I have no idea why this happens.  Our remedy is to drop the connection.
							 | 
						||
| 
								 | 
							
								        return TRUE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else if (error != ERROR_IO_PENDING) {
							 | 
						||
| 
								 | 
							
								        if (b) {
							 | 
						||
| 
								 | 
							
								            pClient->LogMessageV("<!-- **** ReadFile 002 succeeded: %d -->\n", error);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else {
							 | 
						||
| 
								 | 
							
								            pClient->LogMessageV("<!-- **** ReadFile 002 failed: %d -->\n", error);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        CloseConnection(pClient);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return TRUE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								DWORD WINAPI WorkerThread(LPVOID pvVoid)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    PCLIENT pClient;
							 | 
						||
| 
								 | 
							
								    BOOL b;
							 | 
						||
| 
								 | 
							
								    LPOVERLAPPED lpo;
							 | 
						||
| 
								 | 
							
								    DWORD nBytes;
							 | 
						||
| 
								 | 
							
								    HANDLE hCompletionPort = (HANDLE)pvVoid;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (BOOL fKeepLooping = TRUE; fKeepLooping;) {
							 | 
						||
| 
								 | 
							
								        pClient = NULL;
							 | 
						||
| 
								 | 
							
								        lpo = NULL;
							 | 
						||
| 
								 | 
							
								        nBytes = 0;
							 | 
						||
| 
								 | 
							
								        b = GetQueuedCompletionStatus(hCompletionPort,
							 | 
						||
| 
								 | 
							
								                                      &nBytes, (PULONG_PTR)&pClient, &lpo, INFINITE);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (!b) {
							 | 
						||
| 
								 | 
							
								            if (pClient) {
							 | 
						||
| 
								 | 
							
								                if (GetLastError() == ERROR_BROKEN_PIPE) {
							 | 
						||
| 
								 | 
							
								                    pClient->LogMessageV("<!-- Client closed pipe. -->");
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                else {
							 | 
						||
| 
								 | 
							
								                    pClient->LogMessageV("<!-- *** GetQueuedCompletionStatus failed %d -->",
							 | 
						||
| 
								 | 
							
								                                         GetLastError());
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                CloseConnection(pClient);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            continue;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (pClient->fAwaitingAccept) {
							 | 
						||
| 
								 | 
							
								            BOOL fAgain = TRUE;
							 | 
						||
| 
								 | 
							
								            while (fAgain) {
							 | 
						||
| 
								 | 
							
								                LONG nClient = InterlockedIncrement(&s_nTotalClients);
							 | 
						||
| 
								 | 
							
								                InterlockedIncrement(&s_nActiveClients);
							 | 
						||
| 
								 | 
							
								                pClient->fAwaitingAccept = FALSE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                PCLIENT pNew = CreatePipeConnection(hCompletionPort, nClient);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                fAgain = FALSE;
							 | 
						||
| 
								 | 
							
								                if (pNew != NULL) {
							 | 
						||
| 
								 | 
							
								                    fAgain = !pNew->fAwaitingAccept;
							 | 
						||
| 
								 | 
							
								                    DoRead(pNew);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else {
							 | 
						||
| 
								 | 
							
								            if (nBytes <= offsetof(TBLOG_MESSAGE, szMessage)) {
							 | 
						||
| 
								 | 
							
								                pClient->LogMessageV("</t:Process>\n");
							 | 
						||
| 
								 | 
							
								                CloseConnection(pClient);
							 | 
						||
| 
								 | 
							
								                continue;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            pClient->LogMessage(&pClient->Message, nBytes);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        DoRead(pClient);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								BOOL CreateWorkers(HANDLE hCompletionPort)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    DWORD dwThread;
							 | 
						||
| 
								 | 
							
								    HANDLE hThread;
							 | 
						||
| 
								 | 
							
								    DWORD i;
							 | 
						||
| 
								 | 
							
								    SYSTEM_INFO SystemInfo;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    GetSystemInfo(&SystemInfo);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    for (i = 0; i < 1; i++) {
							 | 
						||
| 
								 | 
							
								        hThread = CreateThread(NULL, 0, WorkerThread, hCompletionPort, 0, &dwThread);
							 | 
						||
| 
								 | 
							
								        if (!hThread) {
							 | 
						||
| 
								 | 
							
								            MyErrExit("CreateThread WorkerThread");
							 | 
						||
| 
								 | 
							
								            // Unreachable: return FALSE;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        CloseHandle(hThread);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    return TRUE;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								DWORD CopyEnvironment(PWCHAR pwzzOut, PCWSTR pwzzIn)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    PCWSTR pwzzBeg = pwzzOut;
							 | 
						||
| 
								 | 
							
								    while (*pwzzIn) {
							 | 
						||
| 
								 | 
							
								        while (*pwzzIn) {
							 | 
						||
| 
								 | 
							
								            *pwzzOut++ = *pwzzIn++;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        *pwzzOut++ = *pwzzIn++;   // Copy zero.
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    *pwzzOut++ = '\0';    // Add last zero.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return (DWORD)(pwzzOut - pwzzBeg);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								DWORD main(int argc, char **argv)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								    HANDLE hCompletionPort;
							 | 
						||
| 
								 | 
							
								    BOOL fNeedHelp = FALSE;
							 | 
						||
| 
								 | 
							
								    WCHAR wzzDrop[1024] = L"build\0nmake\0";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    GetSystemTimeAsFileTime((FILETIME *)&s_llStartTime);
							 | 
						||
| 
								 | 
							
								    StringCchPrintfA(s_szPipe, ARRAYSIZE(s_szPipe), "%s.%d", TBLOG_PIPE_NAME, GetCurrentProcessId());
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    int arg = 1;
							 | 
						||
| 
								 | 
							
								    for (; arg < argc && (argv[arg][0] == '-' || argv[arg][0] == '/'); arg++) {
							 | 
						||
| 
								 | 
							
								        CHAR *argn = argv[arg] + 1;
							 | 
						||
| 
								 | 
							
								        CHAR *argp = argn;
							 | 
						||
| 
								 | 
							
								        while (*argp && *argp != ':' && *argp != '=') {
							 | 
						||
| 
								 | 
							
								            argp++;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        if (*argp == ':' || *argp == '=') {
							 | 
						||
| 
								 | 
							
								            *argp++ = '\0';
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        switch (argn[0]) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          case 'd':                                     // Drop Processes
							 | 
						||
| 
								 | 
							
								          case 'D':
							 | 
						||
| 
								 | 
							
								            if (*argp) {
							 | 
						||
| 
								 | 
							
								                PWCHAR pwz = wzzDrop;
							 | 
						||
| 
								 | 
							
								                while (*argp) {
							 | 
						||
| 
								 | 
							
								                    if (*argp == ';') {
							 | 
						||
| 
								 | 
							
								                        *pwz++ = '\0';
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                    else {
							 | 
						||
| 
								 | 
							
								                        *pwz++ = *argp++;
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                *pwz++ = '\0';
							 | 
						||
| 
								 | 
							
								                *pwz = '\0';
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          case 'o':                                 // Output file.
							 | 
						||
| 
								 | 
							
								          case 'O':
							 | 
						||
| 
								 | 
							
								            StringCchCopyA(s_szLogFile, ARRAYSIZE(s_szLogFile), argp);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          case 'v':                                     // Verbose
							 | 
						||
| 
								 | 
							
								          case 'V':
							 | 
						||
| 
								 | 
							
								            s_fVerbose = TRUE;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          case '?':                                 // Help.
							 | 
						||
| 
								 | 
							
								            fNeedHelp = TRUE;
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          default:
							 | 
						||
| 
								 | 
							
								            fNeedHelp = TRUE;
							 | 
						||
| 
								 | 
							
								            printf("TRACEBLD: Bad argument: %s:%s\n", argn, argp);
							 | 
						||
| 
								 | 
							
								            break;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (arg >= argc) {
							 | 
						||
| 
								 | 
							
								        fNeedHelp = TRUE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (fNeedHelp) {
							 | 
						||
| 
								 | 
							
								        printf("Usage:\n"
							 | 
						||
| 
								 | 
							
								               "    tracebld [options] command {command arguments}\n"
							 | 
						||
| 
								 | 
							
								               "Options:\n"
							 | 
						||
| 
								 | 
							
								               "    /o:file    Log all events to the output files.\n"
							 | 
						||
| 
								 | 
							
								               "    /?         Display this help message.\n"
							 | 
						||
| 
								 | 
							
								               "Summary:\n"
							 | 
						||
| 
								 | 
							
								               "    Runs the build commands and figures out which files have dependencies..\n"
							 | 
						||
| 
								 | 
							
								               "\n");
							 | 
						||
| 
								 | 
							
								        exit(9001);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Create the completion port.
							 | 
						||
| 
								 | 
							
								    hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0);
							 | 
						||
| 
								 | 
							
								    if (hCompletionPort == NULL) {
							 | 
						||
| 
								 | 
							
								        MyErrExit("CreateIoCompletionPort");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Create completion port worker threads.
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    CreateWorkers(hCompletionPort);
							 | 
						||
| 
								 | 
							
								    CreatePipeConnection(hCompletionPort, 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    printf("TRACEBLD: Ready for clients.  Press Ctrl-C to stop.\n");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /////////////////////////////////////////////////////////// Validate DLLs.
							 | 
						||
| 
								 | 
							
								    //
							 | 
						||
| 
								 | 
							
								    CHAR szTmpPath[MAX_PATH];
							 | 
						||
| 
								 | 
							
								    CHAR szExePath[MAX_PATH];
							 | 
						||
| 
								 | 
							
								    CHAR szDllPath[MAX_PATH];
							 | 
						||
| 
								 | 
							
								    PCHAR pszFilePart = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!GetModuleFileNameA(NULL, szTmpPath, ARRAYSIZE(szTmpPath))) {
							 | 
						||
| 
								 | 
							
								        printf("TRACEBLD: Couldn't retreive exe name.\n");
							 | 
						||
| 
								 | 
							
								        return 9002;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (!GetFullPathNameA(szTmpPath, ARRAYSIZE(szExePath), szExePath, &pszFilePart) ||
							 | 
						||
| 
								 | 
							
								        pszFilePart == NULL) {
							 | 
						||
| 
								 | 
							
								        printf("TRACEBLD: Error: %s is not a valid path name..\n", szTmpPath);
							 | 
						||
| 
								 | 
							
								        return 9002;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    StringCchCopyA(pszFilePart, szExePath + ARRAYSIZE(szExePath) - pszFilePart,
							 | 
						||
| 
								 | 
							
								             "trcbld" DETOURS_STRINGIFY(DETOURS_BITS) ".dll");
							 | 
						||
| 
								 | 
							
								    StringCchCopyA(szDllPath, ARRAYSIZE(szDllPath), szExePath);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    //////////////////////////////////////////////////////////////////////////
							 | 
						||
| 
								 | 
							
								    STARTUPINFOA si;
							 | 
						||
| 
								 | 
							
								    PROCESS_INFORMATION pi;
							 | 
						||
| 
								 | 
							
								    CHAR szCommand[2048];
							 | 
						||
| 
								 | 
							
								    CHAR szExe[MAX_PATH];
							 | 
						||
| 
								 | 
							
								    CHAR szFullExe[MAX_PATH] = "\0";
							 | 
						||
| 
								 | 
							
								    PCHAR pszFileExe = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ZeroMemory(&si, sizeof(si));
							 | 
						||
| 
								 | 
							
								    ZeroMemory(&pi, sizeof(pi));
							 | 
						||
| 
								 | 
							
								    si.cb = sizeof(si);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    szCommand[0] = L'\0';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    StringCchCopyA(szExe, sizeof(szExe), argv[arg]);
							 | 
						||
| 
								 | 
							
								    for (; arg < argc; arg++) {
							 | 
						||
| 
								 | 
							
								        if (strchr(argv[arg], ' ') != NULL || strchr(argv[arg], '\t') != NULL) {
							 | 
						||
| 
								 | 
							
								            StringCchCatA(szCommand, sizeof(szCommand), "\"");
							 | 
						||
| 
								 | 
							
								            StringCchCatA(szCommand, sizeof(szCommand), argv[arg]);
							 | 
						||
| 
								 | 
							
								            StringCchCatA(szCommand, sizeof(szCommand), "\"");
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        else {
							 | 
						||
| 
								 | 
							
								            StringCchCatA(szCommand, sizeof(szCommand), argv[arg]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (arg + 1 < argc) {
							 | 
						||
| 
								 | 
							
								            StringCchCatA(szCommand, sizeof(szCommand), " ");
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    printf("TRACEBLD: Starting: `%s'\n", szCommand);
							 | 
						||
| 
								 | 
							
								    printf("TRACEBLD:   with `%s'\n", szDllPath);
							 | 
						||
| 
								 | 
							
								    fflush(stdout);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    DWORD dwFlags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    SetLastError(0);
							 | 
						||
| 
								 | 
							
								    SearchPathA(NULL, szExe, ".exe", ARRAYSIZE(szFullExe), szFullExe, &pszFileExe);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!DetourCreateProcessWithDllExA(szFullExe[0] ? szFullExe : NULL, szCommand,
							 | 
						||
| 
								 | 
							
								                                       NULL, NULL, TRUE, dwFlags, NULL, NULL,
							 | 
						||
| 
								 | 
							
								                                       &si, &pi, szDllPath, NULL)) {
							 | 
						||
| 
								 | 
							
								        printf("TRACEBLD: DetourCreateProcessWithDllEx failed: %ld\n", GetLastError());
							 | 
						||
| 
								 | 
							
								        ExitProcess(9007);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ZeroMemory(&s_Payload, sizeof(s_Payload));
							 | 
						||
| 
								 | 
							
								    s_Payload.nParentProcessId = GetCurrentProcessId();
							 | 
						||
| 
								 | 
							
								    s_Payload.nTraceProcessId = GetCurrentProcessId();
							 | 
						||
| 
								 | 
							
								    s_Payload.nGeneology = 1;
							 | 
						||
| 
								 | 
							
								    s_Payload.rGeneology[0] = 0;
							 | 
						||
| 
								 | 
							
								    StringCchCopyW(s_Payload.wzStdin, ARRAYSIZE(s_Payload.wzStdin), L"\\\\.\\CONIN$");
							 | 
						||
| 
								 | 
							
								    StringCchCopyW(s_Payload.wzStdout, ARRAYSIZE(s_Payload.wzStdout), L"\\\\.\\CONOUT$");
							 | 
						||
| 
								 | 
							
								    StringCchCopyW(s_Payload.wzStderr, ARRAYSIZE(s_Payload.wzStderr), L"\\\\.\\CONOUT$");
							 | 
						||
| 
								 | 
							
								    StringCchCopyW(s_Payload.wzParents, ARRAYSIZE(s_Payload.wzParents), L"");
							 | 
						||
| 
								 | 
							
								    CopyEnvironment(s_Payload.wzzDrop, wzzDrop);
							 | 
						||
| 
								 | 
							
								    LPWCH pwStrings = GetEnvironmentStringsW();
							 | 
						||
| 
								 | 
							
								    CopyEnvironment(s_Payload.wzzEnvironment, pwStrings);
							 | 
						||
| 
								 | 
							
								    FreeEnvironmentStringsW(pwStrings);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (!DetourCopyPayloadToProcess(pi.hProcess, s_guidTrace,
							 | 
						||
| 
								 | 
							
								                                    &s_Payload, sizeof(s_Payload))) {
							 | 
						||
| 
								 | 
							
								        printf("TRACEBLD: DetourCopyPayloadToProcess failed: %ld\n", GetLastError());
							 | 
						||
| 
								 | 
							
								        ExitProcess(9008);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ResumeThread(pi.hThread);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    WaitForSingleObject(pi.hProcess, INFINITE);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    DWORD dwResult = 0;
							 | 
						||
| 
								 | 
							
								    if (!GetExitCodeProcess(pi.hProcess, &dwResult)) {
							 | 
						||
| 
								 | 
							
								        printf("TRACEBLD: GetExitCodeProcess failed: %ld\n", GetLastError());
							 | 
						||
| 
								 | 
							
								        return 9008;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    printf("TRACEBLD: %ld processes.\n", s_nTotalClients);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return dwResult;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//////////////////////////////////////////////////////////////////////////////
							 |