OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 |
5 #include <windows.h> | 6 #include <windows.h> |
| 7 #include <DbgHelp.h> |
| 8 #include <string> |
6 | 9 |
7 #include "chrome_frame/chrome_launcher.h" | 10 #include "chrome_frame/chrome_launcher.h" |
| 11 #include "breakpad/src/client/windows/handler/exception_handler.h" |
8 | 12 |
9 // We want to keep this EXE tiny, so we avoid all dependencies and link to no | 13 // TODO(robertshield): Much of the crash report init code is shared with CF and |
10 // libraries, and we do not use the C runtime. | 14 // probably Chrome too. If this pans out, consider refactoring it into a |
11 // | 15 // common lib. |
12 // To catch errors in debug builds, we define an extremely simple assert macro. | |
13 #ifndef NDEBUG | |
14 #define CLM_ASSERT(x) do { if (!(x)) { ::DebugBreak(); } } while (false) | |
15 #else | |
16 #define CLM_ASSERT(x) | |
17 #endif // NDEBUG | |
18 | 16 |
19 // In release builds, we skip the standard library completely to minimize | 17 namespace { |
20 // size. This is more work in debug builds, and unnecessary, hence the | 18 |
21 // different signatures. | 19 // Possible names for Pipes: |
22 #ifndef NDEBUG | 20 // Headless (testing) mode: "NamedPipe\ChromeCrashServices" |
| 21 // System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18" |
| 22 // Per-user install: "NamedPipe\GoogleCrashServices\<user SID>" |
| 23 const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices"; |
| 24 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; |
| 25 const wchar_t kSystemPrincipalSid[] = L"S-1-5-18"; |
| 26 |
| 27 // Assume this implies headless mode and use kChromePipeName if it shows |
| 28 // up in the command line. |
| 29 const wchar_t kFullMemoryCrashReport[] = L"full-memory-crash-report"; |
| 30 |
| 31 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( |
| 32 MiniDumpWithProcessThreadData | // Get PEB and TEB. |
| 33 MiniDumpWithUnloadedModules | // Get unloaded modules when available. |
| 34 MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack. |
| 35 |
| 36 } // namespace |
| 37 |
| 38 google_breakpad::CustomClientInfo* GetCustomInfo() { |
| 39 // TODO(robertshield): Populate this with actual data. |
| 40 std::wstring product(L"ChromeFrame"); |
| 41 std::wstring version(L"0.1.0.0"); |
| 42 static google_breakpad::CustomInfoEntry ver_entry(L"ver", version.c_str()); |
| 43 static google_breakpad::CustomInfoEntry prod_entry(L"prod", product.c_str()); |
| 44 static google_breakpad::CustomInfoEntry plat_entry(L"plat", L"Win32"); |
| 45 static google_breakpad::CustomInfoEntry type_entry(L"ptype", L"chrome_frame"); |
| 46 static google_breakpad::CustomInfoEntry entries[] = { |
| 47 ver_entry, prod_entry, plat_entry, type_entry }; |
| 48 static google_breakpad::CustomClientInfo custom_info = { |
| 49 entries, arraysize(entries) }; |
| 50 return &custom_info; |
| 51 } |
| 52 |
| 53 google_breakpad::ExceptionHandler* InitializeCrashReporting( |
| 54 const wchar_t* cmd_line) { |
| 55 if (cmd_line == NULL) { |
| 56 return NULL; |
| 57 } |
| 58 |
| 59 wchar_t temp_path[MAX_PATH + 1] = {0}; |
| 60 DWORD path_len = ::GetTempPath(MAX_PATH, temp_path); |
| 61 |
| 62 std::wstring pipe_name; |
| 63 if (wcsstr(cmd_line, kFullMemoryCrashReport) != NULL) { |
| 64 pipe_name = kChromePipeName; |
| 65 } else { |
| 66 // TODO(robertshield): Figure out if we're a per-user install and connect |
| 67 // to the per-user named pipe instead. |
| 68 pipe_name = kGoogleUpdatePipeName; |
| 69 pipe_name += kSystemPrincipalSid; |
| 70 } |
| 71 |
| 72 google_breakpad::ExceptionHandler* breakpad = |
| 73 new google_breakpad::ExceptionHandler( |
| 74 temp_path, NULL, NULL, NULL, |
| 75 google_breakpad::ExceptionHandler::HANDLER_ALL, kLargerDumpType, |
| 76 pipe_name.c_str(), GetCustomInfo()); |
| 77 |
| 78 return breakpad; |
| 79 } |
| 80 |
23 int APIENTRY wWinMain(HINSTANCE, HINSTANCE, wchar_t*, int) { | 81 int APIENTRY wWinMain(HINSTANCE, HINSTANCE, wchar_t*, int) { |
24 #else | 82 const wchar_t* cmd_line = ::GetCommandLine(); |
25 extern "C" void __cdecl WinMainCRTStartup() { | |
26 #endif // NDEBUG | |
27 // This relies on the chrome_launcher.exe residing in the same directory | |
28 // as our DLL. We build a full path to avoid loading it from any other | |
29 // directory in the DLL search path. | |
30 // | |
31 // The code is a bit verbose because we can't use the standard library. | |
32 const wchar_t kBaseName[] = L"npchrome_frame.dll"; | |
33 wchar_t file_path[MAX_PATH + (sizeof(kBaseName) / sizeof(kBaseName[0])) + 1]; | |
34 file_path[0] = L'\0'; | |
35 ::GetModuleFileName(::GetModuleHandle(NULL), file_path, MAX_PATH); | |
36 | 83 |
37 // Find index of last slash, and null-terminate the string after it. | 84 google_breakpad::scoped_ptr<google_breakpad::ExceptionHandler> breakpad( |
38 // | 85 InitializeCrashReporting(cmd_line)); |
39 // Proof for security purposes, since we can't use the safe string | |
40 // manipulation functions from the runtime: | |
41 // - File_path is always null-terminated, by us initially and by | |
42 // ::GetModuleFileName if it puts anything into the buffer. | |
43 // - If there is no slash in the path then it's a relative path, not an | |
44 // absolute one, and the code ends up creating a relative path to | |
45 // npchrome_frame.dll. | |
46 // - It's safe to use lstrcatW since we know the maximum length of both | |
47 // parts we are concatenating, and we know the buffer will fit them in | |
48 // the worst case. | |
49 int slash_index = lstrlenW(file_path); | |
50 // Invariant: 0 <= slash_index < MAX_PATH | |
51 CLM_ASSERT(slash_index > 0); | |
52 while (slash_index > 0 && file_path[slash_index] != L'\\') | |
53 --slash_index; | |
54 // Invariant: 0 <= slash_index < MAX_PATH and it is either the index of | |
55 // the last \ in the path, or 0. | |
56 if (slash_index != 0) | |
57 ++slash_index; // don't remove the last '\' | |
58 file_path[slash_index] = L'\0'; | |
59 | |
60 lstrcatW(file_path, kBaseName); | |
61 | 86 |
62 UINT exit_code = ERROR_FILE_NOT_FOUND; | 87 UINT exit_code = ERROR_FILE_NOT_FOUND; |
63 HMODULE chrome_tab = ::LoadLibrary(file_path); | 88 if (chrome_launcher::SanitizeAndLaunchChrome(::GetCommandLine())) { |
64 CLM_ASSERT(chrome_tab); | 89 exit_code = ERROR_SUCCESS; |
65 if (chrome_tab) { | 90 } |
66 chrome_launcher::CfLaunchChromeProc proc = | |
67 reinterpret_cast<chrome_launcher::CfLaunchChromeProc>( | |
68 ::GetProcAddress(chrome_tab, "CfLaunchChrome")); | |
69 CLM_ASSERT(proc); | |
70 if (proc) { | |
71 exit_code = proc(); | |
72 } else { | |
73 exit_code = ERROR_INVALID_FUNCTION; | |
74 } | |
75 | 91 |
76 ::FreeLibrary(chrome_tab); | 92 return exit_code; |
77 } | |
78 ::ExitProcess(exit_code); | |
79 } | 93 } |
OLD | NEW |