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/client.h"
16 :
17 : #include <dbghelp.h>
18 : #include <stdint.h>
19 :
20 : #include <vector>
21 :
22 : #include "base/logging.h"
23 : #include "syzygy/kasko/client.h"
24 : #include "syzygy/kasko/dll_lifetime.h"
25 : #include "syzygy/kasko/minidump_request.h"
26 : #include "syzygy/kasko/api/internal/crash_key_registration.h"
27 :
28 m : namespace kasko {
29 m : namespace api {
30 :
31 m : namespace {
32 :
33 m : static_assert(sizeof(CrashKey) == 256u,
34 m : "CrashKey struct size must match that of the "
35 m : "google_breakpad::CustomInfoEntry struct.");
36 :
37 m : static_assert(kProtobufStreamType > LastReservedStream,
38 m : "kProtobufStreamType <= LastReservedStream.");
39 :
40 m : const DllLifetime* g_dll_lifetime;
41 m : const Client* g_client = nullptr;
42 :
43 : // Returns true if |buffer| is a null-terminated string whose length is greater
44 : // than 0 and less than |buffer_length|.
45 m : bool IsValidNonEmptyString(const base::char16* buffer, size_t buffer_length) {
46 m : size_t string_length = ::wcsnlen(buffer, buffer_length);
47 m : return string_length > 0 && string_length < buffer_length;
48 m : }
49 :
50 m : } // namespace
51 :
52 m : void InitializeClient(const base::char16* endpoint_name) {
53 m : DCHECK(!g_dll_lifetime);
54 m : g_dll_lifetime = new DllLifetime;
55 :
56 m : DCHECK(!g_client);
57 m : DCHECK(endpoint_name);
58 m : g_client = new Client(endpoint_name);
59 m : }
60 :
61 m : void RegisterCrashKeys(const CrashKey* crash_keys, size_t count) {
62 m : internal::RegisterCrashKeys(crash_keys, count);
63 m : }
64 :
65 m : void SendReport(const EXCEPTION_POINTERS* exception_pointers,
66 m : MinidumpType minidump_type,
67 m : const char* protobuf,
68 m : size_t protobuf_length,
69 m : const CrashKey* crash_keys,
70 m : size_t crash_key_count,
71 m : const MemoryRange* user_selected_memory_ranges,
72 m : size_t user_selected_memory_range_count) {
73 m : if (!g_client) {
74 m : LOG(ERROR) << "SendReport failed: uninitialized.";
75 m : return;
76 m : }
77 :
78 m : MinidumpRequest request;
79 m : request.client_exception_pointers = true;
80 m : request.exception_info_address =
81 m : reinterpret_cast<uint32_t>(exception_pointers);
82 m : if (protobuf_length) {
83 m : MinidumpRequest::CustomStream custom_stream = {kProtobufStreamType,
84 m : protobuf, protobuf_length};
85 m : request.custom_streams.push_back(custom_stream);
86 m : }
87 :
88 m : for (size_t i = 0; i < crash_key_count; ++i) {
89 m : if (!IsValidNonEmptyString(crash_keys[i].name,
90 m : arraysize(crash_keys[i].name)) ||
91 m : !IsValidNonEmptyString(crash_keys[i].value,
92 m : arraysize(crash_keys[i].value))) {
93 m : continue;
94 m : }
95 m : request.crash_keys.push_back(
96 m : MinidumpRequest::CrashKey(crash_keys[i].name, crash_keys[i].value));
97 m : }
98 :
99 m : for (size_t i = 0; i < user_selected_memory_range_count; ++i) {
100 m : MinidumpRequest::MemoryRange memory_range = {
101 m : reinterpret_cast<uint32_t>(user_selected_memory_ranges[i].base_address),
102 m : user_selected_memory_ranges[i].length};
103 m : request.user_selected_memory_ranges.push_back(memory_range);
104 m : }
105 :
106 m : switch (minidump_type) {
107 m : case SMALL_DUMP_TYPE:
108 m : request.type = MinidumpRequest::SMALL_DUMP_TYPE;
109 m : break;
110 m : case LARGER_DUMP_TYPE:
111 m : request.type = MinidumpRequest::LARGER_DUMP_TYPE;
112 m : break;
113 m : case FULL_DUMP_TYPE:
114 m : request.type = MinidumpRequest::FULL_DUMP_TYPE;
115 m : break;
116 m : default:
117 m : NOTREACHED();
118 m : break;
119 m : }
120 :
121 m : g_client->SendReport(request);
122 m : }
123 :
124 m : void ShutdownClient() {
125 m : DCHECK(g_client);
126 m : delete g_client;
127 m : g_client = nullptr;
128 :
129 m : DCHECK(g_dll_lifetime);
130 m : delete g_dll_lifetime;
131 m : g_dll_lifetime = nullptr;
132 m : }
133 :
134 m : } // namespace api
135 m : } // namespace kasko
|