1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_DEBUG_CRASH_LOGGING_H_ 6*6777b538SAndroid Build Coastguard Worker #define BASE_DEBUG_CRASH_LOGGING_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #include <stddef.h> 9*6777b538SAndroid Build Coastguard Worker 10*6777b538SAndroid Build Coastguard Worker #include <iosfwd> 11*6777b538SAndroid Build Coastguard Worker #include <memory> 12*6777b538SAndroid Build Coastguard Worker #include <string_view> 13*6777b538SAndroid Build Coastguard Worker #include <type_traits> 14*6777b538SAndroid Build Coastguard Worker 15*6777b538SAndroid Build Coastguard Worker #include "base/base_export.h" 16*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h" 17*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h" 18*6777b538SAndroid Build Coastguard Worker 19*6777b538SAndroid Build Coastguard Worker namespace base { 20*6777b538SAndroid Build Coastguard Worker namespace debug { 21*6777b538SAndroid Build Coastguard Worker 22*6777b538SAndroid Build Coastguard Worker // A crash key is an annotation that is carried along with a crash report, to 23*6777b538SAndroid Build Coastguard Worker // provide additional debugging information beyond a stack trace. Crash keys 24*6777b538SAndroid Build Coastguard Worker // have a name and a string value. 25*6777b538SAndroid Build Coastguard Worker // 26*6777b538SAndroid Build Coastguard Worker // The preferred API is //components/crash/core/common:crash_key, however not 27*6777b538SAndroid Build Coastguard Worker // all clients can hold a direct dependency on that target. The API provided 28*6777b538SAndroid Build Coastguard Worker // in this file indirects the dependency and adds some convenience helpers that 29*6777b538SAndroid Build Coastguard Worker // make the API a bit less clunky. 30*6777b538SAndroid Build Coastguard Worker // 31*6777b538SAndroid Build Coastguard Worker // TODO(dcheng): Some of the nicer APIs should probably be upstreamed into 32*6777b538SAndroid Build Coastguard Worker // //components/crash. 33*6777b538SAndroid Build Coastguard Worker // 34*6777b538SAndroid Build Coastguard Worker // Preferred usage when a crash key value only needs to be set within a scope: 35*6777b538SAndroid Build Coastguard Worker // 36*6777b538SAndroid Build Coastguard Worker // SCOPED_CRASH_KEY_STRING32("category", "name", "value"); 37*6777b538SAndroid Build Coastguard Worker // base::debug::DumpWithoutCrashing(); 38*6777b538SAndroid Build Coastguard Worker // 39*6777b538SAndroid Build Coastguard Worker // If the crash key is pre-allocated elsewhere, but the value only needs to be 40*6777b538SAndroid Build Coastguard Worker // set within a scope: 41*6777b538SAndroid Build Coastguard Worker // 42*6777b538SAndroid Build Coastguard Worker // base::debug::ScopedCrashKeyString scoper( 43*6777b538SAndroid Build Coastguard Worker // GetCrashKeyForComponent(), 44*6777b538SAndroid Build Coastguard Worker // "value"); 45*6777b538SAndroid Build Coastguard Worker // 46*6777b538SAndroid Build Coastguard Worker // Otherwise, if the crash key needs to persist (e.g. the actual crash dump is 47*6777b538SAndroid Build Coastguard Worker // triggered some time later asynchronously): 48*6777b538SAndroid Build Coastguard Worker // 49*6777b538SAndroid Build Coastguard Worker // static auto* const crash_key = base::debug::AllocateCrashKeyString( 50*6777b538SAndroid Build Coastguard Worker // "name", base::debug::CrashKeySize::Size32); 51*6777b538SAndroid Build Coastguard Worker // base::debug::SetCrashKeyString(crash_key, "value"); 52*6777b538SAndroid Build Coastguard Worker // 53*6777b538SAndroid Build Coastguard Worker // // Do other work before calling `base::debug::DumpWithoutCrashing()` later. 54*6777b538SAndroid Build Coastguard Worker // 55*6777b538SAndroid Build Coastguard Worker // ***WARNING*** 56*6777b538SAndroid Build Coastguard Worker // 57*6777b538SAndroid Build Coastguard Worker // Do *not* write this: 58*6777b538SAndroid Build Coastguard Worker // 59*6777b538SAndroid Build Coastguard Worker // base::debug::SetCrashKeyString( 60*6777b538SAndroid Build Coastguard Worker // base::debug::AllocateCrashKeyString( 61*6777b538SAndroid Build Coastguard Worker // "name", base::debug::CrashKeySize::Size32), 62*6777b538SAndroid Build Coastguard Worker // "value"); 63*6777b538SAndroid Build Coastguard Worker // 64*6777b538SAndroid Build Coastguard Worker // As this will leak a heap allocation every time the crash key is set! 65*6777b538SAndroid Build Coastguard Worker 66*6777b538SAndroid Build Coastguard Worker // The maximum length for a crash key's value must be one of the following 67*6777b538SAndroid Build Coastguard Worker // pre-determined values. 68*6777b538SAndroid Build Coastguard Worker enum class CrashKeySize { 69*6777b538SAndroid Build Coastguard Worker Size32 = 32, 70*6777b538SAndroid Build Coastguard Worker Size64 = 64, 71*6777b538SAndroid Build Coastguard Worker Size256 = 256, 72*6777b538SAndroid Build Coastguard Worker Size1024 = 1024, 73*6777b538SAndroid Build Coastguard Worker }; 74*6777b538SAndroid Build Coastguard Worker 75*6777b538SAndroid Build Coastguard Worker struct CrashKeyString; 76*6777b538SAndroid Build Coastguard Worker 77*6777b538SAndroid Build Coastguard Worker // Allocates a new crash key with the specified |name| with storage for a 78*6777b538SAndroid Build Coastguard Worker // value up to length |size|. This will return null if the crash key system is 79*6777b538SAndroid Build Coastguard Worker // not initialized. 80*6777b538SAndroid Build Coastguard Worker // 81*6777b538SAndroid Build Coastguard Worker // Note: this internally allocates, so the returned pointer should always 82*6777b538SAndroid Build Coastguard Worker // be cached in a variable with static storage duration, e.g.: 83*6777b538SAndroid Build Coastguard Worker // static auto* const crash_key = base::debug::AllocateCrashKeyString(...); 84*6777b538SAndroid Build Coastguard Worker BASE_EXPORT CrashKeyString* AllocateCrashKeyString(const char name[], 85*6777b538SAndroid Build Coastguard Worker CrashKeySize size); 86*6777b538SAndroid Build Coastguard Worker 87*6777b538SAndroid Build Coastguard Worker // Stores |value| into the specified |crash_key|. The |crash_key| may be null 88*6777b538SAndroid Build Coastguard Worker // if AllocateCrashKeyString() returned null. If |value| is longer than the 89*6777b538SAndroid Build Coastguard Worker // size with which the key was allocated, it will be truncated. 90*6777b538SAndroid Build Coastguard Worker BASE_EXPORT void SetCrashKeyString(CrashKeyString* crash_key, 91*6777b538SAndroid Build Coastguard Worker std::string_view value); 92*6777b538SAndroid Build Coastguard Worker 93*6777b538SAndroid Build Coastguard Worker // Clears any value that was stored in |crash_key|. The |crash_key| may be 94*6777b538SAndroid Build Coastguard Worker // null. 95*6777b538SAndroid Build Coastguard Worker BASE_EXPORT void ClearCrashKeyString(CrashKeyString* crash_key); 96*6777b538SAndroid Build Coastguard Worker 97*6777b538SAndroid Build Coastguard Worker // Outputs current (i.e. allocated and non-empty) crash keys to `out`. 98*6777b538SAndroid Build Coastguard Worker BASE_EXPORT void OutputCrashKeysToStream(std::ostream& out); 99*6777b538SAndroid Build Coastguard Worker 100*6777b538SAndroid Build Coastguard Worker // A scoper that sets the specified key to value for the lifetime of the 101*6777b538SAndroid Build Coastguard Worker // object, and clears it on destruction. 102*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT [[nodiscard]] ScopedCrashKeyString { 103*6777b538SAndroid Build Coastguard Worker public: 104*6777b538SAndroid Build Coastguard Worker ScopedCrashKeyString(CrashKeyString* crash_key, std::string_view value); 105*6777b538SAndroid Build Coastguard Worker ScopedCrashKeyString(ScopedCrashKeyString&& other); 106*6777b538SAndroid Build Coastguard Worker ~ScopedCrashKeyString(); 107*6777b538SAndroid Build Coastguard Worker 108*6777b538SAndroid Build Coastguard Worker // Disallow copy and assign. 109*6777b538SAndroid Build Coastguard Worker ScopedCrashKeyString(const ScopedCrashKeyString&) = delete; 110*6777b538SAndroid Build Coastguard Worker ScopedCrashKeyString& operator=(const ScopedCrashKeyString&) = delete; 111*6777b538SAndroid Build Coastguard Worker 112*6777b538SAndroid Build Coastguard Worker // Disallow move assign to keep the time at which the crash key is cleared 113*6777b538SAndroid Build Coastguard Worker // easy to reason about. Assigning over an existing instance would 114*6777b538SAndroid Build Coastguard Worker // automatically clear the key instead of at the destruction of the object. 115*6777b538SAndroid Build Coastguard Worker ScopedCrashKeyString& operator=(ScopedCrashKeyString&&) = delete; 116*6777b538SAndroid Build Coastguard Worker 117*6777b538SAndroid Build Coastguard Worker private: 118*6777b538SAndroid Build Coastguard Worker raw_ptr<CrashKeyString> crash_key_; 119*6777b538SAndroid Build Coastguard Worker }; 120*6777b538SAndroid Build Coastguard Worker 121*6777b538SAndroid Build Coastguard Worker // Internal helpers for the SCOPED_CRASH_KEY_... helper macros defined below. 122*6777b538SAndroid Build Coastguard Worker // 123*6777b538SAndroid Build Coastguard Worker // The first static_assert that checks the length of |key_name| is a 124*6777b538SAndroid Build Coastguard Worker // compile-time equivalent of the DCHECK in 125*6777b538SAndroid Build Coastguard Worker // crash_reporter::internal::CrashKeyStringImpl::Set that restricts the name of 126*6777b538SAndroid Build Coastguard Worker // a crash key to 40 characters. 127*6777b538SAndroid Build Coastguard Worker // 128*6777b538SAndroid Build Coastguard Worker // The second static_assert that checks for reserved characters is a compile 129*6777b538SAndroid Build Coastguard Worker // time equivalent of the DCHECK in base::debug::AllocateCrashKeyString. 130*6777b538SAndroid Build Coastguard Worker #define SCOPED_CRASH_KEY_STRING_INTERNAL2(category, name, nonce, data, \ 131*6777b538SAndroid Build Coastguard Worker key_size) \ 132*6777b538SAndroid Build Coastguard Worker static_assert(::std::size(category "-" name) < 40, \ 133*6777b538SAndroid Build Coastguard Worker "Crash key names must be shorter than 40 characters."); \ 134*6777b538SAndroid Build Coastguard Worker static_assert(::std::string_view(category "-" name).find(':') == \ 135*6777b538SAndroid Build Coastguard Worker ::base::StringPiece::npos, \ 136*6777b538SAndroid Build Coastguard Worker "Crash key names must not contain the ':' character."); \ 137*6777b538SAndroid Build Coastguard Worker ::base::debug::ScopedCrashKeyString scoped_crash_key_helper##nonce( \ 138*6777b538SAndroid Build Coastguard Worker [] { \ 139*6777b538SAndroid Build Coastguard Worker static auto* const key = ::base::debug::AllocateCrashKeyString( \ 140*6777b538SAndroid Build Coastguard Worker category "-" name, key_size); \ 141*6777b538SAndroid Build Coastguard Worker return key; \ 142*6777b538SAndroid Build Coastguard Worker }(), \ 143*6777b538SAndroid Build Coastguard Worker (data)) 144*6777b538SAndroid Build Coastguard Worker 145*6777b538SAndroid Build Coastguard Worker // This indirection is needed to expand __COUNTER__. 146*6777b538SAndroid Build Coastguard Worker #define SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, nonce, data, \ 147*6777b538SAndroid Build Coastguard Worker key_size) \ 148*6777b538SAndroid Build Coastguard Worker SCOPED_CRASH_KEY_STRING_INTERNAL2(category, name, nonce, data, key_size) 149*6777b538SAndroid Build Coastguard Worker 150*6777b538SAndroid Build Coastguard Worker // Helper macros for putting a local variable crash key on the stack before 151*6777b538SAndroid Build Coastguard Worker // causing a crash or calling CrashWithoutDumping(). `category` and `name` 152*6777b538SAndroid Build Coastguard Worker // should be string literals. 153*6777b538SAndroid Build Coastguard Worker // 154*6777b538SAndroid Build Coastguard Worker // SCOPED_CRASH_KEY_STRING32("MyCategory", "key_name", "value"); 155*6777b538SAndroid Build Coastguard Worker // 156*6777b538SAndroid Build Coastguard Worker // will set the crash key annotation named "MyCategory-key_name" to "value" 157*6777b538SAndroid Build Coastguard Worker // while in scope. 158*6777b538SAndroid Build Coastguard Worker #define SCOPED_CRASH_KEY_STRING32(category, name, data) \ 159*6777b538SAndroid Build Coastguard Worker SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, __COUNTER__, (data), \ 160*6777b538SAndroid Build Coastguard Worker ::base::debug::CrashKeySize::Size32) 161*6777b538SAndroid Build Coastguard Worker 162*6777b538SAndroid Build Coastguard Worker #define SCOPED_CRASH_KEY_STRING64(category, name, data) \ 163*6777b538SAndroid Build Coastguard Worker SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, __COUNTER__, (data), \ 164*6777b538SAndroid Build Coastguard Worker ::base::debug::CrashKeySize::Size64) 165*6777b538SAndroid Build Coastguard Worker 166*6777b538SAndroid Build Coastguard Worker #define SCOPED_CRASH_KEY_STRING256(category, name, data) \ 167*6777b538SAndroid Build Coastguard Worker SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, __COUNTER__, (data), \ 168*6777b538SAndroid Build Coastguard Worker ::base::debug::CrashKeySize::Size256) 169*6777b538SAndroid Build Coastguard Worker 170*6777b538SAndroid Build Coastguard Worker #define SCOPED_CRASH_KEY_STRING1024(category, name, data) \ 171*6777b538SAndroid Build Coastguard Worker SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, __COUNTER__, (data), \ 172*6777b538SAndroid Build Coastguard Worker ::base::debug::CrashKeySize::Size1024) 173*6777b538SAndroid Build Coastguard Worker 174*6777b538SAndroid Build Coastguard Worker #define SCOPED_CRASH_KEY_BOOL(category, name, data) \ 175*6777b538SAndroid Build Coastguard Worker static_assert(std::is_same_v<std::decay_t<decltype(data)>, bool>, \ 176*6777b538SAndroid Build Coastguard Worker "SCOPED_CRASH_KEY_BOOL must be passed a boolean value."); \ 177*6777b538SAndroid Build Coastguard Worker SCOPED_CRASH_KEY_STRING32(category, name, (data) ? "true" : "false") 178*6777b538SAndroid Build Coastguard Worker 179*6777b538SAndroid Build Coastguard Worker #define SCOPED_CRASH_KEY_NUMBER(category, name, data) \ 180*6777b538SAndroid Build Coastguard Worker SCOPED_CRASH_KEY_STRING32(category, name, ::base::NumberToString(data)) 181*6777b538SAndroid Build Coastguard Worker 182*6777b538SAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////// 183*6777b538SAndroid Build Coastguard Worker // The following declarations are used to initialize the crash key system 184*6777b538SAndroid Build Coastguard Worker // in //base by providing implementations for the above functions. 185*6777b538SAndroid Build Coastguard Worker 186*6777b538SAndroid Build Coastguard Worker // The virtual interface that provides the implementation for the crash key 187*6777b538SAndroid Build Coastguard Worker // API. This is implemented by a higher-layer component, and the instance is 188*6777b538SAndroid Build Coastguard Worker // set using the function below. 189*6777b538SAndroid Build Coastguard Worker class CrashKeyImplementation { 190*6777b538SAndroid Build Coastguard Worker public: 191*6777b538SAndroid Build Coastguard Worker virtual ~CrashKeyImplementation() = default; 192*6777b538SAndroid Build Coastguard Worker 193*6777b538SAndroid Build Coastguard Worker virtual CrashKeyString* Allocate(const char name[], CrashKeySize size) = 0; 194*6777b538SAndroid Build Coastguard Worker virtual void Set(CrashKeyString* crash_key, std::string_view value) = 0; 195*6777b538SAndroid Build Coastguard Worker virtual void Clear(CrashKeyString* crash_key) = 0; 196*6777b538SAndroid Build Coastguard Worker virtual void OutputCrashKeysToStream(std::ostream& out) = 0; 197*6777b538SAndroid Build Coastguard Worker }; 198*6777b538SAndroid Build Coastguard Worker 199*6777b538SAndroid Build Coastguard Worker // Initializes the crash key system in base by replacing the existing 200*6777b538SAndroid Build Coastguard Worker // implementation, if it exists, with |impl|. The |impl| is copied into base. 201*6777b538SAndroid Build Coastguard Worker BASE_EXPORT void SetCrashKeyImplementation( 202*6777b538SAndroid Build Coastguard Worker std::unique_ptr<CrashKeyImplementation> impl); 203*6777b538SAndroid Build Coastguard Worker 204*6777b538SAndroid Build Coastguard Worker // The base structure for a crash key, storing the allocation metadata. 205*6777b538SAndroid Build Coastguard Worker struct CrashKeyString { CrashKeyStringCrashKeyString206*6777b538SAndroid Build Coastguard Worker constexpr CrashKeyString(const char name[], CrashKeySize size) 207*6777b538SAndroid Build Coastguard Worker : name(name), size(size) {} 208*6777b538SAndroid Build Coastguard Worker const char* const name; 209*6777b538SAndroid Build Coastguard Worker const CrashKeySize size; 210*6777b538SAndroid Build Coastguard Worker }; 211*6777b538SAndroid Build Coastguard Worker 212*6777b538SAndroid Build Coastguard Worker } // namespace debug 213*6777b538SAndroid Build Coastguard Worker } // namespace base 214*6777b538SAndroid Build Coastguard Worker 215*6777b538SAndroid Build Coastguard Worker #endif // BASE_DEBUG_CRASH_LOGGING_H_ 216