1eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// Copyright (c) 2008, Google Inc. 2eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// All rights reserved. 3eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// 4eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// Redistribution and use in source and binary forms, with or without 5eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// modification, are permitted provided that the following conditions are 6eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// met: 7eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// 8eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// * Redistributions of source code must retain the above copyright 9eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// notice, this list of conditions and the following disclaimer. 10eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// * Redistributions in binary form must reproduce the above 11eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// copyright notice, this list of conditions and the following disclaimer 12eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// in the documentation and/or other materials provided with the 13eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// distribution. 14eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// * Neither the name of Google Inc. nor the names of its 15eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// contributors may be used to endorse or promote products derived from 16eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// this software without specific prior written permission. 17eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// 18eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai 30eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai#include "client/windows/crash_generation/client_info.h" 310ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun#include "client/windows/common/ipc_protocol.h" 32eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai 333a516e41775099eb27533e7d2b3178c5f353a3a8doshimunstatic const wchar_t kCustomInfoProcessUptimeName[] = L"ptime"; 3414ec03a395dc6b0c9784e0e86ff4574cbe3d3795cdn@chromium.orgstatic const size_t kMaxCustomInfoEntries = 4096; 353a516e41775099eb27533e7d2b3178c5f353a3a8doshimun 36eeca9921c563d802cccc5593bf55dcb7683e7250mmentovainamespace google_breakpad { 37eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai 38eeca9921c563d802cccc5593bf55dcb7683e7250mmentovaiClientInfo::ClientInfo(CrashGenerationServer* crash_server, 39eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai DWORD pid, 40eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai MINIDUMP_TYPE dump_type, 41eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai DWORD* thread_id, 42eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai EXCEPTION_POINTERS** ex_info, 430ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun MDRawAssertionInfo* assert_info, 440ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun const CustomClientInfo& custom_client_info) 45eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai : crash_server_(crash_server), 46eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai pid_(pid), 47eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai dump_type_(dump_type), 48eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai ex_info_(ex_info), 49eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai assert_info_(assert_info), 500ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun custom_client_info_(custom_client_info), 51eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai thread_id_(thread_id), 52eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai process_handle_(NULL), 53eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai dump_requested_handle_(NULL), 54eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai dump_generated_handle_(NULL), 55eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai dump_request_wait_handle_(NULL), 56eb991531e31b7c001200cf23ce07efc5a32b41aecdn@chromium.org process_exit_wait_handle_(NULL), 57eb991531e31b7c001200cf23ce07efc5a32b41aecdn@chromium.org crash_id_(NULL) { 583a516e41775099eb27533e7d2b3178c5f353a3a8doshimun GetSystemTimeAsFileTime(&start_time_); 59eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai} 60eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai 61eeca9921c563d802cccc5593bf55dcb7683e7250mmentovaibool ClientInfo::Initialize() { 6272bafd378d836d9a1fe81a1f26c91d51b2a7892bdoshimun process_handle_ = OpenProcess(GENERIC_ALL, FALSE, pid_); 63eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai if (!process_handle_) { 64eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai return false; 65eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai } 66eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai 67eb991531e31b7c001200cf23ce07efc5a32b41aecdn@chromium.org // The crash_id will be the low order word of the process creation time. 68eb991531e31b7c001200cf23ce07efc5a32b41aecdn@chromium.org FILETIME creation_time, exit_time, kernel_time, user_time; 69eb991531e31b7c001200cf23ce07efc5a32b41aecdn@chromium.org if (GetProcessTimes(process_handle_, &creation_time, &exit_time, 706afe338f2355bf1bbe4b8f869aeb16b093ae2ab2ivanpe@chromium.org &kernel_time, &user_time)) { 716afe338f2355bf1bbe4b8f869aeb16b093ae2ab2ivanpe@chromium.org start_time_ = creation_time; 726afe338f2355bf1bbe4b8f869aeb16b093ae2ab2ivanpe@chromium.org } 736afe338f2355bf1bbe4b8f869aeb16b093ae2ab2ivanpe@chromium.org crash_id_ = start_time_.dwLowDateTime; 74eb991531e31b7c001200cf23ce07efc5a32b41aecdn@chromium.org 75eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai dump_requested_handle_ = CreateEvent(NULL, // Security attributes. 76eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai TRUE, // Manual reset. 77eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai FALSE, // Initial state. 78eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai NULL); // Name. 79eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai if (!dump_requested_handle_) { 80eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai return false; 81eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai } 82eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai 83eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai dump_generated_handle_ = CreateEvent(NULL, // Security attributes. 84eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai TRUE, // Manual reset. 85eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai FALSE, // Initial state. 86eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai NULL); // Name. 87eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai return dump_generated_handle_ != NULL; 88eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai} 89eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai 9055cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.comvoid ClientInfo::UnregisterDumpRequestWaitAndBlockUntilNoPending() { 912d7664e8d477816e0641e822752f63982c1be74fdoshimun if (dump_request_wait_handle_) { 922d7664e8d477816e0641e822752f63982c1be74fdoshimun // Wait for callbacks that might already be running to finish. 932d7664e8d477816e0641e822752f63982c1be74fdoshimun UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE); 9455cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com dump_request_wait_handle_ = NULL; 952d7664e8d477816e0641e822752f63982c1be74fdoshimun } 9655cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com} 972d7664e8d477816e0641e822752f63982c1be74fdoshimun 9855cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.comvoid ClientInfo::UnregisterProcessExitWait(bool block_until_no_pending) { 992d7664e8d477816e0641e822752f63982c1be74fdoshimun if (process_exit_wait_handle_) { 10055cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com if (block_until_no_pending) { 10155cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com // Wait for the callback that might already be running to finish. 10255cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com UnregisterWaitEx(process_exit_wait_handle_, INVALID_HANDLE_VALUE); 10355cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com } else { 10455cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com UnregisterWait(process_exit_wait_handle_); 10555cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com } 10655cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com process_exit_wait_handle_ = NULL; 1072d7664e8d477816e0641e822752f63982c1be74fdoshimun } 10855cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com} 10955cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com 11055cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.comClientInfo::~ClientInfo() { 11155cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com // Waiting for the callback to finish here is safe because ClientInfo's are 11255cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com // never destroyed from the dump request handling callback. 11355cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com UnregisterDumpRequestWaitAndBlockUntilNoPending(); 11455cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com 11555cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com // This is a little tricky because ClientInfo's may be destroyed by the same 11655cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com // callback (OnClientEnd) and waiting for it to finish will cause a deadlock. 11755cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com // Regardless of this complication, wait for any running callbacks to finish 11855cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com // so that the common case is properly handled. In order to avoid deadlocks, 11955cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com // the OnClientEnd callback must call UnregisterProcessExitWait(false) 12055cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com // before deleting the ClientInfo. 12155cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com UnregisterProcessExitWait(true); 1222d7664e8d477816e0641e822752f63982c1be74fdoshimun 123eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai if (process_handle_) { 124eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai CloseHandle(process_handle_); 125eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai } 126eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai 127eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai if (dump_requested_handle_) { 128eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai CloseHandle(dump_requested_handle_); 129eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai } 130eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai 131eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai if (dump_generated_handle_) { 132eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai CloseHandle(dump_generated_handle_); 133eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai } 134eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai} 135eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai 1360ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimunbool ClientInfo::GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const { 137eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai SIZE_T bytes_count = 0; 138eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai if (!ReadProcessMemory(process_handle_, 139eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai ex_info_, 140eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai ex_info, 141eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai sizeof(*ex_info), 142eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai &bytes_count)) { 143eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai return false; 144eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai } 145eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai 146eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai return bytes_count == sizeof(*ex_info); 147eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai} 148eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai 149eeca9921c563d802cccc5593bf55dcb7683e7250mmentovaibool ClientInfo::GetClientThreadId(DWORD* thread_id) const { 150eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai SIZE_T bytes_count = 0; 151eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai if (!ReadProcessMemory(process_handle_, 152eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai thread_id_, 153eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai thread_id, 154eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai sizeof(*thread_id), 155eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai &bytes_count)) { 156eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai return false; 157eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai } 158eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai 159eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai return bytes_count == sizeof(*thread_id); 160eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai} 161eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai 1623a516e41775099eb27533e7d2b3178c5f353a3a8doshimunvoid ClientInfo::SetProcessUptime() { 1633a516e41775099eb27533e7d2b3178c5f353a3a8doshimun FILETIME now = {0}; 1643a516e41775099eb27533e7d2b3178c5f353a3a8doshimun GetSystemTimeAsFileTime(&now); 1653a516e41775099eb27533e7d2b3178c5f353a3a8doshimun 1663a516e41775099eb27533e7d2b3178c5f353a3a8doshimun ULARGE_INTEGER time_start; 1673a516e41775099eb27533e7d2b3178c5f353a3a8doshimun time_start.HighPart = start_time_.dwHighDateTime; 1683a516e41775099eb27533e7d2b3178c5f353a3a8doshimun time_start.LowPart = start_time_.dwLowDateTime; 1693a516e41775099eb27533e7d2b3178c5f353a3a8doshimun 1703a516e41775099eb27533e7d2b3178c5f353a3a8doshimun ULARGE_INTEGER time_now; 1713a516e41775099eb27533e7d2b3178c5f353a3a8doshimun time_now.HighPart = now.dwHighDateTime; 1723a516e41775099eb27533e7d2b3178c5f353a3a8doshimun time_now.LowPart = now.dwLowDateTime; 1733a516e41775099eb27533e7d2b3178c5f353a3a8doshimun 1743a516e41775099eb27533e7d2b3178c5f353a3a8doshimun // Calculate the delay and convert it from 100-nanoseconds to milliseconds. 1753a516e41775099eb27533e7d2b3178c5f353a3a8doshimun __int64 delay = (time_now.QuadPart - time_start.QuadPart) / 10 / 1000; 1763a516e41775099eb27533e7d2b3178c5f353a3a8doshimun 1773a516e41775099eb27533e7d2b3178c5f353a3a8doshimun // Convert it to a string. 1783a516e41775099eb27533e7d2b3178c5f353a3a8doshimun wchar_t* value = custom_info_entries_.get()[custom_client_info_.count].value; 1793a516e41775099eb27533e7d2b3178c5f353a3a8doshimun _i64tow_s(delay, value, CustomInfoEntry::kValueMaxLength, 10); 1803a516e41775099eb27533e7d2b3178c5f353a3a8doshimun} 1813a516e41775099eb27533e7d2b3178c5f353a3a8doshimun 1820ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimunbool ClientInfo::PopulateCustomInfo() { 18314ec03a395dc6b0c9784e0e86ff4574cbe3d3795cdn@chromium.org if (custom_client_info_.count > kMaxCustomInfoEntries) 18414ec03a395dc6b0c9784e0e86ff4574cbe3d3795cdn@chromium.org return false; 18514ec03a395dc6b0c9784e0e86ff4574cbe3d3795cdn@chromium.org 1860ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun SIZE_T bytes_count = 0; 1870ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun SIZE_T read_count = sizeof(CustomInfoEntry) * custom_client_info_.count; 1880ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun 1890ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun // If the scoped array for custom info already has an array, it will be 1900ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun // the same size as what we need. This is because the number of custom info 1910ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun // entries is always the same. So allocate memory only if scoped array has 1920ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun // a NULL pointer. 1930ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun if (!custom_info_entries_.get()) { 1943a516e41775099eb27533e7d2b3178c5f353a3a8doshimun // Allocate an extra entry for reporting uptime for the client process. 1953a516e41775099eb27533e7d2b3178c5f353a3a8doshimun custom_info_entries_.reset( 1963a516e41775099eb27533e7d2b3178c5f353a3a8doshimun new CustomInfoEntry[custom_client_info_.count + 1]); 1973a516e41775099eb27533e7d2b3178c5f353a3a8doshimun // Use the last element in the array for uptime. 1983a516e41775099eb27533e7d2b3178c5f353a3a8doshimun custom_info_entries_.get()[custom_client_info_.count].set_name( 1993a516e41775099eb27533e7d2b3178c5f353a3a8doshimun kCustomInfoProcessUptimeName); 2000ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun } 2010ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun 2020ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun if (!ReadProcessMemory(process_handle_, 2030ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun custom_client_info_.entries, 2040ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun custom_info_entries_.get(), 2050ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun read_count, 2060ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun &bytes_count)) { 2070ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun return false; 2080ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun } 2090ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun 2103a516e41775099eb27533e7d2b3178c5f353a3a8doshimun SetProcessUptime(); 211c20745c254b0934520c5c45de9fdf0c4cbce54fdivan.penkov@gmail.com return (bytes_count == read_count); 2120ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun} 2130ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun 2147ab126ecdd5237ccd566f415cc560b39f87e8a0fdoshimunCustomClientInfo ClientInfo::GetCustomInfo() const { 2157ab126ecdd5237ccd566f415cc560b39f87e8a0fdoshimun CustomClientInfo custom_info; 2167ab126ecdd5237ccd566f415cc560b39f87e8a0fdoshimun custom_info.entries = custom_info_entries_.get(); 2173a516e41775099eb27533e7d2b3178c5f353a3a8doshimun // Add 1 to the count from the client process to account for extra entry for 2183a516e41775099eb27533e7d2b3178c5f353a3a8doshimun // process uptime. 2193a516e41775099eb27533e7d2b3178c5f353a3a8doshimun custom_info.count = custom_client_info_.count + 1; 2207ab126ecdd5237ccd566f415cc560b39f87e8a0fdoshimun return custom_info; 2210ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun} 2220ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun 223eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai} // namespace google_breakpad 224