1 : // Copyright 2014 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/kasko/api/reporter.h"
16 :
17 : #include <stdint.h>
18 :
19 : #include <map>
20 : #include <vector>
21 :
22 : #include "base/bind.h"
23 : #include "base/bind_helpers.h"
24 : #include "base/environment.h"
25 : #include "base/logging.h"
26 : #include "base/files/file_path.h"
27 : #include "base/memory/scoped_ptr.h"
28 : #include "base/strings/string_number_conversions.h"
29 : #include "base/time/time.h"
30 : #include "base/win/scoped_handle.h"
31 : #include "syzygy/kasko/dll_lifetime.h"
32 : #include "syzygy/kasko/minidump.h"
33 : #include "syzygy/kasko/minidump_request.h"
34 : #include "syzygy/kasko/reporter.h"
35 : #include "syzygy/kasko/api/crash_key.h"
36 : #include "syzygy/kasko/api/internal/crash_key_registration.h"
37 :
38 : namespace kasko {
39 : namespace api {
40 : namespace {
41 :
42 : // Default upload and retry times. These can be overridden by an environment
43 : // variable.
44 : const uint16_t kDefaultUploadDelayInSeconds = 180;
45 : const uint16_t kDefaultRetryIntervalInMinutes = 180;
46 :
47 : // Environment variables for overriding the above times.
48 : const char kEnvUploadDelayInSeconds[] = "KASKO_UPLOAD_DELAY_IN_SECONDS";
49 : const char kEnvRetryIntervalInMinutes[] = "KASKO_RETRY_INTERVAL_IN_MINUTES";
50 :
51 : const DllLifetime* g_dll_lifetime;
52 : Reporter* g_reporter;
53 :
54 : void InvokeOnUploadProc(
55 : OnUploadProc* on_upload_proc,
56 : void* on_upload_context,
57 : const base::string16& report_id,
58 : const base::FilePath& minidump_path,
59 E : const std::map<base::string16, base::string16>& crash_keys) {
60 E : std::vector<const base::char16*> crash_key_names;
61 E : std::vector<const base::char16*> crash_key_values;
62 E : crash_key_names.reserve(crash_keys.size() + 1);
63 E : crash_key_values.reserve(crash_keys.size() + 1);
64 :
65 E : for (const auto& entry : crash_keys) {
66 E : crash_key_names.push_back(entry.first.c_str());
67 E : crash_key_values.push_back(entry.second.c_str());
68 E : }
69 E : crash_key_names.push_back(nullptr);
70 E : crash_key_values.push_back(nullptr);
71 :
72 : on_upload_proc(on_upload_context, report_id.c_str(),
73 : minidump_path.value().c_str(), crash_key_names.data(),
74 E : crash_key_values.data());
75 E : }
76 :
77 : // Returns an integer value from the environment. If not present or malformed,
78 : // returns the specified default. Only allows positive values.
79 : int64_t GetIntegerFromEnvironment(const char* key_name,
80 E : int64_t default_value) {
81 E : scoped_ptr<base::Environment> env(base::Environment::Create());
82 E : std::string value;
83 E : if (!env->GetVar(key_name, &value))
84 E : return default_value;
85 :
86 i : int64_t i = 0;
87 i : if (!base::StringToInt64(value, &i))
88 i : return default_value;
89 :
90 i : if (i <= 0)
91 i : return default_value;
92 :
93 i : return i;
94 E : }
95 :
96 : } // namespace
97 :
98 : const base::char16* const kPermanentFailureCrashKeysExtension =
99 E : Reporter::kPermanentFailureCrashKeysExtension;
100 : const base::char16* const kPermanentFailureMinidumpExtension =
101 E : Reporter::kPermanentFailureMinidumpExtension;
102 :
103 : bool InitializeReporter(const base::char16* endpoint_name,
104 : const base::char16* url,
105 : const base::char16* data_directory,
106 : const base::char16* permanent_failure_directory,
107 : OnUploadProc* on_upload_proc,
108 E : void* on_upload_context) {
109 E : DCHECK(!g_dll_lifetime);
110 E : g_dll_lifetime = new DllLifetime;
111 :
112 E : Reporter::OnUploadCallback on_upload_callback;
113 :
114 E : if (on_upload_proc) {
115 : on_upload_callback =
116 : base::Bind(&InvokeOnUploadProc, base::Unretained(on_upload_proc),
117 E : base::Unretained(on_upload_context));
118 : }
119 :
120 :
121 : int64_t upload_delay = GetIntegerFromEnvironment(
122 E : kEnvUploadDelayInSeconds, kDefaultUploadDelayInSeconds);
123 : int64_t retry_interval = GetIntegerFromEnvironment(
124 E : kEnvRetryIntervalInMinutes, kDefaultRetryIntervalInMinutes);
125 E : DCHECK(!g_reporter);
126 : g_reporter =
127 : Reporter::Create(endpoint_name, url, base::FilePath(data_directory),
128 : base::FilePath(permanent_failure_directory),
129 : base::TimeDelta::FromSeconds(upload_delay),
130 : base::TimeDelta::FromMinutes(retry_interval),
131 : on_upload_callback)
132 E : .release();
133 :
134 E : return g_reporter != nullptr;
135 E : }
136 :
137 : void SendReportForProcess(base::ProcessHandle process_handle,
138 : base::PlatformThreadId thread_id,
139 : const EXCEPTION_POINTERS* exception_pointers,
140 : MinidumpType minidump_type,
141 : const base::char16* const* keys,
142 E : const base::char16* const* values) {
143 E : DCHECK(g_reporter);
144 E : if (!g_reporter)
145 i : return;
146 E : DCHECK_EQ(keys == nullptr, values == nullptr);
147 :
148 E : MinidumpRequest request;
149 :
150 : request.exception_info_address =
151 E : reinterpret_cast<uint32_t>(exception_pointers);
152 :
153 E : if (keys != nullptr && values != nullptr) {
154 E : size_t i = 0;
155 E : for (; keys[i] && values[i]; ++i) {
156 E : if (keys[i][0] == 0 || values[i][0] == 0)
157 E : continue;
158 : request.crash_keys.push_back(
159 E : MinidumpRequest::CrashKey(keys[i], values[i]));
160 E : }
161 E : DCHECK(!keys[i]);
162 E : DCHECK(!values[i]);
163 : }
164 :
165 : // Reopen the process handle with the necessary access level to read memory
166 : // and create a minidump.
167 : base::win::ScopedHandle augmented_process_handle(
168 : ::OpenProcess(GetRequiredAccessForMinidumpType(minidump_type), FALSE,
169 E : base::GetProcId(process_handle)));
170 E : if (!augmented_process_handle.IsValid())
171 i : return;
172 :
173 E : std::vector<CrashKey> registered_crash_keys;
174 : if (internal::ReadCrashKeysFromProcess(augmented_process_handle.Get(),
175 E : ®istered_crash_keys)) {
176 E : for (auto& crash_key : registered_crash_keys) {
177 E : if (crash_key.name[0] == 0 || crash_key.value[0] == 0)
178 E : continue;
179 : request.crash_keys.push_back(
180 E : MinidumpRequest::CrashKey(crash_key.name, crash_key.value));
181 E : }
182 : }
183 :
184 E : switch (minidump_type) {
185 : case SMALL_DUMP_TYPE:
186 E : request.type = MinidumpRequest::SMALL_DUMP_TYPE;
187 E : break;
188 : case LARGER_DUMP_TYPE:
189 i : request.type = MinidumpRequest::LARGER_DUMP_TYPE;
190 i : break;
191 : case FULL_DUMP_TYPE:
192 i : request.type = MinidumpRequest::FULL_DUMP_TYPE;
193 i : break;
194 : default:
195 i : NOTREACHED();
196 : break;
197 : }
198 :
199 : g_reporter->SendReportForProcess(augmented_process_handle.Get(), thread_id,
200 E : request);
201 E : }
202 :
203 E : void ShutdownReporter() {
204 E : scoped_ptr<Reporter> reporter(g_reporter);
205 E : g_reporter = nullptr;
206 E : Reporter::Shutdown(reporter.Pass());
207 :
208 E : DCHECK(g_dll_lifetime);
209 E : delete g_dll_lifetime;
210 E : g_dll_lifetime = nullptr;
211 E : }
212 :
213 : } // namespace api
214 : } // namespace kasko
|