mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-28 07:48:14 +08:00
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:
parent
124ace19bd
commit
6083a2706d
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
@ -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, \
|
||||
|
@ -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. */ \
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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',
|
||||
|
Loading…
x
Reference in New Issue
Block a user