1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 // ============================================================
11 // Implements the DebugLog class
13 // ============================================================
15 #if defined(BINDER_DEBUG_LOG)
17 #include "debuglog.hpp"
18 #include "assemblyname.hpp"
20 #include "variables.hpp"
24 namespace BINDER_SPACE
28 void GetStringFromHR(HRESULT hr,
37 info.Append(L"S_FALSE");
40 info.Append(L"E_FAIL");
42 case __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
43 info.Append(L"HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)");
45 case __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER):
46 info.Append(L"HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)");
48 case FUSION_E_REF_DEF_MISMATCH:
49 info.Append(L"FUSION_E_REF_DEF_MISMATCH");
51 case FUSION_E_CODE_DOWNLOAD_DISABLED:
52 info.Append(L"FUSION_E_CODE_DOWNLOAD_DISABLED");
55 info.AppendPrintf(L"%p", hr);
60 HRESULT GetLogFilePath(PathString &logFileDir,
61 PathString &logFilePath)
65 BOOL fFileExists = TRUE;
69 LARGE_INTEGER kCount1;
70 LARGE_INTEGER kCount2;
74 if (!QueryPerformanceCounter(&kCount1))
76 hr = HRESULT_FROM_GetLastError();
78 else if(!QueryPerformanceCounter(&kCount2))
80 hr = HRESULT_FROM_GetLastError();
84 logFilePath.Printf(L"%s\\Log_%u%u_%u%u.tmp",
85 logFileDir.GetUnicode(),
86 static_cast<UINT32>(kCount1.u.LowPart),
88 static_cast<UINT32>(kCount2.u.LowPart),
91 PlatformPath(logFilePath);
94 fFileExists = (FileOrDirectoryExists(logFilePath) == S_OK);
96 while (fFileExists == TRUE);
101 HRESULT WriteToFile(HANDLE hFile,
102 const BYTE *pbBuffer,
106 DWORD dwNumberOfBytesWritten = 0;
108 while ((dwcbBuffer != 0) && (dwNumberOfBytesWritten < dwcbBuffer))
110 if (WriteFile(hFile, pbBuffer, dwcbBuffer, &dwNumberOfBytesWritten, NULL))
112 dwcbBuffer -= dwNumberOfBytesWritten;
113 pbBuffer += dwNumberOfBytesWritten;
117 hr = HRESULT_FROM_GetLastError();
128 HRESULT DebugLog::Startup()
132 PathString logFileDir;
133 PathString logFilePath;
135 REGUTIL::CORConfigLevel kCorConfigLevel =
136 static_cast<REGUTIL::CORConfigLevel>(REGUTIL::COR_CONFIG_ENV |
137 REGUTIL::COR_CONFIG_FUSION);
138 NewArrayHolder<WCHAR> pwzLogDirectory = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_CoreClrBinderLog);
141 g_BinderVariables->m_logCS = ClrCreateCriticalSection(CrstCoreCLRBinderLog, CRST_REENTRANCY);
142 if (!g_BinderVariables->m_logCS)
144 IF_FAIL_GO(E_OUTOFMEMORY);
148 if (pwzLogDirectory == NULL)
153 logFileDir.Set(pwzLogDirectory);
155 if (WszCreateDirectory(logFileDir.GetUnicode(), NULL) ||
156 ((hr = HRESULT_FROM_GetLastError()) == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)))
161 IF_FAIL_GO(GetLogFilePath(logFileDir, logFilePath));
163 g_BinderVariables->m_hDebugLogFile = WszCreateFile(logFilePath.GetUnicode(),
168 FILE_ATTRIBUTE_NORMAL,
171 if (g_BinderVariables->m_hDebugLogFile == INVALID_HANDLE_VALUE)
179 // This is not multi-thread aware by any means. That said, neither is any of this logging mechanism.
180 static int s_scopeLevel = 0;
181 static const ANSI s_szScopeIndent[3] = " ";
184 void DebugLog::Enter(WCHAR *pwzScope)
192 info.Append(pwzScope);
193 info.Append(L": Enter");
196 EX_CATCH_HRESULT(hr);
202 void DebugLog::Leave(WCHAR *pwzScope)
212 info.Append(pwzScope);
213 info.Append(L": Leave(void)");
216 EX_CATCH_HRESULT(hr);
220 void DebugLog::LeaveHR(WCHAR *pwzScope,
231 info.Append(pwzScope);
232 info.Append(L": Leave(hr=");
233 GetStringFromHR(hrLog, info);
238 EX_CATCH_HRESULT(hr);
242 void DebugLog::LeaveBool(WCHAR *pwzScope,
253 info.Append(pwzScope);
254 info.Append(L": Leave(fResult=");
255 info.Append(fResult ? L"TRUE)" : L"FALSE)");
258 EX_CATCH_HRESULT(hr);
262 void DebugLog::Log(WCHAR *pwzComment)
270 info.Append(pwzComment);
273 EX_CATCH_HRESULT(hr);
277 void DebugLog::Log(WCHAR *pwzComment,
286 info.Append(pwzComment);
287 info.Append(L" = '");
293 EX_CATCH_HRESULT(hr);
297 void DebugLog::Log(WCHAR *pwzComment,
306 info.Append(pwzComment);
307 info.Append(L" = '");
317 void DebugLog::Log(WCHAR *pwzComment,
326 info.Append(pwzComment);
328 GetStringFromHR(hrLog, info);
332 EX_CATCH_HRESULT(hr);
336 void DebugLog::Log(WCHAR *pwzComment,
337 AssemblyName *pAssemblyName)
341 PathString assemblyDisplayName;
344 if (pAssemblyName != NULL)
346 pAssemblyName->GetDisplayName(assemblyDisplayName,
347 AssemblyName::INCLUDE_VERSION |
348 AssemblyName::INCLUDE_ARCHITECTURE |
349 AssemblyName::INCLUDE_RETARGETABLE);
353 assemblyDisplayName.Set(L"<NULL>");
356 info.Printf(L"(%d):", static_cast<INT32>(assemblyDisplayName.GetCount()));
357 info.Append(assemblyDisplayName);
359 Log(pwzComment, info);
363 Log(L"<AssemblyDisplayName: Failure>");
365 EX_END_CATCH(SwallowAllExceptions);
369 void DebugLog::Log(WCHAR *pwzComment,
378 info.Append(pwzComment);
379 info.AppendPrintf(L" = %p", pData);
382 EX_CATCH_HRESULT(hr);
386 void DebugLog::Log(SString &info)
390 StackScratchBuffer scratchBuffer;
391 const BYTE *pbRawBuffer = reinterpret_cast<const BYTE *>(info.GetANSI(scratchBuffer));
392 DWORD dwcbRawBuffer = static_cast<DWORD>(info.GetCount());
393 // Work around SString issue
394 const ANSI ansiCRLF[] = { 0x0d, 0x0a };
395 DWORD dwcbAnsiCRLF = 2 * sizeof(ANSI);
397 for (int iScope = 0; iScope < s_scopeLevel; iScope++)
399 IF_FAIL_GO(WriteToFile(g_BinderVariables->m_hDebugLogFile, reinterpret_cast<const BYTE *>(&s_szScopeIndent[0]), sizeof(s_szScopeIndent)));
401 IF_FAIL_GO(WriteToFile(g_BinderVariables->m_hDebugLogFile, pbRawBuffer, dwcbRawBuffer));
402 IF_FAIL_GO(WriteToFile(g_BinderVariables->m_hDebugLogFile,
403 reinterpret_cast<const BYTE *>(ansiCRLF),
405 // Don't cache anything
406 if (!FlushFileBuffers(g_BinderVariables->m_hDebugLogFile))
408 WszOutputDebugString(L"DebugLog::Log(info): FlushFileBuffers failed!\n");