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