| OLD | NEW | 
|---|
| 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 <map> | 
|  | 8 | 
| 7 #include "base/debug/stack_trace.h" | 9 #include "base/debug/stack_trace.h" | 
|  | 10 #include "base/format_macros.h" | 
| 8 #include "base/logging.h" | 11 #include "base/logging.h" | 
| 9 #include "base/string_util.h" | 12 #include "base/string_util.h" | 
| 10 #include "base/stringprintf.h" | 13 #include "base/stringprintf.h" | 
| 11 | 14 | 
| 12 namespace base { | 15 namespace base { | 
| 13 namespace debug { | 16 namespace debug { | 
| 14 | 17 | 
| 15 static SetCrashKeyValueFuncT g_set_key_func_ = NULL; | 18 namespace { | 
| 16 static ClearCrashKeyValueFuncT g_clear_key_func_ = NULL; | 19 | 
|  | 20 typedef std::map<base::StringPiece, CrashKey> CrashKeyMap; | 
|  | 21 CrashKeyMap* g_crash_keys_ = NULL; | 
|  | 22 | 
|  | 23 size_t g_chunk_max_length_ = 0; | 
|  | 24 | 
|  | 25 const char kChunkFormatString[] = "%s-%" PRIuS; | 
|  | 26 | 
|  | 27 SetCrashKeyValueFuncT g_set_key_func_ = NULL; | 
|  | 28 ClearCrashKeyValueFuncT g_clear_key_func_ = NULL; | 
|  | 29 | 
|  | 30 }  // namespace | 
| 17 | 31 | 
| 18 void SetCrashKeyValue(const base::StringPiece& key, | 32 void SetCrashKeyValue(const base::StringPiece& key, | 
| 19                       const base::StringPiece& value) { | 33                       const base::StringPiece& value) { | 
| 20   if (g_set_key_func_) | 34   if (!g_set_key_func_) | 
|  | 35     return; | 
|  | 36 | 
|  | 37   const CrashKey* crash_key = LookupCrashKey(key); | 
|  | 38 | 
|  | 39   // TODO(rsesek): Do this: | 
|  | 40   //DCHECK(crash_key) << "All crash keys must be registered before use " | 
|  | 41   //                  << "(key = " << key << ")"; | 
|  | 42 | 
|  | 43   // Handle the un-chunked case. | 
|  | 44   if (!crash_key || crash_key->num_chunks == 1) { | 
| 21     g_set_key_func_(key, value); | 45     g_set_key_func_(key, value); | 
|  | 46     return; | 
|  | 47   } | 
|  | 48 | 
|  | 49   // Unset the unused chunks. | 
|  | 50   std::vector<std::string> chunks = | 
|  | 51       ChunkCrashKeyValue(*crash_key, value, g_chunk_max_length_); | 
|  | 52   for (size_t i = chunks.size(); i < crash_key->num_chunks; ++i) { | 
|  | 53     g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1)); | 
|  | 54   } | 
|  | 55 | 
|  | 56   // Set the chunked keys. | 
|  | 57   for (size_t i = 0; i < chunks.size(); ++i) { | 
|  | 58     g_set_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1), | 
|  | 59                     chunks[i]); | 
|  | 60   } | 
| 22 } | 61 } | 
| 23 | 62 | 
| 24 void ClearCrashKey(const base::StringPiece& key) { | 63 void ClearCrashKey(const base::StringPiece& key) { | 
| 25   if (g_clear_key_func_) | 64   if (!g_clear_key_func_) | 
|  | 65     return; | 
|  | 66 | 
|  | 67   const CrashKey* crash_key = LookupCrashKey(key); | 
|  | 68 | 
|  | 69   // Handle the un-chunked case. | 
|  | 70   if (!crash_key || crash_key->num_chunks == 1) { | 
| 26     g_clear_key_func_(key); | 71     g_clear_key_func_(key); | 
|  | 72     return; | 
|  | 73   } | 
|  | 74 | 
|  | 75   for (size_t i = 0; i < crash_key->num_chunks; ++i) { | 
|  | 76     g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1)); | 
|  | 77   } | 
| 27 } | 78 } | 
| 28 | 79 | 
| 29 void SetCrashKeyToStackTrace(const base::StringPiece& key, | 80 void SetCrashKeyToStackTrace(const base::StringPiece& key, | 
| 30                              const StackTrace& trace) { | 81                              const StackTrace& trace) { | 
| 31   size_t count = 0; | 82   size_t count = 0; | 
| 32   const void* const* addresses = trace.Addresses(&count); | 83   const void* const* addresses = trace.Addresses(&count); | 
| 33   SetCrashKeyFromAddresses(key, addresses, count); | 84   SetCrashKeyFromAddresses(key, addresses, count); | 
| 34 } | 85 } | 
| 35 | 86 | 
| 36 void SetCrashKeyFromAddresses(const base::StringPiece& key, | 87 void SetCrashKeyFromAddresses(const base::StringPiece& key, | 
| (...skipping 26 matching lines...) Expand all  Loading... | 
| 63 ScopedCrashKey::ScopedCrashKey(const base::StringPiece& key, | 114 ScopedCrashKey::ScopedCrashKey(const base::StringPiece& key, | 
| 64                                const base::StringPiece& value) | 115                                const base::StringPiece& value) | 
| 65     : key_(key.as_string()) { | 116     : key_(key.as_string()) { | 
| 66   SetCrashKeyValue(key, value); | 117   SetCrashKeyValue(key, value); | 
| 67 } | 118 } | 
| 68 | 119 | 
| 69 ScopedCrashKey::~ScopedCrashKey() { | 120 ScopedCrashKey::~ScopedCrashKey() { | 
| 70   ClearCrashKey(key_); | 121   ClearCrashKey(key_); | 
| 71 } | 122 } | 
| 72 | 123 | 
|  | 124 size_t InitCrashKeys(const CrashKey* const keys, size_t count, | 
|  | 125                      size_t chunk_max_length) { | 
|  | 126   DCHECK(!g_crash_keys_) << "Crash logging may only be initialized once"; | 
|  | 127   if (!keys) { | 
|  | 128     delete g_crash_keys_; | 
|  | 129     g_crash_keys_ = NULL; | 
|  | 130     return 0; | 
|  | 131   } | 
|  | 132 | 
|  | 133   g_crash_keys_ = new CrashKeyMap; | 
|  | 134   g_chunk_max_length_ = chunk_max_length; | 
|  | 135 | 
|  | 136   size_t total_keys = 0; | 
|  | 137   for (size_t i = 0; i < count; ++i) { | 
|  | 138     g_crash_keys_->insert(std::make_pair(keys[i].key_name, keys[i])); | 
|  | 139     total_keys += keys[i].num_chunks; | 
|  | 140   } | 
|  | 141   DCHECK_EQ(count, g_crash_keys_->size()) | 
|  | 142       << "Duplicate crash keys were registered"; | 
|  | 143 | 
|  | 144   return total_keys; | 
|  | 145 } | 
|  | 146 | 
|  | 147 const CrashKey* LookupCrashKey(const base::StringPiece& key) { | 
|  | 148   CrashKeyMap::const_iterator it = g_crash_keys_->find(key.as_string()); | 
|  | 149   if (it == g_crash_keys_->end()) | 
|  | 150     return NULL; | 
|  | 151   return &(it->second); | 
|  | 152 } | 
|  | 153 | 
| 73 void SetCrashKeyReportingFunctions( | 154 void SetCrashKeyReportingFunctions( | 
| 74     SetCrashKeyValueFuncT set_key_func, | 155     SetCrashKeyValueFuncT set_key_func, | 
| 75     ClearCrashKeyValueFuncT clear_key_func) { | 156     ClearCrashKeyValueFuncT clear_key_func) { | 
| 76   g_set_key_func_ = set_key_func; | 157   g_set_key_func_ = set_key_func; | 
| 77   g_clear_key_func_ = clear_key_func; | 158   g_clear_key_func_ = clear_key_func; | 
| 78 } | 159 } | 
| 79 | 160 | 
|  | 161 std::vector<std::string> ChunkCrashKeyValue(const CrashKey& crash_key, | 
|  | 162                                             const base::StringPiece& value, | 
|  | 163                                             size_t chunk_max_length) { | 
|  | 164   std::string value_string = value.as_string(); | 
|  | 165   std::vector<std::string> chunks; | 
|  | 166   for (size_t i = 0, offset = 0; | 
|  | 167        i < crash_key.num_chunks && offset < value_string.length(); | 
|  | 168        ++i) { | 
|  | 169     std::string chunk = value_string.substr(offset, chunk_max_length); | 
|  | 170     chunks.push_back(chunk); | 
|  | 171     offset += chunk.length(); | 
|  | 172   } | 
|  | 173   return chunks; | 
|  | 174 } | 
|  | 175 | 
|  | 176 void ResetCrashLoggingForTesting() { | 
|  | 177   delete g_crash_keys_; | 
|  | 178   g_crash_keys_ = NULL; | 
|  | 179   g_chunk_max_length_ = 0; | 
|  | 180   g_set_key_func_ = NULL; | 
|  | 181   g_clear_key_func_ = NULL; | 
|  | 182 } | 
|  | 183 | 
| 80 }  // namespace debug | 184 }  // namespace debug | 
| 81 }  // namespace base | 185 }  // namespace base | 
| OLD | NEW | 
|---|