Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(166)

Side by Side Diff: base/debug/crash_logging.cc

Issue 1360943004: Revert of Use a class instead of several separate globals in crash_logging.cc. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/debug/crash_logging.h ('k') | base/debug/crash_logging_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/debug/crash_logging.h" 5 #include "base/debug/crash_logging.h"
6 6
7 #include <cmath>
7 #include <map> 8 #include <map>
8 9
9 #include "base/debug/stack_trace.h" 10 #include "base/debug/stack_trace.h"
10 #include "base/format_macros.h" 11 #include "base/format_macros.h"
11 #include "base/logging.h" 12 #include "base/logging.h"
12 #include "base/memory/singleton.h"
13 #include "base/strings/string_util.h" 13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h" 14 #include "base/strings/stringprintf.h"
15 15
16 namespace base { 16 namespace base {
17 namespace debug { 17 namespace debug {
18 18
19 namespace { 19 namespace {
20 20
21 // Global map of crash key names to registration entries.
22 typedef std::map<base::StringPiece, CrashKey> CrashKeyMap;
23 CrashKeyMap* g_crash_keys_ = NULL;
24
25 // The maximum length of a single chunk.
26 size_t g_chunk_max_length_ = 0;
27
21 // String used to format chunked key names. 28 // String used to format chunked key names.
22 const char kChunkFormatString[] = "%s-%" PRIuS; 29 const char kChunkFormatString[] = "%s-%" PRIuS;
23 30
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;
35
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_;
41 }
42
24 // The longest max_length allowed by the system. 43 // The longest max_length allowed by the system.
25 const size_t kLargestValueAllowed = 1024; 44 const size_t kLargestValueAllowed = 1024;
26 45
27 // The CrashKeyRegistry is a singleton that holds the global state of the crash
28 // key logging system.
29 class CrashKeyRegistry {
30 public:
31 static CrashKeyRegistry* GetInstance() {
32 return Singleton<CrashKeyRegistry>::get();
33 }
34
35 // Initializes the set of allowed crash keys.
36 size_t Init(const CrashKey* const keys, size_t count,
37 size_t chunk_max_length) {
38 DCHECK(!initialized_) << "Crash logging may only be initialized once";
39
40 chunk_max_length_ = chunk_max_length;
41
42 size_t total_keys = 0;
43 for (size_t i = 0; i < count; ++i) {
44 crash_keys_.insert(std::make_pair(keys[i].key_name, keys[i]));
45 total_keys += NumChunksForLength(keys[i].max_length);
46 DCHECK_LT(keys[i].max_length, kLargestValueAllowed);
47 }
48
49 DCHECK_EQ(count, crash_keys_.size())
50 << "Duplicate crash keys were registered";
51 initialized_ = true;
52
53 return total_keys;
54 }
55
56 // Sets the function pointers to integrate with the platform-specific crash
57 // reporting system.
58 void SetFunctions(SetCrashKeyValueFuncT set_key_func,
59 ClearCrashKeyValueFuncT clear_key_func) {
60 set_key_func_ = set_key_func;
61 clear_key_func_ = clear_key_func;
62 }
63
64 // Looks up the CrashKey object by key.
65 const CrashKey* LookupCrashKey(const base::StringPiece& key) {
66 CrashKeyMap::const_iterator it = crash_keys_.find(key.as_string());
67 if (it == crash_keys_.end())
68 return nullptr;
69 return &(it->second);
70 }
71
72 // For a given |length|, computes the number of chunks a value of that size
73 // will occupy.
74 size_t NumChunksForLength(size_t length) const {
75 // Compute (length / g_chunk_max_length_), rounded up.
76 return (length + chunk_max_length_ - 1) / chunk_max_length_;
77 }
78
79 void SetKeyValue(const base::StringPiece& key,
80 const base::StringPiece& value) {
81 set_key_func_(key, value);
82 }
83
84 void ClearKey(const base::StringPiece& key) {
85 clear_key_func_(key);
86 }
87
88 bool is_initialized() const { return initialized_ && set_key_func_; }
89
90 size_t chunk_max_length() const { return chunk_max_length_; }
91
92 private:
93 friend struct DefaultSingletonTraits<CrashKeyRegistry>;
94
95 CrashKeyRegistry()
96 : initialized_(false),
97 chunk_max_length_(0),
98 set_key_func_(nullptr),
99 clear_key_func_(nullptr) {
100 }
101
102 ~CrashKeyRegistry() {}
103
104 bool initialized_;
105
106 // Map of crash key names to registration entries.
107 using CrashKeyMap = std::map<base::StringPiece, CrashKey>;
108 CrashKeyMap crash_keys_;
109
110 size_t chunk_max_length_;
111
112 // The functions that are called to actually set the key-value pairs in the
113 // crash reportng system.
114 SetCrashKeyValueFuncT set_key_func_;
115 ClearCrashKeyValueFuncT clear_key_func_;
116
117 DISALLOW_COPY_AND_ASSIGN(CrashKeyRegistry);
118 };
119
120 } // namespace 46 } // namespace
121 47
122 void SetCrashKeyValue(const base::StringPiece& key, 48 void SetCrashKeyValue(const base::StringPiece& key,
123 const base::StringPiece& value) { 49 const base::StringPiece& value) {
124 CrashKeyRegistry* registry = CrashKeyRegistry::GetInstance(); 50 if (!g_set_key_func_ || !g_crash_keys_)
125 if (!registry->is_initialized())
126 return; 51 return;
127 52
128 const CrashKey* crash_key = registry->LookupCrashKey(key); 53 const CrashKey* crash_key = LookupCrashKey(key);
129 54
130 DCHECK(crash_key) << "All crash keys must be registered before use " 55 DCHECK(crash_key) << "All crash keys must be registered before use "
131 << "(key = " << key << ")"; 56 << "(key = " << key << ")";
132 57
133 // Handle the un-chunked case. 58 // Handle the un-chunked case.
134 if (!crash_key || crash_key->max_length <= registry->chunk_max_length()) { 59 if (!crash_key || crash_key->max_length <= g_chunk_max_length_) {
135 registry->SetKeyValue(key, value); 60 g_set_key_func_(key, value);
136 return; 61 return;
137 } 62 }
138 63
139 // Unset the unused chunks. 64 // Unset the unused chunks.
140 std::vector<std::string> chunks = 65 std::vector<std::string> chunks =
141 ChunkCrashKeyValue(*crash_key, value, registry->chunk_max_length()); 66 ChunkCrashKeyValue(*crash_key, value, g_chunk_max_length_);
142 for (size_t i = chunks.size(); 67 for (size_t i = chunks.size();
143 i < registry->NumChunksForLength(crash_key->max_length); 68 i < NumChunksForLength(crash_key->max_length);
144 ++i) { 69 ++i) {
145 registry->ClearKey(base::StringPrintf(kChunkFormatString, key.data(), i+1)); 70 g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1));
146 } 71 }
147 72
148 // Set the chunked keys. 73 // Set the chunked keys.
149 for (size_t i = 0; i < chunks.size(); ++i) { 74 for (size_t i = 0; i < chunks.size(); ++i) {
150 registry->SetKeyValue( 75 g_set_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1),
151 base::StringPrintf(kChunkFormatString, key.data(), i+1), 76 chunks[i]);
152 chunks[i]);
153 } 77 }
154 } 78 }
155 79
156 void ClearCrashKey(const base::StringPiece& key) { 80 void ClearCrashKey(const base::StringPiece& key) {
157 CrashKeyRegistry* registry = CrashKeyRegistry::GetInstance(); 81 if (!g_clear_key_func_ || !g_crash_keys_)
158 if (!registry->is_initialized())
159 return; 82 return;
160 83
161 const CrashKey* crash_key = registry->LookupCrashKey(key); 84 const CrashKey* crash_key = LookupCrashKey(key);
162 85
163 // Handle the un-chunked case. 86 // Handle the un-chunked case.
164 if (!crash_key || crash_key->max_length <= registry->chunk_max_length()) { 87 if (!crash_key || crash_key->max_length <= g_chunk_max_length_) {
165 registry->ClearKey(key); 88 g_clear_key_func_(key);
166 return; 89 return;
167 } 90 }
168 91
169 for (size_t i = 0; 92 for (size_t i = 0; i < NumChunksForLength(crash_key->max_length); ++i) {
170 i < registry->NumChunksForLength(crash_key->max_length); 93 g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1));
171 ++i) {
172 registry->ClearKey(base::StringPrintf(kChunkFormatString, key.data(), i+1));
173 } 94 }
174 } 95 }
175 96
176 void SetCrashKeyToStackTrace(const base::StringPiece& key, 97 void SetCrashKeyToStackTrace(const base::StringPiece& key,
177 const StackTrace& trace) { 98 const StackTrace& trace) {
178 size_t count = 0; 99 size_t count = 0;
179 const void* const* addresses = trace.Addresses(&count); 100 const void* const* addresses = trace.Addresses(&count);
180 SetCrashKeyFromAddresses(key, addresses, count); 101 SetCrashKeyFromAddresses(key, addresses, count);
181 } 102 }
182 103
(...skipping 29 matching lines...) Expand all
212 : key_(key.as_string()) { 133 : key_(key.as_string()) {
213 SetCrashKeyValue(key, value); 134 SetCrashKeyValue(key, value);
214 } 135 }
215 136
216 ScopedCrashKey::~ScopedCrashKey() { 137 ScopedCrashKey::~ScopedCrashKey() {
217 ClearCrashKey(key_); 138 ClearCrashKey(key_);
218 } 139 }
219 140
220 size_t InitCrashKeys(const CrashKey* const keys, size_t count, 141 size_t InitCrashKeys(const CrashKey* const keys, size_t count,
221 size_t chunk_max_length) { 142 size_t chunk_max_length) {
222 return CrashKeyRegistry::GetInstance()->Init(keys, count, 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;
148 }
149
150 g_crash_keys_ = new CrashKeyMap;
151 g_chunk_max_length_ = chunk_max_length;
152
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);
158 }
159 DCHECK_EQ(count, g_crash_keys_->size())
160 << "Duplicate crash keys were registered";
161
162 return total_keys;
223 } 163 }
224 164
225 const CrashKey* LookupCrashKey(const base::StringPiece& key) { 165 const CrashKey* LookupCrashKey(const base::StringPiece& key) {
226 return CrashKeyRegistry::GetInstance()->LookupCrashKey(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);
227 } 172 }
228 173
229 void SetCrashKeyReportingFunctions( 174 void SetCrashKeyReportingFunctions(
230 SetCrashKeyValueFuncT set_key_func, 175 SetCrashKeyValueFuncT set_key_func,
231 ClearCrashKeyValueFuncT clear_key_func) { 176 ClearCrashKeyValueFuncT clear_key_func) {
232 CrashKeyRegistry::GetInstance()->SetFunctions(set_key_func, clear_key_func); 177 g_set_key_func_ = set_key_func;
178 g_clear_key_func_ = clear_key_func;
233 } 179 }
234 180
235 std::vector<std::string> ChunkCrashKeyValue(const CrashKey& crash_key, 181 std::vector<std::string> ChunkCrashKeyValue(const CrashKey& crash_key,
236 const base::StringPiece& value, 182 const base::StringPiece& value,
237 size_t chunk_max_length) { 183 size_t chunk_max_length) {
238 std::string value_string = value.substr(0, crash_key.max_length).as_string(); 184 std::string value_string = value.substr(0, crash_key.max_length).as_string();
239 std::vector<std::string> chunks; 185 std::vector<std::string> chunks;
240 for (size_t offset = 0; offset < value_string.length(); ) { 186 for (size_t offset = 0; offset < value_string.length(); ) {
241 std::string chunk = value_string.substr(offset, chunk_max_length); 187 std::string chunk = value_string.substr(offset, chunk_max_length);
242 chunks.push_back(chunk); 188 chunks.push_back(chunk);
243 offset += chunk.length(); 189 offset += chunk.length();
244 } 190 }
245 return chunks; 191 return chunks;
246 } 192 }
247 193
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;
200 }
201
248 } // namespace debug 202 } // namespace debug
249 } // namespace base 203 } // namespace base
OLDNEW
« no previous file with comments | « base/debug/crash_logging.h ('k') | base/debug/crash_logging_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698