Handle injecting environment variable params

* This also fixes the problem of capturing 32-bit programs with 64-bit
  RenderDoc failing to properly insert environment variables and
  error'ing when it tries to do it directly.
This commit is contained in:
baldurk
2016-09-28 17:55:45 +02:00
parent 220e214f4d
commit 9f4a60028e
10 changed files with 214 additions and 67 deletions
+1 -1
View File
@@ -637,7 +637,7 @@ extern "C" RENDERDOC_API uint32_t RENDERDOC_CC
RENDERDOC_ExecuteAndInject(const char *app, const char *workingDir, const char *cmdLine, void *env,
const char *logfile, const CaptureOptions *opts, bool32 waitForExit);
extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_InjectIntoProcess(
uint32_t pid, const char *logfile, const CaptureOptions *opts, bool32 waitForExit);
uint32_t pid, void *env, const char *logfile, const CaptureOptions *opts, bool32 waitForExit);
//////////////////////////////////////////////////////////////////////////
// Miscellaneous!
+2 -2
View File
@@ -80,8 +80,8 @@ void RegisterEnvironmentModification(EnvironmentModification modif);
void ApplyEnvironmentModification();
void StartGlobalHook(const char *pathmatch, const char *logfile, const CaptureOptions *opts);
uint32_t InjectIntoProcess(uint32_t pid, const char *logfile, const CaptureOptions *opts,
bool waitForExit);
uint32_t InjectIntoProcess(uint32_t pid, EnvironmentModification *env, const char *logfile,
const CaptureOptions *opts, bool waitForExit);
uint32_t LaunchProcess(const char *app, const char *workingDir, const char *cmdLine);
uint32_t LaunchAndInjectIntoProcess(const char *app, const char *workingDir, const char *cmdLine,
EnvironmentModification *env, const char *logfile,
+2 -2
View File
@@ -341,8 +341,8 @@ static pid_t RunProcess(const char *app, const char *workingDir, const char *cmd
return childPid;
}
uint32_t Process::InjectIntoProcess(uint32_t pid, const char *logfile, const CaptureOptions *opts,
bool waitForExit)
uint32_t Process::InjectIntoProcess(uint32_t pid, EnvironmentModification *env, const char *logfile,
const CaptureOptions *opts, bool waitForExit)
{
RDCUNIMPLEMENTED("Injecting into already running processes on linux");
return 0;
+2 -2
View File
@@ -146,7 +146,7 @@ private:
if(inject)
{
// inherit logfile and capture options
uint32_t ident = RENDERDOC_InjectIntoProcess(lpProcessInformation->dwProcessId,
uint32_t ident = RENDERDOC_InjectIntoProcess(lpProcessInformation->dwProcessId, NULL,
RenderDoc::Inst().GetLogFile(),
&RenderDoc::Inst().GetCaptureOptions(), false);
@@ -233,7 +233,7 @@ private:
if(inject)
{
// inherit logfile and capture options
uint32_t ident = RENDERDOC_InjectIntoProcess(lpProcessInformation->dwProcessId,
uint32_t ident = RENDERDOC_InjectIntoProcess(lpProcessInformation->dwProcessId, NULL,
RenderDoc::Inst().GetLogFile(),
&RenderDoc::Inst().GetCaptureOptions(), false);
+98 -47
View File
@@ -439,8 +439,8 @@ static PROCESS_INFORMATION RunProcess(const char *app, const char *workingDir, c
return pi;
}
uint32_t Process::InjectIntoProcess(uint32_t pid, const char *logfile, const CaptureOptions *opts,
bool waitForExit)
uint32_t Process::InjectIntoProcess(uint32_t pid, EnvironmentModification *env, const char *logfile,
const CaptureOptions *opts, bool waitForExit)
{
CaptureOptions options;
if(opts)
@@ -539,8 +539,6 @@ uint32_t Process::InjectIntoProcess(uint32_t pid, const char *logfile, const Cap
pSec.nLength = sizeof(pSec);
tSec.nLength = sizeof(tSec);
wchar_t *paramsAlloc = new wchar_t[2048];
// serialise to string with two chars per byte
string optstr;
{
@@ -553,13 +551,78 @@ uint32_t Process::InjectIntoProcess(uint32_t pid, const char *logfile, const Cap
}
}
wchar_t *paramsAlloc = new wchar_t[2048];
_snwprintf_s(paramsAlloc, 2047, 2047,
L"\"%ls\" cap32for64 --pid=%d --log=\"%ls\" --capopts=\"%hs\"", renderdocPath, pid,
wlogfile.c_str(), optstr.c_str());
paramsAlloc[2047] = 0;
BOOL retValue = CreateProcessW(NULL, paramsAlloc, &pSec, &tSec, false, CREATE_SUSPENDED, NULL,
wchar_t *commandLine = paramsAlloc;
wstring cmdWithEnv;
if(env)
{
cmdWithEnv = paramsAlloc;
for(;;)
{
string name = trim(env->name);
string value = env->value;
ModificationType type = env->type;
if(name == "")
break;
cmdWithEnv += L" +env-";
switch(type)
{
case eEnvModification_Replace: cmdWithEnv += L"replace "; break;
case eEnvModification_AppendPlatform: cmdWithEnv += L"append-platform "; break;
case eEnvModification_AppendSemiColon: cmdWithEnv += L"append-semicolon "; break;
case eEnvModification_AppendColon: cmdWithEnv += L"append-colon "; break;
case eEnvModification_Append: cmdWithEnv += L"append "; break;
case eEnvModification_PrependPlatform: cmdWithEnv += L"prepend-platform "; break;
case eEnvModification_PrependSemiColon: cmdWithEnv += L"prepend-semicolon "; break;
case eEnvModification_PrependColon: cmdWithEnv += L"prepend-colon "; break;
case eEnvModification_Prepend: cmdWithEnv += L"prepend "; break;
}
// escape the parameters
for(auto it = name.begin(); it != name.end(); ++it)
{
if(*it == '"')
it = name.insert(it, '\\') + 1;
}
for(auto it = value.begin(); it != value.end(); ++it)
{
if(*it == '"')
it = value.insert(it, '\\') + 1;
}
if(name.back() == '\\')
name += "\\";
if(value.back() == '\\')
value += "\\";
cmdWithEnv += L"\"" + StringFormat::UTF82Wide(name) + L"\" ";
cmdWithEnv += L"\"" + StringFormat::UTF82Wide(value) + L"\" ";
env++;
}
commandLine = (wchar_t *)cmdWithEnv.c_str();
}
BOOL retValue = CreateProcessW(NULL, commandLine, &pSec, &tSec, false, CREATE_SUSPENDED, NULL,
NULL, &si, &pi);
SAFE_DELETE_ARRAY(paramsAlloc);
@@ -610,6 +673,31 @@ uint32_t Process::InjectIntoProcess(uint32_t pid, const char *logfile, const Cap
InjectFunctionCall(hProcess, loc, "RENDERDOC_GetTargetControlIdent", &controlident,
sizeof(controlident));
if(env)
{
for(;;)
{
string name = trim(env->name);
string value = env->value;
ModificationType type = env->type;
if(name == "")
break;
InjectFunctionCall(hProcess, loc, "RENDERDOC_EnvModName", (void *)name.c_str(),
name.size() + 1);
InjectFunctionCall(hProcess, loc, "RENDERDOC_EnvModValue", (void *)value.c_str(),
value.size() + 1);
InjectFunctionCall(hProcess, loc, "RENDERDOC_EnvMod", &type, sizeof(type));
env++;
}
// parameter is unused
InjectFunctionCall(hProcess, loc, "RENDERDOC_ApplyEnvMods", env,
sizeof(EnvironmentModification));
}
}
if(waitForExit)
@@ -657,55 +745,18 @@ uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workin
if(pi.dwProcessId == 0)
return 0;
uint32_t ret = InjectIntoProcess(pi.dwProcessId, logfile, opts, false);
uint32_t ret = InjectIntoProcess(pi.dwProcessId, env, logfile, opts, false);
CloseHandle(pi.hProcess);
ResumeThread(pi.hThread);
ResumeThread(pi.hThread);
if(ret == 0)
{
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 0;
}
if(env)
{
uintptr_t loc = FindRemoteDLL(pi.dwProcessId, L"renderdoc.dll");
if(loc == 0)
{
RDCERR("Can't locate renderdoc.dll in remote PID %d", pi.dwProcessId);
}
else
{
for(;;)
{
string name = trim(env->name);
string value = env->value;
ModificationType type = env->type;
if(name == "")
break;
InjectFunctionCall(pi.hProcess, loc, "RENDERDOC_EnvModName", (void *)name.c_str(),
name.size() + 1);
InjectFunctionCall(pi.hProcess, loc, "RENDERDOC_EnvModValue", (void *)value.c_str(),
value.size() + 1);
InjectFunctionCall(pi.hProcess, loc, "RENDERDOC_EnvMod", &type, sizeof(type));
env++;
}
// parameter is unused
InjectFunctionCall(pi.hProcess, loc, "RENDERDOC_ApplyEnvMods", env,
sizeof(EnvironmentModification));
}
}
// done with it
CloseHandle(pi.hProcess);
ResumeThread(pi.hThread);
if(waitForExit)
WaitForSingleObject(pi.hThread, INFINITE);
+3 -2
View File
@@ -402,9 +402,10 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartGlobalHook(const char
}
extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_InjectIntoProcess(
uint32_t pid, const char *logfile, const CaptureOptions *opts, bool32 waitForExit)
uint32_t pid, void *env, const char *logfile, const CaptureOptions *opts, bool32 waitForExit)
{
return Process::InjectIntoProcess(pid, logfile, opts, waitForExit != 0);
return Process::InjectIntoProcess(pid, (Process::EnvironmentModification *)env, logfile, opts,
waitForExit != 0);
}
extern "C" RENDERDOC_API bool32 RENDERDOC_CC RENDERDOC_GetThumbnail(const char *filename, byte *buf,
+84 -4
View File
@@ -374,8 +374,8 @@ struct InjectCommand : public Command
std::cout << "Injecting into PID " << PID << std::endl;
uint32_t ident = RENDERDOC_InjectIntoProcess(PID, logFile.empty() ? "" : logFile.c_str(), &opts,
parser.exist("wait-for-exit"));
uint32_t ident = RENDERDOC_InjectIntoProcess(PID, NULL, logFile.empty() ? "" : logFile.c_str(),
&opts, parser.exist("wait-for-exit"));
if(ident == 0)
{
@@ -539,6 +539,7 @@ struct Cap32For64Command : public Command
parser.add<uint32_t>("pid", 0, "");
parser.add<string>("log", 0, "");
parser.add<string>("capopts", 0, "");
parser.stop_at_rest(true);
}
virtual const char *Description() { return "Internal use only!"; }
virtual bool IsInternalOnly() { return true; }
@@ -548,8 +549,87 @@ struct Cap32For64Command : public Command
CaptureOptions cmdopts;
readCapOpts(parser.get<string>("capopts").c_str(), &cmdopts);
return RENDERDOC_InjectIntoProcess(parser.get<uint32_t>("pid"),
parser.get<string>("log").c_str(), &cmdopts, false);
std::vector<std::string> rest = parser.rest();
if(rest.size() % 3 != 0)
{
std::cerr << "Invalid generated cap32for64 command rest.size() == " << rest.size() << std::endl;
return 0;
}
int numEnvs = int(rest.size() / 3);
void *env = RENDERDOC_MakeEnvironmentModificationList(numEnvs);
for(int i = 0; i < numEnvs; i++)
{
string typeString = rest[i * 3 + 0];
EnvironmentModificationType type = eEnvMod_Set;
EnvironmentSeparator sep = eEnvSep_None;
if(typeString == "+env-replace")
{
type = eEnvMod_Set;
sep = eEnvSep_None;
}
else if(typeString == "+env-append-platform")
{
type = eEnvMod_Append;
sep = eEnvSep_Platform;
}
else if(typeString == "+env-append-semicolon")
{
type = eEnvMod_Append;
sep = eEnvSep_SemiColon;
}
else if(typeString == "+env-append-colon")
{
type = eEnvMod_Append;
sep = eEnvSep_Colon;
}
else if(typeString == "+env-append")
{
type = eEnvMod_Append;
sep = eEnvSep_None;
}
else if(typeString == "+env-prepend-platform")
{
type = eEnvMod_Prepend;
sep = eEnvSep_Platform;
}
else if(typeString == "+env-prepend-semicolon")
{
type = eEnvMod_Prepend;
sep = eEnvSep_SemiColon;
}
else if(typeString == "+env-prepend-colon")
{
type = eEnvMod_Prepend;
sep = eEnvSep_Colon;
}
else if(typeString == "+env-prepend")
{
type = eEnvMod_Prepend;
sep = eEnvSep_None;
}
else
{
std::cerr << "Invalid generated cap32for64 env '" << rest[i * 3 + 0] << std::endl;
RENDERDOC_FreeEnvironmentModificationList(env);
return 0;
}
RENDERDOC_SetEnvironmentModification(env, i, rest[i * 3 + 1].c_str(), rest[i * 3 + 2].c_str(),
type, sep);
}
int ret = RENDERDOC_InjectIntoProcess(parser.get<uint32_t>("pid"), env,
parser.get<string>("log").c_str(), &cmdopts, false);
RENDERDOC_FreeEnvironmentModificationList(env);
return ret;
}
};
+18 -3
View File
@@ -62,7 +62,7 @@ namespace renderdoc
IntPtr logfile, CaptureOptions opts, bool waitForExit);
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern UInt32 RENDERDOC_InjectIntoProcess(UInt32 pid, IntPtr logfile, CaptureOptions opts, bool waitForExit);
private static extern UInt32 RENDERDOC_InjectIntoProcess(UInt32 pid, IntPtr env, IntPtr logfile, CaptureOptions opts, bool waitForExit);
[DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr RENDERDOC_CreateTargetControl(IntPtr host, UInt32 ident, IntPtr clientName, bool forceConnection);
@@ -191,11 +191,26 @@ namespace renderdoc
return ret;
}
public static UInt32 InjectIntoProcess(UInt32 pid, string logfile, CaptureOptions opts)
public static UInt32 InjectIntoProcess(UInt32 pid, EnvironmentModification[] env, string logfile, CaptureOptions opts)
{
IntPtr logfile_mem = CustomMarshal.MakeUTF8String(logfile);
UInt32 ret = RENDERDOC_InjectIntoProcess(pid, logfile_mem, opts, false);
IntPtr env_mem = RENDERDOC_MakeEnvironmentModificationList(env.Length);
for (int i = 0; i < env.Length; i++)
{
IntPtr var_mem = CustomMarshal.MakeUTF8String(env[i].variable);
IntPtr val_mem = CustomMarshal.MakeUTF8String(env[i].value);
RENDERDOC_SetEnvironmentModification(env_mem, i, var_mem, val_mem, env[i].type, env[i].separator);
CustomMarshal.Free(var_mem);
CustomMarshal.Free(val_mem);
}
UInt32 ret = RENDERDOC_InjectIntoProcess(pid, env_mem, logfile_mem, opts, false);
RENDERDOC_FreeEnvironmentModificationList(env_mem);
CustomMarshal.Free(logfile_mem);
+2 -2
View File
@@ -260,7 +260,7 @@ namespace renderdocui.Windows.Dialogs
#region Callbacks
public delegate LiveCapture OnCaptureMethod(string exe, string workingDir, string cmdLine, EnvironmentModification[] env, CaptureOptions opts);
public delegate LiveCapture OnInjectMethod(UInt32 PID, string name, CaptureOptions opts);
public delegate LiveCapture OnInjectMethod(UInt32 PID, EnvironmentModification[] env, string name, CaptureOptions opts);
private OnCaptureMethod m_CaptureCallback = null;
private OnInjectMethod m_InjectCallback = null;
@@ -445,7 +445,7 @@ namespace renderdocui.Windows.Dialogs
string name = item.SubItems[1].Text;
UInt32 PID = (UInt32)item.Tag;
var live = m_InjectCallback(PID, name, GetSettings().Options);
var live = m_InjectCallback(PID, GetSettings().Environment, name, GetSettings().Options);
if (queueFrameCap.Checked && live != null)
live.QueueCapture((int)queuedCapFrame.Value);
+2 -2
View File
@@ -1022,14 +1022,14 @@ namespace renderdocui.Windows
return live;
}
private LiveCapture OnInjectTrigger(UInt32 PID, string name, CaptureOptions opts)
private LiveCapture OnInjectTrigger(UInt32 PID, EnvironmentModification[] env, string name, CaptureOptions opts)
{
if (!PromptCloseLog())
return null;
string logfile = m_Core.TempLogFilename(name);
UInt32 ret = StaticExports.InjectIntoProcess(PID, logfile, opts);
UInt32 ret = StaticExports.InjectIntoProcess(PID, env, logfile, opts);
if (ret == 0)
{