diff --git a/snapshot/mac/mach_o_image_annotations_reader.cc b/snapshot/mac/mach_o_image_annotations_reader.cc index 6c6831bd..1e2b7404 100644 --- a/snapshot/mac/mach_o_image_annotations_reader.cc +++ b/snapshot/mac/mach_o_image_annotations_reader.cc @@ -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 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; } diff --git a/snapshot/mac/mach_o_image_annotations_reader_test.cc b/snapshot/mac/mach_o_image_annotations_reader_test.cc index 12dc6e51..6609b059 100644 --- a/snapshot/mac/mach_o_image_annotations_reader_test.cc +++ b/snapshot/mac/mach_o_image_annotations_reader_test.cc @@ -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 dyld’s 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); diff --git a/snapshot/mac/mach_o_image_annotations_reader_test_module_crashy_initializer.cc b/snapshot/mac/mach_o_image_annotations_reader_test_module_crashy_initializer.cc new file mode 100644 index 00000000..2ba9bee0 --- /dev/null +++ b/snapshot/mac/mach_o_image_annotations_reader_test_module_crashy_initializer.cc @@ -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 diff --git a/snapshot/mac/process_types.cc b/snapshot/mac/process_types.cc index 8c907b2f..196a01dd 100644 --- a/snapshot/mac/process_types.cc +++ b/snapshot/mac/process_types.cc @@ -17,6 +17,7 @@ #include #include +#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* 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::Size(); \ - } else { \ - return internal::struct_name::Size(); \ - } \ - } \ - \ - bool struct_name::ReadInto(ProcessReader* process_reader, \ - mach_vm_address_t address, \ - struct_name* generic) { \ - if (!process_reader->Is64Bit()) { \ - return ReadIntoInternal >( \ - process_reader, address, generic); \ - } else { \ - return ReadIntoInternal >( \ - process_reader, address, generic); \ - } \ - } \ - \ - template \ - 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 \ - void struct_name::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::Size(); \ + } else { \ + return internal::struct_name::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 >( \ + process_reader, address, generic); \ + } else { \ + return ReadIntoInternal >( \ + process_reader, address, generic); \ + } \ + } \ + \ + /* static */ \ + template \ + 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 \ + void struct_name::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* destination, const uuid_t& source) { namespace process_types { \ namespace internal { \ \ + /* static */ \ template \ bool struct_name::ReadInto(ProcessReader* process_reader, \ mach_vm_address_t address, \ @@ -189,16 +206,25 @@ inline void Assign(uuid_t* destination, const uuid_t& source) { namespace process_types { \ namespace internal { \ \ + /* static */ \ template \ bool struct_name::ReadArrayInto(ProcessReader* process_reader, \ mach_vm_address_t address, \ size_t count, \ struct_name* specific) { \ return process_reader->Memory()->Read( \ - address, sizeof(struct_name [count]), specific); \ + address, sizeof(struct_name[count]), specific); \ + } \ + \ + /* static */ \ + template \ + size_t struct_name::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* destination, const uuid_t& source) { return true; \ } \ \ + /* static */ \ template \ bool struct_name::ReadArrayIntoInternal(ProcessReader* process_reader, \ mach_vm_address_t address, \ diff --git a/snapshot/mac/process_types.h b/snapshot/mac/process_types.h index b38fea78..62b46636 100644 --- a/snapshot/mac/process_types.h +++ b/snapshot/mac/process_types.h @@ -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* specific); \ static size_t Size() { return sizeof(struct_name); } \ + static size_t ExpectedSizeForVersion(uint64_t version); \ \ /* Translates a struct from the representation used in the remote process \ * into the generic form. */ \ diff --git a/snapshot/mac/process_types/crashreporterclient.proctype b/snapshot/mac/process_types/crashreporterclient.proctype index 7d83c233..7afaddea 100644 --- a/snapshot/mac/process_types/crashreporterclient.proctype +++ b/snapshot/mac/process_types/crashreporterclient.proctype @@ -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 structure’s 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 diff --git a/snapshot/mac/process_types/custom.cc b/snapshot/mac/process_types/custom.cc index 49553cf9..ba055c0e 100644 --- a/snapshot/mac/process_types/custom.cc +++ b/snapshot/mac/process_types/custom.cc @@ -16,6 +16,7 @@ #include +#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 -bool dyld_all_image_infos::ReadInto( - ProcessReader* process_reader, - mach_vm_address_t address, - dyld_all_image_infos* specific) { +template +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); - } else if (specific->version >= 13) { - size = offsetof(dyld_all_image_infos, reserved); - } else if (specific->version >= 12) { - size = offsetof(dyld_all_image_infos, sharedCacheUUID); - } else if (specific->version >= 11) { - size = offsetof(dyld_all_image_infos, sharedCacheSlide); - } else if (specific->version >= 10) { - size = offsetof(dyld_all_image_infos, errorKind); - } else if (specific->version >= 9) { - size = offsetof(dyld_all_image_infos, initialImageCount); - } else if (specific->version >= 8) { - size = offsetof(dyld_all_image_infos, dyldAllImageInfosAddress); - } else if (specific->version >= 7) { - size = offsetof(dyld_all_image_infos, uuidArrayCount); - } else if (specific->version >= 6) { - size = offsetof(dyld_all_image_infos, systemOrderFlag); - } else if (specific->version >= 5) { - size = offsetof(dyld_all_image_infos, coreSymbolicationShmPage); - } else if (specific->version >= 3) { - size = offsetof(dyld_all_image_infos, dyldVersion); - } else if (specific->version >= 2) { - size = offsetof(dyld_all_image_infos, jitInfo); - } else if (specific->version >= 1) { - size = offsetof(dyld_all_image_infos, libSystemInitialized); - } else { - size = offsetof(dyld_all_image_infos, 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::ReadInto( return true; } -#define PROCESS_TYPE_FLAVOR_TRAITS(lp_bits) \ - template bool dyld_all_image_infos::ReadInto( \ - ProcessReader*, \ - mach_vm_address_t, \ - dyld_all_image_infos*); +// static +template +size_t dyld_all_image_infos::ExpectedSizeForVersion(uint64_t version) { + if (version >= 14) { + return sizeof(dyld_all_image_infos); + } + if (version >= 13) { + return offsetof(dyld_all_image_infos, reserved); + } + if (version >= 12) { + return offsetof(dyld_all_image_infos, sharedCacheUUID); + } + if (version >= 11) { + return offsetof(dyld_all_image_infos, sharedCacheSlide); + } + if (version >= 10) { + return offsetof(dyld_all_image_infos, errorKind); + } + if (version >= 9) { + return offsetof(dyld_all_image_infos, initialImageCount); + } + if (version >= 8) { + return offsetof(dyld_all_image_infos, dyldAllImageInfosAddress); + } + if (version >= 7) { + return offsetof(dyld_all_image_infos, uuidArrayCount); + } + if (version >= 6) { + return offsetof(dyld_all_image_infos, systemOrderFlag); + } + if (version >= 5) { + return offsetof(dyld_all_image_infos, coreSymbolicationShmPage); + } + if (version >= 3) { + return offsetof(dyld_all_image_infos, dyldVersion); + } + if (version >= 2) { + return offsetof(dyld_all_image_infos, jitInfo); + } + if (version >= 1) { + return offsetof(dyld_all_image_infos, libSystemInitialized); + } + return offsetof(dyld_all_image_infos, infoArrayCount); +} + +// static +template +bool dyld_all_image_infos::ReadInto( + ProcessReader* process_reader, + mach_vm_address_t address, + dyld_all_image_infos* specific) { + return ReadIntoVersioned(process_reader, address, specific); +} + +// static +template +size_t crashreporter_annotations_t::ExpectedSizeForVersion( + uint64_t version) { + if (version >= 5) { + return sizeof(crashreporter_annotations_t); + } + if (version >= 4) { + return offsetof(crashreporter_annotations_t, unknown_0); + } + return offsetof(crashreporter_annotations_t, message); +} + +// static +template +bool crashreporter_annotations_t::ReadInto( + ProcessReader* process_reader, + mach_vm_address_t address, + crashreporter_annotations_t* specific) { + return ReadIntoVersioned(process_reader, address, specific); +} + +#define PROCESS_TYPE_FLAVOR_TRAITS(lp_bits) \ + template size_t \ + dyld_all_image_infos::ExpectedSizeForVersion(uint64_t); \ + template bool dyld_all_image_infos::ReadInto( \ + ProcessReader*, \ + mach_vm_address_t, \ + dyld_all_image_infos*); \ + template size_t \ + crashreporter_annotations_t::ExpectedSizeForVersion( \ + uint64_t); \ + template bool crashreporter_annotations_t::ReadInto( \ + ProcessReader*, \ + mach_vm_address_t, \ + crashreporter_annotations_t*); #include "snapshot/mac/process_types/flavors.h" diff --git a/snapshot/snapshot_test.gyp b/snapshot/snapshot_test.gyp index 538e7c60..9b94a106 100644 --- a/snapshot/snapshot_test.gyp +++ b/snapshot/snapshot_test.gyp @@ -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',