Recognize crashreporter_annotations_t version 5 found on OS X 10.11.

The system’s crashreporter_annotations_t structure was always present
as version 4 since Mac OS X 10.7. In OS X 10.11, it is now present as
version 5. It has also grown from 56 to 64 bytes per otool examination
of CoreFoundation’s __DATA,__crash_info section. The extra 8 bytes are
presumed to be a new field at the end of the structure, although this
is not confirmed.

The existing MachOImageAnnotationsReader.CrashAbort test only validated
that the “message” field in crashreporter_annotations_t was recovered
correctly, but
MachOImageAnnotationsReader::ReadCrashReporterClientAnnotations() also
recovers the “message2” field. A new test,
MachOImageAnnotationsReader.CrashModuleInitialization, is added to
ensure that the “messgae2” field can be recovered properly.

This change will resolve warnings such as:
[pid:tid:yyyymmdd,hhmmss.uuuuuu:WARNING
mach_o_image_annotations_reader.cc:82] unexpected crash info version 5
in
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation

BUG=crashpad:40
TEST=crashpad_snapshot_test MachOImageAnnotationsReader.CrashAbort,
     MachOImageAnnotationsReader.CrashModuleInitialization

R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/1277513003 .
This commit is contained in:
Mark Mentovai 2015-08-07 13:59:45 -04:00
parent 124ace19bd
commit 6083a2706d
8 changed files with 316 additions and 113 deletions

View File

@ -67,31 +67,34 @@ void MachOImageAnnotationsReader::ReadCrashReporterClientAnnotations(
}
process_types::crashreporter_annotations_t crash_info;
if (crash_info_section->size < crash_info.ExpectedSize(process_reader_)) {
LOG(WARNING) << "small crash info section size " << crash_info_section->size
<< " in " << name_;
return;
}
if (!crash_info.Read(process_reader_, crash_info_address)) {
LOG(WARNING) << "could not read crash info from " << name_;
return;
}
if (crash_info.version != 4) {
if (crash_info.version != 4 && crash_info.version != 5) {
LOG(WARNING) << "unexpected crash info version " << crash_info.version
<< " in " << name_;
return;
}
size_t expected_size =
process_types::crashreporter_annotations_t::ExpectedSizeForVersion(
process_reader_, crash_info.version);
if (crash_info_section->size < expected_size) {
LOG(WARNING) << "small crash info section size " << crash_info_section->size
<< " < " << expected_size << " for version "
<< crash_info.version << " in " << name_;
return;
}
// This number was totally made up out of nowhere, but it seems prudent to
// enforce some limit.
const size_t kMaxMessageSize = 1024;
if (crash_info.message) {
std::string message;
if (process_reader_->Memory()->
ReadCStringSizeLimited(
crash_info.message, kMaxMessageSize, &message)) {
if (process_reader_->Memory()->ReadCStringSizeLimited(
crash_info.message, kMaxMessageSize, &message)) {
vector_annotations->push_back(message);
} else {
LOG(WARNING) << "could not read crash message in " << name_;
@ -100,9 +103,8 @@ void MachOImageAnnotationsReader::ReadCrashReporterClientAnnotations(
if (crash_info.message2) {
std::string message;
if (process_reader_->Memory()->
ReadCStringSizeLimited(
crash_info.message2, kMaxMessageSize, &message)) {
if (process_reader_->Memory()->ReadCStringSizeLimited(
crash_info.message2, kMaxMessageSize, &message)) {
vector_annotations->push_back(message);
} else {
LOG(WARNING) << "could not read crash message 2 in " << name_;
@ -127,8 +129,8 @@ void MachOImageAnnotationsReader::ReadDyldErrorStringAnnotation(
std::string message;
// 1024 here is distinct from kMaxMessageSize above, because it refers to a
// precisely-sized buffer inside dyld.
if (process_reader_->Memory()->
ReadCStringSizeLimited(error_string_address, 1024, &message)) {
if (process_reader_->Memory()->ReadCStringSizeLimited(
error_string_address, 1024, &message)) {
if (!message.empty()) {
vector_annotations->push_back(message);
}
@ -150,10 +152,10 @@ void MachOImageAnnotationsReader::ReadCrashpadSimpleAnnotations(
std::vector<SimpleStringDictionary::Entry>
simple_annotations(SimpleStringDictionary::num_entries);
if (!process_reader_->Memory()
->Read(crashpad_info.simple_annotations,
simple_annotations.size() * sizeof(simple_annotations[0]),
&simple_annotations[0])) {
if (!process_reader_->Memory()->Read(
crashpad_info.simple_annotations,
simple_annotations.size() * sizeof(simple_annotations[0]),
&simple_annotations[0])) {
LOG(WARNING) << "could not read simple annotations from " << name_;
return;
}

View File

@ -47,6 +47,11 @@ namespace crashpad {
namespace test {
namespace {
// \return The path to crashpad_snapshot_test_module_crashy_initializer.so
std::string ModuleWithCrashyInitializer() {
return Paths::Executable().value() + "_module_crashy_initializer.so";
}
//! \return The path to the crashpad_snapshot_test_no_op executable.
base::FilePath NoOpExecutable() {
return base::FilePath(Paths::Executable().value() + "_no_op");
@ -62,8 +67,24 @@ class TestMachOImageAnnotationsReader final
// The child process should crash by calling abort(). The parent verifies
// that the system libraries set the expected annotations.
//
// This test verifies that the message field in crashreporter_annotations_t
// can be recovered. Either 10.10.2 Libc-1044.1.2/stdlib/FreeBSD/abort.c
// abort() or 10.10.2 Libc-1044.10.1/sys/_libc_fork_child.c
// _libc_fork_child() calls CRSetCrashLogMessage() to set the message field.
kCrashAbort,
// The child process should crash at module initialization time, when dyld
// will have set an annotation matching the path of the module being
// initialized.
//
// This test exists to verify that the message2 field in
// crashreporter_annotations_t can be recovered. 10.10.2
// dyld-353.2.1/src/ImageLoaderMachO.cpp
// ImageLoaderMachO::doInitialization() calls CRSetCrashLogMessage2() to set
// the message2 field.
kCrashModuleInitialization,
// The child process should crash by setting DYLD_INSERT_LIBRARIES to
// contain a nonexistent library. The parent verifies that dyld sets the
// expected annotations.
@ -126,7 +147,7 @@ class TestMachOImageAnnotationsReader final
if (mac_os_x_minor_version > 7) {
EXPECT_GE(all_annotations_vector.size(), 1u);
const char* expected_annotation = nullptr;
std::string expected_annotation;
switch (test_type_) {
case kCrashAbort:
// The child process calls abort(), so the expected annotation
@ -145,6 +166,12 @@ class TestMachOImageAnnotationsReader final
: "crashed on child side of fork pre-exec";
break;
case kCrashModuleInitialization:
// This message is set by dyld-353.2.1/src/ImageLoaderMachO.cpp
// ImageLoaderMachO::doInitialization().
expected_annotation = ModuleWithCrashyInitializer();
break;
case kCrashDyld:
// This is independent of dylds error_string, which is tested
// below.
@ -156,20 +183,19 @@ class TestMachOImageAnnotationsReader final
break;
}
size_t expected_annotation_length = strlen(expected_annotation);
bool found = false;
for (const std::string& annotation : all_annotations_vector) {
// Look for the expectation as a leading susbtring, because the actual
// string that dyld uses will have the contents of the
// DYLD_INSERT_LIBRARIES environment variable appended to it on Mac
// OS X 10.10.
if (annotation.substr(0, expected_annotation_length) ==
if (annotation.substr(0, expected_annotation.length()) ==
expected_annotation) {
found = true;
break;
}
}
EXPECT_TRUE(found);
EXPECT_TRUE(found) << expected_annotation;
}
// dyld exposes its error_string at least as far back as Mac OS X 10.4.
@ -188,7 +214,7 @@ class TestMachOImageAnnotationsReader final
}
}
EXPECT_TRUE(found);
EXPECT_TRUE(found) << kExpectedAnnotation;
}
}
@ -250,6 +276,12 @@ class TestMachOImageAnnotationsReader final
SetExpectedChildTermination(kTerminationSignal, SIGABRT);
break;
case kCrashModuleInitialization:
// This crash is triggered by __builtin_trap(), which shows up as
// SIGILL.
SetExpectedChildTermination(kTerminationSignal, SIGILL);
break;
case kCrashDyld:
// dyld fatal errors result in the execution of an int3 instruction on
// x86 and a trap instruction on ARM, both of which raise SIGTRAP.
@ -293,12 +325,27 @@ class TestMachOImageAnnotationsReader final
EXC_MASK_CRASH, RemotePort(), EXCEPTION_DEFAULT, THREAD_STATE_NONE));
switch (test_type_) {
case kDontCrash:
case kDontCrash: {
break;
}
case kCrashAbort:
case kCrashAbort: {
abort();
break;
}
case kCrashModuleInitialization: {
// Load a module that crashes while executing a module initializer.
void* dl_handle = dlopen(ModuleWithCrashyInitializer().c_str(),
RTLD_LAZY | RTLD_LOCAL);
// This should have crashed in the dlopen(). If dlopen() failed, the
// ASSERT_NE() will show the message. If it succeeded without crashing,
// the FAIL() will fail the test.
ASSERT_NE(nullptr, dl_handle) << dlerror();
FAIL();
break;
}
case kCrashDyld: {
// Set DYLD_INSERT_LIBRARIES to contain a library that does not exist.
@ -345,6 +392,12 @@ TEST(MachOImageAnnotationsReader, CrashAbort) {
test_mach_o_image_annotations_reader.Run();
}
TEST(MachOImageAnnotationsReader, CrashModuleInitialization) {
TestMachOImageAnnotationsReader test_mach_o_image_annotations_reader(
TestMachOImageAnnotationsReader::kCrashModuleInitialization);
test_mach_o_image_annotations_reader.Run();
}
TEST(MachOImageAnnotationsReader, CrashDyld) {
TestMachOImageAnnotationsReader test_mach_o_image_annotations_reader(
TestMachOImageAnnotationsReader::kCrashDyld);

View File

@ -0,0 +1,31 @@
// 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.
namespace crashpad {
namespace test {
namespace {
class CrashyClass {
public:
CrashyClass() {
__builtin_trap();
}
};
// __attribute__((used)) keeps the dead code stripper away.
__attribute__((used)) CrashyClass g_crashy_object;
} // namespace
} // namespace test
} // namespace crashpad

View File

@ -17,6 +17,7 @@
#include <string.h>
#include <uuid/uuid.h>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "snapshot/mac/process_types/internal.h"
#include "util/mach/task_memory.h"
@ -82,48 +83,63 @@ inline void Assign<uuid_t, uuid_t>(uuid_t* destination, const uuid_t& source) {
// operates on each member in the struct.
#define PROCESS_TYPE_STRUCT_IMPLEMENT 1
#define PROCESS_TYPE_STRUCT_BEGIN(struct_name) \
namespace crashpad { \
namespace process_types { \
\
size_t struct_name::ExpectedSize(ProcessReader* process_reader) { \
if (!process_reader->Is64Bit()) { \
return internal::struct_name<internal::Traits32>::Size(); \
} else { \
return internal::struct_name<internal::Traits64>::Size(); \
} \
} \
\
bool struct_name::ReadInto(ProcessReader* process_reader, \
mach_vm_address_t address, \
struct_name* generic) { \
if (!process_reader->Is64Bit()) { \
return ReadIntoInternal<internal::struct_name<internal::Traits32> >( \
process_reader, address, generic); \
} else { \
return ReadIntoInternal<internal::struct_name<internal::Traits64> >( \
process_reader, address, generic); \
} \
} \
\
template <typename T> \
bool struct_name::ReadIntoInternal(ProcessReader* process_reader, \
mach_vm_address_t address, \
struct_name* generic) { \
T specific; \
if (!specific.Read(process_reader, address)) { \
return false; \
} \
specific.GenericizeInto(generic, &generic->size_); \
return true; \
} \
\
namespace internal { \
\
template <typename Traits> \
void struct_name<Traits>::GenericizeInto( \
process_types::struct_name* generic, \
size_t* specific_size) { \
#define PROCESS_TYPE_STRUCT_BEGIN(struct_name) \
namespace crashpad { \
namespace process_types { \
\
/* static */ \
size_t struct_name::ExpectedSize(ProcessReader* process_reader) { \
if (!process_reader->Is64Bit()) { \
return internal::struct_name<internal::Traits32>::Size(); \
} else { \
return internal::struct_name<internal::Traits64>::Size(); \
} \
} \
\
/* static */ \
size_t struct_name::ExpectedSizeForVersion(ProcessReader* process_reader, \
uint64_t version) { \
if (!process_reader->Is64Bit()) { \
return internal::struct_name< \
internal::Traits32>::ExpectedSizeForVersion(version); \
} else { \
return internal::struct_name< \
internal::Traits64>::ExpectedSizeForVersion(version); \
} \
} \
\
/* static */ \
bool struct_name::ReadInto(ProcessReader* process_reader, \
mach_vm_address_t address, \
struct_name* generic) { \
if (!process_reader->Is64Bit()) { \
return ReadIntoInternal<internal::struct_name<internal::Traits32> >( \
process_reader, address, generic); \
} else { \
return ReadIntoInternal<internal::struct_name<internal::Traits64> >( \
process_reader, address, generic); \
} \
} \
\
/* static */ \
template <typename T> \
bool struct_name::ReadIntoInternal(ProcessReader* process_reader, \
mach_vm_address_t address, \
struct_name* generic) { \
T specific; \
if (!specific.Read(process_reader, address)) { \
return false; \
} \
specific.GenericizeInto(generic, &generic->size_); \
return true; \
} \
\
namespace internal { \
\
template <typename Traits> \
void struct_name<Traits>::GenericizeInto( \
process_types::struct_name* generic, \
size_t* specific_size) { \
*specific_size = Size();
#define PROCESS_TYPE_STRUCT_MEMBER(member_type, member_name, ...) \
@ -155,6 +171,7 @@ inline void Assign<uuid_t, uuid_t>(uuid_t* destination, const uuid_t& source) {
namespace process_types { \
namespace internal { \
\
/* static */ \
template <typename Traits> \
bool struct_name<Traits>::ReadInto(ProcessReader* process_reader, \
mach_vm_address_t address, \
@ -189,16 +206,25 @@ inline void Assign<uuid_t, uuid_t>(uuid_t* destination, const uuid_t& source) {
namespace process_types { \
namespace internal { \
\
/* static */ \
template <typename Traits> \
bool struct_name<Traits>::ReadArrayInto(ProcessReader* process_reader, \
mach_vm_address_t address, \
size_t count, \
struct_name<Traits>* specific) { \
return process_reader->Memory()->Read( \
address, sizeof(struct_name<Traits> [count]), specific); \
address, sizeof(struct_name<Traits>[count]), specific); \
} \
\
/* static */ \
template <typename Traits> \
size_t struct_name<Traits>::ExpectedSizeForVersion(uint64_t version) { \
NOTREACHED(); \
return 0; \
} \
} /* namespace internal */ \
\
/* static */ \
bool struct_name::ReadArrayInto(ProcessReader* process_reader, \
mach_vm_address_t address, \
size_t count, \
@ -215,6 +241,7 @@ inline void Assign<uuid_t, uuid_t>(uuid_t* destination, const uuid_t& source) {
return true; \
} \
\
/* static */ \
template <typename T> \
bool struct_name::ReadArrayIntoInternal(ProcessReader* process_reader, \
mach_vm_address_t address, \

View File

@ -85,7 +85,14 @@ DECLARE_PROCESS_TYPE_TRAITS_CLASS(Generic, 64)
/* Similar to Size(), but computes the expected size of a structure based \
* on the process bitness. This can be used prior to reading any data \
* from a process. */ \
static size_t ExpectedSize(ProcessReader* process_reader);
static size_t ExpectedSize(ProcessReader* process_reader); \
\
/* Similar to ExpectedSize(), but computes the expected size of a \
* structure based on the process bitness and a custom value, such as a \
* structure version number. This can be used prior to reading any data \
* from a process. */ \
static size_t ExpectedSizeForVersion(ProcessReader* process_reader, \
uint64_t version);
#define PROCESS_TYPE_STRUCT_MEMBER(member_type, member_name, ...) \
member_type member_name __VA_ARGS__;
@ -143,8 +150,8 @@ DECLARE_PROCESS_TYPE_TRAITS_CLASS(Generic, 64)
using UIntPtr = typename Traits::UIntPtr; \
using Reserved64Only = typename Traits::Reserved64Only; \
\
/* Read(), ReadArrayInto(), and Size() are as in the generic user-visible \
* struct above. */ \
/* Read(), ReadArrayInto(), Size(), and ExpectedSizeForVersion() are as in \
* the generic user-visible struct above. */ \
bool Read(ProcessReader* process_reader, mach_vm_address_t address) { \
return ReadInto(process_reader, address, this); \
} \
@ -153,6 +160,7 @@ DECLARE_PROCESS_TYPE_TRAITS_CLASS(Generic, 64)
size_t count, \
struct_name<Traits>* specific); \
static size_t Size() { return sizeof(struct_name<Traits>); } \
static size_t ExpectedSizeForVersion(uint64_t version); \
\
/* Translates a struct from the representation used in the remote process \
* into the generic form. */ \

View File

@ -27,14 +27,32 @@
// Client Mach-O images will contain a __DATA,__crash_info section formatted
// according to this structure.
//
// crashreporter_annotations_t is variable-length. Its length dictated by its
// |version| field which is always present. A custom implementation of the
// flavored ReadSpecificInto function that understands how to map this field to
// the structures actual size is provided in
// snapshot/mac/process_types/custom.cc. No implementation of ReadArrayInto is
// provided because dyld_all_image_infos structs are singletons in a process and
// are never present in arrays, so the functionality is unnecessary.
#if !defined(PROCESS_TYPE_STRUCT_IMPLEMENT_INTERNAL_READ_INTO) && \
!defined(PROCESS_TYPE_STRUCT_IMPLEMENT_ARRAY)
PROCESS_TYPE_STRUCT_BEGIN(crashreporter_annotations_t)
// The only known version is 4.
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, version) // unsigned long
// Version 4 (Mac OS X 10.7)
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, message) // char*
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, signature_string) // char*
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, backtrace) // char*
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, message2) // char*
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, thread)
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, dialog_mode) // unsigned int
// Version 5 (OS X 10.11)
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, unknown_0)
PROCESS_TYPE_STRUCT_END(crashreporter_annotations_t)
#endif // ! PROCESS_TYPE_STRUCT_IMPLEMENT_INTERNAL_READ_INTO &&
// ! PROCESS_TYPE_STRUCT_IMPLEMENT_ARRAY

View File

@ -16,6 +16,7 @@
#include <string.h>
#include "base/logging.h"
#include "snapshot/mac/process_types/internal.h"
#include "util/mach/task_memory.h"
@ -23,47 +24,17 @@ namespace crashpad {
namespace process_types {
namespace internal {
template <typename Traits>
bool dyld_all_image_infos<Traits>::ReadInto(
ProcessReader* process_reader,
mach_vm_address_t address,
dyld_all_image_infos<Traits>* specific) {
template <typename T>
bool ReadIntoVersioned(ProcessReader* process_reader,
mach_vm_address_t address,
T* specific) {
TaskMemory* task_memory = process_reader->Memory();
if (!task_memory->Read(
address, sizeof(specific->version), &specific->version)) {
return false;
}
mach_vm_size_t size;
if (specific->version >= 14) {
size = sizeof(dyld_all_image_infos<Traits>);
} else if (specific->version >= 13) {
size = offsetof(dyld_all_image_infos<Traits>, reserved);
} else if (specific->version >= 12) {
size = offsetof(dyld_all_image_infos<Traits>, sharedCacheUUID);
} else if (specific->version >= 11) {
size = offsetof(dyld_all_image_infos<Traits>, sharedCacheSlide);
} else if (specific->version >= 10) {
size = offsetof(dyld_all_image_infos<Traits>, errorKind);
} else if (specific->version >= 9) {
size = offsetof(dyld_all_image_infos<Traits>, initialImageCount);
} else if (specific->version >= 8) {
size = offsetof(dyld_all_image_infos<Traits>, dyldAllImageInfosAddress);
} else if (specific->version >= 7) {
size = offsetof(dyld_all_image_infos<Traits>, uuidArrayCount);
} else if (specific->version >= 6) {
size = offsetof(dyld_all_image_infos<Traits>, systemOrderFlag);
} else if (specific->version >= 5) {
size = offsetof(dyld_all_image_infos<Traits>, coreSymbolicationShmPage);
} else if (specific->version >= 3) {
size = offsetof(dyld_all_image_infos<Traits>, dyldVersion);
} else if (specific->version >= 2) {
size = offsetof(dyld_all_image_infos<Traits>, jitInfo);
} else if (specific->version >= 1) {
size = offsetof(dyld_all_image_infos<Traits>, libSystemInitialized);
} else {
size = offsetof(dyld_all_image_infos<Traits>, infoArrayCount);
}
mach_vm_size_t size = T::ExpectedSizeForVersion(specific->version);
if (!task_memory->Read(address, size, specific)) {
return false;
@ -80,11 +51,96 @@ bool dyld_all_image_infos<Traits>::ReadInto(
return true;
}
#define PROCESS_TYPE_FLAVOR_TRAITS(lp_bits) \
template bool dyld_all_image_infos<Traits##lp_bits>::ReadInto( \
ProcessReader*, \
mach_vm_address_t, \
dyld_all_image_infos<Traits##lp_bits>*);
// static
template <typename Traits>
size_t dyld_all_image_infos<Traits>::ExpectedSizeForVersion(uint64_t version) {
if (version >= 14) {
return sizeof(dyld_all_image_infos<Traits>);
}
if (version >= 13) {
return offsetof(dyld_all_image_infos<Traits>, reserved);
}
if (version >= 12) {
return offsetof(dyld_all_image_infos<Traits>, sharedCacheUUID);
}
if (version >= 11) {
return offsetof(dyld_all_image_infos<Traits>, sharedCacheSlide);
}
if (version >= 10) {
return offsetof(dyld_all_image_infos<Traits>, errorKind);
}
if (version >= 9) {
return offsetof(dyld_all_image_infos<Traits>, initialImageCount);
}
if (version >= 8) {
return offsetof(dyld_all_image_infos<Traits>, dyldAllImageInfosAddress);
}
if (version >= 7) {
return offsetof(dyld_all_image_infos<Traits>, uuidArrayCount);
}
if (version >= 6) {
return offsetof(dyld_all_image_infos<Traits>, systemOrderFlag);
}
if (version >= 5) {
return offsetof(dyld_all_image_infos<Traits>, coreSymbolicationShmPage);
}
if (version >= 3) {
return offsetof(dyld_all_image_infos<Traits>, dyldVersion);
}
if (version >= 2) {
return offsetof(dyld_all_image_infos<Traits>, jitInfo);
}
if (version >= 1) {
return offsetof(dyld_all_image_infos<Traits>, libSystemInitialized);
}
return offsetof(dyld_all_image_infos<Traits>, infoArrayCount);
}
// static
template <typename Traits>
bool dyld_all_image_infos<Traits>::ReadInto(
ProcessReader* process_reader,
mach_vm_address_t address,
dyld_all_image_infos<Traits>* specific) {
return ReadIntoVersioned(process_reader, address, specific);
}
// static
template <typename Traits>
size_t crashreporter_annotations_t<Traits>::ExpectedSizeForVersion(
uint64_t version) {
if (version >= 5) {
return sizeof(crashreporter_annotations_t<Traits>);
}
if (version >= 4) {
return offsetof(crashreporter_annotations_t<Traits>, unknown_0);
}
return offsetof(crashreporter_annotations_t<Traits>, message);
}
// static
template <typename Traits>
bool crashreporter_annotations_t<Traits>::ReadInto(
ProcessReader* process_reader,
mach_vm_address_t address,
crashreporter_annotations_t<Traits>* specific) {
return ReadIntoVersioned(process_reader, address, specific);
}
#define PROCESS_TYPE_FLAVOR_TRAITS(lp_bits) \
template size_t \
dyld_all_image_infos<Traits##lp_bits>::ExpectedSizeForVersion(uint64_t); \
template bool dyld_all_image_infos<Traits##lp_bits>::ReadInto( \
ProcessReader*, \
mach_vm_address_t, \
dyld_all_image_infos<Traits##lp_bits>*); \
template size_t \
crashreporter_annotations_t<Traits##lp_bits>::ExpectedSizeForVersion( \
uint64_t); \
template bool crashreporter_annotations_t<Traits##lp_bits>::ReadInto( \
ProcessReader*, \
mach_vm_address_t, \
crashreporter_annotations_t<Traits##lp_bits>*);
#include "snapshot/mac/process_types/flavors.h"

View File

@ -81,6 +81,7 @@
'conditions': [
['OS=="mac"', {
'dependencies': [
'crashpad_snapshot_test_module_crashy_initializer',
'crashpad_snapshot_test_no_op',
],
'link_settings': {
@ -109,6 +110,13 @@
'conditions': [
['OS=="mac"', {
'targets': [
{
'target_name': 'crashpad_snapshot_test_module_crashy_initializer',
'type': 'loadable_module',
'sources': [
'mac/mach_o_image_annotations_reader_test_module_crashy_initializer.cc',
],
},
{
'target_name': 'crashpad_snapshot_test_no_op',
'type': 'executable',