mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-29 00:00:08 +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;
|
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)) {
|
if (!crash_info.Read(process_reader_, crash_info_address)) {
|
||||||
LOG(WARNING) << "could not read crash info from " << name_;
|
LOG(WARNING) << "could not read crash info from " << name_;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crash_info.version != 4) {
|
if (crash_info.version != 4 && crash_info.version != 5) {
|
||||||
LOG(WARNING) << "unexpected crash info version " << crash_info.version
|
LOG(WARNING) << "unexpected crash info version " << crash_info.version
|
||||||
<< " in " << name_;
|
<< " in " << name_;
|
||||||
return;
|
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
|
// This number was totally made up out of nowhere, but it seems prudent to
|
||||||
// enforce some limit.
|
// enforce some limit.
|
||||||
const size_t kMaxMessageSize = 1024;
|
const size_t kMaxMessageSize = 1024;
|
||||||
if (crash_info.message) {
|
if (crash_info.message) {
|
||||||
std::string message;
|
std::string message;
|
||||||
if (process_reader_->Memory()->
|
if (process_reader_->Memory()->ReadCStringSizeLimited(
|
||||||
ReadCStringSizeLimited(
|
crash_info.message, kMaxMessageSize, &message)) {
|
||||||
crash_info.message, kMaxMessageSize, &message)) {
|
|
||||||
vector_annotations->push_back(message);
|
vector_annotations->push_back(message);
|
||||||
} else {
|
} else {
|
||||||
LOG(WARNING) << "could not read crash message in " << name_;
|
LOG(WARNING) << "could not read crash message in " << name_;
|
||||||
@ -100,9 +103,8 @@ void MachOImageAnnotationsReader::ReadCrashReporterClientAnnotations(
|
|||||||
|
|
||||||
if (crash_info.message2) {
|
if (crash_info.message2) {
|
||||||
std::string message;
|
std::string message;
|
||||||
if (process_reader_->Memory()->
|
if (process_reader_->Memory()->ReadCStringSizeLimited(
|
||||||
ReadCStringSizeLimited(
|
crash_info.message2, kMaxMessageSize, &message)) {
|
||||||
crash_info.message2, kMaxMessageSize, &message)) {
|
|
||||||
vector_annotations->push_back(message);
|
vector_annotations->push_back(message);
|
||||||
} else {
|
} else {
|
||||||
LOG(WARNING) << "could not read crash message 2 in " << name_;
|
LOG(WARNING) << "could not read crash message 2 in " << name_;
|
||||||
@ -127,8 +129,8 @@ void MachOImageAnnotationsReader::ReadDyldErrorStringAnnotation(
|
|||||||
std::string message;
|
std::string message;
|
||||||
// 1024 here is distinct from kMaxMessageSize above, because it refers to a
|
// 1024 here is distinct from kMaxMessageSize above, because it refers to a
|
||||||
// precisely-sized buffer inside dyld.
|
// precisely-sized buffer inside dyld.
|
||||||
if (process_reader_->Memory()->
|
if (process_reader_->Memory()->ReadCStringSizeLimited(
|
||||||
ReadCStringSizeLimited(error_string_address, 1024, &message)) {
|
error_string_address, 1024, &message)) {
|
||||||
if (!message.empty()) {
|
if (!message.empty()) {
|
||||||
vector_annotations->push_back(message);
|
vector_annotations->push_back(message);
|
||||||
}
|
}
|
||||||
@ -150,10 +152,10 @@ void MachOImageAnnotationsReader::ReadCrashpadSimpleAnnotations(
|
|||||||
|
|
||||||
std::vector<SimpleStringDictionary::Entry>
|
std::vector<SimpleStringDictionary::Entry>
|
||||||
simple_annotations(SimpleStringDictionary::num_entries);
|
simple_annotations(SimpleStringDictionary::num_entries);
|
||||||
if (!process_reader_->Memory()
|
if (!process_reader_->Memory()->Read(
|
||||||
->Read(crashpad_info.simple_annotations,
|
crashpad_info.simple_annotations,
|
||||||
simple_annotations.size() * sizeof(simple_annotations[0]),
|
simple_annotations.size() * sizeof(simple_annotations[0]),
|
||||||
&simple_annotations[0])) {
|
&simple_annotations[0])) {
|
||||||
LOG(WARNING) << "could not read simple annotations from " << name_;
|
LOG(WARNING) << "could not read simple annotations from " << name_;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,11 @@ namespace crashpad {
|
|||||||
namespace test {
|
namespace test {
|
||||||
namespace {
|
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.
|
//! \return The path to the crashpad_snapshot_test_no_op executable.
|
||||||
base::FilePath NoOpExecutable() {
|
base::FilePath NoOpExecutable() {
|
||||||
return base::FilePath(Paths::Executable().value() + "_no_op");
|
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
|
// The child process should crash by calling abort(). The parent verifies
|
||||||
// that the system libraries set the expected annotations.
|
// 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,
|
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
|
// The child process should crash by setting DYLD_INSERT_LIBRARIES to
|
||||||
// contain a nonexistent library. The parent verifies that dyld sets the
|
// contain a nonexistent library. The parent verifies that dyld sets the
|
||||||
// expected annotations.
|
// expected annotations.
|
||||||
@ -126,7 +147,7 @@ class TestMachOImageAnnotationsReader final
|
|||||||
if (mac_os_x_minor_version > 7) {
|
if (mac_os_x_minor_version > 7) {
|
||||||
EXPECT_GE(all_annotations_vector.size(), 1u);
|
EXPECT_GE(all_annotations_vector.size(), 1u);
|
||||||
|
|
||||||
const char* expected_annotation = nullptr;
|
std::string expected_annotation;
|
||||||
switch (test_type_) {
|
switch (test_type_) {
|
||||||
case kCrashAbort:
|
case kCrashAbort:
|
||||||
// The child process calls abort(), so the expected annotation
|
// The child process calls abort(), so the expected annotation
|
||||||
@ -145,6 +166,12 @@ class TestMachOImageAnnotationsReader final
|
|||||||
: "crashed on child side of fork pre-exec";
|
: "crashed on child side of fork pre-exec";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kCrashModuleInitialization:
|
||||||
|
// This message is set by dyld-353.2.1/src/ImageLoaderMachO.cpp
|
||||||
|
// ImageLoaderMachO::doInitialization().
|
||||||
|
expected_annotation = ModuleWithCrashyInitializer();
|
||||||
|
break;
|
||||||
|
|
||||||
case kCrashDyld:
|
case kCrashDyld:
|
||||||
// This is independent of dyld’s error_string, which is tested
|
// This is independent of dyld’s error_string, which is tested
|
||||||
// below.
|
// below.
|
||||||
@ -156,20 +183,19 @@ class TestMachOImageAnnotationsReader final
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t expected_annotation_length = strlen(expected_annotation);
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (const std::string& annotation : all_annotations_vector) {
|
for (const std::string& annotation : all_annotations_vector) {
|
||||||
// Look for the expectation as a leading susbtring, because the actual
|
// Look for the expectation as a leading susbtring, because the actual
|
||||||
// string that dyld uses will have the contents of the
|
// string that dyld uses will have the contents of the
|
||||||
// DYLD_INSERT_LIBRARIES environment variable appended to it on Mac
|
// DYLD_INSERT_LIBRARIES environment variable appended to it on Mac
|
||||||
// OS X 10.10.
|
// OS X 10.10.
|
||||||
if (annotation.substr(0, expected_annotation_length) ==
|
if (annotation.substr(0, expected_annotation.length()) ==
|
||||||
expected_annotation) {
|
expected_annotation) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
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.
|
// 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);
|
SetExpectedChildTermination(kTerminationSignal, SIGABRT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kCrashModuleInitialization:
|
||||||
|
// This crash is triggered by __builtin_trap(), which shows up as
|
||||||
|
// SIGILL.
|
||||||
|
SetExpectedChildTermination(kTerminationSignal, SIGILL);
|
||||||
|
break;
|
||||||
|
|
||||||
case kCrashDyld:
|
case kCrashDyld:
|
||||||
// dyld fatal errors result in the execution of an int3 instruction on
|
// dyld fatal errors result in the execution of an int3 instruction on
|
||||||
// x86 and a trap instruction on ARM, both of which raise SIGTRAP.
|
// 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));
|
EXC_MASK_CRASH, RemotePort(), EXCEPTION_DEFAULT, THREAD_STATE_NONE));
|
||||||
|
|
||||||
switch (test_type_) {
|
switch (test_type_) {
|
||||||
case kDontCrash:
|
case kDontCrash: {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case kCrashAbort:
|
case kCrashAbort: {
|
||||||
abort();
|
abort();
|
||||||
break;
|
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: {
|
case kCrashDyld: {
|
||||||
// Set DYLD_INSERT_LIBRARIES to contain a library that does not exist.
|
// 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_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) {
|
TEST(MachOImageAnnotationsReader, CrashDyld) {
|
||||||
TestMachOImageAnnotationsReader test_mach_o_image_annotations_reader(
|
TestMachOImageAnnotationsReader test_mach_o_image_annotations_reader(
|
||||||
TestMachOImageAnnotationsReader::kCrashDyld);
|
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 <string.h>
|
||||||
#include <uuid/uuid.h>
|
#include <uuid/uuid.h>
|
||||||
|
|
||||||
|
#include "base/logging.h"
|
||||||
#include "base/memory/scoped_ptr.h"
|
#include "base/memory/scoped_ptr.h"
|
||||||
#include "snapshot/mac/process_types/internal.h"
|
#include "snapshot/mac/process_types/internal.h"
|
||||||
#include "util/mach/task_memory.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.
|
// operates on each member in the struct.
|
||||||
#define PROCESS_TYPE_STRUCT_IMPLEMENT 1
|
#define PROCESS_TYPE_STRUCT_IMPLEMENT 1
|
||||||
|
|
||||||
#define PROCESS_TYPE_STRUCT_BEGIN(struct_name) \
|
#define PROCESS_TYPE_STRUCT_BEGIN(struct_name) \
|
||||||
namespace crashpad { \
|
namespace crashpad { \
|
||||||
namespace process_types { \
|
namespace process_types { \
|
||||||
\
|
\
|
||||||
size_t struct_name::ExpectedSize(ProcessReader* process_reader) { \
|
/* static */ \
|
||||||
if (!process_reader->Is64Bit()) { \
|
size_t struct_name::ExpectedSize(ProcessReader* process_reader) { \
|
||||||
return internal::struct_name<internal::Traits32>::Size(); \
|
if (!process_reader->Is64Bit()) { \
|
||||||
} else { \
|
return internal::struct_name<internal::Traits32>::Size(); \
|
||||||
return internal::struct_name<internal::Traits64>::Size(); \
|
} else { \
|
||||||
} \
|
return internal::struct_name<internal::Traits64>::Size(); \
|
||||||
} \
|
} \
|
||||||
\
|
} \
|
||||||
bool struct_name::ReadInto(ProcessReader* process_reader, \
|
\
|
||||||
mach_vm_address_t address, \
|
/* static */ \
|
||||||
struct_name* generic) { \
|
size_t struct_name::ExpectedSizeForVersion(ProcessReader* process_reader, \
|
||||||
if (!process_reader->Is64Bit()) { \
|
uint64_t version) { \
|
||||||
return ReadIntoInternal<internal::struct_name<internal::Traits32> >( \
|
if (!process_reader->Is64Bit()) { \
|
||||||
process_reader, address, generic); \
|
return internal::struct_name< \
|
||||||
} else { \
|
internal::Traits32>::ExpectedSizeForVersion(version); \
|
||||||
return ReadIntoInternal<internal::struct_name<internal::Traits64> >( \
|
} else { \
|
||||||
process_reader, address, generic); \
|
return internal::struct_name< \
|
||||||
} \
|
internal::Traits64>::ExpectedSizeForVersion(version); \
|
||||||
} \
|
} \
|
||||||
\
|
} \
|
||||||
template <typename T> \
|
\
|
||||||
bool struct_name::ReadIntoInternal(ProcessReader* process_reader, \
|
/* static */ \
|
||||||
mach_vm_address_t address, \
|
bool struct_name::ReadInto(ProcessReader* process_reader, \
|
||||||
struct_name* generic) { \
|
mach_vm_address_t address, \
|
||||||
T specific; \
|
struct_name* generic) { \
|
||||||
if (!specific.Read(process_reader, address)) { \
|
if (!process_reader->Is64Bit()) { \
|
||||||
return false; \
|
return ReadIntoInternal<internal::struct_name<internal::Traits32> >( \
|
||||||
} \
|
process_reader, address, generic); \
|
||||||
specific.GenericizeInto(generic, &generic->size_); \
|
} else { \
|
||||||
return true; \
|
return ReadIntoInternal<internal::struct_name<internal::Traits64> >( \
|
||||||
} \
|
process_reader, address, generic); \
|
||||||
\
|
} \
|
||||||
namespace internal { \
|
} \
|
||||||
\
|
\
|
||||||
template <typename Traits> \
|
/* static */ \
|
||||||
void struct_name<Traits>::GenericizeInto( \
|
template <typename T> \
|
||||||
process_types::struct_name* generic, \
|
bool struct_name::ReadIntoInternal(ProcessReader* process_reader, \
|
||||||
size_t* specific_size) { \
|
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();
|
*specific_size = Size();
|
||||||
|
|
||||||
#define PROCESS_TYPE_STRUCT_MEMBER(member_type, member_name, ...) \
|
#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 process_types { \
|
||||||
namespace internal { \
|
namespace internal { \
|
||||||
\
|
\
|
||||||
|
/* static */ \
|
||||||
template <typename Traits> \
|
template <typename Traits> \
|
||||||
bool struct_name<Traits>::ReadInto(ProcessReader* process_reader, \
|
bool struct_name<Traits>::ReadInto(ProcessReader* process_reader, \
|
||||||
mach_vm_address_t address, \
|
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 process_types { \
|
||||||
namespace internal { \
|
namespace internal { \
|
||||||
\
|
\
|
||||||
|
/* static */ \
|
||||||
template <typename Traits> \
|
template <typename Traits> \
|
||||||
bool struct_name<Traits>::ReadArrayInto(ProcessReader* process_reader, \
|
bool struct_name<Traits>::ReadArrayInto(ProcessReader* process_reader, \
|
||||||
mach_vm_address_t address, \
|
mach_vm_address_t address, \
|
||||||
size_t count, \
|
size_t count, \
|
||||||
struct_name<Traits>* specific) { \
|
struct_name<Traits>* specific) { \
|
||||||
return process_reader->Memory()->Read( \
|
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 */ \
|
} /* namespace internal */ \
|
||||||
\
|
\
|
||||||
|
/* static */ \
|
||||||
bool struct_name::ReadArrayInto(ProcessReader* process_reader, \
|
bool struct_name::ReadArrayInto(ProcessReader* process_reader, \
|
||||||
mach_vm_address_t address, \
|
mach_vm_address_t address, \
|
||||||
size_t count, \
|
size_t count, \
|
||||||
@ -215,6 +241,7 @@ inline void Assign<uuid_t, uuid_t>(uuid_t* destination, const uuid_t& source) {
|
|||||||
return true; \
|
return true; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
|
/* static */ \
|
||||||
template <typename T> \
|
template <typename T> \
|
||||||
bool struct_name::ReadArrayIntoInternal(ProcessReader* process_reader, \
|
bool struct_name::ReadArrayIntoInternal(ProcessReader* process_reader, \
|
||||||
mach_vm_address_t address, \
|
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 \
|
/* 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 \
|
* on the process’ bitness. This can be used prior to reading any data \
|
||||||
* from a process. */ \
|
* 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, ...) \
|
#define PROCESS_TYPE_STRUCT_MEMBER(member_type, member_name, ...) \
|
||||||
member_type member_name __VA_ARGS__;
|
member_type member_name __VA_ARGS__;
|
||||||
@ -143,8 +150,8 @@ DECLARE_PROCESS_TYPE_TRAITS_CLASS(Generic, 64)
|
|||||||
using UIntPtr = typename Traits::UIntPtr; \
|
using UIntPtr = typename Traits::UIntPtr; \
|
||||||
using Reserved64Only = typename Traits::Reserved64Only; \
|
using Reserved64Only = typename Traits::Reserved64Only; \
|
||||||
\
|
\
|
||||||
/* Read(), ReadArrayInto(), and Size() are as in the generic user-visible \
|
/* Read(), ReadArrayInto(), Size(), and ExpectedSizeForVersion() are as in \
|
||||||
* struct above. */ \
|
* the generic user-visible struct above. */ \
|
||||||
bool Read(ProcessReader* process_reader, mach_vm_address_t address) { \
|
bool Read(ProcessReader* process_reader, mach_vm_address_t address) { \
|
||||||
return ReadInto(process_reader, address, this); \
|
return ReadInto(process_reader, address, this); \
|
||||||
} \
|
} \
|
||||||
@ -153,6 +160,7 @@ DECLARE_PROCESS_TYPE_TRAITS_CLASS(Generic, 64)
|
|||||||
size_t count, \
|
size_t count, \
|
||||||
struct_name<Traits>* specific); \
|
struct_name<Traits>* specific); \
|
||||||
static size_t Size() { return sizeof(struct_name<Traits>); } \
|
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 \
|
/* Translates a struct from the representation used in the remote process \
|
||||||
* into the generic form. */ \
|
* into the generic form. */ \
|
||||||
|
@ -27,14 +27,32 @@
|
|||||||
|
|
||||||
// Client Mach-O images will contain a __DATA,__crash_info section formatted
|
// Client Mach-O images will contain a __DATA,__crash_info section formatted
|
||||||
// according to this structure.
|
// 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)
|
PROCESS_TYPE_STRUCT_BEGIN(crashreporter_annotations_t)
|
||||||
// The only known version is 4.
|
|
||||||
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, version) // unsigned long
|
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, message) // char*
|
||||||
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, signature_string) // char*
|
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, signature_string) // char*
|
||||||
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, backtrace) // char*
|
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, backtrace) // char*
|
||||||
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, message2) // char*
|
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, message2) // char*
|
||||||
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, thread)
|
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, thread)
|
||||||
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, dialog_mode) // unsigned int
|
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)
|
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 <string.h>
|
||||||
|
|
||||||
|
#include "base/logging.h"
|
||||||
#include "snapshot/mac/process_types/internal.h"
|
#include "snapshot/mac/process_types/internal.h"
|
||||||
#include "util/mach/task_memory.h"
|
#include "util/mach/task_memory.h"
|
||||||
|
|
||||||
@ -23,47 +24,17 @@ namespace crashpad {
|
|||||||
namespace process_types {
|
namespace process_types {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
template <typename Traits>
|
template <typename T>
|
||||||
bool dyld_all_image_infos<Traits>::ReadInto(
|
bool ReadIntoVersioned(ProcessReader* process_reader,
|
||||||
ProcessReader* process_reader,
|
mach_vm_address_t address,
|
||||||
mach_vm_address_t address,
|
T* specific) {
|
||||||
dyld_all_image_infos<Traits>* specific) {
|
|
||||||
TaskMemory* task_memory = process_reader->Memory();
|
TaskMemory* task_memory = process_reader->Memory();
|
||||||
if (!task_memory->Read(
|
if (!task_memory->Read(
|
||||||
address, sizeof(specific->version), &specific->version)) {
|
address, sizeof(specific->version), &specific->version)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mach_vm_size_t size;
|
mach_vm_size_t size = T::ExpectedSizeForVersion(specific->version);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!task_memory->Read(address, size, specific)) {
|
if (!task_memory->Read(address, size, specific)) {
|
||||||
return false;
|
return false;
|
||||||
@ -80,11 +51,96 @@ bool dyld_all_image_infos<Traits>::ReadInto(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PROCESS_TYPE_FLAVOR_TRAITS(lp_bits) \
|
// static
|
||||||
template bool dyld_all_image_infos<Traits##lp_bits>::ReadInto( \
|
template <typename Traits>
|
||||||
ProcessReader*, \
|
size_t dyld_all_image_infos<Traits>::ExpectedSizeForVersion(uint64_t version) {
|
||||||
mach_vm_address_t, \
|
if (version >= 14) {
|
||||||
dyld_all_image_infos<Traits##lp_bits>*);
|
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"
|
#include "snapshot/mac/process_types/flavors.h"
|
||||||
|
|
||||||
|
@ -81,6 +81,7 @@
|
|||||||
'conditions': [
|
'conditions': [
|
||||||
['OS=="mac"', {
|
['OS=="mac"', {
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
|
'crashpad_snapshot_test_module_crashy_initializer',
|
||||||
'crashpad_snapshot_test_no_op',
|
'crashpad_snapshot_test_no_op',
|
||||||
],
|
],
|
||||||
'link_settings': {
|
'link_settings': {
|
||||||
@ -109,6 +110,13 @@
|
|||||||
'conditions': [
|
'conditions': [
|
||||||
['OS=="mac"', {
|
['OS=="mac"', {
|
||||||
'targets': [
|
'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',
|
'target_name': 'crashpad_snapshot_test_no_op',
|
||||||
'type': 'executable',
|
'type': 'executable',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user