| Index: base/debug/crash_logging.cc | 
| diff --git a/base/debug/crash_logging.cc b/base/debug/crash_logging.cc | 
| index 1e20677ec4a32f94408811f773e17f75eaf018ce..f68fda5ecb74334e9a449aa34a04838cd155e4b1 100644 | 
| --- a/base/debug/crash_logging.cc | 
| +++ b/base/debug/crash_logging.cc | 
| @@ -4,6 +4,8 @@ | 
|  | 
| #include "base/debug/crash_logging.h" | 
|  | 
| +#include <map> | 
| + | 
| #include "base/debug/stack_trace.h" | 
| #include "base/logging.h" | 
| #include "base/string_util.h" | 
| @@ -12,18 +14,62 @@ | 
| namespace base { | 
| namespace debug { | 
|  | 
| -static SetCrashKeyValueFuncT g_set_key_func_ = NULL; | 
| -static ClearCrashKeyValueFuncT g_clear_key_func_ = NULL; | 
| +namespace { | 
| + | 
| +std::map<base::StringPiece, CrashKey>* g_crash_keys_ = NULL; | 
| + | 
| +const char kChunkFormatString[] = "%s-%zu"; | 
| + | 
| +SetCrashKeyValueFuncT g_set_key_func_ = NULL; | 
| +ClearCrashKeyValueFuncT g_clear_key_func_ = NULL; | 
| + | 
| +}  // namespace | 
|  | 
| void SetCrashKeyValue(const base::StringPiece& key, | 
| const base::StringPiece& value) { | 
| -  if (g_set_key_func_) | 
| +  if (!g_set_key_func_) | 
| +    return; | 
| + | 
| +  const CrashKey* crash_key = LookupCrashKey(key); | 
| + | 
| +  // TODO(rsesek): Do this: | 
| +  //DCHECK(crash_key) << "All crash keys must be registered before use " | 
| +  //                  << "(key = " << key << ")"; | 
| + | 
| +  // Handle the un-chunked case. | 
| +  if (!crash_key || crash_key->num_chunks == 1) { | 
| g_set_key_func_(key, value); | 
| +    return; | 
| +  } | 
| + | 
| +  // Unset the unused chunks. | 
| +  std::vector<std::string> chunks = ChunkCrashKeyValue(*crash_key, value); | 
| +  for (size_t i = chunks.size(); i < crash_key->num_chunks; ++i) { | 
| +    g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1)); | 
| +  } | 
| + | 
| +  // Set the chunked keys. | 
| +  for (size_t i = 0; i < chunks.size(); ++i) { | 
| +    g_set_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1), | 
| +                    chunks[i]); | 
| +  } | 
| } | 
|  | 
| void ClearCrashKey(const base::StringPiece& key) { | 
| -  if (g_clear_key_func_) | 
| +  if (!g_clear_key_func_) | 
| +    return; | 
| + | 
| +  const CrashKey* crash_key = LookupCrashKey(key); | 
| + | 
| +  // Handle the un-chunked case. | 
| +  if (!crash_key || crash_key->num_chunks == 1) { | 
| g_clear_key_func_(key); | 
| +    return; | 
| +  } | 
| + | 
| +  for (size_t i = 0; i < crash_key->num_chunks; ++i) { | 
| +    g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1)); | 
| +  } | 
| } | 
|  | 
| void SetCrashKeyToStackTrace(const base::StringPiece& key, | 
| @@ -70,6 +116,35 @@ ScopedCrashKey::~ScopedCrashKey() { | 
| ClearCrashKey(key_); | 
| } | 
|  | 
| +size_t InitCrashKeys(const CrashKey* const keys, size_t count) { | 
| +  DCHECK(!g_crash_keys_) << "Crash logging may only be initialized once"; | 
| +  if (!keys) { | 
| +    delete g_crash_keys_; | 
| +    g_crash_keys_ = NULL; | 
| +    return 0; | 
| +  } | 
| + | 
| +  g_crash_keys_ = new std::map<base::StringPiece, CrashKey>; | 
| + | 
| +  size_t total_keys = 0; | 
| +  for (size_t i = 0; i < count; ++i) { | 
| +    g_crash_keys_->insert(std::make_pair(keys[i].key_name, keys[i])); | 
| +    total_keys += keys[i].num_chunks; | 
| +  } | 
| +  DCHECK_EQ(count, g_crash_keys_->size()) | 
| +      << "Duplicate crash keys were registered"; | 
| + | 
| +  return total_keys; | 
| +} | 
| + | 
| +const CrashKey* LookupCrashKey(const base::StringPiece& key) { | 
| +  std::map<base::StringPiece, CrashKey>::const_iterator it = | 
| +      g_crash_keys_->find(key.as_string()); | 
| +  if (it == g_crash_keys_->end()) | 
| +    return NULL; | 
| +  return &(it->second); | 
| +} | 
| + | 
| void SetCrashKeyReportingFunctions( | 
| SetCrashKeyValueFuncT set_key_func, | 
| ClearCrashKeyValueFuncT clear_key_func) { | 
| @@ -77,5 +152,26 @@ void SetCrashKeyReportingFunctions( | 
| g_clear_key_func_ = clear_key_func; | 
| } | 
|  | 
| +std::vector<std::string> ChunkCrashKeyValue(const CrashKey& crash_key, | 
| +                                            const base::StringPiece& value) { | 
| +  std::string value_string = value.as_string(); | 
| +  std::vector<std::string> chunks; | 
| +  for (size_t i = 0, offset = 0; | 
| +       i < crash_key.num_chunks && offset < value_string.length(); | 
| +       ++i) { | 
| +    std::string chunk = value_string.substr(offset, crash_key.max_length); | 
| +    chunks.push_back(chunk); | 
| +    offset += chunk.length(); | 
| +  } | 
| +  return chunks; | 
| +} | 
| + | 
| +void ResetCrashLoggingForTesting() { | 
| +  delete g_crash_keys_; | 
| +  g_crash_keys_ = NULL; | 
| +  g_set_key_func_ = NULL; | 
| +  g_clear_key_func_ = NULL; | 
| +} | 
| + | 
| }  // namespace debug | 
| }  // namespace base | 
|  |