From 13c1cf6ad44777b201dbbb21006bd7229207ab50 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 20 Feb 2018 11:54:57 +0000 Subject: [PATCH] Return ReplayStatus when launching/injecting, use to indicate JDWP error * If android studio or other android tools are open when a package is launched for debugging, they greedily jump on it and connect which prevents us from connecting. --- qrenderdoc/Code/Interface/QRDInterface.h | 15 +++--- qrenderdoc/Code/ReplayManager.cpp | 10 ++-- qrenderdoc/Code/ReplayManager.h | 6 +-- qrenderdoc/Windows/MainWindow.cpp | 58 +++++++++++++++++------ renderdoc/android/android.cpp | 18 ++++++-- renderdoc/android/android.h | 4 +- renderdoc/api/replay/renderdoc_replay.h | 59 +++++++++++++++--------- renderdoc/api/replay/renderdoc_tostr.inl | 1 + renderdoc/api/replay/replay_enums.h | 1 + renderdoc/core/remote_server.cpp | 21 +++++---- renderdoc/os/os_specific.h | 11 +++-- renderdoc/os/posix/posix_process.cpp | 21 +++++---- renderdoc/os/win32/sys_win32_hooks.cpp | 9 ++-- renderdoc/os/win32/win32_process.cpp | 42 +++++++++-------- renderdoc/replay/entry_points.cpp | 4 +- renderdoc/replay/renderdoc_serialise.inl | 10 ++++ renderdoccmd/renderdoccmd.cpp | 39 ++++++++-------- 17 files changed, 206 insertions(+), 123 deletions(-) diff --git a/qrenderdoc/Code/Interface/QRDInterface.h b/qrenderdoc/Code/Interface/QRDInterface.h index f1f704e80..e0d769a38 100644 --- a/qrenderdoc/Code/Interface/QRDInterface.h +++ b/qrenderdoc/Code/Interface/QRDInterface.h @@ -714,14 +714,15 @@ This happens either locally, or on the remote server, depending on whether a con the program. :param str capturefile: The location to save any captures, if running locally. :param CaptureOptions opts: The capture options to use when injecting into the program. -:return: The ident where the new application is listening for target control, or 0 if something went - wrong. -:rtype: ``int`` +:return: The :class:`ExecuteResult` indicating both the status of the operation (success or failure) + and any reason for failure, or else the ident where the new application is listening for target + control if everything succeeded. +:rtype: ExecuteResult )"); - virtual uint32_t ExecuteAndInject(const rdcstr &exe, const rdcstr &workingDir, - const rdcstr &cmdLine, - const rdcarray &env, - const rdcstr &capturefile, CaptureOptions opts) = 0; + virtual ExecuteResult ExecuteAndInject(const rdcstr &exe, const rdcstr &workingDir, + const rdcstr &cmdLine, + const rdcarray &env, + const rdcstr &capturefile, CaptureOptions opts) = 0; DOCUMENT(R"(Retrieve a list of drivers that the current remote server supports. diff --git a/qrenderdoc/Code/ReplayManager.cpp b/qrenderdoc/Code/ReplayManager.cpp index 604751870..02ce5da69 100644 --- a/qrenderdoc/Code/ReplayManager.cpp +++ b/qrenderdoc/Code/ReplayManager.cpp @@ -372,12 +372,12 @@ void ReplayManager::ReopenCaptureFile(const QString &path) m_CaptureFile->OpenFile(path.toUtf8().data(), "rdc", NULL); } -uint32_t ReplayManager::ExecuteAndInject(const rdcstr &exe, const rdcstr &workingDir, - const rdcstr &cmdLine, - const rdcarray &env, - const rdcstr &capturefile, CaptureOptions opts) +ExecuteResult ReplayManager::ExecuteAndInject(const rdcstr &exe, const rdcstr &workingDir, + const rdcstr &cmdLine, + const rdcarray &env, + const rdcstr &capturefile, CaptureOptions opts) { - uint32_t ret = 0; + ExecuteResult ret; if(m_Remote) { diff --git a/qrenderdoc/Code/ReplayManager.h b/qrenderdoc/Code/ReplayManager.h index 9360878d0..c8cb10d3f 100644 --- a/qrenderdoc/Code/ReplayManager.h +++ b/qrenderdoc/Code/ReplayManager.h @@ -85,9 +85,9 @@ public: ICaptureFile *GetCaptureFile() { return m_CaptureFile; } void ReopenCaptureFile(const QString &path); const RemoteHost *CurrentRemote() { return m_RemoteHost; } - uint32_t ExecuteAndInject(const rdcstr &exe, const rdcstr &workingDir, const rdcstr &cmdLine, - const rdcarray &env, const rdcstr &capturefile, - CaptureOptions opts); + ExecuteResult ExecuteAndInject(const rdcstr &exe, const rdcstr &workingDir, const rdcstr &cmdLine, + const rdcarray &env, + const rdcstr &capturefile, CaptureOptions opts); rdcarray GetRemoteSupport(); void GetHomeFolder(bool synchronous, DirectoryBrowseCallback cb); diff --git a/qrenderdoc/Windows/MainWindow.cpp b/qrenderdoc/Windows/MainWindow.cpp index 2e1408335..799e78239 100644 --- a/qrenderdoc/Windows/MainWindow.cpp +++ b/qrenderdoc/Windows/MainWindow.cpp @@ -504,22 +504,38 @@ void MainWindow::OnCaptureTrigger(const QString &exe, const QString &workingDir, LambdaThread *th = new LambdaThread([this, exe, workingDir, cmdLine, env, opts, callback]() { QString capturefile = m_Ctx.TempCaptureFilename(QFileInfo(exe).baseName()); - uint32_t ret = m_Ctx.Replay().ExecuteAndInject(exe, workingDir, cmdLine, env, capturefile, opts); + ExecuteResult ret = + m_Ctx.Replay().ExecuteAndInject(exe, workingDir, cmdLine, env, capturefile, opts); GUIInvoke::call([this, exe, ret, callback]() { - if(ret == 0) + + if(ret.status == ReplayStatus::JDWPFailure) + { + RDDialog::critical( + this, tr("Error connecting to debugger"), + tr("Error launching %1 for capture.\n\n" + "Something went wrong connecting to the debugger on the Android device.\n\n" + "This can happen if the package is not " + "marked as debuggable, or if another android tool such as android studio " + "or other tool is interfering with the debug connection.") + .arg(exe)); + return; + } + + if(ret.status != ReplayStatus::Succeeded) { RDDialog::critical(this, tr("Error kicking capture"), - tr("Error launching %1 for capture.\n\nCheck diagnostic log in Help " - "menu for more details.") - .arg(exe)); + tr("Error launching %1 for capture.\n\n%2. Check the diagnostic log in " + "the help menu for more details") + .arg(exe) + .arg(ToQStr(ret.status))); return; } LiveCapture *live = new LiveCapture( m_Ctx, m_Ctx.Replay().CurrentRemote() ? m_Ctx.Replay().CurrentRemote()->hostname : "", - m_Ctx.Replay().CurrentRemote() ? m_Ctx.Replay().CurrentRemote()->Name() : "", ret, this, - this); + m_Ctx.Replay().CurrentRemote() ? m_Ctx.Replay().CurrentRemote()->Name() : "", ret.ident, + this, this); ShowLiveCapture(live); callback(live); }); @@ -546,20 +562,36 @@ void MainWindow::OnInjectTrigger(uint32_t PID, const rdcarrayShutdown(); + ret.status = ReplayStatus::Succeeded; break; } diff --git a/renderdoc/android/android.h b/renderdoc/android/android.h index 46909afd9..69b31d8c1 100644 --- a/renderdoc/android/android.h +++ b/renderdoc/android/android.h @@ -31,8 +31,8 @@ namespace Android { bool IsHostADB(const char *hostname); -uint32_t StartAndroidPackageForCapture(const char *host, const char *package, - const CaptureOptions &opts); +ExecuteResult StartAndroidPackageForCapture(const char *host, const char *package, + const CaptureOptions &opts); void ResetCaptureSettings(const std::string &deviceID); void ExtractDeviceIDAndIndex(const std::string &hostname, int &index, std::string &deviceID); Process::ProcessResult adbExecCommand(const std::string &deviceID, const std::string &args, diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index 959a33921..4d1e04e2e 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -463,13 +463,6 @@ inline const WindowingData CreateAndroidWindowingData(ANativeWindow *window) return ret; } -DOCUMENT(R"(Internal structure used for initialising environment in a replay application.)"); -struct GlobalEnvironment -{ - DOCUMENT("The handle to the X display to use internally. If left ``NULL``, one will be opened."); - Display *xlibDisplay = NULL; -}; - // declare metatype/reflection for ResourceId here as the struct itself is declared before including // all relevant headers above #if defined(RENDERDOC_QT_COMPAT) @@ -488,6 +481,27 @@ DECLARE_REFLECTION_STRUCT(ResourceId); #include "shader_types.h" #include "vk_pipestate.h" +DOCUMENT(R"(Internal structure used for initialising environment in a replay application.)"); +struct GlobalEnvironment +{ + DOCUMENT("The handle to the X display to use internally. If left ``NULL``, one will be opened."); + Display *xlibDisplay = NULL; +}; + +DOCUMENT("The result of executing or injecting into a program.") +struct ExecuteResult +{ + DOCUMENT( + "The :class:`ReplayStatus` resulting from the operation, indicating success or failure."); + ReplayStatus status; + DOCUMENT(R"(The ident where the new application is listening for target control, or 0 if something +went wrong. +)"); + uint32_t ident; +}; + +DECLARE_REFLECTION_STRUCT(ExecuteResult); + // there's not a good way to document a callback, so for lack of a better place we declare these // here and document them immediately below. They can be linked to from anywhere by name. typedef std::function RENDERDOC_KillCallback; @@ -1384,13 +1398,14 @@ This happens on the remote system, so all paths are relative to the remote files platform specific way to generate arguments. :param list env: Any :class:`EnvironmentModification` that should be made when running the program. :param CaptureOptions opts: The capture options to use when injecting into the program. -:return: The ident where the new application is listening for target control, or 0 if something went - wrong. -:rtype: ``int`` +:return: The :class:`ExecuteResult` indicating both the status of the operation (success or failure) + and any reason for failure, or else the ident where the new application is listening for target + control if everything succeeded. +:rtype: ExecuteResult )"); - virtual uint32_t ExecuteAndInject(const char *app, const char *workingDir, const char *cmdLine, - const rdcarray &env, - const CaptureOptions &opts) = 0; + virtual ExecuteResult ExecuteAndInject(const char *app, const char *workingDir, const char *cmdLine, + const rdcarray &env, + const CaptureOptions &opts) = 0; DOCUMENT(R"(Take ownership over a capture file. @@ -1965,11 +1980,12 @@ DOCUMENT(R"(Launch an application and inject into it to allow capturing. :param list env: Any :class:`EnvironmentModification` that should be made when running the program. :param CaptureOptions opts: The capture options to use when injecting into the program. :param bool waitForExit: If ``True`` this function will block until the process exits. -:return: The ident where the new application is listening for target control, or 0 if something went - wrong. -:rtype: ``int`` +:return: The :class:`ExecuteResult` indicating both the status of the operation (success or failure) + and any reason for failure, or else the ident where the new application is listening for target + control if everything succeeded. +:rtype: ExecuteResult )"); -extern "C" RENDERDOC_API uint32_t RENDERDOC_CC +extern "C" RENDERDOC_API ExecuteResult RENDERDOC_CC RENDERDOC_ExecuteAndInject(const char *app, const char *workingDir, const char *cmdLine, const rdcarray &env, const char *logfile, const CaptureOptions &opts, bool waitForExit); @@ -1980,11 +1996,12 @@ DOCUMENT(R"(Where supported by operating system and permissions, inject into a r :param list env: Any :class:`EnvironmentModification` that should be made when running the program. :param CaptureOptions opts: The capture options to use when injecting into the program. :param bool waitForExit: If ``True`` this function will block until the process exits. -:return: The ident where the new application is listening for target control, or 0 if something went - wrong. -:rtype: ``int`` +:return: The :class:`ExecuteResult` indicating both the status of the operation (success or failure) + and any reason for failure, or else the ident where the new application is listening for target + control if everything succeeded. +:rtype: ExecuteResult )"); -extern "C" RENDERDOC_API uint32_t RENDERDOC_CC +extern "C" RENDERDOC_API ExecuteResult RENDERDOC_CC RENDERDOC_InjectIntoProcess(uint32_t pid, const rdcarray &env, const char *logfile, const CaptureOptions &opts, bool waitForExit); diff --git a/renderdoc/api/replay/renderdoc_tostr.inl b/renderdoc/api/replay/renderdoc_tostr.inl index ade5df5e5..0e02a287f 100644 --- a/renderdoc/api/replay/renderdoc_tostr.inl +++ b/renderdoc/api/replay/renderdoc_tostr.inl @@ -49,6 +49,7 @@ std::string DoStringise(const ReplayStatus &el) STRINGISE_ENUM_CLASS_NAMED(APIDataCorrupted, "Replaying the capture encountered invalid/corrupted data"); STRINGISE_ENUM_CLASS_NAMED(APIReplayFailed, "Replaying the capture failed at the API level"); + STRINGISE_ENUM_CLASS_NAMED(JDWPFailure, "JDWP debugger connection could not be established"); } END_ENUM_STRINGISE(); } diff --git a/renderdoc/api/replay/replay_enums.h b/renderdoc/api/replay/replay_enums.h index 248365c1f..78a32f954 100644 --- a/renderdoc/api/replay/replay_enums.h +++ b/renderdoc/api/replay/replay_enums.h @@ -2899,6 +2899,7 @@ enum class ReplayStatus : uint32_t APIHardwareUnsupported, APIDataCorrupted, APIReplayFailed, + JDWPFailure, }; DECLARE_REFLECTION_ENUM(ReplayStatus); diff --git a/renderdoc/core/remote_server.cpp b/renderdoc/core/remote_server.cpp index a46f5522d..eff52338d 100644 --- a/renderdoc/core/remote_server.cpp +++ b/renderdoc/core/remote_server.cpp @@ -747,12 +747,12 @@ static void ActiveRemoteClientThread(ClientThread *threadData, reader.EndChunk(); - uint32_t ident = 0; + ExecuteResult ret = {}; if(threadData->allowExecution) { - ident = Process::LaunchAndInjectIntoProcess(app.c_str(), workingDir.c_str(), - cmdLine.c_str(), env, "", opts, false); + ret = Process::LaunchAndInjectIntoProcess(app.c_str(), workingDir.c_str(), cmdLine.c_str(), + env, "", opts, false); } else { @@ -762,7 +762,7 @@ static void ActiveRemoteClientThread(ClientThread *threadData, { WRITE_DATA_SCOPE(); SCOPED_SERIALISE_CHUNK(eRemoteServer_ExecuteAndInject); - SERIALISE_ELEMENT(ident); + SERIALISE_ELEMENT(ret); } } else if((int)type >= eReplayProxy_First && proxy) @@ -1230,8 +1230,9 @@ public: return files; } - uint32_t ExecuteAndInject(const char *a, const char *w, const char *c, - const rdcarray &env, const CaptureOptions &opts) + ExecuteResult ExecuteAndInject(const char *a, const char *w, const char *c, + const rdcarray &env, + const CaptureOptions &opts) { std::string app = a && a[0] ? a : ""; std::string workingDir = w && w[0] ? w : ""; @@ -1249,7 +1250,7 @@ public: ok = Ping(); }); - uint32_t ret = Android::StartAndroidPackageForCapture(host, app.c_str(), opts); + ExecuteResult ret = Android::StartAndroidPackageForCapture(host, app.c_str(), opts); Atomic::Inc32(&done); @@ -1269,7 +1270,7 @@ public: SERIALISE_ELEMENT(env); } - uint32_t ident = 0; + ExecuteResult ret = {}; { READ_DATA_SCOPE(); @@ -1277,7 +1278,7 @@ public: if(type == eRemoteServer_ExecuteAndInject) { - SERIALISE_ELEMENT(ident); + SERIALISE_ELEMENT(ret); } else { @@ -1287,7 +1288,7 @@ public: ser.EndChunk(); } - return ident; + return ret; } void CopyCaptureFromRemote(const char *remotepath, const char *localpath, diff --git a/renderdoc/os/os_specific.h b/renderdoc/os/os_specific.h index 1a0240c85..e87c489a0 100644 --- a/renderdoc/os/os_specific.h +++ b/renderdoc/os/os_specific.h @@ -60,8 +60,8 @@ bool StartGlobalHook(const char *pathmatch, const char *logfile, const CaptureOp bool IsGlobalHookActive(); void StopGlobalHook(); -uint32_t InjectIntoProcess(uint32_t pid, const rdcarray &env, - const char *logfile, const CaptureOptions &opts, bool waitForExit); +ExecuteResult InjectIntoProcess(uint32_t pid, const rdcarray &env, + const char *logfile, const CaptureOptions &opts, bool waitForExit); struct ProcessResult { string strStdout, strStderror; @@ -71,9 +71,10 @@ uint32_t LaunchProcess(const char *app, const char *workingDir, const char *cmdL ProcessResult *result = NULL); uint32_t LaunchScript(const char *script, const char *workingDir, const char *args, bool internal, ProcessResult *result = NULL); -uint32_t LaunchAndInjectIntoProcess(const char *app, const char *workingDir, const char *cmdLine, - const rdcarray &env, const char *logfile, - const CaptureOptions &opts, bool waitForExit); +ExecuteResult LaunchAndInjectIntoProcess(const char *app, const char *workingDir, const char *cmdLine, + const rdcarray &env, + const char *logfile, const CaptureOptions &opts, + bool waitForExit); void *LoadModule(const char *module); void *GetFunctionAddress(void *module, const char *function); uint32_t GetCurrentPID(); diff --git a/renderdoc/os/posix/posix_process.cpp b/renderdoc/os/posix/posix_process.cpp index 4fffe0676..8e9b224c4 100644 --- a/renderdoc/os/posix/posix_process.cpp +++ b/renderdoc/os/posix/posix_process.cpp @@ -404,11 +404,12 @@ static pid_t RunProcess(const char *app, const char *workingDir, const char *cmd return childPid; } -uint32_t Process::InjectIntoProcess(uint32_t pid, const rdcarray &env, - const char *logfile, const CaptureOptions &opts, bool waitForExit) +ExecuteResult Process::InjectIntoProcess(uint32_t pid, const rdcarray &env, + const char *logfile, const CaptureOptions &opts, + bool waitForExit) { RDCUNIMPLEMENTED("Injecting into already running processes on linux"); - return 0; + return {ReplayStatus::InjectionFailed, 0}; } uint32_t Process::LaunchProcess(const char *app, const char *workingDir, const char *cmdLine, @@ -472,16 +473,16 @@ uint32_t Process::LaunchScript(const char *script, const char *workingDir, const return LaunchProcess("bash", workingDir, args.c_str(), internal, result); } -uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workingDir, - const char *cmdLine, - const rdcarray &envList, - const char *logfile, const CaptureOptions &opts, - bool waitForExit) +ExecuteResult Process::LaunchAndInjectIntoProcess(const char *app, const char *workingDir, + const char *cmdLine, + const rdcarray &envList, + const char *logfile, const CaptureOptions &opts, + bool waitForExit) { if(app == NULL || app[0] == 0) { RDCERR("Invalid empty 'app'"); - return 0; + return {ReplayStatus::InternalError, 0}; } // turn environment string to a UTF-8 map @@ -596,7 +597,7 @@ uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workin } CleanupStringArray(envp, NULL); - return ret; + return {ret == 0 ? ReplayStatus::InjectionFailed : ReplayStatus::Succeeded, (uint32_t)ret}; } bool Process::StartGlobalHook(const char *pathmatch, const char *logfile, const CaptureOptions &opts) diff --git a/renderdoc/os/win32/sys_win32_hooks.cpp b/renderdoc/os/win32/sys_win32_hooks.cpp index 7b8b9130d..9f281d1d5 100644 --- a/renderdoc/os/win32/sys_win32_hooks.cpp +++ b/renderdoc/os/win32/sys_win32_hooks.cpp @@ -250,11 +250,12 @@ private: rdcarray env; // inherit logfile and capture options - uint32_t ident = RENDERDOC_InjectIntoProcess(lpProcessInformation->dwProcessId, env, - RenderDoc::Inst().GetLogFile(), - RenderDoc::Inst().GetCaptureOptions(), false); + ExecuteResult res = RENDERDOC_InjectIntoProcess(lpProcessInformation->dwProcessId, env, + RenderDoc::Inst().GetLogFile(), + RenderDoc::Inst().GetCaptureOptions(), false); - RenderDoc::Inst().AddChildProcess((uint32_t)lpProcessInformation->dwProcessId, ident); + if(res.status == ReplayStatus::Succeeded) + RenderDoc::Inst().AddChildProcess((uint32_t)lpProcessInformation->dwProcessId, res.ident); } if(resume) diff --git a/renderdoc/os/win32/win32_process.cpp b/renderdoc/os/win32/win32_process.cpp index 30d132e2c..7e7ea9ee9 100644 --- a/renderdoc/os/win32/win32_process.cpp +++ b/renderdoc/os/win32/win32_process.cpp @@ -500,8 +500,9 @@ static PROCESS_INFORMATION RunProcess(const char *app, const char *workingDir, c return pi; } -uint32_t Process::InjectIntoProcess(uint32_t pid, const rdcarray &env, - const char *logfile, const CaptureOptions &opts, bool waitForExit) +ExecuteResult Process::InjectIntoProcess(uint32_t pid, const rdcarray &env, + const char *logfile, const CaptureOptions &opts, + bool waitForExit) { wstring wlogfile = logfile == NULL ? L"" : StringFormat::UTF82Wide(logfile); @@ -561,7 +562,7 @@ uint32_t Process::InjectIntoProcess(uint32_t pid, const rdcarray &env, - const char *logfile, const CaptureOptions &opts, - bool waitForExit) +ExecuteResult Process::LaunchAndInjectIntoProcess(const char *app, const char *workingDir, + const char *cmdLine, + const rdcarray &env, + const char *logfile, const CaptureOptions &opts, + bool waitForExit) { void *func = GetProcAddress(GetModuleHandleA(STRINGIZE(RDOC_DLL_FILE) ".dll"), "INTERNAL_SetLogFile"); @@ -997,24 +1003,24 @@ uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workin { RDCERR("Can't find required export function in " STRINGIZE( RDOC_DLL_FILE) ".dll - corrupted/missing file?"); - return 0; + return {ReplayStatus::InternalError, 0}; } PROCESS_INFORMATION pi = RunProcess(app, workingDir, cmdLine, false, NULL, NULL); if(pi.dwProcessId == 0) - return 0; + return {ReplayStatus::InjectionFailed, 0}; - uint32_t ret = InjectIntoProcess(pi.dwProcessId, env, logfile, opts, false); + ExecuteResult ret = InjectIntoProcess(pi.dwProcessId, env, logfile, opts, false); CloseHandle(pi.hProcess); ResumeThread(pi.hThread); ResumeThread(pi.hThread); - if(ret == 0) + if(ret.ident == 0 || ret.status != ReplayStatus::Succeeded) { CloseHandle(pi.hThread); - return 0; + return ret; } if(waitForExit) diff --git a/renderdoc/replay/entry_points.cpp b/renderdoc/replay/entry_points.cpp index 4e6c52bf7..65b56fa6f 100644 --- a/renderdoc/replay/entry_points.cpp +++ b/renderdoc/replay/entry_points.cpp @@ -296,7 +296,7 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_UnregisterMemoryRegion(void handler->UnregisterMemoryRegion(base); } -extern "C" RENDERDOC_API uint32_t RENDERDOC_CC +extern "C" RENDERDOC_API ExecuteResult RENDERDOC_CC RENDERDOC_ExecuteAndInject(const char *app, const char *workingDir, const char *cmdLine, const rdcarray &env, const char *logfile, const CaptureOptions &opts, bool waitForExit) @@ -332,7 +332,7 @@ extern "C" RENDERDOC_API bool RENDERDOC_CC RENDERDOC_CanGlobalHook() return Process::CanGlobalHook(); } -extern "C" RENDERDOC_API uint32_t RENDERDOC_CC +extern "C" RENDERDOC_API ExecuteResult RENDERDOC_CC RENDERDOC_InjectIntoProcess(uint32_t pid, const rdcarray &env, const char *logfile, const CaptureOptions &opts, bool waitForExit) { diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 5d607c447..7bb6a95bc 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -53,6 +53,15 @@ class undersized #define SIZE_CHECK(expected) #endif +template +void DoSerialise(SerialiserType &ser, ExecuteResult &el) +{ + SERIALISE_MEMBER(status); + SERIALISE_MEMBER(ident); + + SIZE_CHECK(8); +} + template void DoSerialise(SerialiserType &ser, PathEntry &el) { @@ -2057,6 +2066,7 @@ void DoSerialise(SerialiserType &ser, VKPipe::State &el) #pragma endregion Vulkan pipeline state +INSTANTIATE_SERIALISE_TYPE(ExecuteResult) INSTANTIATE_SERIALISE_TYPE(PathEntry) INSTANTIATE_SERIALISE_TYPE(SectionProperties) INSTANTIATE_SERIALISE_TYPE(EnvironmentModification) diff --git a/renderdoccmd/renderdoccmd.cpp b/renderdoccmd/renderdoccmd.cpp index 374d85637..b16e737d1 100644 --- a/renderdoccmd/renderdoccmd.cpp +++ b/renderdoccmd/renderdoccmd.cpp @@ -363,28 +363,28 @@ struct CaptureCommand : public Command rdcarray env; - uint32_t ident = RENDERDOC_ExecuteAndInject( + ExecuteResult res = RENDERDOC_ExecuteAndInject( executable.c_str(), workingDir.empty() ? "" : workingDir.c_str(), cmdLine.empty() ? "" : cmdLine.c_str(), env, logFile.empty() ? "" : logFile.c_str(), opts, parser.exist("wait-for-exit")); - if(ident == 0) + if(res.status != ReplayStatus::Succeeded) { - std::cerr << "Failed to create & inject." << std::endl; - return 2; + std::cerr << "Failed to create & inject: " << ToStr(res.status) << std::endl; + return (int)res.status; } if(parser.exist("wait-for-exit")) { std::cerr << "'" << executable << "' finished executing." << std::endl; - ident = 0; + res.ident = 0; } else { - std::cerr << "Launched as ID " << ident << std::endl; + std::cerr << "Launched as ID " << res.ident << std::endl; } - return ident; + return res.ident; } std::string EscapeArgument(const std::string &arg) @@ -430,26 +430,26 @@ struct InjectCommand : public Command RENDERDOC_InitGlobalEnv(m_Env, convertArgs(parser.rest())); - uint32_t ident = RENDERDOC_InjectIntoProcess(PID, env, logFile.empty() ? "" : logFile.c_str(), - opts, parser.exist("wait-for-exit")); + ExecuteResult res = RENDERDOC_InjectIntoProcess( + PID, env, logFile.empty() ? "" : logFile.c_str(), opts, parser.exist("wait-for-exit")); - if(ident == 0) + if(res.status != ReplayStatus::Succeeded) { - std::cerr << "Failed to inject." << std::endl; - return 2; + std::cerr << "Failed to inject: " << ToStr(res.status) << std::endl; + return (int)res.status; } if(parser.exist("wait-for-exit")) { std::cerr << PID << " finished executing." << std::endl; - ident = 0; + res.ident = 0; } else { - std::cerr << "Launched as ID " << ident << std::endl; + std::cerr << "Launched as ID " << res.ident << std::endl; } - return ident; + return res.ident; } }; @@ -879,10 +879,13 @@ struct CapAltBitCommand : public Command RENDERDOC_SetDebugLogFile(debuglog.c_str()); - int ret = RENDERDOC_InjectIntoProcess(parser.get("pid"), env, - parser.get("log").c_str(), cmdopts, false); + ExecuteResult result = RENDERDOC_InjectIntoProcess( + parser.get("pid"), env, parser.get("log").c_str(), cmdopts, false); - return ret; + if(result.status == ReplayStatus::Succeeded) + return result.ident; + + return (int)result.status; } };