Roll gyp r1967:1970.
[chromium-blink-merge.git] / base / debug / crash_logging.cc
blobcaf10b49b07185dfcf26eeb9b6fcdbe471f21151
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 return std::ceil(length / static_cast<float>(g_chunk_max_length_));
42 // The longest max_length allowed by the system.
43 const size_t kLargestValueAllowed = 1024;
45 } // namespace
47 void SetCrashKeyValue(const base::StringPiece& key,
48 const base::StringPiece& value) {
49 if (!g_set_key_func_ || !g_crash_keys_)
50 return;
52 const CrashKey* crash_key = LookupCrashKey(key);
54 DCHECK(crash_key) << "All crash keys must be registered before use "
55 << "(key = " << key << ")";
57 // Handle the un-chunked case.
58 if (!crash_key || crash_key->max_length <= g_chunk_max_length_) {
59 g_set_key_func_(key, value);
60 return;
63 // Unset the unused chunks.
64 std::vector<std::string> chunks =
65 ChunkCrashKeyValue(*crash_key, value, g_chunk_max_length_);
66 for (size_t i = chunks.size();
67 i < NumChunksForLength(crash_key->max_length);
68 ++i) {
69 g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1));
72 // Set the chunked keys.
73 for (size_t i = 0; i < chunks.size(); ++i) {
74 g_set_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1),
75 chunks[i]);
79 void ClearCrashKey(const base::StringPiece& key) {
80 if (!g_clear_key_func_ || !g_crash_keys_)
81 return;
83 const CrashKey* crash_key = LookupCrashKey(key);
85 // Handle the un-chunked case.
86 if (!crash_key || crash_key->max_length <= g_chunk_max_length_) {
87 g_clear_key_func_(key);
88 return;
91 for (size_t i = 0; i < NumChunksForLength(crash_key->max_length); ++i) {
92 g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1));
96 void SetCrashKeyToStackTrace(const base::StringPiece& key,
97 const StackTrace& trace) {
98 size_t count = 0;
99 const void* const* addresses = trace.Addresses(&count);
100 SetCrashKeyFromAddresses(key, addresses, count);
103 void SetCrashKeyFromAddresses(const base::StringPiece& key,
104 const void* const* addresses,
105 size_t count) {
106 std::string value = "<null>";
107 if (addresses && count) {
108 const size_t kBreakpadValueMax = 255;
110 std::vector<std::string> hex_backtrace;
111 size_t length = 0;
113 for (size_t i = 0; i < count; ++i) {
114 std::string s = base::StringPrintf("%p", addresses[i]);
115 length += s.length() + 1;
116 if (length > kBreakpadValueMax)
117 break;
118 hex_backtrace.push_back(s);
121 value = JoinString(hex_backtrace, ' ');
123 // Warn if this exceeds the breakpad limits.
124 DCHECK_LE(value.length(), kBreakpadValueMax);
127 SetCrashKeyValue(key, value);
130 ScopedCrashKey::ScopedCrashKey(const base::StringPiece& key,
131 const base::StringPiece& value)
132 : key_(key.as_string()) {
133 SetCrashKeyValue(key, value);
136 ScopedCrashKey::~ScopedCrashKey() {
137 ClearCrashKey(key_);
140 size_t InitCrashKeys(const CrashKey* const keys, size_t count,
141 size_t chunk_max_length) {
142 DCHECK(!g_crash_keys_) << "Crash logging may only be initialized once";
143 if (!keys) {
144 delete g_crash_keys_;
145 g_crash_keys_ = NULL;
146 return 0;
149 g_crash_keys_ = new CrashKeyMap;
150 g_chunk_max_length_ = chunk_max_length;
152 size_t total_keys = 0;
153 for (size_t i = 0; i < count; ++i) {
154 g_crash_keys_->insert(std::make_pair(keys[i].key_name, keys[i]));
155 total_keys += NumChunksForLength(keys[i].max_length);
156 DCHECK_LT(keys[i].max_length, kLargestValueAllowed);
158 DCHECK_EQ(count, g_crash_keys_->size())
159 << "Duplicate crash keys were registered";
161 return total_keys;
164 const CrashKey* LookupCrashKey(const base::StringPiece& key) {
165 if (!g_crash_keys_)
166 return NULL;
167 CrashKeyMap::const_iterator it = g_crash_keys_->find(key.as_string());
168 if (it == g_crash_keys_->end())
169 return NULL;
170 return &(it->second);
173 void SetCrashKeyReportingFunctions(
174 SetCrashKeyValueFuncT set_key_func,
175 ClearCrashKeyValueFuncT clear_key_func) {
176 g_set_key_func_ = set_key_func;
177 g_clear_key_func_ = clear_key_func;
180 std::vector<std::string> ChunkCrashKeyValue(const CrashKey& crash_key,
181 const base::StringPiece& value,
182 size_t chunk_max_length) {
183 std::string value_string = value.substr(0, crash_key.max_length).as_string();
184 std::vector<std::string> chunks;
185 for (size_t offset = 0; offset < value_string.length(); ) {
186 std::string chunk = value_string.substr(offset, chunk_max_length);
187 chunks.push_back(chunk);
188 offset += chunk.length();
190 return chunks;
193 void ResetCrashLoggingForTesting() {
194 delete g_crash_keys_;
195 g_crash_keys_ = NULL;
196 g_chunk_max_length_ = 0;
197 g_set_key_func_ = NULL;
198 g_clear_key_func_ = NULL;
201 } // namespace debug
202 } // namespace base