Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / base / debug / crash_logging.cc
blob058b476800da3a65bd35f3b6cb2f804533986e26
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/debug/crash_logging.h"
7 #include <cmath>
8 #include <map>
10 #include "base/debug/stack_trace.h"
11 #include "base/format_macros.h"
12 #include "base/logging.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
16 namespace base {
17 namespace debug {
19 namespace {
21 // Global map of crash key names to registration entries.
22 typedef std::map<base::StringPiece, CrashKey> CrashKeyMap;
23 CrashKeyMap* g_crash_keys_ = NULL;
25 // The maximum length of a single chunk.
26 size_t g_chunk_max_length_ = 0;
28 // String used to format chunked key names.
29 const char kChunkFormatString[] = "%s-%" PRIuS;
31 // The functions that are called to actually set the key-value pairs in the
32 // crash reportng system.
33 SetCrashKeyValueFuncT g_set_key_func_ = NULL;
34 ClearCrashKeyValueFuncT g_clear_key_func_ = NULL;
36 // For a given |length|, computes the number of chunks a value of that size
37 // will occupy.
38 size_t NumChunksForLength(size_t length) {
39 // Compute (length / g_chunk_max_length_), rounded up.
40 return (length + g_chunk_max_length_ - 1) / g_chunk_max_length_;
43 // The longest max_length allowed by the system.
44 const size_t kLargestValueAllowed = 1024;
46 } // namespace
48 void SetCrashKeyValue(const base::StringPiece& key,
49 const base::StringPiece& value) {
50 if (!g_set_key_func_ || !g_crash_keys_)
51 return;
53 const CrashKey* crash_key = LookupCrashKey(key);
55 DCHECK(crash_key) << "All crash keys must be registered before use "
56 << "(key = " << key << ")";
58 // Handle the un-chunked case.
59 if (!crash_key || crash_key->max_length <= g_chunk_max_length_) {
60 g_set_key_func_(key, value);
61 return;
64 // Unset the unused chunks.
65 std::vector<std::string> chunks =
66 ChunkCrashKeyValue(*crash_key, value, g_chunk_max_length_);
67 for (size_t i = chunks.size();
68 i < NumChunksForLength(crash_key->max_length);
69 ++i) {
70 g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1));
73 // Set the chunked keys.
74 for (size_t i = 0; i < chunks.size(); ++i) {
75 g_set_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1),
76 chunks[i]);
80 void ClearCrashKey(const base::StringPiece& key) {
81 if (!g_clear_key_func_ || !g_crash_keys_)
82 return;
84 const CrashKey* crash_key = LookupCrashKey(key);
86 // Handle the un-chunked case.
87 if (!crash_key || crash_key->max_length <= g_chunk_max_length_) {
88 g_clear_key_func_(key);
89 return;
92 for (size_t i = 0; i < NumChunksForLength(crash_key->max_length); ++i) {
93 g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1));
97 void SetCrashKeyToStackTrace(const base::StringPiece& key,
98 const StackTrace& trace) {
99 size_t count = 0;
100 const void* const* addresses = trace.Addresses(&count);
101 SetCrashKeyFromAddresses(key, addresses, count);
104 void SetCrashKeyFromAddresses(const base::StringPiece& key,
105 const void* const* addresses,
106 size_t count) {
107 std::string value = "<null>";
108 if (addresses && count) {
109 const size_t kBreakpadValueMax = 255;
111 std::vector<std::string> hex_backtrace;
112 size_t length = 0;
114 for (size_t i = 0; i < count; ++i) {
115 std::string s = base::StringPrintf("%p", addresses[i]);
116 length += s.length() + 1;
117 if (length > kBreakpadValueMax)
118 break;
119 hex_backtrace.push_back(s);
122 value = base::JoinString(hex_backtrace, " ");
124 // Warn if this exceeds the breakpad limits.
125 DCHECK_LE(value.length(), kBreakpadValueMax);
128 SetCrashKeyValue(key, value);
131 ScopedCrashKey::ScopedCrashKey(const base::StringPiece& key,
132 const base::StringPiece& value)
133 : key_(key.as_string()) {
134 SetCrashKeyValue(key, value);
137 ScopedCrashKey::~ScopedCrashKey() {
138 ClearCrashKey(key_);
141 size_t InitCrashKeys(const CrashKey* const keys, size_t count,
142 size_t chunk_max_length) {
143 DCHECK(!g_crash_keys_) << "Crash logging may only be initialized once";
144 if (!keys) {
145 delete g_crash_keys_;
146 g_crash_keys_ = NULL;
147 return 0;
150 g_crash_keys_ = new CrashKeyMap;
151 g_chunk_max_length_ = chunk_max_length;
153 size_t total_keys = 0;
154 for (size_t i = 0; i < count; ++i) {
155 g_crash_keys_->insert(std::make_pair(keys[i].key_name, keys[i]));
156 total_keys += NumChunksForLength(keys[i].max_length);
157 DCHECK_LT(keys[i].max_length, kLargestValueAllowed);
159 DCHECK_EQ(count, g_crash_keys_->size())
160 << "Duplicate crash keys were registered";
162 return total_keys;
165 const CrashKey* LookupCrashKey(const base::StringPiece& key) {
166 if (!g_crash_keys_)
167 return NULL;
168 CrashKeyMap::const_iterator it = g_crash_keys_->find(key.as_string());
169 if (it == g_crash_keys_->end())
170 return NULL;
171 return &(it->second);
174 void SetCrashKeyReportingFunctions(
175 SetCrashKeyValueFuncT set_key_func,
176 ClearCrashKeyValueFuncT clear_key_func) {
177 g_set_key_func_ = set_key_func;
178 g_clear_key_func_ = clear_key_func;
181 std::vector<std::string> ChunkCrashKeyValue(const CrashKey& crash_key,
182 const base::StringPiece& value,
183 size_t chunk_max_length) {
184 std::string value_string = value.substr(0, crash_key.max_length).as_string();
185 std::vector<std::string> chunks;
186 for (size_t offset = 0; offset < value_string.length(); ) {
187 std::string chunk = value_string.substr(offset, chunk_max_length);
188 chunks.push_back(chunk);
189 offset += chunk.length();
191 return chunks;
194 void ResetCrashLoggingForTesting() {
195 delete g_crash_keys_;
196 g_crash_keys_ = NULL;
197 g_chunk_max_length_ = 0;
198 g_set_key_func_ = NULL;
199 g_clear_key_func_ = NULL;
202 } // namespace debug
203 } // namespace base