209 lines
8.5 KiB
C++
209 lines
8.5 KiB
C++
// Copyright 2012 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef BASE_DEBUG_CRASH_LOGGING_H_
|
|
#define BASE_DEBUG_CRASH_LOGGING_H_
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <iosfwd>
|
|
#include <memory>
|
|
#include <type_traits>
|
|
|
|
#include "base/base_export.h"
|
|
#include "base/memory/raw_ptr.h"
|
|
#include "base/strings/string_number_conversions.h"
|
|
#include "base/strings/string_piece.h"
|
|
|
|
namespace base {
|
|
namespace debug {
|
|
|
|
// A crash key is an annotation that is carried along with a crash report, to
|
|
// provide additional debugging information beyond a stack trace. Crash keys
|
|
// have a name and a string value.
|
|
//
|
|
// The preferred API is //components/crash/core/common:crash_key, however not
|
|
// all clients can hold a direct dependency on that target. The API provided
|
|
// in this file indirects the dependency and adds some convenience helpers that
|
|
// make the API a bit less clunky.
|
|
//
|
|
// TODO(dcheng): Some of the nicer APIs should probably be upstreamed into
|
|
// //components/crash.
|
|
//
|
|
// Preferred usage when a crash key value only needs to be set within a scope:
|
|
//
|
|
// SCOPED_CRASH_KEY_STRING32("category", "name", "value");
|
|
// base::debug::DumpWithoutCrashing();
|
|
//
|
|
// If the crash key is pre-allocated elsewhere, but the value only needs to be
|
|
// set within a scope:
|
|
//
|
|
// base::debug::ScopedCrashKeyString scoper(
|
|
// GetCrashKeyForComponent(),
|
|
// "value");
|
|
//
|
|
// Otherwise, if the crash key needs to persist (e.g. the actual crash dump is
|
|
// triggered some time later asynchronously):
|
|
//
|
|
// static auto* const crash_key = base::debug::AllocateCrashKeyString(
|
|
// "name", base::debug::CrashKeySize::Size32);
|
|
// base::debug::SetCrashKeyString(crash_key, "value");
|
|
//
|
|
// // Do other work before calling `base::debug::DumpWithoutCrashing()` later.
|
|
//
|
|
// ***WARNING***
|
|
//
|
|
// Do *not* write this:
|
|
//
|
|
// base::debug::SetCrashKeyString(
|
|
// base::debug::AllocateCrashKeyString(
|
|
// "name", base::debug::CrashKeySize::Size32),
|
|
// "value");
|
|
//
|
|
// As this will leak a heap allocation every time the crash key is set!
|
|
|
|
// The maximum length for a crash key's value must be one of the following
|
|
// pre-determined values.
|
|
enum class CrashKeySize {
|
|
Size32 = 32,
|
|
Size64 = 64,
|
|
Size256 = 256,
|
|
Size1024 = 1024,
|
|
};
|
|
|
|
struct CrashKeyString;
|
|
|
|
// Allocates a new crash key with the specified |name| with storage for a
|
|
// value up to length |size|. This will return null if the crash key system is
|
|
// not initialized.
|
|
//
|
|
// Note: this internally allocates, so the returned pointer should always
|
|
// be cached in a variable with static storage duration, e.g.:
|
|
// static auto* const crash_key = base::debug::AllocateCrashKeyString(...);
|
|
BASE_EXPORT CrashKeyString* AllocateCrashKeyString(const char name[],
|
|
CrashKeySize size);
|
|
|
|
// Stores |value| into the specified |crash_key|. The |crash_key| may be null
|
|
// if AllocateCrashKeyString() returned null. If |value| is longer than the
|
|
// size with which the key was allocated, it will be truncated.
|
|
BASE_EXPORT void SetCrashKeyString(CrashKeyString* crash_key,
|
|
base::StringPiece value);
|
|
|
|
// Clears any value that was stored in |crash_key|. The |crash_key| may be
|
|
// null.
|
|
BASE_EXPORT void ClearCrashKeyString(CrashKeyString* crash_key);
|
|
|
|
// Outputs current (i.e. allocated and non-empty) crash keys to `out`.
|
|
BASE_EXPORT void OutputCrashKeysToStream(std::ostream& out);
|
|
|
|
// A scoper that sets the specified key to value for the lifetime of the
|
|
// object, and clears it on destruction.
|
|
class BASE_EXPORT ScopedCrashKeyString {
|
|
public:
|
|
ScopedCrashKeyString(CrashKeyString* crash_key, base::StringPiece value);
|
|
ScopedCrashKeyString(ScopedCrashKeyString&& other);
|
|
~ScopedCrashKeyString();
|
|
|
|
// Disallow copy and assign.
|
|
ScopedCrashKeyString(const ScopedCrashKeyString&) = delete;
|
|
ScopedCrashKeyString& operator=(const ScopedCrashKeyString&) = delete;
|
|
|
|
// Disallow move assign to keep the time at which the crash key is cleared
|
|
// easy to reason about. Assigning over an existing instance would
|
|
// automatically clear the key instead of at the destruction of the object.
|
|
ScopedCrashKeyString& operator=(ScopedCrashKeyString&&) = delete;
|
|
|
|
private:
|
|
raw_ptr<CrashKeyString> crash_key_;
|
|
};
|
|
|
|
// Internal helpers for the SCOPED_CRASH_KEY_... helper macros defined below.
|
|
//
|
|
// The static_assert that checks the length of |key_name| is a compile-time
|
|
// equivalent of the DCHECK in crash_reporter::internal::CrashKeyStringImpl::Set
|
|
// that restricts the name of a crash key to 40 characters.
|
|
#define SCOPED_CRASH_KEY_STRING_INTERNAL2(category, name, nonce, data, \
|
|
key_size) \
|
|
static_assert(::std::size(category "-" name) < 40, \
|
|
"Crash key names must be shorter than 40 characters."); \
|
|
::base::debug::ScopedCrashKeyString scoped_crash_key_helper##nonce( \
|
|
[] { \
|
|
static auto* const key = ::base::debug::AllocateCrashKeyString( \
|
|
category "-" name, key_size); \
|
|
return key; \
|
|
}(), \
|
|
(data))
|
|
|
|
// This indirection is needed to expand __COUNTER__.
|
|
#define SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, nonce, data, \
|
|
key_size) \
|
|
SCOPED_CRASH_KEY_STRING_INTERNAL2(category, name, nonce, data, key_size)
|
|
|
|
// Helper macros for putting a local variable crash key on the stack before
|
|
// causing a crash or calling CrashWithoutDumping(). `category` and `name`
|
|
// should be string literals.
|
|
//
|
|
// SCOPED_CRASH_KEY_STRING32("MyCategory", "key_name", "value");
|
|
//
|
|
// will set the crash key annotation named "MyCategory-key_name" to "value"
|
|
// while in scope.
|
|
#define SCOPED_CRASH_KEY_STRING32(category, name, data) \
|
|
SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, __COUNTER__, (data), \
|
|
::base::debug::CrashKeySize::Size32)
|
|
|
|
#define SCOPED_CRASH_KEY_STRING64(category, name, data) \
|
|
SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, __COUNTER__, (data), \
|
|
::base::debug::CrashKeySize::Size64)
|
|
|
|
#define SCOPED_CRASH_KEY_STRING256(category, name, data) \
|
|
SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, __COUNTER__, (data), \
|
|
::base::debug::CrashKeySize::Size256)
|
|
|
|
#define SCOPED_CRASH_KEY_STRING1024(category, name, data) \
|
|
SCOPED_CRASH_KEY_STRING_INTERNAL(category, name, __COUNTER__, (data), \
|
|
::base::debug::CrashKeySize::Size1024)
|
|
|
|
#define SCOPED_CRASH_KEY_BOOL(category, name, data) \
|
|
static_assert(std::is_same<std::decay_t<decltype(data)>, bool>::value, \
|
|
"SCOPED_CRASH_KEY_BOOL must be passed a boolean value."); \
|
|
SCOPED_CRASH_KEY_STRING32(category, name, (data) ? "true" : "false")
|
|
|
|
#define SCOPED_CRASH_KEY_NUMBER(category, name, data) \
|
|
SCOPED_CRASH_KEY_STRING32(category, name, ::base::NumberToString(data))
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// The following declarations are used to initialize the crash key system
|
|
// in //base by providing implementations for the above functions.
|
|
|
|
// The virtual interface that provides the implementation for the crash key
|
|
// API. This is implemented by a higher-layer component, and the instance is
|
|
// set using the function below.
|
|
class CrashKeyImplementation {
|
|
public:
|
|
virtual ~CrashKeyImplementation() = default;
|
|
|
|
virtual CrashKeyString* Allocate(const char name[], CrashKeySize size) = 0;
|
|
virtual void Set(CrashKeyString* crash_key, base::StringPiece value) = 0;
|
|
virtual void Clear(CrashKeyString* crash_key) = 0;
|
|
virtual void OutputCrashKeysToStream(std::ostream& out) = 0;
|
|
};
|
|
|
|
// Initializes the crash key system in base by replacing the existing
|
|
// implementation, if it exists, with |impl|. The |impl| is copied into base.
|
|
BASE_EXPORT void SetCrashKeyImplementation(
|
|
std::unique_ptr<CrashKeyImplementation> impl);
|
|
|
|
// The base structure for a crash key, storing the allocation metadata.
|
|
struct CrashKeyString {
|
|
constexpr CrashKeyString(const char name[], CrashKeySize size)
|
|
: name(name), size(size) {}
|
|
const char* const name;
|
|
const CrashKeySize size;
|
|
};
|
|
|
|
} // namespace debug
|
|
} // namespace base
|
|
|
|
#endif // BASE_DEBUG_CRASH_LOGGING_H_
|