Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
+264
View File
@@ -0,0 +1,264 @@
// 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/logging.h"
#include "base/macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_piece.h"
#include "build/build_config.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 an annotations name, in bytes.
static constexpr size_t kNameMaxLength = 64;
//! \brief The maximum size of an annotations value, 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 A constructor tag that enables braced initialization in C arrays.
//!
//! \sa StringAnnotation()
enum class Tag { kArray };
//! \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 Constructs a new StringAnnotation with the given \a name.
//!
//! This constructor takes the ArrayInitializerTag for use when
//! initializing a C array of annotations. The main constructor is
//! explicit and cannot be brace-initialized. As an example:
//!
//! \code
//! static crashpad::StringAnnotation<32> annotations[] = {
//! {"name-1", crashpad::StringAnnotation<32>::Tag::kArray},
//! {"name-2", crashpad::StringAnnotation<32>::Tag::kArray},
//! {"name-3", crashpad::StringAnnotation<32>::Tag::kArray},
//! };
//! \endcode
//!
//! \param[in] name The Annotation name.
//! \param[in] tag A constructor tag.
constexpr StringAnnotation(const char name[], Tag tag)
: StringAnnotation(name) {}
//! \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))));
}
//! \brief Sets the Annotation's string value.
//!
//! \param[in] string The string value.
void Set(base::StringPiece string) {
Annotation::ValueSizeType size =
std::min(MaxSize, base::saturated_cast<ValueSizeType>(string.size()));
memcpy(value_, string.data(), size);
// Check for no embedded `NUL` characters.
DCHECK(!memchr(value_, '\0', size)) << "embedded NUL";
SetSize(size);
}
const base::StringPiece value() const {
return base::StringPiece(value_, size());
}
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_
@@ -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,48 @@
// Copyright 2014 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_CAPTURE_CONTEXT_MAC_H_
#define CRASHPAD_CLIENT_CAPTURE_CONTEXT_MAC_H_
#include <mach/mach.h>
#include "build/build_config.h"
namespace crashpad {
#if defined(ARCH_CPU_X86_FAMILY)
using NativeCPUContext = x86_thread_state;
#endif
//! \brief Saves the CPU context.
//!
//! The CPU context will be captured as accurately and completely as possible,
//! containing an atomic snapshot at the point of this functions return. This
//! function does not modify any registers.
//!
//! \param[out] cpu_context The structure to store the context in.
//!
//! \note On x86_64, the value for `%%rdi` will be populated with the address of
//! this functions argument, as mandated by the ABI. If the value of
//! `%%rdi` prior to calling this function is needed, it must be obtained
//! separately prior to calling this function. For example:
//! \code
//! uint64_t rdi;
//! asm("movq %%rdi, %0" : "=m"(rdi));
//! \endcode
void CaptureContext(NativeCPUContext* cpu_context);
} // namespace crashpad
#endif // CRASHPAD_CLIENT_CAPTURE_CONTEXT_MAC_H_
@@ -0,0 +1,367 @@
// Copyright 2015 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_CRASH_REPORT_DATABASE_H_
#define CRASHPAD_CLIENT_CRASH_REPORT_DATABASE_H_
#include <time.h>
#include <memory>
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/macros.h"
#include "util/file/file_io.h"
#include "util/misc/metrics.h"
#include "util/misc/uuid.h"
namespace crashpad {
class Settings;
//! \brief An interface for managing a collection of crash report files and
//! metadata associated with the crash reports.
//!
//! All Report objects that are returned by this class are logically const.
//! They are snapshots of the database at the time the query was run, and the
//! data returned is liable to change after the query is executed.
//!
//! The lifecycle of a crash report has three stages:
//!
//! 1. New: A crash report is created with PrepareNewCrashReport(), the
//! the client then writes the report, and then calls
//! FinishedWritingCrashReport() to make the report Pending.
//! 2. Pending: The report has been written but has not been locally
//! processed, or it was has been brought back from 'Completed' state by
//! user request.
//! 3. Completed: The report has been locally processed, either by uploading
//! it to a collection server and calling RecordUploadAttempt(), or by
//! calling SkipReportUpload().
class CrashReportDatabase {
public:
//! \brief A crash report record.
//!
//! This represents the metadata for a crash report, as well as the location
//! of the report itself. A CrashReportDatabase maintains at least this
//! information.
struct Report {
Report();
//! A unique identifier by which this report will always be known to the
//! database.
UUID uuid;
//! The current location of the crash report on the clients filesystem.
//! The location of a crash report may change over time, so the UUID should
//! be used as the canonical identifier.
base::FilePath file_path;
//! An identifier issued to this crash report by a collection server.
std::string id;
//! The time at which the report was generated.
time_t creation_time;
//! Whether this crash report was successfully uploaded to a collection
//! server.
bool uploaded;
//! The last timestamp at which an attempt was made to submit this crash
//! report to a collection server. If this is zero, then the report has
//! never been uploaded. If #uploaded is true, then this timestamp is the
//! time at which the report was uploaded, and no other attempts to upload
//! this report will be made.
time_t last_upload_attempt_time;
//! The number of times an attempt was made to submit this report to
//! a collection server. If this is more than zero, then
//! #last_upload_attempt_time will be set to the timestamp of the most
//! recent attempt.
int upload_attempts;
//! Whether this crash report was explicitly requested by user to be
//! uploaded. This can be true only if report is in the 'pending' state.
bool upload_explicitly_requested;
};
//! \brief A crash report that is in the process of being written.
//!
//! An instance of this struct should be created via PrepareNewCrashReport()
//! and destroyed with FinishedWritingCrashReport().
struct NewReport {
//! The file handle to which the report should be written.
FileHandle handle;
//! A unique identifier by which this report will always be known to the
//! database.
UUID uuid;
//! The path to the crash report being written.
base::FilePath path;
};
//! \brief A scoper to cleanly handle the interface requirement imposed by
//! PrepareNewCrashReport().
//!
//! Calls ErrorWritingCrashReport() upon destruction unless disarmed by
//! calling Disarm(). Armed upon construction.
class CallErrorWritingCrashReport {
public:
//! \brief Arms the object to call ErrorWritingCrashReport() on \a database
//! with an argument of \a new_report on destruction.
CallErrorWritingCrashReport(CrashReportDatabase* database,
NewReport* new_report);
//! \brief Calls ErrorWritingCrashReport() if the object is armed.
~CallErrorWritingCrashReport();
//! \brief Disarms the object so that CallErrorWritingCrashReport() will not
//! be called upon destruction.
void Disarm();
private:
CrashReportDatabase* database_; // weak
NewReport* new_report_; // weak
DISALLOW_COPY_AND_ASSIGN(CallErrorWritingCrashReport);
};
//! \brief The result code for operations performed on a database.
enum OperationStatus {
//! \brief No error occurred.
kNoError = 0,
//! \brief The report that was requested could not be located.
//!
//! This may occur when the report is present in the database but not in a
//! state appropriate for the requested operation, for example, if
//! GetReportForUploading() is called to obtain report thats already in the
//! completed state.
kReportNotFound,
//! \brief An error occured while performing a file operation on a crash
//! report.
//!
//! A database is responsible for managing both the metadata about a report
//! and the actual crash report itself. This error is returned when an
//! error occurred when managing the report file. Additional information
//! will be logged.
kFileSystemError,
//! \brief An error occured while recording metadata for a crash report or
//! database-wide settings.
//!
//! A database is responsible for managing both the metadata about a report
//! and the actual crash report itself. This error is returned when an
//! error occurred when managing the metadata about a crash report or
//! database-wide settings. Additional information will be logged.
kDatabaseError,
//! \brief The operation could not be completed because a concurrent
//! operation affecting the report is occurring.
kBusyError,
//! \brief The report cannot be uploaded by user request as it has already
//! been uploaded.
kCannotRequestUpload,
};
virtual ~CrashReportDatabase() {}
//! \brief Opens a database of crash reports, possibly creating it.
//!
//! \param[in] path A path to the database to be created or opened. If the
//! database does not yet exist, it will be created if possible. Note that
//! for databases implemented as directory structures, existence refers
//! solely to the outermost directory.
//!
//! \return A database object on success, `nullptr` on failure with an error
//! logged.
//!
//! \sa InitializeWithoutCreating
static std::unique_ptr<CrashReportDatabase> Initialize(
const base::FilePath& path);
//! \brief Opens an existing database of crash reports.
//!
//! \param[in] path A path to the database to be opened. If the database does
//! not yet exist, it will not be created. Note that for databases
//! implemented as directory structures, existence refers solely to the
//! outermost directory. On such databases, as long as the outermost
//! directory is present, this method will create the inner structure.
//!
//! \return A database object on success, `nullptr` on failure with an error
//! logged.
//!
//! \sa Initialize
static std::unique_ptr<CrashReportDatabase> InitializeWithoutCreating(
const base::FilePath& path);
//! \brief Returns the Settings object for this database.
//!
//! \return A weak pointer to the Settings object, which is owned by the
//! database.
virtual Settings* GetSettings() = 0;
//! \brief Creates a record of a new crash report.
//!
//! Callers can then write the crash report using the file handle provided.
//! The caller does not own the new crash report record or its file handle,
//! both of which must be explicitly disposed of by calling
//! FinishedWritingCrashReport() or ErrorWritingCrashReport().
//!
//! To arrange to call ErrorWritingCrashReport() during any early return, use
//! CallErrorWritingCrashReport.
//!
//! \param[out] report A NewReport object containing a file handle to which
//! the crash report data should be written. Only valid if this returns
//! #kNoError. The caller must not delete the NewReport object or close
//! the file handle within.
//!
//! \return The operation status code.
virtual OperationStatus PrepareNewCrashReport(NewReport** report) = 0;
//! \brief Informs the database that a crash report has been written.
//!
//! After calling this method, the database is permitted to move and rename
//! the file at NewReport::path.
//!
//! \param[in] report A NewReport obtained with PrepareNewCrashReport(). The
//! NewReport object and file handle within will be invalidated as part of
//! this call.
//! \param[out] uuid The UUID of this crash report.
//!
//! \return The operation status code.
virtual OperationStatus FinishedWritingCrashReport(NewReport* report,
UUID* uuid) = 0;
//! \brief Informs the database that an error occurred while attempting to
//! write a crash report, and that any resources associated with it should
//! be cleaned up.
//!
//! After calling this method, the database is permitted to remove the file at
//! NewReport::path.
//!
//! \param[in] report A NewReport obtained with PrepareNewCrashReport(). The
//! NewReport object and file handle within will be invalidated as part of
//! this call.
//!
//! \return The operation status code.
virtual OperationStatus ErrorWritingCrashReport(NewReport* report) = 0;
//! \brief Returns the crash report record for the unique identifier.
//!
//! \param[in] uuid The crash report record unique identifier.
//! \param[out] report A crash report record. Only valid if this returns
//! #kNoError.
//!
//! \return The operation status code.
virtual OperationStatus LookUpCrashReport(const UUID& uuid,
Report* report) = 0;
//! \brief Returns a list of crash report records that have not been uploaded.
//!
//! \param[out] reports A list of crash report record objects. This must be
//! empty on entry. Only valid if this returns #kNoError.
//!
//! \return The operation status code.
virtual OperationStatus GetPendingReports(std::vector<Report>* reports) = 0;
//! \brief Returns a list of crash report records that have been completed,
//! either by being uploaded or by skipping upload.
//!
//! \param[out] reports A list of crash report record objects. This must be
//! empty on entry. Only valid if this returns #kNoError.
//!
//! \return The operation status code.
virtual OperationStatus GetCompletedReports(std::vector<Report>* reports) = 0;
//! \brief Obtains a report object for uploading to a collection server.
//!
//! The file at Report::file_path should be uploaded by the caller, and then
//! the returned Report object must be disposed of via a call to
//! RecordUploadAttempt().
//!
//! A subsequent call to this method with the same \a uuid is illegal until
//! RecordUploadAttempt() has been called.
//!
//! \param[in] uuid The unique identifier for the crash report record.
//! \param[out] report A crash report record for the report to be uploaded.
//! The caller does not own this object. Only valid if this returns
//! #kNoError.
//!
//! \return The operation status code.
virtual OperationStatus GetReportForUploading(const UUID& uuid,
const Report** report) = 0;
//! \brief Adjusts a crash report records metadata to account for an upload
//! attempt, and updates the last upload attempt time as returned by
//! Settings::GetLastUploadAttemptTime().
//!
//! After calling this method, the database is permitted to move and rename
//! the file at Report::file_path.
//!
//! \param[in] report The report object obtained from
//! GetReportForUploading(). This object is invalidated after this call.
//! \param[in] successful Whether the upload attempt was successful.
//! \param[in] id The identifier assigned to this crash report by the
//! collection server. Must be empty if \a successful is `false`; may be
//! empty if it is `true`.
//!
//! \return The operation status code.
virtual OperationStatus RecordUploadAttempt(const Report* report,
bool successful,
const std::string& id) = 0;
//! \brief Moves a report from the pending state to the completed state, but
//! without the report being uploaded.
//!
//! This can be used if the user has disabled crash report collection, but
//! crash generation is still enabled in the product.
//!
//! \param[in] uuid The unique identifier for the crash report record.
//! \param[in] reason The reason the report upload is being skipped for
//! metrics tracking purposes.
//!
//! \return The operation status code.
virtual OperationStatus SkipReportUpload(
const UUID& uuid,
Metrics::CrashSkippedReason reason) = 0;
//! \brief Deletes a crash report file and its associated metadata.
//!
//! \param[in] uuid The UUID of the report to delete.
//!
//! \return The operation status code.
virtual OperationStatus DeleteReport(const UUID& uuid) = 0;
//! \brief Marks a crash report as explicitly requested to be uploaded by the
//! user and moves it to 'pending' state.
//!
//! \param[in] uuid The unique identifier for the crash report record.
//!
//! \return The operation status code.
virtual OperationStatus RequestUpload(const UUID& uuid) = 0;
protected:
CrashReportDatabase() {}
private:
DISALLOW_COPY_AND_ASSIGN(CrashReportDatabase);
};
} // namespace crashpad
#endif // CRASHPAD_CLIENT_CRASH_REPORT_DATABASE_H_
@@ -0,0 +1,294 @@
// Copyright 2014 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_CRASHPAD_CLIENT_H_
#define CRASHPAD_CLIENT_CRASHPAD_CLIENT_H_
#include <map>
#include <string>
#include <vector>
#include <stdint.h>
#include "base/files/file_path.h"
#include "base/macros.h"
#include "build/build_config.h"
#if defined(OS_MACOSX)
#include "base/mac/scoped_mach_port.h"
#elif defined(OS_WIN)
#include <windows.h>
#include "util/win/scoped_handle.h"
#endif
namespace crashpad {
//! \brief The primary interface for an application to have Crashpad monitor
//! it for crashes.
class CrashpadClient {
public:
CrashpadClient();
~CrashpadClient();
//! \brief Starts a Crashpad handler process, performing any necessary
//! handshake to configure it.
//!
//! This method directs crashes to the Crashpad handler. On macOS, this is
//! applicable to this process and all subsequent child processes. On Windows,
//! child processes must also register by using SetHandlerIPCPipe().
//!
//! On macOS, this method starts a Crashpad handler and obtains a Mach send
//! right corresponding to a receive right held by the handler process. The
//! handler process runs an exception server on this port. This method sets
//! the tasks exception port for `EXC_CRASH`, `EXC_RESOURCE`, and `EXC_GUARD`
//! exceptions to the Mach send right obtained. The handler will be installed
//! with behavior `EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES` and thread
//! state flavor `MACHINE_THREAD_STATE`. Exception ports are inherited, so a
//! Crashpad handler started here will remain the handler for any child
//! processes created after StartHandler() is called. These child processes do
//! not need to call StartHandler() or be aware of Crashpad in any way. The
//! Crashpad handler will receive crashes from child processes that have
//! inherited it as their exception handler even after the process that called
//! StartHandler() exits.
//!
//! On Windows, if \a asynchronous_start is `true`, this function will not
//! directly call `CreateProcess()`, making it suitable for use in a
//! `DllMain()`. In that case, the handler is started from a background
//! thread, deferring the handler's startup. Nevertheless, regardless of the
//! value of \a asynchronous_start, after calling this method, the global
//! unhandled exception filter is set up, and all crashes will be handled by
//! Crashpad. Optionally, use WaitForHandlerStart() to join with the
//! background thread and retrieve the status of handler startup.
//!
//! \param[in] handler The path to a Crashpad handler executable.
//! \param[in] database The path to a Crashpad database. The handler will be
//! started with this path as its `--database` argument.
//! \param[in] metrics_dir The path to an already existing directory where
//! metrics files can be stored. The handler will be started with this
//! path as its `--metrics-dir` argument.
//! \param[in] url The URL of an upload server. The handler will be started
//! with this URL as its `--url` argument.
//! \param[in] annotations Process annotations to set in each crash report.
//! The handler will be started with an `--annotation` argument for each
//! element in this map.
//! \param[in] arguments Additional arguments to pass to the Crashpad handler.
//! Arguments passed in other parameters and arguments required to perform
//! the handshake are the responsibility of this method, and must not be
//! specified in this parameter.
//! \param[in] restartable If `true`, the handler will be restarted if it
//! dies, if this behavior is supported. This option is not available on
//! all platforms, and does not function on all OS versions. If it is
//! not supported, it will be ignored.
//! \param[out] asynchronous_start If `true`, the handler will be started from
//! a background thread. Optionally, WaitForHandlerStart() can be used at
//! a suitable time to retreive the result of background startup. This
//! option is only used on Windows.
//!
//! \return `true` on success, `false` on failure with a message logged.
bool StartHandler(const base::FilePath& handler,
const base::FilePath& database,
const base::FilePath& metrics_dir,
const std::string& url,
const std::map<std::string, std::string>& annotations,
const std::vector<std::string>& arguments,
bool restartable,
bool asynchronous_start);
#if defined(OS_MACOSX) || DOXYGEN
//! \brief Sets the process crash handler to a Mach service registered with
//! the bootstrap server.
//!
//! This method is only defined on macOS.
//!
//! See StartHandler() for more detail on how the port and handler are
//! configured.
//!
//! \param[in] service_name The service name of a Crashpad exception handler
//! service previously registered with the bootstrap server.
//!
//! \return `true` on success, `false` on failure with a message logged.
bool SetHandlerMachService(const std::string& service_name);
//! \brief Sets the process crash handler to a Mach port.
//!
//! This method is only defined on macOS.
//!
//! See StartHandler() for more detail on how the port and handler are
//! configured.
//!
//! \param[in] exception_port An `exception_port_t` corresponding to a
//! Crashpad exception handler service.
//!
//! \return `true` on success, `false` on failure with a message logged.
bool SetHandlerMachPort(base::mac::ScopedMachSendRight exception_port);
//! \brief Retrieves a send right to the process crash handler Mach port.
//!
//! This method is only defined on macOS.
//!
//! This method can be used to obtain the crash handler Mach port when a
//! Crashpad client process wishes to provide a send right to this port to
//! another process. The IPC mechanism used to convey the right is under the
//! applications control. If the other process wishes to become a client of
//! the same crash handler, it can provide the transferred right to
//! SetHandlerMachPort().
//!
//! See StartHandler() for more detail on how the port and handler are
//! configured.
//!
//! \return The Mach port set by SetHandlerMachPort(), possibly indirectly by
//! a call to another method such as StartHandler() or
//! SetHandlerMachService(). This method must only be called after a
//! successful call to one of those methods. `MACH_PORT_NULL` on failure
//! with a message logged.
base::mac::ScopedMachSendRight GetHandlerMachPort() const;
#endif
#if defined(OS_WIN) || DOXYGEN
//! \brief Sets the IPC pipe of a presumably-running Crashpad handler process
//! which was started with StartHandler() or by other compatible means
//! and does an IPC message exchange to register this process with the
//! handler. Crashes will be serviced once this method returns.
//!
//! This method is only defined on Windows.
//!
//! This method sets the unhandled exception handler to a local
//! function that when reached will "signal and wait" for the crash handler
//! process to create the dump.
//!
//! \param[in] ipc_pipe The full name of the crash handler IPC pipe. This is
//! a string of the form `&quot;\\.\pipe\NAME&quot;`.
//!
//! \return `true` on success and `false` on failure.
bool SetHandlerIPCPipe(const std::wstring& ipc_pipe);
//! \brief Retrieves the IPC pipe name used to register with the Crashpad
//! handler.
//!
//! This method is only defined on Windows.
//!
//! This method retrieves the IPC pipe name set by SetHandlerIPCPipe(), or a
//! suitable IPC pipe name chosen by StartHandler(). It must only be called
//! after a successful call to one of those methods. It is intended to be used
//! to obtain the IPC pipe name so that it may be passed to other processes,
//! so that they may register with an existing Crashpad handler by calling
//! SetHandlerIPCPipe().
//!
//! \return The full name of the crash handler IPC pipe, a string of the form
//! `&quot;\\.\pipe\NAME&quot;`.
std::wstring GetHandlerIPCPipe() const;
//! \brief When `asynchronous_start` is used with StartHandler(), this method
//! can be used to block until the handler launch has been completed to
//! retrieve status information.
//!
//! This method should not be used unless `asynchronous_start` was `true`.
//!
//! \param[in] timeout_ms The number of milliseconds to wait for a result from
//! the background launch, or `0xffffffff` to block indefinitely.
//!
//! \return `true` if the hander startup succeeded, `false` otherwise, and an
//! error message will have been logged.
bool WaitForHandlerStart(unsigned int timeout_ms);
//! \brief Requests that the handler capture a dump even though there hasn't
//! been a crash.
//!
//! \param[in] context A `CONTEXT`, generally captured by CaptureContext() or
//! similar.
static void DumpWithoutCrash(const CONTEXT& context);
//! \brief Requests that the handler capture a dump using the given \a
//! exception_pointers to get the `EXCEPTION_RECORD` and `CONTEXT`.
//!
//! This function is not necessary in general usage as an unhandled exception
//! filter is installed by StartHandler() or SetHandlerIPCPipe().
//!
//! \param[in] exception_pointers An `EXCEPTION_POINTERS`, as would generally
//! passed to an unhandled exception filter.
static void DumpAndCrash(EXCEPTION_POINTERS* exception_pointers);
//! \brief Requests that the handler capture a dump of a different process.
//!
//! The target process must be an already-registered Crashpad client. An
//! exception will be triggered in the target process, and the regular dump
//! mechanism used. This function will block until the exception in the target
//! process has been handled by the Crashpad handler.
//!
//! This function is unavailable when running on Windows XP and will return
//! `false`.
//!
//! \param[in] process A `HANDLE` identifying the process to be dumped.
//! \param[in] blame_thread If non-null, a `HANDLE` valid in the caller's
//! process, referring to a thread in the target process. If this is
//! supplied, instead of the exception referring to the location where the
//! exception was injected, an exception record will be fabricated that
//! refers to the current location of the given thread.
//! \param[in] exception_code If \a blame_thread is non-null, this will be
//! used as the exception code in the exception record.
//!
//! \return `true` if the exception was triggered successfully.
bool DumpAndCrashTargetProcess(HANDLE process,
HANDLE blame_thread,
DWORD exception_code) const;
enum : uint32_t {
//! \brief The exception code (roughly "Client called") used when
//! DumpAndCrashTargetProcess() triggers an exception in a target
//! process.
//!
//! \note This value does not have any bits of the top nibble set, to avoid
//! confusion with real exception codes which tend to have those bits
//! set.
kTriggeredExceptionCode = 0xcca11ed,
};
#endif
#if defined(OS_MACOSX) || DOXYGEN
//! \brief Configures the process to direct its crashes to the default handler
//! for the operating system.
//!
//! On macOS, this sets the tasks exception port as in SetHandlerMachPort(),
//! but the exception handler used is obtained from
//! SystemCrashReporterHandler(). If the systems crash reporter handler
//! cannot be determined or set, the tasks exception ports for crash-type
//! exceptions are cleared.
//!
//! Use of this function is strongly discouraged.
//!
//! \warning After a call to this function, Crashpad will no longer monitor
//! the process for crashes until a subsequent call to
//! SetHandlerMachPort().
//!
//! \note This is provided as a static function to allow it to be used in
//! situations where a CrashpadClient object is not otherwise available.
//! This may be useful when a child process inherits its parents Crashpad
//! handler, but wants to sever this tie.
static void UseSystemDefaultHandler();
#endif
private:
#if defined(OS_MACOSX)
base::mac::ScopedMachSendRight exception_port_;
#elif defined(OS_WIN)
std::wstring ipc_pipe_;
ScopedKernelHANDLE handler_start_thread_;
#endif // OS_MACOSX
DISALLOW_COPY_AND_ASSIGN(CrashpadClient);
};
} // namespace crashpad
#endif // CRASHPAD_CLIENT_CRASHPAD_CLIENT_H_
@@ -0,0 +1,266 @@
// Copyright 2014 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_CRASHPAD_INFO_H_
#define CRASHPAD_CLIENT_CRASHPAD_INFO_H_
#include <stdint.h>
#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"
#if defined(OS_WIN)
#include <windows.h>
#endif // OS_WIN
namespace crashpad {
namespace internal {
//! \brief A linked list of blocks representing custom streams in the minidump,
//! with addresses (and size) stored as uint64_t to simplify reading from
//! the handler process.
struct UserDataMinidumpStreamListEntry {
//! \brief The address of the next entry in the linked list.
uint64_t next;
//! \brief The base address of the memory block in the target process' address
//! space that represents the user data stream.
uint64_t base_address;
//! \brief The size of memory block in the target process' address space that
//! represents the user data stream.
uint64_t size;
//! \brief The stream type identifier.
uint32_t stream_type;
};
} // namespace internal
//! \brief A structure that can be used by a Crashpad-enabled program to
//! provide information to the Crashpad crash handler.
//!
//! It is possible for one CrashpadInfo structure to appear in each loaded code
//! module in a process, but from the perspective of the user of the client
//! interface, there is only one global CrashpadInfo structure, located in the
//! module that contains the client interface code.
struct CrashpadInfo {
public:
//! \brief Returns the global CrashpadInfo structure.
static CrashpadInfo* GetCrashpadInfo();
CrashpadInfo();
//! \brief Sets the bag of extra memory ranges to be included in the snapshot.
//!
//! Extra memory ranges may exist in \a address_range_bag at the time that
//! this method is called, or they may be added, removed, or modified in \a
//! address_range_bag after this method is called.
//!
//! TODO(scottmg) This is currently only supported on Windows.
//!
//! \param[in] address_range_bag A bag of address ranges. The CrashpadInfo
//! object does not take ownership of the SimpleAddressRangeBag object.
//! It is the callers responsibility to ensure that this pointer remains
//! valid while it is in effect for a CrashpadInfo object.
void set_extra_memory_ranges(SimpleAddressRangeBag* address_range_bag) {
extra_memory_ranges_ = address_range_bag;
}
//! \brief Sets the simple annotations dictionary.
//!
//! Simple annotations set on a CrashpadInfo structure are interpreted by
//! Crashpad as module-level annotations.
//!
//! Annotations may exist in \a simple_annotations at the time that this
//! method is called, or they may be added, removed, or modified in \a
//! simple_annotations after this method is called.
//!
//! \param[in] simple_annotations A dictionary that maps string keys to string
//! values. The CrashpadInfo object does not take ownership of the
//! SimpleStringDictionary object. It is the callers responsibility to
//! ensure that this pointer remains valid while it is in effect for a
//! CrashpadInfo object.
//!
//! \sa simple_annotations()
void set_simple_annotations(SimpleStringDictionary* simple_annotations) {
simple_annotations_ = simple_annotations;
}
//! \return The simple annotations dictionary.
//!
//! \sa set_simple_annotations()
SimpleStringDictionary* simple_annotations() const {
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 list at the time that this method is called,
//! or they may be added, removed, or modified in \a list after this method is
//! called.
//!
//! \param[in] 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
//! a process. The first one that has a CrashpadInfo structure populated with
//! a value other than #kUnset for this field will dictate whether the handler
//! is functional or not. If all modules with a CrashpadInfo structure specify
//! #kUnset, the handler will be enabled. If disabled, the Crashpad handler
//! will still run and receive exceptions, but will not take any action on an
//! exception on its own behalf, except for the action necessary to determine
//! that it has been disabled.
//!
//! The Crashpad handler should not normally be disabled. More commonly, it
//! is appropriate to disable crash report upload by calling
//! Settings::SetUploadsEnabled().
void set_crashpad_handler_behavior(TriState crashpad_handler_behavior) {
crashpad_handler_behavior_ = crashpad_handler_behavior;
}
//! \brief Enables or disables Crashpad forwarding of exceptions to the
//! systems crash reporter.
//!
//! When handling an exception, the Crashpad handler will scan all modules in
//! a process. The first one that has a CrashpadInfo structure populated with
//! a value other than #kUnset for this field will dictate whether the
//! exception is forwarded to the systems crash reporter. If all modules with
//! a CrashpadInfo structure specify #kUnset, forwarding will be enabled.
//! Unless disabled, forwarding may still occur if the Crashpad handler is
//! disabled by SetCrashpadHandlerState(). Even when forwarding is enabled,
//! the Crashpad handler may choose not to forward all exceptions to the
//! systems crash reporter in cases where it has reason to believe that the
//! systems crash reporter would not normally have handled the exception in
//! Crashpads absence.
void set_system_crash_reporter_forwarding(
TriState system_crash_reporter_forwarding) {
system_crash_reporter_forwarding_ = system_crash_reporter_forwarding;
}
//! \brief Enables or disables Crashpad capturing indirectly referenced memory
//! in the minidump.
//!
//! When handling an exception, the Crashpad handler will scan all modules in
//! a process. The first one that has a CrashpadInfo structure populated with
//! a value other than #kUnset for this field will dictate whether the extra
//! memory is captured.
//!
//! This causes Crashpad to include pages of data referenced by locals or
//! other stack memory. Turning this on can increase the size of the minidump
//! significantly.
//!
//! \param[in] gather_indirectly_referenced_memory Whether extra memory should
//! be gathered.
//! \param[in] limit The amount of memory in bytes after which no more
//! indirectly gathered memory should be captured. This value is only used
//! when \a gather_indirectly_referenced_memory is TriState::kEnabled.
void set_gather_indirectly_referenced_memory(
TriState gather_indirectly_referenced_memory,
uint32_t limit) {
gather_indirectly_referenced_memory_ = gather_indirectly_referenced_memory;
indirectly_referenced_memory_cap_ = limit;
}
//! \brief Adds a custom stream to the minidump.
//!
//! The memory block referenced by \a data and \a size will added to the
//! minidump as separate stream with type \a stream_type. The memory referred
//! to by \a data and \a size is owned by the caller and must remain valid
//! while it is in effect for the CrashpadInfo object.
//!
//! Note that streams will appear in the minidump in the reverse order to
//! which they are added.
//!
//! TODO(scottmg) This is currently only supported on Windows.
//!
//! \param[in] stream_type The stream type identifier to use. This should be
//! normally be larger than `MINIDUMP_STREAM_TYPE::LastReservedStream`
//! which is `0xffff`.
//! \param[in] data The base pointer of the stream data.
//! \param[in] size The size of the stream data.
void AddUserDataMinidumpStream(uint32_t stream_type,
const void* data,
size_t size);
enum : uint32_t {
kSignature = 'CPad',
};
private:
// The compiler wont necessarily see anyone using these fields, but it
// shouldnt warn about that. These fields arent intended for use by the
// process theyre found in, theyre supposed to be read by the crash
// reporting process.
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-private-field"
#endif
// Fields present in version 1, subject to a check of the size_ field:
uint32_t signature_; // kSignature
uint32_t size_; // The size of the entire CrashpadInfo structure.
uint32_t version_; // kCrashpadInfoVersion
uint32_t indirectly_referenced_memory_cap_;
uint32_t padding_0_;
TriState crashpad_handler_behavior_;
TriState system_crash_reporter_forwarding_;
TriState gather_indirectly_referenced_memory_;
uint8_t padding_1_;
SimpleAddressRangeBag* extra_memory_ranges_; // weak
SimpleStringDictionary* simple_annotations_; // weak
internal::UserDataMinidumpStreamListEntry* user_data_minidump_stream_head_;
AnnotationList* annotations_list_; // weak
// Its generally safe to add new fields without changing
// kCrashpadInfoVersion, because readers should check size_ and ignore fields
// that arent present, as well as unknown fields.
//
// Adding fields? Consider snapshot/crashpad_info_size_test_module.cc too.
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
DISALLOW_COPY_AND_ASSIGN(CrashpadInfo);
};
} // namespace crashpad
#endif // CRASHPAD_CLIENT_CRASHPAD_INFO_H_
@@ -0,0 +1,148 @@
// Copyright 2015 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_PRUNE_CRASH_REPORTS_H_
#define CRASHPAD_CLIENT_PRUNE_CRASH_REPORTS_H_
#include <sys/types.h>
#include <time.h>
#include <memory>
#include "base/macros.h"
#include "client/crash_report_database.h"
namespace crashpad {
class PruneCondition;
//! \brief Deletes crash reports from \a database that match \a condition.
//!
//! This function can be used to remove old or large reports from the database.
//! The \a condition will be evaluated against each report in the \a database,
//! sorted in descending order by CrashReportDatabase::Report::creation_time.
//! This guarantee allows conditions to be stateful.
//!
//! \param[in] database The database from which crash reports will be deleted.
//! \param[in] condition The condition against which all reports in the database
//! will be evaluated.
void PruneCrashReportDatabase(CrashReportDatabase* database,
PruneCondition* condition);
std::unique_ptr<PruneCondition> GetDefaultDatabasePruneCondition();
//! \brief An abstract base class for evaluating crash reports for deletion.
//!
//! When passed to PruneCrashReportDatabase(), each crash report in the
//! database will be evaluated according to ShouldPruneReport(). The reports
//! are evaluated serially in descending sort order by
//! CrashReportDatabase::Report::creation_time.
class PruneCondition {
public:
//! \brief Returns a sensible default condition for removing obsolete crash
//! reports.
//!
//! The default is to keep reports for one year or a maximum database size
//! of 128 MB.
//!
//! \return A PruneCondition for use with PruneCrashReportDatabase().
static std::unique_ptr<PruneCondition> GetDefault();
virtual ~PruneCondition() {}
//! \brief Evaluates a crash report for deletion.
//!
//! \param[in] report The crash report to evaluate.
//!
//! \return `true` if the crash report should be deleted, `false` if it
//! should be kept.
virtual bool ShouldPruneReport(const CrashReportDatabase::Report& report) = 0;
};
//! \brief A PruneCondition that deletes reports older than the specified number
//! days.
class AgePruneCondition final : public PruneCondition {
public:
//! \brief Creates a PruneCondition based on Report::creation_time.
//!
//! \param[in] max_age_in_days Reports created more than this many days ago
//! will be deleted.
explicit AgePruneCondition(int max_age_in_days);
~AgePruneCondition();
bool ShouldPruneReport(const CrashReportDatabase::Report& report) override;
private:
const time_t oldest_report_time_;
DISALLOW_COPY_AND_ASSIGN(AgePruneCondition);
};
//! \brief A PruneCondition that deletes older reports to keep the total
//! Crashpad database size under the specified limit.
class DatabaseSizePruneCondition final : public PruneCondition {
public:
//! \brief Creates a PruneCondition that will keep newer reports, until the
//! sum of the size of all reports is not smaller than \a max_size_in_kb.
//! After the limit is reached, older reports will be pruned.
//!
//! \param[in] max_size_in_kb The maximum number of kilobytes that all crash
//! reports should consume.
explicit DatabaseSizePruneCondition(size_t max_size_in_kb);
~DatabaseSizePruneCondition();
bool ShouldPruneReport(const CrashReportDatabase::Report& report) override;
private:
const size_t max_size_in_kb_;
size_t measured_size_in_kb_;
DISALLOW_COPY_AND_ASSIGN(DatabaseSizePruneCondition);
};
//! \brief A PruneCondition that conjoins two other PruneConditions.
class BinaryPruneCondition final : public PruneCondition {
public:
enum Operator {
AND,
OR,
};
//! \brief Evaluates two sub-conditions according to the specified logical
//! operator.
//!
//! This implements left-to-right evaluation. For Operator::AND, this means
//! if the \a lhs is `false`, the \a rhs will not be consulted. Similarly,
//! with Operator::OR, if the \a lhs is `true`, the \a rhs will not be
//! consulted.
//!
//! \param[in] op The logical operator to apply on \a lhs and \a rhs.
//! \param[in] lhs The left-hand side of \a op. This class takes ownership.
//! \param[in] rhs The right-hand side of \a op. This class takes ownership.
BinaryPruneCondition(Operator op, PruneCondition* lhs, PruneCondition* rhs);
~BinaryPruneCondition();
bool ShouldPruneReport(const CrashReportDatabase::Report& report) override;
private:
const Operator op_;
std::unique_ptr<PruneCondition> lhs_;
std::unique_ptr<PruneCondition> rhs_;
DISALLOW_COPY_AND_ASSIGN(BinaryPruneCondition);
};
} // namespace crashpad
#endif // CRASHPAD_CLIENT_PRUNE_CRASH_REPORTS_H_
+183
View File
@@ -0,0 +1,183 @@
// Copyright 2015 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_SETTINGS_H_
#define CRASHPAD_CLIENT_SETTINGS_H_
#include <time.h>
#include <string>
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/scoped_generic.h"
#include "util/file/file_io.h"
#include "util/misc/initialization_state.h"
#include "util/misc/uuid.h"
namespace crashpad {
namespace internal {
struct ScopedLockedFileHandleTraits {
static FileHandle InvalidValue() { return kInvalidFileHandle; }
static void Free(FileHandle handle);
};
} // namespace internal
//! \brief An interface for accessing and modifying the settings of a
//! CrashReportDatabase.
//!
//! This class must not be instantiated directly, but rather an instance of it
//! should be retrieved via CrashReportDatabase::GetSettings().
class Settings {
public:
explicit Settings(const base::FilePath& file_path);
~Settings();
bool Initialize();
//! \brief Retrieves the immutable identifier for this client, which is used
//! on a server to locate all crash reports from a specific Crashpad
//! database.
//!
//! This is automatically initialized when the database is created.
//!
//! \param[out] client_id The unique client identifier.
//!
//! \return On success, returns `true`, otherwise returns `false` with an
//! error logged.
bool GetClientID(UUID* client_id);
//! \brief Retrieves the users preference for submitting crash reports to a
//! collection server.
//!
//! The default value is `false`.
//!
//! \param[out] enabled Whether crash reports should be uploaded.
//!
//! \return On success, returns `true`, otherwise returns `false` with an
//! error logged.
bool GetUploadsEnabled(bool* enabled);
//! \brief Sets the users preference for submitting crash reports to a
//! collection server.
//!
//! \param[in] enabled Whether crash reports should be uploaded.
//!
//! \return On success, returns `true`, otherwise returns `false` with an
//! error logged.
bool SetUploadsEnabled(bool enabled);
//! \brief Retrieves the last time at which a report was attempted to be
//! uploaded.
//!
//! The default value is `0` if it has never been set before.
//!
//! \param[out] time The last time at which a report was uploaded.
//!
//! \return On success, returns `true`, otherwise returns `false` with an
//! error logged.
bool GetLastUploadAttemptTime(time_t* time);
//! \brief Sets the last time at which a report was attempted to be uploaded.
//!
//! This is only meant to be used internally by the CrashReportDatabase.
//!
//! \param[in] time The last time at which a report was uploaded.
//!
//! \return On success, returns `true`, otherwise returns `false` with an
//! error logged.
bool SetLastUploadAttemptTime(time_t time);
private:
struct Data;
// This must be constructed with MakeScopedLockedFileHandle(). It both unlocks
// and closes the file on destruction.
using ScopedLockedFileHandle =
base::ScopedGeneric<FileHandle, internal::ScopedLockedFileHandleTraits>;
static ScopedLockedFileHandle MakeScopedLockedFileHandle(FileHandle file,
FileLocking locking);
// Opens the settings file for reading. On error, logs a message and returns
// the invalid handle.
ScopedLockedFileHandle OpenForReading();
// Opens the settings file for reading and writing. On error, logs a message
// and returns the invalid handle. |mode| determines how the file will be
// opened. |mode| must not be FileWriteMode::kTruncateOrCreate.
//
// If |log_open_error| is false, nothing will be logged for an error
// encountered when attempting to open the file, but this method will still
// return false. This is intended to be used to suppress error messages when
// attempting to create a new settings file when multiple attempts are made.
ScopedLockedFileHandle OpenForReadingAndWriting(FileWriteMode mode,
bool log_open_error);
// Opens the settings file and reads the data. If that fails, an error will
// be logged and the settings will be recovered and re-initialized. If that
// also fails, returns false with additional log data from recovery.
bool OpenAndReadSettings(Data* out_data);
// Opens the settings file for writing and reads the data. If reading fails,
// recovery is attempted. Returns the opened file handle on success, or the
// invalid file handle on failure, with an error logged.
ScopedLockedFileHandle OpenForWritingAndReadSettings(Data* out_data);
// Reads the settings from |handle|. Logs an error and returns false on
// failure. This does not perform recovery.
//
// |handle| must be the result of OpenForReading() or
// OpenForReadingAndWriting().
//
// If |log_read_error| is false, nothing will be logged for a read error, but
// this method will still return false. This is intended to be used to
// suppress error messages when attempting to read a newly created settings
// file.
bool ReadSettings(FileHandle handle, Data* out_data, bool log_read_error);
// Writes the settings to |handle|. Logs an error and returns false on
// failure. This does not perform recovery.
//
// |handle| must be the result of OpenForReadingAndWriting().
bool WriteSettings(FileHandle handle, const Data& data);
// Recovers the settings file by re-initializing the data. If |handle| is the
// invalid handle, this will open the file; if it is not, then it must be the
// result of OpenForReadingAndWriting(). If the invalid handle is passed, the
// caller must not be holding the handle. The new settings data are stored in
// |out_data|. Returns true on success and false on failure, with an error
// logged.
bool RecoverSettings(FileHandle handle, Data* out_data);
// Initializes a settings file and writes the data to |handle|. Returns true
// on success and false on failure, with an error logged.
//
// |handle| must be the result of OpenForReadingAndWriting().
bool InitializeSettings(FileHandle handle);
const base::FilePath& file_path() const { return file_path_; }
base::FilePath file_path_;
InitializationState initialized_;
DISALLOW_COPY_AND_ASSIGN(Settings);
};
} // namespace crashpad
#endif // CRASHPAD_CLIENT_SETTINGS_H_
@@ -0,0 +1,198 @@
// Copyright 2016 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_SIMPLE_ADDRESS_RANGE_BAG_H_
#define CRASHPAD_CLIENT_SIMPLE_ADDRESS_RANGE_BAG_H_
#include <stdint.h>
#include <type_traits>
#include "base/logging.h"
#include "base/macros.h"
#include "base/numerics/safe_conversions.h"
#include "util/misc/from_pointer_cast.h"
#include "util/numeric/checked_range.h"
namespace crashpad {
//! \brief A bag implementation using a fixed amount of storage, so that it does
//! not perform any dynamic allocations for its operations.
//!
//! The actual bag storage (TSimpleAddressRangeBag::Entry) is POD, so that it
//! can be transmitted over various IPC mechanisms.
template <size_t NumEntries = 64>
class TSimpleAddressRangeBag {
public:
//! Constant and publicly accessible version of the template parameter.
static const size_t num_entries = NumEntries;
//! \brief A single entry in the bag.
struct Entry {
//! \brief The base address of the range.
uint64_t base;
//! \brief The size of the range in bytes.
uint64_t size;
//! \brief Returns the validity of the entry.
//!
//! If #base and #size are both zero, the entry is considered inactive, and
//! this method returns `false`. Otherwise, returns `true`.
bool is_active() const {
return base != 0 || size != 0;
}
};
//! \brief An iterator to traverse all of the active entries in a
//! TSimpleAddressRangeBag.
class Iterator {
public:
explicit Iterator(const TSimpleAddressRangeBag& bag)
: bag_(bag),
current_(0) {
}
//! \brief Returns the next entry in the bag, or `nullptr` if at the end of
//! the collection.
const Entry* Next() {
while (current_ < bag_.num_entries) {
const Entry* entry = &bag_.entries_[current_++];
if (entry->is_active()) {
return entry;
}
}
return nullptr;
}
private:
const TSimpleAddressRangeBag& bag_;
size_t current_;
DISALLOW_COPY_AND_ASSIGN(Iterator);
};
TSimpleAddressRangeBag()
: entries_() {
}
TSimpleAddressRangeBag(const TSimpleAddressRangeBag& other) {
*this = other;
}
TSimpleAddressRangeBag& operator=(const TSimpleAddressRangeBag& other) {
memcpy(entries_, other.entries_, sizeof(entries_));
return *this;
}
//! \brief Returns the number of active entries. The upper limit for this is
//! \a NumEntries.
size_t GetCount() const {
size_t count = 0;
for (size_t i = 0; i < num_entries; ++i) {
if (entries_[i].is_active()) {
++count;
}
}
return count;
}
//! \brief Inserts the given range into the bag. Duplicates and overlapping
//! ranges are supported and allowed, but not coalesced.
//!
//! \param[in] range The range to be inserted. The range must have either a
//! non-zero base address or size.
//!
//! \return `true` if there was space to insert the range into the bag,
//! otherwise `false` with an error logged.
bool Insert(CheckedRange<uint64_t> range) {
DCHECK(range.base() != 0 || range.size() != 0);
for (size_t i = 0; i < num_entries; ++i) {
if (!entries_[i].is_active()) {
entries_[i].base = range.base();
entries_[i].size = range.size();
return true;
}
}
LOG(ERROR) << "no space available to insert range";
return false;
}
//! \brief Inserts the given range into the bag. Duplicates and overlapping
//! ranges are supported and allowed, but not coalesced.
//!
//! \param[in] base The base of the range to be inserted. May not be null.
//! \param[in] size The size of the range to be inserted. May not be zero.
//!
//! \return `true` if there was space to insert the range into the bag,
//! otherwise `false` with an error logged.
bool Insert(void* base, size_t size) {
DCHECK(base != nullptr);
DCHECK_NE(0u, size);
return Insert(CheckedRange<uint64_t>(FromPointerCast<uint64_t>(base),
base::checked_cast<uint64_t>(size)));
}
//! \brief Removes the given range from the bag.
//!
//! \param[in] range The range to be removed. The range must have either a
//! non-zero base address or size.
//!
//! \return `true` if the range was found and removed, otherwise `false` with
//! an error logged.
bool Remove(CheckedRange<uint64_t> range) {
DCHECK(range.base() != 0 || range.size() != 0);
for (size_t i = 0; i < num_entries; ++i) {
if (entries_[i].base == range.base() &&
entries_[i].size == range.size()) {
entries_[i].base = entries_[i].size = 0;
return true;
}
}
LOG(ERROR) << "did not find range to remove";
return false;
}
//! \brief Removes the given range from the bag.
//!
//! \param[in] base The base of the range to be removed. May not be null.
//! \param[in] size The size of the range to be removed. May not be zero.
//!
//! \return `true` if the range was found and removed, otherwise `false` with
//! an error logged.
bool Remove(void* base, size_t size) {
DCHECK(base != nullptr);
DCHECK_NE(0u, size);
return Remove(CheckedRange<uint64_t>(FromPointerCast<uint64_t>(base),
base::checked_cast<uint64_t>(size)));
}
private:
Entry entries_[NumEntries];
};
//! \brief A TSimpleAddressRangeBag with default template parameters.
using SimpleAddressRangeBag = TSimpleAddressRangeBag<64>;
static_assert(std::is_standard_layout<SimpleAddressRangeBag>::value,
"SimpleAddressRangeBag must be standard layout");
} // namespace crashpad
#endif // CRASHPAD_CLIENT_SIMPLE_ADDRESS_RANGE_BAG_H_
@@ -0,0 +1,288 @@
// Copyright 2014 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_SIMPLE_STRING_DICTIONARY_H_
#define CRASHPAD_CLIENT_SIMPLE_STRING_DICTIONARY_H_
#include <string.h>
#include <sys/types.h>
#include <algorithm>
#include <type_traits>
#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "util/misc/implicit_cast.h"
namespace crashpad {
//! \brief A map/dictionary collection implementation using a fixed amount of
//! storage, so that it does not perform any dynamic allocations for its
//! operations.
//!
//! The actual map storage (TSimpleStringDictionary::Entry) is guaranteed to be
//! POD, so that it can be transmitted over various IPC mechanisms.
//!
//! The template parameters control the amount of storage used for the key,
//! value, and map. The \a KeySize and \a ValueSize are measured in bytes, not
//! glyphs, and include space for a trailing `NUL` byte. This gives space for
//! `KeySize - 1` and `ValueSize - 1` characters in an entry. \a NumEntries is
//! the total number of entries that will fit in the map.
template <size_t KeySize = 256, size_t ValueSize = 256, size_t NumEntries = 64>
class TSimpleStringDictionary {
public:
//! \brief Constant and publicly accessible versions of the template
//! parameters.
//! \{
static const size_t key_size = KeySize;
static const size_t value_size = ValueSize;
static const size_t num_entries = NumEntries;
//! \}
//! \brief A single entry in the map.
struct Entry {
//! \brief The entrys key.
//!
//! This string is always `NUL`-terminated. If this is a 0-length
//! `NUL`-terminated string, the entry is inactive.
char key[KeySize];
//! \brief The entrys value.
//!
//! This string is always `NUL`-terminated.
char value[ValueSize];
//! \brief Returns the validity of the entry.
//!
//! If #key is an empty string, the entry is considered inactive, and this
//! method returns `false`. Otherwise, returns `true`.
bool is_active() const {
return key[0] != '\0';
}
};
//! \brief An iterator to traverse all of the active entries in a
//! TSimpleStringDictionary.
class Iterator {
public:
explicit Iterator(const TSimpleStringDictionary& map)
: map_(map),
current_(0) {
}
//! \brief Returns the next entry in the map, or `nullptr` if at the end of
//! the collection.
const Entry* Next() {
while (current_ < map_.num_entries) {
const Entry* entry = &map_.entries_[current_++];
if (entry->is_active()) {
return entry;
}
}
return nullptr;
}
private:
const TSimpleStringDictionary& map_;
size_t current_;
DISALLOW_COPY_AND_ASSIGN(Iterator);
};
TSimpleStringDictionary()
: entries_() {
}
TSimpleStringDictionary(const TSimpleStringDictionary& other) {
*this = other;
}
TSimpleStringDictionary& operator=(const TSimpleStringDictionary& other) {
memcpy(entries_, other.entries_, sizeof(entries_));
return *this;
}
//! \brief Returns the number of active key/value pairs. The upper limit for
//! this is \a NumEntries.
size_t GetCount() const {
size_t count = 0;
for (size_t i = 0; i < num_entries; ++i) {
if (entries_[i].is_active()) {
++count;
}
}
return count;
}
//! \brief Given \a key, returns its corresponding value.
//!
//! \param[in] key The key to look up. This must not be `nullptr`, nor an
//! empty string. It must not contain embedded `NUL`s.
//!
//! \return The corresponding value for \a key, or if \a key is not found,
//! `nullptr`.
const char* GetValueForKey(base::StringPiece key) const {
DCHECK(key.data());
DCHECK(key.size());
DCHECK_EQ(key.find('\0', 0), base::StringPiece::npos);
if (!key.data() || !key.size()) {
return nullptr;
}
const Entry* entry = GetConstEntryForKey(key);
if (!entry) {
return nullptr;
}
return entry->value;
}
//! \brief Stores \a value into \a key, replacing the existing value if \a key
//! is already present.
//!
//! If \a key is not yet in the map and the map is already full (containing
//! \a NumEntries active entries), this operation silently fails.
//!
//! \param[in] key The key to store. This must not be `nullptr`, nor an empty
//! string. It must not contain embedded `NUL`s.
//! \param[in] value The value to store. If `nullptr`, \a key is removed from
//! the map. Must not contain embedded `NUL`s.
void SetKeyValue(base::StringPiece key, base::StringPiece value) {
if (!value.data()) {
RemoveKey(key);
return;
}
DCHECK(key.data());
DCHECK(key.size());
DCHECK_EQ(key.find('\0', 0), base::StringPiece::npos);
if (!key.data() || !key.size()) {
return;
}
// |key| must not be an empty string.
DCHECK_NE(key[0], '\0');
if (key[0] == '\0') {
return;
}
// |value| must not contain embedded NULs.
DCHECK_EQ(value.find('\0', 0), base::StringPiece::npos);
Entry* entry = GetEntryForKey(key);
// If it does not yet exist, attempt to insert it.
if (!entry) {
for (size_t i = 0; i < num_entries; ++i) {
if (!entries_[i].is_active()) {
entry = &entries_[i];
SetFromStringPiece(key, entry->key, key_size);
break;
}
}
}
// If the map is out of space, |entry| will be nullptr.
if (!entry) {
return;
}
#ifndef NDEBUG
// Sanity check that the key only appears once.
int count = 0;
for (size_t i = 0; i < num_entries; ++i) {
if (EntryKeyEquals(key, entries_[i])) {
++count;
}
}
DCHECK_EQ(count, 1);
#endif
SetFromStringPiece(value, entry->value, value_size);
}
//! \brief Removes \a key from the map.
//!
//! If \a key is not found, this is a no-op.
//!
//! \param[in] key The key of the entry to remove. This must not be `nullptr`,
//! nor an empty string. It must not contain embedded `NUL`s.
void RemoveKey(base::StringPiece key) {
DCHECK(key.data());
DCHECK(key.size());
DCHECK_EQ(key.find('\0', 0), base::StringPiece::npos);
if (!key.data() || !key.size()) {
return;
}
Entry* entry = GetEntryForKey(key);
if (entry) {
entry->key[0] = '\0';
entry->value[0] = '\0';
}
DCHECK_EQ(GetEntryForKey(key), implicit_cast<Entry*>(nullptr));
}
private:
static void SetFromStringPiece(base::StringPiece src,
char* dst,
size_t dst_size) {
size_t copy_len = std::min(dst_size - 1, src.size());
src.copy(dst, copy_len);
dst[copy_len] = '\0';
}
static bool EntryKeyEquals(base::StringPiece key, const Entry& entry) {
if (key.size() >= KeySize)
return false;
// Test for a NUL terminator and early out if it's absent.
if (entry.key[key.size()] != '\0')
return false;
// As there's a NUL terminator at the right position in the entries
// string, strncmp can do the rest.
return strncmp(key.data(), entry.key, key.size()) == 0;
}
const Entry* GetConstEntryForKey(base::StringPiece key) const {
for (size_t i = 0; i < num_entries; ++i) {
if (EntryKeyEquals(key, entries_[i])) {
return &entries_[i];
}
}
return nullptr;
}
Entry* GetEntryForKey(base::StringPiece key) {
return const_cast<Entry*>(GetConstEntryForKey(key));
}
Entry entries_[NumEntries];
};
//! \brief A TSimpleStringDictionary with default template parameters.
//!
//! For historical reasons this specialized version is available with the same
//! size factors as a previous implementation.
using SimpleStringDictionary = TSimpleStringDictionary<256, 256, 64>;
static_assert(std::is_standard_layout<SimpleStringDictionary>::value,
"SimpleStringDictionary must be standard layout");
} // namespace crashpad
#endif // CRASHPAD_CLIENT_SIMPLE_STRING_DICTIONARY_H_
@@ -0,0 +1,26 @@
// Copyright 2014 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_SIMULATE_CRASH_H_
#define CRASHPAD_CLIENT_SIMULATE_CRASH_H_
#include "build/build_config.h"
#if defined(OS_MACOSX)
#include "client/simulate_crash_mac.h"
#elif defined(OS_WIN)
#include "client/simulate_crash_win.h"
#endif
#endif // CRASHPAD_CLIENT_SIMULATE_CRASH_H_
@@ -0,0 +1,60 @@
// Copyright 2014 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_SIMULATE_CRASH_MAC_H_
#define CRASHPAD_CLIENT_SIMULATE_CRASH_MAC_H_
#include <mach/mach.h>
#include "client/capture_context_mac.h"
//! \file
namespace crashpad {
//! \brief Simulates a exception without crashing.
//!
//! This function searches for an `EXC_CRASH` handler in the same manner that
//! the kernel does, and sends it an exception message to that handler in the
//! format that the handler expects, considering the behavior and thread state
//! flavor that are registered for it. The exception sent to the handler will be
//! ::kMachExceptionSimulated, not `EXC_CRASH`.
//!
//! Typically, the CRASHPAD_SIMULATE_CRASH() macro will be used in preference to
//! this function, because it combines the context-capture operation with the
//! raising of a simulated exception.
//!
//! This function returns normally after the exception message is processed. If
//! no valid handler was found, or no handler processed the exception
//! successfully, a warning will be logged, but these conditions are not
//! considered fatal.
//!
//! \param[in] cpu_context The thread state to pass to the exception handler as
//! the exception context, provided that it is compatible with the thread
//! state flavor that the exception handler accepts. If it is not
//! compatible, the correct thread state for the handler will be obtained by
//! calling `thread_get_state()`.
void SimulateCrash(const NativeCPUContext& cpu_context);
} // namespace crashpad
//! \brief Captures the CPU context and simulates an exception without crashing.
#define CRASHPAD_SIMULATE_CRASH() \
do { \
crashpad::NativeCPUContext cpu_context; \
crashpad::CaptureContext(&cpu_context); \
crashpad::SimulateCrash(cpu_context); \
} while (false)
#endif // CRASHPAD_CLIENT_SIMULATE_CRASH_MAC_H_
@@ -0,0 +1,33 @@
// Copyright 2015 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_SIMULATE_CRASH_WIN_H_
#define CRASHPAD_CLIENT_SIMULATE_CRASH_WIN_H_
#include <windows.h>
#include "client/crashpad_client.h"
#include "util/win/capture_context.h"
//! \file
//! \brief Captures the CPU context and captures a dump without an exception.
#define CRASHPAD_SIMULATE_CRASH() \
do { \
CONTEXT context; \
crashpad::CaptureContext(&context); \
crashpad::CrashpadClient::DumpWithoutCrash(context); \
} while (false)
#endif // CRASHPAD_CLIENT_SIMULATE_CRASH_WIN_H_