/// Check the wrappers depending on whether PerfStudio is using DLL replacement or not.
/// If using DLL replacement, PerfStudio's versions of the API dll's (D3D12.dll, dxgi.dll etc)
/// will have been loaded by the OS. The UpdateHooks() method needs to be called on these
/// replaced Dll's to do some initialization that can't be done from DllMain, such as loading
/// in the system dll of the same name and getting the addresses of the real function
/// pointers.
/// If not using dll replacement, CheckWrapperOnLoadLibrary() is called, which loads the
/// appropriate PerfStudio server plugin, based on which system dll's have been loaded (ie
/// if D3D12.dll has been loaded, then load DX12Server.dll and call its UpdateHooks method
static void CheckWrappers()
{
    if (SG_GET_BOOL(OptionDllReplacement) == false)
    {
        CheckWrapperOnLoadLibrary();
    }
    else
    {
        UpdateHooksOnLoadLibrary();
    }
}
// Returns reference to file that is currently being used.
//
const char* GetLogFilename()
{
    if (SG_GET_BOOL(OptionNoLogfile))
    {
        return (NULL);
    }
    else
    {
        return (SG_GET_PATH(LogfilePath));
    }
}
//--------------------------------------------------------------------------
/// Constructor
//--------------------------------------------------------------------------
FrameDebugger::FrameDebugger()
{
    m_dwBreakPoint = 0;
    m_bAutoRenderTarget = true;
    m_ulDrawCallCounter = 0;

    m_bForceClear = true;
    m_ClearColor[0] = 0.0f; // red
    m_ClearColor[1] = 0.4f; // green
    m_ClearColor[2] = 0.8f; // blue
    m_ClearColor[3] = 1.0f; // alpha

    m_iWireframeColor = SG_GET_INT(OptionWireFrameColor);

    m_bWireframeOverlay = SG_GET_BOOL(OptionWireFrameOverlay);

    // 1 = pink/purple, 2 = green, 3 = blue
    if (2 == m_iWireframeColor)
    {
        // green
        m_fWireframeOverlayColor[0] = 0.0f;
        m_fWireframeOverlayColor[1] = 1.0f;
        m_fWireframeOverlayColor[2] = 0.0f;
    }
    else if (3 == m_iWireframeColor)
    {
        // blue
        m_fWireframeOverlayColor[0] = 0.0f;
        m_fWireframeOverlayColor[1] = 0.0f;
        m_fWireframeOverlayColor[2] = 1.0f;
    }
    else
    {
        // 1 or other
        // pink / purple
        m_fWireframeOverlayColor[0] = 1.0f;
        m_fWireframeOverlayColor[1] = 0.0f;
        m_fWireframeOverlayColor[2] = 1.0f;
    }

    m_fWireframeOverlayColor[3] = 1.0f;

    AddCommand(CONTENT_XML, "breakpoint",          "BreakPoint",            CMD_BREAKPOINT,           NO_DISPLAY, INCLUDE, m_dwBreakPoint);
    AddCommand(CONTENT_XML, "autorendertarget",    "Auto Render Target",    CMD_AUTORENDERTARGET,     NO_DISPLAY, INCLUDE, m_bAutoRenderTarget);
    AddCommand(CONTENT_XML, "forceclear",          "Force Clear",           CMD_FORCECLEAR,           NO_DISPLAY, INCLUDE, m_bForceClear);
    AddCommand(CONTENT_XML, "wireframeoverlay",    "WireFrame Overlay",     CMD_WIREFRAMEOVERLAY,     NO_DISPLAY, INCLUDE, m_bWireframeOverlay);
    AddCommand(CONTENT_XML, "stats",               "Stats",                 CMD_STATISTICS,           NO_DISPLAY, INCLUDE, m_Stats);
    AddCommand(CONTENT_XML, "currentdrawcall",     "Current Draw Call",     CMD_CURRENTDRAWCALL,      NO_DISPLAY, INCLUDE, m_CurrentDrawCall);
    AddCommand(CONTENT_XML, "DrawCallList",        "DrawCallList",          "DrawCallList.xml",       NO_DISPLAY, INCLUDE, m_drawCallList);
    AddCommand(CONTENT_XML, "ConfigHUD",           "Config HUD",            CMD_CONFIGHUD,            NO_DISPLAY, INCLUDE, m_bConfigHUD);

    SetLayerName("FrameDebugger");
}
void ProcessTracker::UpdateListOfInjectedProcesses()
{
    this->m_injectedProcessList.clear();

    ProcessInfoList localProcessInfoArray;
#ifdef _WIN32

    // If using DLL replacement, get any process running that has a replaced
    // dll loaded into it
    // just D3D12.dll & OpenGL32.dll at the moment (D3D11 / GLES can be added later if needed)
    if (SG_GET_BOOL(OptionDllReplacement) == true)
    {
        get_process_list("D3D12.dll", localProcessInfoArray);
        get_process_list("OpenGL32.dll", localProcessInfoArray);
    }
    else
    {
        get_process_list(MICRODLLNAME GDT_DEBUG_SUFFIX GDT_BUILD_SUFFIX ".dll", localProcessInfoArray);
        get_process_list(MICRODLLNAME "-x64" GDT_DEBUG_SUFFIX GDT_BUILD_SUFFIX ".dll", localProcessInfoArray);
    }

#else
    get_process_list("GLServer" GDT_PROJECT_SUFFIX ".so", localProcessInfoArray);
    get_process_list("GLESServer" GDT_PROJECT_SUFFIX ".so", localProcessInfoArray);
#endif

    for (ProcessInfoList::const_iterator iter = localProcessInfoArray.begin();
         iter != localProcessInfoArray.end();
         ++iter)
    {

        // find if we've already listed this process (because it has more than 1 plugin attached)
        bool bAlreadyHaveProcess = false;

        for (ProcessInfoList::iterator aProc = this->m_injectedProcessList.begin();
             aProc != this->m_injectedProcessList.end();
             ++aProc)
        {
            if (aProc->th32ProcessID == iter->th32ProcessID)
            {
                bAlreadyHaveProcess = true;
            }
        }

        // only add new processes
        if (bAlreadyHaveProcess == false)
        {
            this->m_injectedProcessList.push_back(*iter);
        }
    }
}
/// Pause application to allow debugger to attach
/// This functionality only happens once - on the first call to LoadLibrary.
static void CheckForDebuggerAttach(void)
{
    static bool alreadyChecked = false;  // only pause application once.
    static const char fmtString[] = "The application has been paused to allow the Visual Studio debugger to be attached to the process.\n\nProcess ID = %d \n\nProcess Name: %s\n\nPress OK to continue";

    if (SG_GET_BOOL(OptionBreak) && !alreadyChecked)         // did we run PerfServer with --break option
    {
        char message[sizeof(fmtString) + 4 + MAX_PATH];    // Add 4 extra bytes for process ID - allows for up to 6 digits of process ID in total

        char modulename[MAX_PATH];
        GetModuleFileNameA(NULL, modulename, MAX_PATH);

        alreadyChecked = true;
        sprintf_s(message, sizeof(message), fmtString, GetCurrentProcessId(), modulename);
        MessageBoxStop(message);
    }
}
Example #6
0
//-----------------------------------------------------------------------------
/// Put up a dialog box to give the user time to attach a debugger to the
/// application rather than the perf studio app.
/// \param serverName the name of the server plugin loaded into the target
/// application
/// \param initialized has the server plugin been initialized
/// \return 0 if successful, non-zero on error
//-----------------------------------------------------------------------------
int ServerUtils::CheckForDebuggerAttach(const char* serverName, bool initialized)
{
    char commandString[1024];
    int retVal = 0;

    static bool alreadyChecked = false;  // only pause application once.
    static const char fmtString[] = "The application has been paused to allow GDB to be attached to the process.\nApplication name: %s\nOpen a terminal and cd to where the %s.so is running from\n(so that gdb can load debug symbols). Use:\n\nsudo gdb attach %d\n\nPress OK to continue";
    char message[sizeof(fmtString) + 10 + PS_MAX_PATH];    // Add extra bytes for process ID

    if (SG_GET_BOOL(OptionBreak) && !alreadyChecked && initialized)         // did we run PerfServer with --break option
    {
        alreadyChecked = true;
        sprintf_s(message, sizeof(message), fmtString, program_invocation_short_name, serverName, osGetCurrentProcessId());
        sprintf(commandString, "xmessage \"%s\" -center -buttons OK", message);
        retVal = system(commandString);
    }

    return retVal;
}
Example #7
0
//--------------------------------------------------------------
/// Is micro dll allowed to be injected into this process?
/// check the current executable with the filelist specified. If
/// it is in the list, or the list contains 'all', then injection
/// is allowed.
/// \param modulename name of the executable being started
/// \returns true if injection is allowed, false otherwise
static bool InjectionAllowed(const char* modulename)
{
    // if not using AppInit_DLLs registry key, always allow injection
    if (SG_GET_BOOL(OptionAppInitDll) == false)
    {
        return true;
    }

    // get the filename from the path. If there's an error here, don't inject
    char path[PS_MAX_PATH];
    char* filename;
    DWORD res = GetFullPathName(modulename, PS_MAX_PATH, path, &filename);

    if (res == 0)
    {
        return false;
    }

    gtASCIIString fileString = SG_GET_PATH(AppInitDllFileList);

    // if 'all' specified, always inject
    if (fileString.compareNoCase("all") == 0)
    {
        return true;
    }

    // split the list up and see if the current exe is in the list
    std::list<gtASCIIString> fileList;
    fileString.Split(",", false, fileList);

    for (std::list<gtASCIIString>::const_iterator it = fileList.begin(); it != fileList.end(); ++it)
    {
        if ((*it).compareNoCase(filename) == 0)
        {
            // file is in list, inject
            return true;
        }
    }

    return false;
}
//--------------------------------------------------------------
//  LaunchAppInNewProcess
//--------------------------------------------------------------
PROCESS_INFORMATION ProcessTracker::LaunchAppInNewProcess(gtASCIIString strApp, gtASCIIString strDir, gtASCIIString strArgs, osModuleArchitecture binaryType)
{
#ifdef _LINUX
    PS_UNREFERENCED_PARAMETER(binaryType);
#endif
    LogConsole(logMESSAGE, "About to launch: %s\n", strApp.asCharArray());
    LogConsole(logMESSAGE, "Params: %s\n", strArgs.asCharArray());
    LogConsole(logMESSAGE, "Working Directory: %s\n", strDir.asCharArray());

    // Get app directory and make it default
    if (strDir.isEmpty())
    {
        size_t pos = strApp.find_last_of("\\");

        if (pos != std::string::npos)
        {
            strDir = strApp.substr(0, (int)pos);

            if (strApp[0] == '\"')
            {
                strDir += "\"";
            }
        }
    }

    PROCESS_INFORMATION pi;
    ZeroMemory(&pi, sizeof(pi));

#ifdef _WIN32
    DWORD dwFlags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED;

    SetLastError(0);

    STARTUPINFO si;
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
#endif

    // Cmd line has to include the exe name since many apps expect the executable name to be in argv[0]!
    // Note argv[0] on the command line needs to be surrounded with quotes if it contains spaces.
    // The arguments in strArgs have already been "quoted" as they are parsed.

    gtASCIIString strCmdLine = AddQuotesIfStringHasSpaces(strApp.asCharArray());
    strCmdLine += " ";
    strCmdLine += strArgs;

    LogConsole(logMESSAGE, "strApp: %s\n", strApp.asCharArray());
    LogConsole(logMESSAGE, "strCmdLine: %s\n", strCmdLine.asCharArray());

    // Attempt to initialize the environment that the new process will run in. The child process should inherit "this" environment.
    if (!PrelaunchEnvironmentInitialization())
    {
        // Log a warning if this failed- initializing the environment for the new process can fail if Mantle support isn't installed.
        // In these cases, if the user is attempting to debug a Mantle application, they will have bigger problems to deal with.
        // In cases where a DX/GL app is being debugged, this warning can be ignored without any side effects.
        Log(logWARNING, "Environment initialization failed. If using DX/GL, it is safe to ignore this warning.\n");
    }

    BOOL succeeded = FALSE;

#ifdef _WIN32

    char microDLLPath[PS_MAX_PATH];
    const char* strServerPath;
    strServerPath = SG_GET_PATH(ServerPath);

    if (SG_GET_BOOL(OptionDllReplacement) == true)
    {
        DllReplacement::SetDllDirectory(binaryType == OS_X86_64_ARCHITECTURE);
    }

    // if using manual dll replacement or the AppInit_DLLs registry setting, don't use any kind of dll injection
    if (SG_GET_BOOL(OptionManualDllReplacement) == true || SG_GET_BOOL(OptionAppInitDll))
    {
        succeeded = CreateProcess(strApp.asCharArray(), (LPSTR)strCmdLine.asCharArray(), NULL, NULL, TRUE, dwFlags, NULL, strDir.asCharArray(), &si, &pi);
    }
    else
    {
#ifdef X64

        // can only launch 64 bit applications
        if (binaryType != OS_X86_64_ARCHITECTURE)
        {
            sprintf_s(microDLLPath, PS_MAX_PATH, "%s" MICRODLLNAME "%s%s.dll", SG_GET_PATH(ServerPath), GDT_DEBUG_SUFFIX, GDT_BUILD_SUFFIX);
            succeeded = AMDT::CreateProcessAndInjectDll(strApp.asCharArray(), (LPSTR)strCmdLine.asCharArray(),
                                                        NULL, NULL, TRUE, dwFlags, NULL,
                                                        strDir.asCharArray(),
                                                        &si, &pi,
                                                        microDLLPath);
        }

#else

        if (binaryType != OS_I386_ARCHITECTURE)
        {
            sprintf_s(microDLLPath, PS_MAX_PATH, "%s" MICRODLLNAME "-x64%s%s.dll", SG_GET_PATH(ServerPath), GDT_DEBUG_SUFFIX, GDT_BUILD_SUFFIX);
            succeeded = AMDT::CreateProcessAndInjectDll(strApp.asCharArray(), (LPSTR)strCmdLine.asCharArray(),
                                                        NULL, NULL, TRUE, dwFlags, NULL,
                                                        strDir.asCharArray(),
                                                        &si, &pi,
                                                        microDLLPath);
        }

#endif // X64
        else
        {
            succeeded = AMDT::CreateProcessAndInjectDll(strApp.asCharArray(), (LPSTR)strCmdLine.asCharArray(),
                                                        NULL, NULL, TRUE, dwFlags, NULL,
                                                        strDir.asCharArray(),
                                                        &si, &pi,
                                                        SG_GET_PATH(MicroDLLPath));
        }
    }

#else

    // Create the app process
    succeeded = CreateProcess(strApp.asCharArray(), strCmdLine.asCharArray(), strDir.asCharArray(), &pi);
#endif // _WIN32

    if (!succeeded)
    {
        osSystemErrorCode systemLastError = osGetLastSystemError();

        gtString systemErrorString;
        osGetLastSystemErrorAsString(systemErrorString);

        Log(logERROR, "CreateProcessAndInjectDll failed; Error %d: %s\n", systemLastError, systemErrorString.asASCIICharArray());
        pi.dwProcessId = 0;
    }

#ifdef _WIN32
    else
    {
        // Check to see if the Steam.exe has been hooked and if so, set the value in shared memory
        // If Steam.exe was used to launch the target application, then the checks for cmd.exe and fcx.exe
        // need to be ignored.
        if (strApp.length() > 0)
        {
            if (strstr(strApp.toLowerCase().asCharArray(), "steam.exe") != NULL)
            {
                SG_SET_BOOL(SteamInjected, true);
            }

            ShowLauncherReminder(strApp.toLowerCase().asCharArray());
        }
        else
        {
            if (strstr(strCmdLine.toLowerCase().asCharArray(), "steam.exe") != NULL)
            {
                SG_SET_BOOL(SteamInjected, true);
            }

            ShowLauncherReminder(strCmdLine.toLowerCase().asCharArray());
        }
    }

#endif // _WIN32

    return pi;
}
//--------------------------------------------------------------
/// Generates XML that describes the injected processes and which
/// plugins were injected.
/// \return string containing the XML
//--------------------------------------------------------------
gtASCIIString ProcessTracker::GetProcessesXML()
{
    std::unordered_map< DWORD, gtASCIIString > procXMLMap;

    this->UpdateListOfInjectedProcesses();

    ProcessInfoList injectedProcesses = this->GetListOfInjectedProcesses();

    WrapperMap wrappers = GetWrapperMap();

    // the strPlatform is named this way to match options in the client.
#ifdef X64
    gtASCIIString strPlatform = "Win64";
#else
    gtASCIIString strPlatform = "Win32";
#endif

#ifndef CODEXL_GRAPHICS

    if (injectedProcesses.empty() == true)
    {
        LogConsole(logERROR, "There are no processes running which have been injected with the GPU PerfStudio server plugin\n");
        LogConsole(logERROR, "Please ensure that the server has the same bitness as the target application\n");
        LogConsole(logERROR, "For example, use the 64-bit GPU PerfStudio server with a 64-bit application\n");
    }

#endif

    for (ProcessInfoList::iterator procIter = injectedProcesses.begin();
         procIter != injectedProcesses.end();
         ++procIter)
    {

        DWORD pid = procIter->th32ProcessID;

        // only add the process info if it wasn't already found.
        if (procXMLMap.find(pid) == procXMLMap.end())
        {
            // insert new process and the process info
            gtASCIIString tmpString = XML("Name", XMLEscape(procIter->szExeFile).asCharArray());
            tmpString += XML("PID", pid);
            tmpString += XML("Path", XMLEscape(procIter->szPath).asCharArray());
            tmpString += XML("Platform",  strPlatform.asCharArray());
            procXMLMap[ pid ] = tmpString;

            // if this process is the one that was launched, then we know what the args and working directory were.
            // we could probably get the actual args and working dir from MicroDLL if it is a different app though, which
            // would be the case if this app uses a launcher app.
            if (m_injectedAppName.compare(procIter->szPath) == 0)
            {
                tmpString = XML("Args", XMLEscape(m_injectedAppArgs.c_str()).asCharArray());
                tmpString += XML("WDir", XMLEscape(m_injectedAppDir.c_str()).asCharArray());
                procXMLMap[ pid ] += tmpString.asCharArray();
            }
        }

        // add an API node for each of the wrappers that are injected into the app
        for (WrapperMap::const_iterator wrapperIter = wrappers.begin(); wrapperIter != wrappers.end(); ++wrapperIter)
        {
            // List of plugin extensions to check for. On Windows, test for 32 and 64 bit plugins.
            // On linux, just check for the plugin corresponding to the server bitness
            static const char* pluginExtensions[] =
            {
#ifdef WIN32
                GDT_DEBUG_SUFFIX GDT_BUILD_SUFFIX "." DLL_EXTENSION,
                "-x64" GDT_DEBUG_SUFFIX GDT_BUILD_SUFFIX "." DLL_EXTENSION
#else
                GDT_PROJECT_SUFFIX "." DLL_EXTENSION
#endif
            };

            int numPlugins = sizeof(pluginExtensions) / sizeof(pluginExtensions[0]);

            for (int loop = 0; loop < numPlugins; loop++)
            {
                // check to see if this wrapper is in the application
                gtASCIIString strPluginName = wrapperIter->second.strPluginName;

                if (SG_GET_BOOL(OptionDllReplacement) == false)
                {
                    strPluginName += pluginExtensions[loop];
                }

                if (IsLibraryLoadedInProcess(pid, strPluginName.asCharArray(), NULL))
                {
                    bool attached = false;

                    if (g_activeWrappersMap.find(FormatText("%lu/%s", pid, wrapperIter->first.c_str()).asCharArray()) != g_activeWrappersMap.end())
                    {
                        // the pid/plugin string was listed in the active wrappers map, so the plugin must be active.
                        attached = true;
                    }

                    procXMLMap[pid] += XMLAttrib("API", FormatText("attached='%s'", attached ? "TRUE" : "FALSE").asCharArray(), wrapperIter->second.strPluginShortDesc.asCharArray());
                }
            }
        }
    }

    // concatenate the process XML and additional info
    gtASCIIString xml;

    for (std::unordered_map< DWORD, gtASCIIString >::iterator iterP = procXMLMap.begin();
         iterP != procXMLMap.end();
         iterP++)
    {
        xml += XML("Process", (iterP->second).asCharArray());
    }

    gtASCIIString out = XMLHeader();
    out += XML("ProcessList", xml.asCharArray());

    return out;
}
bool ProcessTracker::HandleRequest(HTTPRequestHeader* pRequestHeader,
                                   CommunicationID requestID,
                                   NetSocket* pClientSocket,
                                   bool renderLoopStalled)
{
    char* ptr = pRequestHeader->GetUrl();
    char* sCmd = &ptr[1];

#ifdef CODEXL_GRAPHICS
#ifdef USE_GRAPHICS_SERVER_STATUS_RETURN_CODES

    // Handle process not running condition
    if (pRequestHeader->CheckProcessStillRunning() == false)
    {
        Log(logMESSAGE, "Rejecting the command above due to process no longer running: %s\n", pRequestHeader->GetUrl());
        // Need to return the correct error data for process not running
        HandleServerStatusResponse(GRAPHICS_SERVER_STATE_PROCESS_NOT_RUNNING, pRequestHeader, pClientSocket);
        // This request never gets passed to the graphics server.
        return true;
    }

    // Check if renering has stalled.
    if (renderLoopStalled == true)
    {
        Log(logMESSAGE, "Rejecting the command above due to render stall: %s\n", pRequestHeader->GetUrl());
        // Need to return the correct error data for process not running
        HandleServerStatusResponse(GRAPHICS_SERVER_STATE_STALLED, pRequestHeader, pClientSocket);
        // This request never gets passed to the graphics server.
        return true;
    }

#else
    UNREFERENCED_PARAMETER(renderLoopStalled);
#endif
#else
    PS_UNREFERENCED_PARAMETER(renderLoopStalled);
#endif


#ifdef _WIN32

    // if using AppInit_Dll, clear the registry as soon as a process.xml request is sent.
    // TODO: move this to where a connection has definately been made
    if (SG_GET_BOOL(OptionAppInitDll) == true)
    {
        if (registryCleared == false)
        {
            RestoreAppInit();
            registryCleared = true;
        }
    }

#endif

    if (IsToken(&sCmd, "inject?"))
    {
        DoInjectCommand(requestID, &sCmd, pClientSocket);
    }
    else
    {
        // do commands that depend on PID

        for (WrapperMap::iterator wrapperIter = g_activeWrappersMap.begin();
             wrapperIter != g_activeWrappersMap.end();
             ++wrapperIter)
        {
            // parse out the process ID
            unsigned long pid = 0;
            sscanf_s(wrapperIter->first.c_str(), "%lu/", &pid);

            // make PID string for easier parsing of the command
            gtASCIIString strPID;
            strPID.appendFormattedString("%lu", pid);

            gtASCIIString strPidSlashPlugin = wrapperIter->first.c_str();

            // the key in the activeWrappersMap is formatted as pid/plugin (ie: "435/DX11")
            // and this conveniently matches the format of the commands coming into the server, so parse for matching commands
            gtASCIIString tmpString = strPidSlashPlugin;
            tmpString += "/";

            if (IsToken(&sCmd, tmpString.asCharArray()))
            {
                // we know this command is targetting the current plugin
                pRequestHeader->SetUrl(sCmd);

                // pass the request to the plugin
#ifdef _WIN32
                const char* memoryName = strPidSlashPlugin.asCharArray();
#else
                // the '/' character can't be used as a filename in Linux, so just use the plugin name as the shared memory name
                // (ignore the process ID)
                char memoryName[PS_MAX_PATH];
                char pluginShortDesc[ PS_MAX_PATH ];
                sscanf_s(strPidSlashPlugin.asCharArray(), "%lu/%s", &pid, pluginShortDesc, sizeof(pluginShortDesc));
                sprintf_s(memoryName, PS_MAX_PATH, "%lu %s", pid, pluginShortDesc);
#endif

                if (PassRequestToPlugin(memoryName, pRequestHeader, pid, pClientSocket))
                {
                    return true;
                }
                else
                {
                    Log(logERROR, "Request '%s' is not targeted to an active plugin.\n", GetRequestText(requestID));
                    SendHTMLResponse(requestID, "<html>Error: Targeted plugin is not currently active.</html>", pClientSocket);
                }
            }
            else
            {
                tmpString = strPID;
                tmpString += "/Kill";

                if (IsToken(&sCmd, tmpString.asCharArray()))
                {
                    if (KillProcess(pid))
                    {
                        SendTextResponse(requestID, "Ok", pClientSocket);

                        // if the app was launched from the command line or drag and drop
                        // then killing the app should cause the server to shutdown also
                        if (g_bAppSpecifiedAtCmdLine)
                        {
                            g_shutdownEvent.Signal();
                            CloseStreamThread();
                            CloseStreamSockets();
                            SendTextResponse(requestID, "OK", pClientSocket);
                            return true;
                        }
                    }
                    else
                    {
                        Log(logERROR, "Failed to Kill the process\n");
                        SendTextResponse(requestID, "Error: Failed to Kill the process.", pClientSocket);
                    }
                }
            }
        }
    }

    return false;
}
Example #11
0
/////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Checks to see if the app has stopped rendering (or ever rendered at all).
/// The result is stored in g_bRenderLoopStalled and it is used when incoming messages are processed.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
void RenderStallThread::CheckForRenderStall()
{
    static double lastPresentTime = 0.0f;
    int delay = 0;
    int outerDelay = 0;

    NamedEvent shutdownEvent;
    bool opened = shutdownEvent.Open("GPS_SHUTDOWN_SERVER");

    while (opened && false == shutdownEvent.IsSignaled())
    {
        if (GetServerShutdownState() == true)
        {
            return;
        }

        // Get the last value that the server wrote into the slot. It may never have written to the slot.
        double checkTime = SG_GET_DOUBLE(LastPresentTime);
        bool bForceStall = SG_GET_BOOL(ForceRenderStallState);

        // Until the server actually renders lastPresentTime will always be 0
        if (lastPresentTime == 0.0f)
        {
            lastPresentTime = checkTime;
        }

        // Get the diff between renders
        double diffTime = checkTime - lastPresentTime;

        // record the last time so that our diffs are correct next time around
        lastPresentTime = checkTime;

        if (bForceStall == true)
        {
            SetServerStalledState(true);
            Log(logMESSAGE, "Keypress capture is blocking client commands.\n");
        }
        else
        {
            // If there is no diff then there was no rendering so we have stalled.
            if (diffTime == 0.0f)
            {
                // The server has stopped rendering or has never rendered
                if (delay > GRAPHICS_SERVER_STATUS_STALL_THRESHOLD_TIME)
                {
                    SetServerStalledState(true);

#ifdef CODEXL_GRAPHICS
#ifdef USE_GRAPHICS_SERVER_STATUS_RETURN_CODES
                    int inFlight = RequestsInFlightDatabase::Instance()->InFlightCount();

                    Log(logMESSAGE, "RenderStallThread::CheckForRenderStall(): App has not rendered for %ld (ms), inFlightCount = %d\n", outerDelay, inFlight);

                    if (inFlight > 0)
                    {
                        // Send stalled status back to the messages in flight
                        Log(logMESSAGE, "RenderStallThread::CheckForRenderStall(): Check messages in flight to see if process is still running\n");
                        RequestsInFlightDatabase::Instance()->CheckProcessesAreRunning();
                    }
#endif
#endif

                    delay = 0;
                }

                delay += GRAPHICS_SERVER_STATUS_STALL_LOOP_SLEEP_TIME;

                outerDelay += GRAPHICS_SERVER_STATUS_STALL_LOOP_SLEEP_TIME;
            }
            else
            {
                SetServerStalledState(false);
                delay = 0;
                outerDelay = 0;
            }
        }

        // Wait a reasonable time. 10ms is too short as it is below a games 16ms typical update and will lead to diffs of zero (a stall condition).
        osSleep(GRAPHICS_SERVER_STATUS_STALL_LOOP_SLEEP_TIME);
    }

    shutdownEvent.Close();
}
Example #12
0
//--------------------------------------------------------------
///   DllMain
/// \param hModule Module
/// \param ul_reason_for_call Reason for call
/// \param lpReserved Reserved
/// \return True or false
//--------------------------------------------------------------
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    PS_UNREFERENCED_PARAMETER(hModule);
    PS_UNREFERENCED_PARAMETER(lpReserved);

    if (AMDT::InitHookDLL(ul_reason_for_call) == false)
    {
        return TRUE;
    }

    BOOL retVal = TRUE;
    char modulename[MAX_PATH];
    GetModuleFileNameA(NULL, modulename, MAX_PATH);

    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
        {
            if (OSWrappers::IsProcessRunning(sWebServerName, true) && InjectionAllowed(modulename))
            {
                Log(logMESSAGE, "Attaching to %s\n", modulename);
                Log(logMESSAGE, "DllMain DLL_PROCESS_ATTACH module %s\n", modulename);

                if (SG_GET_BOOL(OptionDllReplacement) == true)
                {
                    UpdateHooksOnLoadLibrary();
                }

#ifdef _WIN32
                {
                    // Initialize and register the unhandled exception handler:
                    bool rc1 = UnhandledExceptionHandler::init();

                    if (rc1)
                    {
                        Log(logMESSAGE, "Registered unhandled exception handler\n");
                    }
                    else
                    {
                        Log(logERROR, "Failed to register unhandled exception handler\n");
                    }
                }
#endif

                // @Note: Do we need to do this? Overwriting it doesn't seem to break anything?
                // get current directory so we can specify as a location for DLLs to be loaded from
                char curDir[PS_MAX_PATH];
                GetCurrentDirectory(PS_MAX_PATH, curDir);

                // SetDllDirectory requires XP SP1 or later.
                SetDllDirectory(curDir);

                sprintf_s(g_MicroDLLPath, PS_MAX_PATH, "%s", SG_GET_PATH(MicroDLLPath));

                CollectWrapperInfo();

                if (SG_GET_BOOL(OptionNoProcessTrack) == false)
                {
                    HookCreateProcess();
                    Log(logMESSAGE, "Process Tracking is ON\n");
                }
                else
                {
                    Log(logMESSAGE, "Process Tracking is OFF\n");
                }

                // At the moment, dxgi.dll is implicitly loaded from HookLoadLibrary
                // Force the Dll folder to point to our replaced dll's so the replace version
                // of dxgi.dll is loaded
                if (SG_GET_BOOL(OptionDllReplacement) == true)
                {
                    // Get architecture of parent application (32 or 64 bit)
                    osModuleArchitecture binaryType;
                    OSWrappers::GetBinaryType(modulename, &binaryType);
                    DllReplacement::SetDllDirectory(binaryType == OS_X86_64_ARCHITECTURE);
                }

                if (SG_GET_BOOL(OptionManualDllReplacement) == false)
                {
                    HookLoadLibrary();
                }
            }
            else
            {
                // set return value to FALSE. This will indicate a load error so the loader will
                // next unload this dll
                retVal = FALSE;
            }

            break;
        }

        case DLL_THREAD_ATTACH:
        {
            Log(logMESSAGE, "DllMain DLL_THREAD_ATTACH to %i %s\n", GetCurrentProcessId(), modulename);
        }
        break;

        case DLL_THREAD_DETACH:
        {
            Log(logMESSAGE, "DllMain DLL_THREAD_DETACH to %i %s\n", GetCurrentProcessId(), modulename);
        }
        break;

        case DLL_PROCESS_DETACH:
        {
            if (OSWrappers::IsProcessRunning(sWebServerName, true))
            {
                Log(logMESSAGE, "DllMain DLL_PROCESS_DETACH from module %s\n", modulename);

                if (SG_GET_BOOL(OptionNoProcessTrack) == false)
                {
                    UnhookCreateProcess();
                }

                UnhookLoadLibrary();
            }
        }
        break;

        default:
        {
            Log(logMESSAGE, "DllMain Unhandled switch case module %s\n", modulename);
        }
        break;
    }

    return retVal;
}