Create client data structures for typed Annotations.

This introduces the Annotation object, used to declare typed
annotations, and the AnnotationList object, used to reference these. The
AnnotationList is referenced by the CrashpadInfo structure. Currently
nothing reads these.

The AnnotationList implements a lock-free linked list, into which
Annotation objects are added exactly once, when they are first set.
Clearing an Annotation merely marks it internally as such, rather than
removing it from the list.

Bug: crashpad:192
Change-Id: I72414b1f83d624c4ae323e09ecea8cfb69a68c5e
Reviewed-on: https://chromium-review.googlesource.com/547135
Reviewed-by: Mark Mentovai <mark@chromium.org>
Commit-Queue: Robert Sesek <rsesek@chromium.org>
This commit is contained in:
Robert Sesek 2017-10-25 16:57:44 -04:00 коммит произвёл Commit Bot
Родитель 9bc5989125
Коммит 34699d378b
12 изменённых файлов: 789 добавлений и 1 удалений

41
client/annotation.cc Normal file
Просмотреть файл

@ -0,0 +1,41 @@
// Copyright 2017 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "client/annotation.h"
#include <type_traits>
#include "base/logging.h"
#include "client/annotation_list.h"
namespace crashpad {
static_assert(std::is_standard_layout<Annotation>::value,
"Annotation must be POD");
// static
constexpr size_t Annotation::kNameMaxLength;
constexpr size_t Annotation::kValueMaxSize;
void Annotation::SetSize(ValueSizeType size) {
DCHECK_LT(size, kValueMaxSize);
size_ = size;
AnnotationList::Get()->Add(this);
}
void Annotation::Clear() {
size_ = 0;
}
} // namespace crashpad

221
client/annotation.h Normal file
Просмотреть файл

@ -0,0 +1,221 @@
// Copyright 2017 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CRASHPAD_CLIENT_ANNOTATION_H_
#define CRASHPAD_CLIENT_ANNOTATION_H_
#include <algorithm>
#include <atomic>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include "base/macros.h"
#include "base/numerics/safe_conversions.h"
namespace crashpad {
class AnnotationList;
//! \brief Base class for an annotation, which records a name-value pair of
//! arbitrary data when set.
//!
//! After an annotation is declared, its `value_ptr_` will not be captured in a
//! crash report until a call to \a SetSize() specifies how much data from the
//! value should be recorded.
//!
//! Annotations should be declared with static storage duration.
//!
//! An example declaration and usage:
//!
//! \code
//! // foo.cc:
//!
//! namespace {
//! char g_buffer[1024];
//! crashpad::Annotation g_buffer_annotation(
//! crashpad::Annotation::Type::kString, "buffer_head", g_buffer);
//! } // namespace
//!
//! void OnBufferProduced(size_t n) {
//! // Capture the head of the buffer, in case we crash when parsing it.
//! g_buffer_annotation.SetSize(std::min(64, n));
//!
//! // Start parsing the header.
//! Frobinate(g_buffer, n);
//! }
//! \endcode
//!
//! Annotation objects are not inherently thread-safe. To manipulate them
//! from multiple threads, external synchronization must be used.
//!
//! Annotation objects should never be destroyed. Once they are Set(), they
//! are permanently referenced by a global object.
class Annotation {
public:
//! \brief The maximum length of the #name field in bytes.
static constexpr size_t kNameMaxLength = 64;
//! \brief The maximum size of the #value field in bytes.
static constexpr size_t kValueMaxSize = 2048;
//! \brief The type used for \a SetSize().
using ValueSizeType = uint32_t;
//! \brief The type of data stored in the annotation.
enum class Type : uint16_t {
//! \brief An invalid annotation. Reserved for internal use.
kInvalid = 0,
//! \brief A `NUL`-terminated C-string.
kString = 1,
//! \brief Clients may declare their own custom types by using values
//! greater than this.
kUserDefinedStart = 0x8000,
};
//! \brief Creates a user-defined Annotation::Type.
//!
//! This exists to remove the casting overhead of `enum class`.
//!
//! \param[in] value A value used to create a user-defined type.
//!
//! \returns The value added to Type::kUserDefinedStart and casted.
constexpr static Type UserDefinedType(uint16_t value) {
using UnderlyingType = std::underlying_type<Type>::type;
// MSVS 2015 doesn't have full C++14 support and complains about local
// variables defined in a constexpr function, which is valid. Avoid them
// and the also-problematic DCHECK until all the infrastructure is updated:
// https://crbug.com/crashpad/201.
#if !defined(OS_WIN) || (defined(_MSC_VER) && _MSC_VER >= 1910)
const UnderlyingType start =
static_cast<UnderlyingType>(Type::kUserDefinedStart);
const UnderlyingType user_type = start + value;
DCHECK(user_type > start) << "User-defined Type is 0 or overflows";
return static_cast<Type>(user_type);
#else
return static_cast<Type>(
static_cast<UnderlyingType>(Type::kUserDefinedStart) + value);
#endif
}
//! \brief Constructs a new annotation.
//!
//! Upon construction, the annotation will not be included in any crash
//! reports until \sa SetSize() is called with a value greater than `0`.
//!
//! \param[in] type The data type of the value of the annotation.
//! \param[in] name A `NUL`-terminated C-string name for the annotation. Names
//! do not have to be unique, though not all crash processors may handle
//! Annotations with the same name. Names should be constexpr data with
//! static storage duration.
//! \param[in] value_ptr A pointer to the value for the annotation. The
//! pointer may not be changed once associated with an annotation, but
//! the data may be mutated.
constexpr Annotation(Type type, const char name[], void* const value_ptr)
: link_node_(nullptr),
name_(name),
value_ptr_(value_ptr),
size_(0),
type_(type) {}
//! \brief Specifies the number of bytes in \a value_ptr_ to include when
//! generating a crash report.
//!
//! A size of `0` indicates that no value should be recorded and is the
//! equivalent of calling \sa Clear().
//!
//! This method does not mutate the data referenced by the annotation, it
//! merely updates the annotation system's bookkeeping.
//!
//! Subclasses of this base class that provide additional Set methods to
//! mutate the value of the annotation must call always call this method.
//!
//! \param[in] size The number of bytes.
void SetSize(ValueSizeType size);
//! \brief Marks the annotation as cleared, indicating the \a value_ptr_
//! should not be included in a crash report.
//!
//! This method does not mutate the data referenced by the annotation, it
//! merely updates the annotation system's bookkeeping.
void Clear();
//! \brief Tests whether the annotation has been set.
bool is_set() const { return size_ > 0; }
Type type() const { return type_; }
ValueSizeType size() const { return size_; }
const char* name() const { return name_; }
const void* value() const { return value_ptr_; }
protected:
friend class AnnotationList;
std::atomic<Annotation*>& link_node() { return link_node_; }
private:
//! \brief Linked list next-node pointer. Accessed only by \sa AnnotationList.
//!
//! This will be null until the first call to \sa SetSize(), after which the
//! presence of the pointer will prevent the node from being added to the
//! list again.
std::atomic<Annotation*> link_node_;
const char* const name_;
void* const value_ptr_;
ValueSizeType size_;
const Type type_;
DISALLOW_COPY_AND_ASSIGN(Annotation);
};
//! \brief An \sa Annotation that stores a `NUL`-terminated C-string value.
//!
//! The storage for the value is allocated by the annotation and the template
//! parameter \a MaxSize controls the maxmium length for the value.
//!
//! It is expected that the string value be valid UTF-8, although this is not
//! validated.
template <Annotation::ValueSizeType MaxSize>
class StringAnnotation : public Annotation {
public:
//! \brief Constructs a new StringAnnotation with the given \a name.
//!
//! \param[in] name The Annotation name.
constexpr explicit StringAnnotation(const char name[])
: Annotation(Type::kString, name, value_), value_() {}
//! \brief Sets the Annotation's string value.
//!
//! \param[in] value The `NUL`-terminated C-string value.
void Set(const char* value) {
strncpy(value_, value, MaxSize);
SetSize(
std::min(MaxSize, base::saturated_cast<ValueSizeType>(strlen(value))));
}
private:
// This value is not `NUL`-terminated, since the size is stored by the base
// annotation.
char value_[MaxSize];
DISALLOW_COPY_AND_ASSIGN(StringAnnotation);
};
} // namespace crashpad
#endif // CRASHPAD_CLIENT_ANNOTATION_H_

97
client/annotation_list.cc Normal file
Просмотреть файл

@ -0,0 +1,97 @@
// Copyright 2017 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "client/annotation_list.h"
#include "base/logging.h"
#include "client/crashpad_info.h"
namespace crashpad {
AnnotationList::AnnotationList()
: tail_pointer_(&tail_),
head_(Annotation::Type::kInvalid, nullptr, nullptr),
tail_(Annotation::Type::kInvalid, nullptr, nullptr) {
head_.link_node().store(&tail_);
}
AnnotationList::~AnnotationList() {}
// static
AnnotationList* AnnotationList::Get() {
return CrashpadInfo::GetCrashpadInfo()->annotations_list();
}
// static
AnnotationList* AnnotationList::Register() {
AnnotationList* list = Get();
if (!list) {
list = new AnnotationList();
CrashpadInfo::GetCrashpadInfo()->set_annotations_list(list);
}
return list;
}
void AnnotationList::Add(Annotation* annotation) {
Annotation* null = nullptr;
Annotation* head_next = head_.link_node().load(std::memory_order_relaxed);
if (!annotation->link_node().compare_exchange_strong(null, head_next)) {
// If |annotation|'s link node is not null, then it has been added to the
// list already and no work needs to be done.
return;
}
// Check that the annotation's name is less than the maximum size. This is
// done here, since the Annotation constructor must be constexpr and this
// path is taken once per annotation.
DCHECK_LT(strlen(annotation->name_), Annotation::kNameMaxLength);
// Update the head link to point to the new |annotation|.
while (!head_.link_node().compare_exchange_weak(head_next, annotation)) {
// Another thread has updated the head-next pointer, so try again with the
// re-loaded |head_next|.
annotation->link_node().store(head_next, std::memory_order_relaxed);
}
}
AnnotationList::Iterator::Iterator(Annotation* head, const Annotation* tail)
: curr_(head), tail_(tail) {}
AnnotationList::Iterator::~Iterator() = default;
Annotation* AnnotationList::Iterator::operator*() const {
CHECK_NE(curr_, tail_);
return curr_;
}
AnnotationList::Iterator& AnnotationList::Iterator::operator++() {
CHECK_NE(curr_, tail_);
curr_ = curr_->link_node();
return *this;
}
bool AnnotationList::Iterator::operator==(
const AnnotationList::Iterator& other) const {
return curr_ == other.curr_;
}
AnnotationList::Iterator AnnotationList::begin() {
return Iterator(head_.link_node(), tail_pointer_);
}
AnnotationList::Iterator AnnotationList::end() {
return Iterator(&tail_, tail_pointer_);
}
} // namespace crashpad

94
client/annotation_list.h Normal file
Просмотреть файл

@ -0,0 +1,94 @@
// Copyright 2017 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CRASHPAD_CLIENT_ANNOTATION_LIST_H_
#define CRASHPAD_CLIENT_ANNOTATION_LIST_H_
#include "base/macros.h"
#include "client/annotation.h"
namespace crashpad {
//! \brief A list that contains all the currently set annotations.
//!
//! An instance of this class must be registered on the \a CrashpadInfo
//! structure in order to use the annotations system. Once a list object has
//! been registered on the CrashpadInfo, a different instance should not
//! be used instead.
class AnnotationList {
public:
AnnotationList();
~AnnotationList();
//! \brief Returns the instance of the list that has been registered on the
//! CrashapdInfo structure.
static AnnotationList* Get();
//! \brief Returns the instace of the list, creating and registering
//! it if one is not already set on the CrashapdInfo structure.
static AnnotationList* Register();
//! \brief Adds \a annotation to the global list. This method does not need
//! to be called by clients directly. The Annotation object will do so
//! automatically.
//!
//! Once an annotation is added to the list, it is not removed. This is
//! because the AnnotationList avoids the use of locks/mutexes, in case it is
//! being manipulated in a compromised context. Instead, an Annotation keeps
//! track of when it has been cleared, which excludes it from a crash report.
//! This design also avoids linear scans of the list when repeatedly setting
//! and/or clearing the value.
void Add(Annotation* annotation);
//! \brief An InputIterator for the AnnotationList.
class Iterator {
public:
~Iterator();
Annotation* operator*() const;
Iterator& operator++();
bool operator==(const Iterator& other) const;
bool operator!=(const Iterator& other) const { return !(*this == other); }
private:
friend class AnnotationList;
Iterator(Annotation* head, const Annotation* tail);
Annotation* curr_;
const Annotation* const tail_;
// Copy and assign are required.
};
//! \brief Returns an iterator to the first element of the annotation list.
Iterator begin();
//! \brief Returns an iterator past the last element of the annotation list.
Iterator end();
private:
// To make it easier for the handler to locate the dummy tail node, store the
// pointer. Placed first for packing.
const Annotation* const tail_pointer_;
// Dummy linked-list head and tail elements of \a Annotation::Type::kInvalid.
Annotation head_;
Annotation tail_;
DISALLOW_COPY_AND_ASSIGN(AnnotationList);
};
} // namespace crashpad
#endif // CRASHPAD_CLIENT_ANNOTATION_LIST_H_

Просмотреть файл

@ -0,0 +1,183 @@
// Copyright 2017 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "client/annotation.h"
#include <string>
#include <vector>
#include "base/rand_util.h"
#include "client/crashpad_info.h"
#include "gtest/gtest.h"
#include "util/misc/clock.h"
#include "util/thread/thread.h"
namespace crashpad {
namespace test {
namespace {
TEST(AnnotationListStatic, Register) {
ASSERT_FALSE(AnnotationList::Get());
EXPECT_TRUE(AnnotationList::Register());
EXPECT_TRUE(AnnotationList::Get());
EXPECT_EQ(AnnotationList::Get(), AnnotationList::Register());
// This isn't expected usage of the AnnotationList API, but it is necessary
// for testing.
AnnotationList* list = AnnotationList::Get();
CrashpadInfo::GetCrashpadInfo()->set_annotations_list(nullptr);
delete list;
EXPECT_FALSE(AnnotationList::Get());
}
class AnnotationList : public testing::Test {
public:
void SetUp() override {
CrashpadInfo::GetCrashpadInfo()->set_annotations_list(&annotations_);
}
void TearDown() override {
CrashpadInfo::GetCrashpadInfo()->set_annotations_list(nullptr);
}
// NOTE: Annotations should be declared at file-scope, but in order to test
// them, they are declared as part of the test. These members are public so
// they are accessible from global helpers.
crashpad::StringAnnotation<8> one_{"First"};
crashpad::StringAnnotation<256> two_{"Second"};
crashpad::StringAnnotation<101> three_{"First"};
protected:
using AllAnnotations = std::vector<std::pair<std::string, std::string>>;
AllAnnotations CollectAnnotations() {
AllAnnotations annotations;
for (Annotation* curr : annotations_) {
if (!curr->is_set())
continue;
std::string value(static_cast<const char*>(curr->value()), curr->size());
annotations.push_back(std::make_pair(curr->name(), value));
}
return annotations;
}
bool ContainsNameValue(const AllAnnotations& annotations,
const std::string& name,
const std::string& value) {
return std::find(annotations.begin(),
annotations.end(),
std::make_pair(name, value)) != annotations.end();
}
crashpad::AnnotationList annotations_;
};
TEST_F(AnnotationList, SetAndClear) {
one_.Set("this is a value longer than 8 bytes");
AllAnnotations annotations = CollectAnnotations();
EXPECT_EQ(1u, annotations.size());
EXPECT_TRUE(ContainsNameValue(annotations, "First", "this is "));
one_.Clear();
EXPECT_EQ(0u, CollectAnnotations().size());
one_.Set("short");
two_.Set(std::string(500, 'A').data());
annotations = CollectAnnotations();
EXPECT_EQ(2u, annotations.size());
EXPECT_EQ(5u, one_.size());
EXPECT_EQ(256u, two_.size());
EXPECT_TRUE(ContainsNameValue(annotations, "First", "short"));
EXPECT_TRUE(ContainsNameValue(annotations, "Second", std::string(256, 'A')));
}
TEST_F(AnnotationList, DuplicateKeys) {
ASSERT_EQ(0u, CollectAnnotations().size());
one_.Set("1");
three_.Set("2");
AllAnnotations annotations = CollectAnnotations();
EXPECT_EQ(2u, annotations.size());
EXPECT_TRUE(ContainsNameValue(annotations, "First", "1"));
EXPECT_TRUE(ContainsNameValue(annotations, "First", "2"));
one_.Clear();
annotations = CollectAnnotations();
EXPECT_EQ(1u, annotations.size());
}
class RaceThread : public Thread {
public:
explicit RaceThread(test::AnnotationList* test) : Thread(), test_(test) {}
private:
void ThreadMain() override {
for (int i = 0; i <= 50; ++i) {
if (i % 2 == 0) {
test_->three_.Set("three");
test_->two_.Clear();
} else {
test_->three_.Clear();
}
SleepNanoseconds(base::RandInt(1, 1000));
}
}
test::AnnotationList* test_;
};
TEST_F(AnnotationList, MultipleThreads) {
ASSERT_EQ(0u, CollectAnnotations().size());
RaceThread other_thread(this);
other_thread.Start();
for (int i = 0; i <= 50; ++i) {
if (i % 2 == 0) {
one_.Set("one");
two_.Set("two");
} else {
one_.Clear();
}
SleepNanoseconds(base::RandInt(1, 1000));
}
other_thread.Join();
AllAnnotations annotations = CollectAnnotations();
EXPECT_GE(annotations.size(), 2u);
EXPECT_LE(annotations.size(), 3u);
EXPECT_TRUE(ContainsNameValue(annotations, "First", "one"));
EXPECT_TRUE(ContainsNameValue(annotations, "First", "three"));
if (annotations.size() == 3) {
EXPECT_TRUE(ContainsNameValue(annotations, "Second", "two"));
}
}
} // namespace
} // namespace test
} // namespace crashpad

112
client/annotation_test.cc Normal file
Просмотреть файл

@ -0,0 +1,112 @@
// Copyright 2017 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "client/annotation.h"
#include <string>
#include "client/annotation_list.h"
#include "client/crashpad_info.h"
#include "gtest/gtest.h"
namespace crashpad {
namespace test {
namespace {
class Annotation : public testing::Test {
public:
void SetUp() override {
CrashpadInfo::GetCrashpadInfo()->set_annotations_list(&annotations_);
}
void TearDown() override {
CrashpadInfo::GetCrashpadInfo()->set_annotations_list(nullptr);
}
size_t AnnotationsCount() {
size_t result = 0;
for (auto* annotation : annotations_) {
if (annotation->is_set())
++result;
}
return result;
}
protected:
crashpad::AnnotationList annotations_;
};
TEST_F(Annotation, Basics) {
constexpr crashpad::Annotation::Type kType =
crashpad::Annotation::UserDefinedType(1);
const char kName[] = "annotation 1";
char buffer[1024];
crashpad::Annotation annotation(kType, kName, buffer);
EXPECT_FALSE(annotation.is_set());
EXPECT_EQ(0u, AnnotationsCount());
EXPECT_EQ(kType, annotation.type());
EXPECT_EQ(0u, annotation.size());
EXPECT_EQ(std::string(kName), annotation.name());
EXPECT_EQ(buffer, annotation.value());
annotation.SetSize(10);
EXPECT_TRUE(annotation.is_set());
EXPECT_EQ(1u, AnnotationsCount());
EXPECT_EQ(10u, annotation.size());
EXPECT_EQ(&annotation, *annotations_.begin());
annotation.Clear();
EXPECT_FALSE(annotation.is_set());
EXPECT_EQ(0u, AnnotationsCount());
EXPECT_EQ(0u, annotation.size());
}
TEST_F(Annotation, StringType) {
crashpad::StringAnnotation<5> annotation("name");
const char* value_ptr = static_cast<const char*>(annotation.value());
EXPECT_FALSE(annotation.is_set());
EXPECT_EQ(crashpad::Annotation::Type::kString, annotation.type());
EXPECT_EQ(0u, annotation.size());
EXPECT_EQ(std::string("name"), annotation.name());
EXPECT_EQ(0u, strlen(value_ptr));
annotation.Set("test");
EXPECT_TRUE(annotation.is_set());
EXPECT_EQ(1u, AnnotationsCount());
EXPECT_EQ(4u, annotation.size());
EXPECT_EQ(std::string("test"), value_ptr);
annotation.Set("loooooooooooong");
EXPECT_TRUE(annotation.is_set());
EXPECT_EQ(1u, AnnotationsCount());
EXPECT_EQ(5u, annotation.size());
EXPECT_EQ(std::string("loooo"), std::string(value_ptr, annotation.size()));
}
} // namespace
} // namespace test
} // namespace crashpad

Просмотреть файл

@ -29,6 +29,10 @@
'..',
],
'sources': [
'annotation.cc',
'annotation.h',
'annotation_list.cc',
'annotation_list.h',
'capture_context_mac.S',
'capture_context_mac.h',
'crash_report_database.cc',

Просмотреть файл

@ -35,6 +35,8 @@
'..',
],
'sources': [
'annotation_test.cc',
'annotation_list_test.cc',
'capture_context_mac_test.cc',
'crash_report_database_test.cc',
'crashpad_client_win_test.cc',

Просмотреть файл

@ -105,7 +105,8 @@ CrashpadInfo::CrashpadInfo()
padding_1_(0),
extra_memory_ranges_(nullptr),
simple_annotations_(nullptr),
user_data_minidump_stream_head_(nullptr)
user_data_minidump_stream_head_(nullptr),
annotations_list_(nullptr)
#if !defined(NDEBUG) && defined(OS_WIN)
,
invalid_read_detection_(0xbadc0de)

Просмотреть файл

@ -19,6 +19,7 @@
#include "base/macros.h"
#include "build/build_config.h"
#include "client/annotation_list.h"
#include "client/simple_address_range_bag.h"
#include "client/simple_string_dictionary.h"
#include "util/misc/tri_state.h"
@ -109,6 +110,33 @@ struct CrashpadInfo {
return simple_annotations_;
}
//! \brief Sets the annotations list.
//!
//! Unlike the \a simple_annotations structure, the \a annotations can
//! typed data and it is not limited to a dictionary form. Annotations are
//! interpreted by Crashpad as module-level annotations.
//!
//! Annotations may exist in \a annotations_list at the time that this
//! method is called, or they may be added, removed, or modified in \a
//! annotations_list after this method is called.
//!
//! \param[in] annotations_list A list of set Annotation objects that maintain
//! arbitrary, typed key-value state. The CrashpadInfo object does not
//! take ownership of the AnnotationsList object. It is the callers
//! responsibility to ensure that this pointer remains valid while it is
//! in effect for a CrashpadInfo object.
//!
//! \sa annotations_list()
//! \sa AnnotationList::Register()
void set_annotations_list(AnnotationList* list) { annotations_list_ = list; }
//! \return The annotations list.
//!
//! \sa set_annotations_list()
//! \sa AnnotationList::Get()
//! \sa AnnotationList::Register()
AnnotationList* annotations_list() const { return annotations_list_; }
//! \brief Enables or disables Crashpad handler processing.
//!
//! When handling an exception, the Crashpad handler will scan all modules in
@ -218,6 +246,7 @@ struct CrashpadInfo {
SimpleAddressRangeBag* extra_memory_ranges_; // weak
SimpleStringDictionary* simple_annotations_; // weak
internal::UserDataMinidumpStreamListEntry* user_data_minidump_stream_head_;
AnnotationList* annotations_list_; // weak
#if !defined(NDEBUG) && defined(OS_WIN)
uint32_t invalid_read_detection_;

Просмотреть файл

@ -47,4 +47,7 @@ PROCESS_TYPE_STRUCT_BEGIN(CrashpadInfo)
// UserDataStreamListEntry*
PROCESS_TYPE_STRUCT_MEMBER(Pointer, user_data_minidump_stream_head)
// AnnotationList*
PROCESS_TYPE_STRUCT_MEMBER(Pointer, annotations_list)
PROCESS_TYPE_STRUCT_END(CrashpadInfo)

Просмотреть файл

@ -48,6 +48,7 @@ struct CrashpadInfo {
typename Traits::Pointer extra_address_ranges;
typename Traits::Pointer simple_annotations;
typename Traits::Pointer user_data_minidump_stream_head;
typename Traits::Pointer annotations_list;
};
} // namespace process_types