crash_logging.cc 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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.
  4. #include "base/debug/crash_logging.h"
  5. #include <cmath>
  6. #include <map>
  7. #include "base/debug/stack_trace.h"
  8. #include "base/format_macros.h"
  9. #include "base/logging.h"
  10. #include "base/strings/string_util.h"
  11. #include "base/strings/stringprintf.h"
  12. namespace base {
  13. namespace debug {
  14. namespace {
  15. // Global map of crash key names to registration entries.
  16. typedef std::map<base::StringPiece, CrashKey> CrashKeyMap;
  17. CrashKeyMap* g_crash_keys_ = NULL;
  18. // The maximum length of a single chunk.
  19. size_t g_chunk_max_length_ = 0;
  20. // String used to format chunked key names.
  21. const char kChunkFormatString[] = "%s-%" PRIuS;
  22. // The functions that are called to actually set the key-value pairs in the
  23. // crash reportng system.
  24. SetCrashKeyValueFuncT g_set_key_func_ = NULL;
  25. ClearCrashKeyValueFuncT g_clear_key_func_ = NULL;
  26. // For a given |length|, computes the number of chunks a value of that size
  27. // will occupy.
  28. size_t NumChunksForLength(size_t length) {
  29. return (size_t)std::ceil(length / static_cast<double>(g_chunk_max_length_));
  30. }
  31. // The longest max_length allowed by the system.
  32. const size_t kLargestValueAllowed = 1024;
  33. } // namespace
  34. void SetCrashKeyValue(const base::StringPiece& key,
  35. const base::StringPiece& value) {
  36. if (!g_set_key_func_ || !g_crash_keys_)
  37. return;
  38. const CrashKey* crash_key = LookupCrashKey(key);
  39. DCHECK(crash_key) << "All crash keys must be registered before use "
  40. << "(key = " << key << ")";
  41. // Handle the un-chunked case.
  42. if (!crash_key || crash_key->max_length <= g_chunk_max_length_) {
  43. g_set_key_func_(key, value);
  44. return;
  45. }
  46. // Unset the unused chunks.
  47. std::vector<std::string> chunks =
  48. ChunkCrashKeyValue(*crash_key, value, g_chunk_max_length_);
  49. for (size_t i = chunks.size();
  50. i < NumChunksForLength(crash_key->max_length);
  51. ++i) {
  52. g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1));
  53. }
  54. // Set the chunked keys.
  55. for (size_t i = 0; i < chunks.size(); ++i) {
  56. g_set_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1),
  57. chunks[i]);
  58. }
  59. }
  60. void ClearCrashKey(const base::StringPiece& key) {
  61. if (!g_clear_key_func_ || !g_crash_keys_)
  62. return;
  63. const CrashKey* crash_key = LookupCrashKey(key);
  64. // Handle the un-chunked case.
  65. if (!crash_key || crash_key->max_length <= g_chunk_max_length_) {
  66. g_clear_key_func_(key);
  67. return;
  68. }
  69. for (size_t i = 0; i < NumChunksForLength(crash_key->max_length); ++i) {
  70. g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1));
  71. }
  72. }
  73. void SetCrashKeyToStackTrace(const base::StringPiece& key,
  74. const StackTrace& trace) {
  75. size_t count = 0;
  76. const void* const* addresses = trace.Addresses(&count);
  77. SetCrashKeyFromAddresses(key, addresses, count);
  78. }
  79. void SetCrashKeyFromAddresses(const base::StringPiece& key,
  80. const void* const* addresses,
  81. size_t count) {
  82. std::string value = "<null>";
  83. if (addresses && count) {
  84. const size_t kBreakpadValueMax = 255;
  85. std::vector<std::string> hex_backtrace;
  86. size_t length = 0;
  87. for (size_t i = 0; i < count; ++i) {
  88. std::string s = base::StringPrintf("%p", addresses[i]);
  89. length += s.length() + 1;
  90. if (length > kBreakpadValueMax)
  91. break;
  92. hex_backtrace.push_back(s);
  93. }
  94. value = JoinString(hex_backtrace, ' ');
  95. // Warn if this exceeds the breakpad limits.
  96. DCHECK_LE(value.length(), kBreakpadValueMax);
  97. }
  98. SetCrashKeyValue(key, value);
  99. }
  100. ScopedCrashKey::ScopedCrashKey(const base::StringPiece& key,
  101. const base::StringPiece& value)
  102. : key_(key.as_string()) {
  103. SetCrashKeyValue(key, value);
  104. }
  105. ScopedCrashKey::~ScopedCrashKey() {
  106. ClearCrashKey(key_);
  107. }
  108. size_t InitCrashKeys(const CrashKey* const keys, size_t count,
  109. size_t chunk_max_length) {
  110. DCHECK(!g_crash_keys_) << "Crash logging may only be initialized once";
  111. if (!keys) {
  112. delete g_crash_keys_;
  113. g_crash_keys_ = NULL;
  114. return 0;
  115. }
  116. g_crash_keys_ = new CrashKeyMap;
  117. g_chunk_max_length_ = chunk_max_length;
  118. size_t total_keys = 0;
  119. for (size_t i = 0; i < count; ++i) {
  120. g_crash_keys_->insert(std::make_pair(keys[i].key_name, keys[i]));
  121. total_keys += NumChunksForLength(keys[i].max_length);
  122. DCHECK_LT(keys[i].max_length, kLargestValueAllowed);
  123. }
  124. DCHECK_EQ(count, g_crash_keys_->size())
  125. << "Duplicate crash keys were registered";
  126. return total_keys;
  127. }
  128. const CrashKey* LookupCrashKey(const base::StringPiece& key) {
  129. if (!g_crash_keys_)
  130. return NULL;
  131. CrashKeyMap::const_iterator it = g_crash_keys_->find(key.as_string());
  132. if (it == g_crash_keys_->end())
  133. return NULL;
  134. return &(it->second);
  135. }
  136. void SetCrashKeyReportingFunctions(
  137. SetCrashKeyValueFuncT set_key_func,
  138. ClearCrashKeyValueFuncT clear_key_func) {
  139. g_set_key_func_ = set_key_func;
  140. g_clear_key_func_ = clear_key_func;
  141. }
  142. std::vector<std::string> ChunkCrashKeyValue(const CrashKey& crash_key,
  143. const base::StringPiece& value,
  144. size_t chunk_max_length) {
  145. std::string value_string = value.substr(0, crash_key.max_length).as_string();
  146. std::vector<std::string> chunks;
  147. for (size_t offset = 0; offset < value_string.length(); ) {
  148. std::string chunk = value_string.substr(offset, chunk_max_length);
  149. chunks.push_back(chunk);
  150. offset += chunk.length();
  151. }
  152. return chunks;
  153. }
  154. void ResetCrashLoggingForTesting() {
  155. delete g_crash_keys_;
  156. g_crash_keys_ = NULL;
  157. g_chunk_max_length_ = 0;
  158. g_set_key_func_ = NULL;
  159. g_clear_key_func_ = NULL;
  160. }
  161. } // namespace debug
  162. } // namespace base