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 <memory>
21 : #include <vector>
22 :
23 : #include "base/bind.h"
24 : #include "base/bind_helpers.h"
25 : #include "base/environment.h"
26 : #include "base/logging.h"
27 : #include "base/files/file_path.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 m : namespace kasko {
39 m : namespace api {
40 m : namespace {
41 :
42 : // Default upload and retry times. These can be overridden by an environment
43 : // variable.
44 m : const uint16_t kDefaultUploadDelayInSeconds = 180;
45 m : const uint16_t kDefaultRetryIntervalInMinutes = 180;
46 :
47 : // Environment variables for overriding the above times.
48 m : const char kEnvUploadDelayInSeconds[] = "KASKO_UPLOAD_DELAY_IN_SECONDS";
49 m : const char kEnvRetryIntervalInMinutes[] = "KASKO_RETRY_INTERVAL_IN_MINUTES";
50 :
51 m : const DllLifetime* g_dll_lifetime;
52 m : Reporter* g_reporter;
53 :
54 m : void InvokeOnUploadProc(
55 m : OnUploadProc* on_upload_proc,
56 m : void* on_upload_context,
57 m : const base::string16& report_id,
58 m : const base::FilePath& minidump_path,
59 m : const std::map<base::string16, base::string16>& crash_keys) {
60 m : std::vector<const base::char16*> crash_key_names;
61 m : std::vector<const base::char16*> crash_key_values;
62 m : crash_key_names.reserve(crash_keys.size() + 1);
63 m : crash_key_values.reserve(crash_keys.size() + 1);
64 :
65 m : for (const auto& entry : crash_keys) {
66 m : crash_key_names.push_back(entry.first.c_str());
67 m : crash_key_values.push_back(entry.second.c_str());
68 m : }
69 m : crash_key_names.push_back(nullptr);
70 m : crash_key_values.push_back(nullptr);
71 :
72 m : on_upload_proc(on_upload_context, report_id.c_str(),
73 m : minidump_path.value().c_str(), crash_key_names.data(),
74 m : crash_key_values.data());
75 m : }
76 :
77 : // Returns an integer value from the environment. If not present or malformed,
78 : // returns the specified default. Only allows positive values.
79 m : int64_t GetIntegerFromEnvironment(const char* key_name,
80 m : int64_t default_value) {
81 m : std::unique_ptr<base::Environment> env(base::Environment::Create());
82 m : std::string value;
83 m : if (!env->GetVar(key_name, &value))
84 m : return default_value;
85 :
86 m : int64_t i = 0;
87 m : if (!base::StringToInt64(value, &i))
88 m : return default_value;
89 :
90 m : if (i <= 0)
91 m : return default_value;
92 :
93 m : return i;
94 m : }
95 :
96 m : } // namespace
97 :
98 m : const base::char16* const kPermanentFailureCrashKeysExtension =
99 m : Reporter::kPermanentFailureCrashKeysExtension;
100 m : const base::char16* const kPermanentFailureMinidumpExtension =
101 m : Reporter::kPermanentFailureMinidumpExtension;
102 :
103 m : bool InitializeReporter(const base::char16* endpoint_name,
104 m : const base::char16* url,
105 m : const base::char16* data_directory,
106 m : const base::char16* permanent_failure_directory,
107 m : OnUploadProc* on_upload_proc,
108 m : void* on_upload_context) {
109 m : DCHECK(!g_dll_lifetime);
110 m : g_dll_lifetime = new DllLifetime;
111 :
112 m : Reporter::OnUploadCallback on_upload_callback;
113 :
114 m : if (on_upload_proc) {
115 m : on_upload_callback =
116 m : base::Bind(&InvokeOnUploadProc, base::Unretained(on_upload_proc),
117 m : base::Unretained(on_upload_context));
118 m : }
119 :
120 :
121 m : int64_t upload_delay = GetIntegerFromEnvironment(
122 m : kEnvUploadDelayInSeconds, kDefaultUploadDelayInSeconds);
123 m : int64_t retry_interval = GetIntegerFromEnvironment(
124 m : kEnvRetryIntervalInMinutes, kDefaultRetryIntervalInMinutes);
125 m : DCHECK(!g_reporter);
126 m : g_reporter =
127 m : Reporter::Create(endpoint_name, url, base::FilePath(data_directory),
128 m : base::FilePath(permanent_failure_directory),
129 m : base::TimeDelta::FromSeconds(upload_delay),
130 m : base::TimeDelta::FromMinutes(retry_interval),
131 m : on_upload_callback)
132 m : .release();
133 :
134 m : return g_reporter != nullptr;
135 m : }
136 :
137 m : void SendReportForProcess(base::ProcessHandle process_handle,
138 m : base::PlatformThreadId thread_id,
139 m : const EXCEPTION_POINTERS* exception_pointers,
140 m : MinidumpType minidump_type,
141 m : const base::char16* const* keys,
142 m : const base::char16* const* values) {
143 m : DCHECK(g_reporter);
144 m : if (!g_reporter)
145 m : return;
146 m : DCHECK_EQ(keys == nullptr, values == nullptr);
147 :
148 m : MinidumpRequest request;
149 :
150 m : request.exception_info_address =
151 m : reinterpret_cast<uint32_t>(exception_pointers);
152 :
153 m : if (keys != nullptr && values != nullptr) {
154 m : size_t i = 0;
155 m : for (; keys[i] && values[i]; ++i) {
156 m : if (keys[i][0] == 0 || values[i][0] == 0)
157 m : continue;
158 m : request.crash_keys.push_back(
159 m : MinidumpRequest::CrashKey(keys[i], values[i]));
160 m : }
161 m : DCHECK(!keys[i]);
162 m : DCHECK(!values[i]);
163 m : }
164 :
165 : // Reopen the process handle with the necessary access level to read memory
166 : // and create a minidump.
167 m : base::win::ScopedHandle augmented_process_handle(
168 m : ::OpenProcess(GetRequiredAccessForMinidumpType(minidump_type), FALSE,
169 m : base::GetProcId(process_handle)));
170 m : if (!augmented_process_handle.IsValid())
171 m : return;
172 :
173 m : std::vector<CrashKey> registered_crash_keys;
174 m : if (internal::ReadCrashKeysFromProcess(augmented_process_handle.Get(),
175 m : ®istered_crash_keys)) {
176 m : for (auto& crash_key : registered_crash_keys) {
177 m : if (crash_key.name[0] == 0 || crash_key.value[0] == 0)
178 m : continue;
179 m : request.crash_keys.push_back(
180 m : MinidumpRequest::CrashKey(crash_key.name, crash_key.value));
181 m : }
182 m : }
183 :
184 m : switch (minidump_type) {
185 m : case SMALL_DUMP_TYPE:
186 m : request.type = MinidumpRequest::SMALL_DUMP_TYPE;
187 m : break;
188 m : case LARGER_DUMP_TYPE:
189 m : request.type = MinidumpRequest::LARGER_DUMP_TYPE;
190 m : break;
191 m : case FULL_DUMP_TYPE:
192 m : request.type = MinidumpRequest::FULL_DUMP_TYPE;
193 m : break;
194 m : default:
195 m : NOTREACHED();
196 m : break;
197 m : }
198 :
199 m : g_reporter->SendReportForProcess(augmented_process_handle.Get(), thread_id,
200 m : request);
201 m : }
202 :
203 m : void ShutdownReporter() {
204 m : std::unique_ptr<Reporter> reporter(g_reporter);
205 m : g_reporter = nullptr;
206 m : Reporter::Shutdown(std::move(reporter));
207 :
208 m : DCHECK(g_dll_lifetime);
209 m : delete g_dll_lifetime;
210 m : g_dll_lifetime = nullptr;
211 m : }
212 :
213 m : } // namespace api
214 m : } // namespace kasko
|