diff --git a/renderdoc/common/common.cpp b/renderdoc/common/common.cpp index 3e948652b..6ea495a1d 100644 --- a/renderdoc/common/common.cpp +++ b/renderdoc/common/common.cpp @@ -252,24 +252,40 @@ uint64_t Log2Floor(uint64_t value) } #endif -static string &logfile() -{ - // deliberately leak this so that it doesn't get destructed while we're still logging in process - // teardown. - static string *fn = new string; - return *fn; -} +static string logfile; +static void *logfileHandle = NULL; const char *rdclog_getfilename() { - return logfile().c_str(); + return logfile.c_str(); } void rdclog_filename(const char *filename) { - logfile() = ""; + string previous = logfile; + + logfile = ""; if(filename && filename[0]) - logfile() = filename; + logfile = filename; + + FileIO::logfile_close(logfileHandle); + + if(!logfile.empty()) + { + logfileHandle = FileIO::logfile_open(filename); + + if(logfileHandle && previous.c_str()) + { + vector previousContents; + FileIO::slurp(previous.c_str(), previousContents); + + if(!previousContents.empty()) + FileIO::logfile_append(logfileHandle, (const char *)&previousContents[0], + previousContents.size()); + + FileIO::Delete(previous.c_str()); + } + } } static bool log_output_enabled = false; @@ -279,6 +295,13 @@ void rdclog_enableoutput() log_output_enabled = true; } +void rdclog_closelog() +{ + log_output_enabled = false; + if(logfileHandle) + FileIO::logfile_close(logfileHandle); +} + void rdclog_flush() { } @@ -303,15 +326,10 @@ void rdclogprint_int(LogType type, const char *fullMsg, const char *msg) OSUtility::WriteOutput(OSUtility::Output_StdErr, msg); #endif #if defined(OUTPUT_LOG_TO_DISK) - if(!logfile().empty()) + if(logfileHandle) { - FILE *f = FileIO::fopen(logfile().c_str(), "a"); - if(f) - { - // strlen used as byte length - str is UTF-8 so this is NOT number of characters - FileIO::fwrite(fullMsg, 1, strlen(fullMsg), f); - FileIO::fclose(f); - } + // strlen used as byte length - str is UTF-8 so this is NOT number of characters + FileIO::logfile_append(logfileHandle, fullMsg, strlen(fullMsg)); } #endif } @@ -356,8 +374,9 @@ void rdclog_int(LogType type, const char *project, const char *file, unsigned in char *output = rdclog_outputBuffer; size_t available = rdclog_outBufSize; - int numWritten = StringFormat::snprintf(output, available, "% 4s: %s%s%s - ", project, timestamp, - location, typestr[type]); + int numWritten = + StringFormat::snprintf(output, available, "% 4s %06u: %s%s%s - ", project, + Process::GetCurrentPID(), timestamp, location, typestr[type]); if(numWritten < 0) { diff --git a/renderdoc/common/common.h b/renderdoc/common/common.h index 0a2f405a9..0bd42cf3c 100644 --- a/renderdoc/common/common.h +++ b/renderdoc/common/common.h @@ -266,11 +266,13 @@ void rdclog_int(LogType type, const char *project, const char *file, unsigned in const char *rdclog_getfilename(); void rdclog_filename(const char *filename); void rdclog_enableoutput(); +void rdclog_closelog(); #define RDCLOGFILE(fn) rdclog_filename(fn) #define RDCGETLOGFILE() rdclog_getfilename() #define RDCLOGOUTPUT() rdclog_enableoutput() +#define RDCSTOPLOGGING() rdclog_closelog() #if(!defined(RELEASE) || defined(FORCE_DEBUG_LOGS)) && !defined(STRIP_DEBUG_LOGS) #define RDCDEBUG(...) rdclog(RDCLog_Debug, __VA_ARGS__) diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp index a357088c7..8b8969214 100644 --- a/renderdoc/core/core.cpp +++ b/renderdoc/core/core.cpp @@ -292,15 +292,13 @@ void RenderDoc::Initialise() const char *base = "RenderDoc_app"; if(IsReplayApp()) - base = "RenderDoc_replay"; + base = "RenderDoc"; FileIO::GetDefaultFiles(base, capture_filename, m_LoggingFilename, m_Target); if(m_LogFile.empty()) SetLogFile(capture_filename.c_str()); - string existingLog = RDCGETLOGFILE(); - FileIO::Copy(existingLog.c_str(), m_LoggingFilename.c_str(), true); RDCLOGFILE(m_LoggingFilename.c_str()); } @@ -359,6 +357,8 @@ RenderDoc::~RenderDoc() } } + RDCSTOPLOGGING(); + FileIO::Delete(m_LoggingFilename.c_str()); if(m_RemoteThread) diff --git a/renderdoc/core/crash_handler.h b/renderdoc/core/crash_handler.h index f6fa8537c..6ff0c7f52 100644 --- a/renderdoc/core/crash_handler.h +++ b/renderdoc/core/crash_handler.h @@ -51,7 +51,7 @@ public: GetTempPathW(MAX_PATH - 1, tempPath); wstring dumpFolder = tempPath; - dumpFolder += L"RenderDocDumps"; + dumpFolder += L"RenderDoc/dumps"; CreateDirectoryW(dumpFolder.c_str(), NULL); diff --git a/renderdoc/hooks/hooks.cpp b/renderdoc/hooks/hooks.cpp index 91c299468..8a46aa578 100644 --- a/renderdoc/hooks/hooks.cpp +++ b/renderdoc/hooks/hooks.cpp @@ -42,16 +42,10 @@ void LibraryHooks::CreateHooks() HOOKS_BEGIN(); for(auto it = m_Hooks.begin(); it != m_Hooks.end(); ++it) { - RDCDEBUG("Attempting to hook %s", it->first); + RDCDEBUG("Hooking %s", it->first); - if(it->second->CreateHooks(it->first)) - { - RDCLOG("Loaded and hooked into %s, PID %d", it->first, Process::GetCurrentPID()); - } - else - { + if(!it->second->CreateHooks(it->first)) RDCWARN("Couldn't hook into %s", it->first); - } } HOOKS_END(); } diff --git a/renderdoc/os/os_specific.h b/renderdoc/os/os_specific.h index ef8652399..0d99074c2 100644 --- a/renderdoc/os/os_specific.h +++ b/renderdoc/os/os_specific.h @@ -307,6 +307,12 @@ bool feof(FILE *f); int fclose(FILE *f); +// functions for atomically appending to a log that may be in use in multiple +// processes +void *logfile_open(const char *filename); +void logfile_append(void *handle, const char *msg, size_t length); +void logfile_close(void *handle); + // utility functions inline bool dump(const char *filename, const void *buffer, size_t size) { diff --git a/renderdoc/os/posix/posix_process.cpp b/renderdoc/os/posix/posix_process.cpp index b8b4ef5b4..dca4d9cd2 100644 --- a/renderdoc/os/posix/posix_process.cpp +++ b/renderdoc/os/posix/posix_process.cpp @@ -421,6 +421,8 @@ uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workin EnvironmentModification(eEnvModification_Replace, "RENDERDOC_LOGFILE", logfile)); modifications.push_back( EnvironmentModification(eEnvModification_Replace, "RENDERDOC_CAPTUREOPTS", optstr.c_str())); + modifications.push_back(EnvironmentModification(eEnvModification_Replace, + "RENDERDOC_DEBUG_LOG_FILE", RDCGETLOGFILE())); for(size_t i = 0; i < modifications.size(); i++) { diff --git a/renderdoc/os/posix/posix_stringio.cpp b/renderdoc/os/posix/posix_stringio.cpp index e90c2d237..f29cdc38a 100644 --- a/renderdoc/os/posix/posix_stringio.cpp +++ b/renderdoc/os/posix/posix_stringio.cpp @@ -25,6 +25,7 @@ #include #include // for dladdr #include +#include #include #include #include @@ -168,17 +169,22 @@ void GetDefaultFiles(const char *logBaseName, string &capture_filename, string & char temp_filename[2048] = {0}; - snprintf(temp_filename, sizeof(temp_filename) - 1, "%s/%s_%04d.%02d.%02d_%02d.%02d.rdc", + snprintf(temp_filename, sizeof(temp_filename) - 1, "%s/RenderDoc/%s_%04d.%02d.%02d_%02d.%02d.rdc", temp_folder, mod, 1900 + now.tm_year, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min); capture_filename = string(temp_filename); - snprintf(temp_filename, sizeof(temp_filename) - 1, "%s/%s_%04d.%02d.%02d_%02d.%02d.%02d.log", - temp_folder, logBaseName, 1900 + now.tm_year, now.tm_mon + 1, now.tm_mday, now.tm_hour, - now.tm_min, now.tm_sec); + snprintf(temp_filename, sizeof(temp_filename) - 1, + "%s/RenderDoc/%s_%04d.%02d.%02d_%02d.%02d.%02d.log", temp_folder, logBaseName, + 1900 + now.tm_year, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec); - logging_filename = string(temp_filename); + // set by UI when launching programs so all logging goes to the same file + char *logfile_override = getenv("RENDERDOC_DEBUG_LOG_FILE"); + if(logfile_override) + logging_filename = string(logfile_override); + else + logging_filename = string(temp_filename); } uint64_t GetModifiedTimestamp(const string &filename) @@ -361,6 +367,30 @@ int fclose(FILE *f) { return ::fclose(f); } + +void *logfile_open(const char *filename) +{ + int fd = open(filename, O_APPEND | O_WRONLY | O_CREAT, S_IWRITE); + return (void *)(intptr_t)fd; +} + +void logfile_append(void *handle, const char *msg, size_t length) +{ + if(handle) + { + int fd = ((intptr_t)handle & 0xffffffff); + write(fd, msg, (unsigned int)length); + } +} + +void logfile_close(void *handle) +{ + if(handle) + { + int fd = ((intptr_t)handle & 0xffffffff); + close(fd); + } +} }; namespace StringFormat diff --git a/renderdoc/os/win32/win32_process.cpp b/renderdoc/os/win32/win32_process.cpp index 17f5fbe14..3091c9f58 100644 --- a/renderdoc/os/win32/win32_process.cpp +++ b/renderdoc/os/win32/win32_process.cpp @@ -154,39 +154,45 @@ void Process::ApplyEnvironmentModification() } // helpers for various shims and dlls etc, not part of the public API -extern "C" __declspec(dllexport) void __cdecl RENDERDOC_GetTargetControlIdent(uint32_t *ident) +extern "C" __declspec(dllexport) void __cdecl INTERNAL_GetTargetControlIdent(uint32_t *ident) { if(ident) *ident = RenderDoc::Inst().GetTargetControlIdent(); } -extern "C" __declspec(dllexport) void __cdecl RENDERDOC_SetCaptureOptions(CaptureOptions *opts) +extern "C" __declspec(dllexport) void __cdecl INTERNAL_SetCaptureOptions(CaptureOptions *opts) { if(opts) RenderDoc::Inst().SetCaptureOptions(*opts); } -extern "C" __declspec(dllexport) void __cdecl RENDERDOC_SetLogFile(const char *log) +extern "C" __declspec(dllexport) void __cdecl INTERNAL_SetLogFile(const char *log) { if(log) RenderDoc::Inst().SetLogFile(log); } +extern "C" __declspec(dllexport) void __cdecl INTERNAL_SetDebugLogFile(const char *log) +{ + if(log) + RDCLOGFILE(log); +} + static Process::EnvironmentModification tempEnvMod; -extern "C" __declspec(dllexport) void __cdecl RENDERDOC_EnvModName(const char *name) +extern "C" __declspec(dllexport) void __cdecl INTERNAL_EnvModName(const char *name) { if(name) tempEnvMod.name = name; } -extern "C" __declspec(dllexport) void __cdecl RENDERDOC_EnvModValue(const char *value) +extern "C" __declspec(dllexport) void __cdecl INTERNAL_EnvModValue(const char *value) { if(value) tempEnvMod.value = value; } -extern "C" __declspec(dllexport) void __cdecl RENDERDOC_EnvMod(Process::ModificationType *type) +extern "C" __declspec(dllexport) void __cdecl INTERNAL_EnvMod(Process::ModificationType *type) { if(type) { @@ -195,7 +201,7 @@ extern "C" __declspec(dllexport) void __cdecl RENDERDOC_EnvMod(Process::Modifica } } -extern "C" __declspec(dllexport) void __cdecl RENDERDOC_ApplyEnvMods(void *ignored) +extern "C" __declspec(dllexport) void __cdecl INTERNAL_ApplyEnvMods(void *ignored) { Process::ApplyEnvironmentModification(); } @@ -701,13 +707,18 @@ uint32_t Process::InjectIntoProcess(uint32_t pid, EnvironmentModification *env, // safe to cast away the const as we know these functions don't modify the parameters if(logfile != NULL) - InjectFunctionCall(hProcess, loc, "RENDERDOC_SetLogFile", (void *)logfile, strlen(logfile) + 1); + InjectFunctionCall(hProcess, loc, "INTERNAL_SetLogFile", (void *)logfile, strlen(logfile) + 1); + + std::string debugLogfile = RDCGETLOGFILE(); + + InjectFunctionCall(hProcess, loc, "INTERNAL_SetDebugLogFile", (void *)debugLogfile.c_str(), + debugLogfile.size() + 1); if(opts != NULL) - InjectFunctionCall(hProcess, loc, "RENDERDOC_SetCaptureOptions", (CaptureOptions *)opts, + InjectFunctionCall(hProcess, loc, "INTERNAL_SetCaptureOptions", (CaptureOptions *)opts, sizeof(CaptureOptions)); - InjectFunctionCall(hProcess, loc, "RENDERDOC_GetTargetControlIdent", &controlident, + InjectFunctionCall(hProcess, loc, "INTERNAL_GetTargetControlIdent", &controlident, sizeof(controlident)); if(env) @@ -721,17 +732,17 @@ uint32_t Process::InjectIntoProcess(uint32_t pid, EnvironmentModification *env, if(name == "") break; - InjectFunctionCall(hProcess, loc, "RENDERDOC_EnvModName", (void *)name.c_str(), + InjectFunctionCall(hProcess, loc, "INTERNAL_EnvModName", (void *)name.c_str(), name.size() + 1); - InjectFunctionCall(hProcess, loc, "RENDERDOC_EnvModValue", (void *)value.c_str(), + InjectFunctionCall(hProcess, loc, "INTERNAL_EnvModValue", (void *)value.c_str(), value.size() + 1); - InjectFunctionCall(hProcess, loc, "RENDERDOC_EnvMod", &type, sizeof(type)); + InjectFunctionCall(hProcess, loc, "INTERNAL_EnvMod", &type, sizeof(type)); env++; } // parameter is unused - InjectFunctionCall(hProcess, loc, "RENDERDOC_ApplyEnvMods", env, + InjectFunctionCall(hProcess, loc, "INTERNAL_ApplyEnvMods", env, sizeof(EnvironmentModification)); } } @@ -802,7 +813,7 @@ uint32_t Process::LaunchAndInjectIntoProcess(const char *app, const char *workin bool waitForExit) { void *func = - GetProcAddress(GetModuleHandleA(STRINGIZE(RDOC_DLL_FILE) ".dll"), "RENDERDOC_SetLogFile"); + GetProcAddress(GetModuleHandleA(STRINGIZE(RDOC_DLL_FILE) ".dll"), "INTERNAL_SetLogFile"); if(func == NULL) { diff --git a/renderdoc/os/win32/win32_stringio.cpp b/renderdoc/os/win32/win32_stringio.cpp index 1614325ad..1846a0790 100644 --- a/renderdoc/os/win32/win32_stringio.cpp +++ b/renderdoc/os/win32/win32_stringio.cpp @@ -270,7 +270,7 @@ void GetDefaultFiles(const char *logBaseName, string &capture_filename, string & wchar_t *filename_start = temp_filename + wcslen(temp_filename); - wsprintf(filename_start, L"%ls_%04d.%02d.%02d_%02d.%02d.rdc", mod, 1900 + now.tm_year, + wsprintf(filename_start, L"RenderDoc\\%ls_%04d.%02d.%02d_%02d.%02d.rdc", mod, 1900 + now.tm_year, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min); capture_filename = StringFormat::Wide2UTF8(wstring(temp_filename)); @@ -279,7 +279,7 @@ void GetDefaultFiles(const char *logBaseName, string &capture_filename, string & wstring wbase = StringFormat::UTF82Wide(string(logBaseName)); - wsprintf(filename_start, L"%ls_%04d.%02d.%02d_%02d.%02d.%02d.log", wbase.c_str(), + wsprintf(filename_start, L"RenderDoc\\%ls_%04d.%02d.%02d_%02d.%02d.%02d.log", wbase.c_str(), 1900 + now.tm_year, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec); logging_filename = StringFormat::Wide2UTF8(wstring(temp_filename)); @@ -500,6 +500,27 @@ int fclose(FILE *f) { return ::fclose(f); } + +void *logfile_open(const char *filename) +{ + wstring wfn = StringFormat::UTF82Wide(string(filename)); + return (void *)CreateFileW(wfn.c_str(), FILE_APPEND_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); +} + +void logfile_append(void *handle, const char *msg, size_t length) +{ + if(handle) + { + DWORD bytesWritten = 0; + WriteFile((HANDLE)handle, msg, (DWORD)length, &bytesWritten, NULL); + } +} + +void logfile_close(void *handle) +{ + CloseHandle((HANDLE)handle); +} }; namespace StringFormat diff --git a/renderdoccmd/renderdoccmd_win32.cpp b/renderdoccmd/renderdoccmd_win32.cpp index 05e13e09e..5866366a9 100644 --- a/renderdoccmd/renderdoccmd_win32.cpp +++ b/renderdoccmd/renderdoccmd_win32.cpp @@ -506,7 +506,7 @@ struct CrashHandlerCommand : public Command Sleep(100); wstring dumpFolder = tempPath; - dumpFolder += L"RenderDocDumps"; + dumpFolder += L"RenderDoc/dumps"; CreateDirectoryW(dumpFolder.c_str(), NULL);