mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-20 02:23:47 +00:00
Add crashpad_info, MachOImageAnnotationsReader, and its test.
TEST=snapshot_test MachOImageAnnotationsReader.* R=rsesek@chromium.org Review URL: https://codereview.chromium.org/651283003
This commit is contained in:
parent
bcae4d94d5
commit
b43f510a52
@ -26,6 +26,8 @@
|
|||||||
'sources': [
|
'sources': [
|
||||||
'capture_context_mac.h',
|
'capture_context_mac.h',
|
||||||
'capture_context_mac.S',
|
'capture_context_mac.S',
|
||||||
|
'crashpad_info.cc',
|
||||||
|
'crashpad_info.h',
|
||||||
'simple_string_dictionary.cc',
|
'simple_string_dictionary.cc',
|
||||||
'simple_string_dictionary.h',
|
'simple_string_dictionary.h',
|
||||||
'simulate_crash.h',
|
'simulate_crash.h',
|
||||||
|
76
client/crashpad_info.cc
Normal file
76
client/crashpad_info.cc
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "client/crashpad_info.h"
|
||||||
|
|
||||||
|
#include <mach-o/loader.h>
|
||||||
|
|
||||||
|
#if CXX_LIBRARY_VERSION >= 2011
|
||||||
|
#include <type_traits>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static const uint32_t kCrashpadInfoVersion = 1;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
#if CXX_LIBRARY_VERSION >= 2011
|
||||||
|
// In C++11, check that CrashpadInfo has standard layout, which is what is
|
||||||
|
// actually important.
|
||||||
|
static_assert(std::is_standard_layout<CrashpadInfo>::value,
|
||||||
|
"CrashpadInfo must be standard layout");
|
||||||
|
#else
|
||||||
|
// In C++98 (ISO 14882), section 9.5.1 says that a union cannot have a member
|
||||||
|
// with a non-trivial ctor, copy ctor, dtor, or assignment operator. Use this
|
||||||
|
// property to ensure that CrashpadInfo remains POD. This doesn’t work for C++11
|
||||||
|
// because the requirements for unions have been relaxed.
|
||||||
|
union Compile_Assert {
|
||||||
|
CrashpadInfo Compile_Assert__CrashpadInfo_must_be_pod;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Put the structure in __DATA,__crashpad_info where it can be easily found
|
||||||
|
// without having to consult the symbol table. The “used” attribute prevents it
|
||||||
|
// from being dead-stripped. This isn’t placed in an unnamed namespace:
|
||||||
|
// hopefully, this will catch attempts to place multiple copies of this
|
||||||
|
// structure into the same module. If that’s attempted, and the name of the
|
||||||
|
// symbol is the same in each translation unit, it will result in a linker
|
||||||
|
// error, which is better than having multiple structures show up.
|
||||||
|
//
|
||||||
|
// This may result in a static module initializer in debug-mode builds, but
|
||||||
|
// because it’s POD, no code should need to run to initialize this under
|
||||||
|
// release-mode optimization.
|
||||||
|
__attribute__((section(SEG_DATA ",__crashpad_info"),
|
||||||
|
used,
|
||||||
|
visibility("hidden"))) CrashpadInfo g_crashpad_info;
|
||||||
|
|
||||||
|
// static
|
||||||
|
CrashpadInfo* CrashpadInfo::GetCrashpadInfo() {
|
||||||
|
return &g_crashpad_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
CrashpadInfo::CrashpadInfo()
|
||||||
|
: signature_(kSignature),
|
||||||
|
size_(sizeof(*this)),
|
||||||
|
version_(kCrashpadInfoVersion),
|
||||||
|
padding_0_(0),
|
||||||
|
simple_annotations_(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t CrashpadInfo::kSignature;
|
||||||
|
|
||||||
|
} // namespace crashpad
|
66
client/crashpad_info.h
Normal file
66
client/crashpad_info.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CRASHPAD_CLIENT_CRASHPAD_INFO_H_
|
||||||
|
#define CRASHPAD_CLIENT_CRASHPAD_INFO_H_
|
||||||
|
|
||||||
|
#include "base/basictypes.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "client/simple_string_dictionary.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
//! \brief A structure that can be used by a Crashpad-enabled program to
|
||||||
|
//! provide information to the Crashpad crash handler.
|
||||||
|
//!
|
||||||
|
//! It is possible for one CrashpadInfo structure to appear in each loaded code
|
||||||
|
//! module in a process, but from the perspective of the user of the client
|
||||||
|
//! interface, there is only one global CrashpadInfo structure, located in the
|
||||||
|
//! module that contains the client interface code.
|
||||||
|
struct CrashpadInfo {
|
||||||
|
public:
|
||||||
|
//! \brief Returns the global CrashpadInfo structure.
|
||||||
|
static CrashpadInfo* GetCrashpadInfo();
|
||||||
|
|
||||||
|
CrashpadInfo();
|
||||||
|
|
||||||
|
void set_simple_annotations(SimpleStringDictionary* simple_annotations) {
|
||||||
|
simple_annotations_ = simple_annotations;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint32_t kSignature = 'CPad';
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The compiler won’t necessarily see anyone using these fields, but it
|
||||||
|
// shouldn’t warn about that. These fields aren’t intended for use by the
|
||||||
|
// process they’re found in, they’re supposed to be read by the crash
|
||||||
|
// reporting process.
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-private-field"
|
||||||
|
// Fields present in version 1:
|
||||||
|
uint32_t signature_; // kSignature
|
||||||
|
uint32_t size_; // The size of the entire CrashpadInfo structure.
|
||||||
|
uint32_t version_; // kVersion
|
||||||
|
uint32_t padding_0_;
|
||||||
|
SimpleStringDictionary* simple_annotations_; // weak
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(CrashpadInfo);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace crashpad
|
||||||
|
|
||||||
|
#endif // CRASHPAD_CLIENT_CRASHPAD_INFO_H_
|
198
snapshot/mac/mach_o_image_annotations_reader.cc
Normal file
198
snapshot/mac/mach_o_image_annotations_reader.cc
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "snapshot/mac/mach_o_image_annotations_reader.h"
|
||||||
|
|
||||||
|
#include <mach-o/loader.h>
|
||||||
|
#include <mach/mach.h>
|
||||||
|
|
||||||
|
#include "base/logging.h"
|
||||||
|
#include "client/crashpad_info.h"
|
||||||
|
#include "client/simple_string_dictionary.h"
|
||||||
|
#include "snapshot/mac/mach_o_image_reader.h"
|
||||||
|
#include "snapshot/mac/process_reader.h"
|
||||||
|
#include "snapshot/mac/process_types.h"
|
||||||
|
#include "util/mach/task_memory.h"
|
||||||
|
#include "util/stdlib/strnlen.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
MachOImageAnnotationsReader::MachOImageAnnotationsReader(
|
||||||
|
ProcessReader* process_reader,
|
||||||
|
const MachOImageReader* image_reader,
|
||||||
|
const std::string& name)
|
||||||
|
: name_(name),
|
||||||
|
process_reader_(process_reader),
|
||||||
|
image_reader_(image_reader) {
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> MachOImageAnnotationsReader::Vector() const {
|
||||||
|
std::vector<std::string> vector_annotations;
|
||||||
|
|
||||||
|
ReadCrashReporterClientAnnotations(&vector_annotations);
|
||||||
|
ReadDyldErrorStringAnnotation(&vector_annotations);
|
||||||
|
|
||||||
|
return vector_annotations;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, std::string> MachOImageAnnotationsReader::SimpleMap()
|
||||||
|
const {
|
||||||
|
std::map<std::string, std::string> simple_map_annotations;
|
||||||
|
|
||||||
|
ReadCrashpadSimpleAnnotations(&simple_map_annotations);
|
||||||
|
|
||||||
|
return simple_map_annotations;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MachOImageAnnotationsReader::ReadCrashReporterClientAnnotations(
|
||||||
|
std::vector<std::string>* vector_annotations) const {
|
||||||
|
mach_vm_address_t crash_info_address;
|
||||||
|
const process_types::section* crash_info_section =
|
||||||
|
image_reader_->GetSectionByName(
|
||||||
|
SEG_DATA, "__crash_info", &crash_info_address);
|
||||||
|
if (!crash_info_section) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
LOG(WARNING) << "unexpected crash info 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)) {
|
||||||
|
vector_annotations->push_back(message);
|
||||||
|
} else {
|
||||||
|
LOG(WARNING) << "could not read crash message in " << name_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crash_info.message2) {
|
||||||
|
std::string 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_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MachOImageAnnotationsReader::ReadDyldErrorStringAnnotation(
|
||||||
|
std::vector<std::string>* vector_annotations) const {
|
||||||
|
// dyld stores its error string at the external symbol for |const char
|
||||||
|
// error_string[1024]|. See 10.9.5 dyld-239.4/src/dyld.cpp error_string.
|
||||||
|
if (image_reader_->FileType() != MH_DYLINKER) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mach_vm_address_t error_string_address;
|
||||||
|
if (!image_reader_->LookUpExternalDefinedSymbol("_error_string",
|
||||||
|
&error_string_address)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (!message.empty()) {
|
||||||
|
vector_annotations->push_back(message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(WARNING) << "could not read dylinker error string from " << name_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MachOImageAnnotationsReader::ReadCrashpadSimpleAnnotations(
|
||||||
|
std::map<std::string, std::string>* simple_map_annotations) const {
|
||||||
|
mach_vm_address_t crashpad_info_address;
|
||||||
|
const process_types::section* crashpad_info_section =
|
||||||
|
image_reader_->GetSectionByName(
|
||||||
|
SEG_DATA, "__crashpad_info", &crashpad_info_address);
|
||||||
|
if (!crashpad_info_section) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
process_types::CrashpadInfo crashpad_info;
|
||||||
|
if (crashpad_info_section->size <
|
||||||
|
crashpad_info.ExpectedSize(process_reader_)) {
|
||||||
|
LOG(WARNING) << "small crashpad info section size "
|
||||||
|
<< crashpad_info_section->size << " in " << name_;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!crashpad_info.Read(process_reader_, crashpad_info_address)) {
|
||||||
|
LOG(WARNING) << "could not read crashpad info from " << name_;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crashpad_info.signature != CrashpadInfo::kSignature ||
|
||||||
|
crashpad_info.size != crashpad_info_section->size ||
|
||||||
|
crashpad_info.version < 1) {
|
||||||
|
LOG(WARNING) << "unexpected crashpad info data in " << name_;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!crashpad_info.simple_annotations) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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])) {
|
||||||
|
LOG(WARNING) << "could not read simple annotations from " << name_;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& entry : simple_annotations) {
|
||||||
|
size_t key_length = strnlen(entry.key, sizeof(entry.key));
|
||||||
|
if (key_length) {
|
||||||
|
std::string key(entry.key, key_length);
|
||||||
|
std::string value(entry.value, strnlen(entry.value, sizeof(entry.value)));
|
||||||
|
if (!simple_map_annotations->count(key)) {
|
||||||
|
simple_map_annotations->insert(
|
||||||
|
std::pair<std::string, std::string>(key, value));
|
||||||
|
} else {
|
||||||
|
LOG(INFO) << "duplicate simple annotation " << key << " in " << name_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace crashpad
|
92
snapshot/mac/mach_o_image_annotations_reader.h
Normal file
92
snapshot/mac/mach_o_image_annotations_reader.h
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CRASHPAD_SNAPSHOT_MAC_MACH_O_IMAGE_ANNOTATIONS_READER_H_
|
||||||
|
#define CRASHPAD_SNAPSHOT_MAC_MACH_O_IMAGE_ANNOTATIONS_READER_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "base/basictypes.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
class MachOImageReader;
|
||||||
|
class ProcessReader;
|
||||||
|
|
||||||
|
//! \brief A reader for annotations stored in a Mach-O image mapped into another
|
||||||
|
//! process.
|
||||||
|
//!
|
||||||
|
//! These annotations are stored for the benefit of crash reporters, and provide
|
||||||
|
//! information though to be potentially useful for crash analysis. This class
|
||||||
|
//! can decode annotations stored in these formats:
|
||||||
|
//! - CrashpadInfo. This format is used by Crashpad clients. The “simple
|
||||||
|
//! annotations” are recovered from any module with a compatible data
|
||||||
|
//! section, and are included in the annotations returned by SimpleMap().
|
||||||
|
//! - `CrashReporterClient.h`’s `crashreporter_annotations_t`. This format is
|
||||||
|
//! used by Apple code. The `message` and `message2` fields can be recovered
|
||||||
|
//! from any module with a compatible data section, and are included in the
|
||||||
|
//! annotations returned by Vector().
|
||||||
|
//! - `dyld`’s `error_string`. This format is used exclusively by dyld,
|
||||||
|
//! typically for fatal errors. This string can be recovered from any
|
||||||
|
//! `MH_DYLINKER`-type module with this symbol, and is included in the
|
||||||
|
//! annotations returned by Vector().
|
||||||
|
class MachOImageAnnotationsReader {
|
||||||
|
public:
|
||||||
|
//! \brief Constructs an object.
|
||||||
|
//!
|
||||||
|
//! \param[in] process_reader The reader for the remote process.
|
||||||
|
//! \param[in] image_reader The MachOImageReader for the Mach-O image file
|
||||||
|
//! contained within the remote process.
|
||||||
|
//! \param[in] name The module’s name, a string to be used in logged messages.
|
||||||
|
//! This string is for diagnostic purposes only, and may be empty.
|
||||||
|
MachOImageAnnotationsReader(ProcessReader* process_reader,
|
||||||
|
const MachOImageReader* image_reader,
|
||||||
|
const std::string& name);
|
||||||
|
|
||||||
|
~MachOImageAnnotationsReader() {}
|
||||||
|
|
||||||
|
//! \brief Returns the module’s annotations that are organized as a vector of
|
||||||
|
//! strings.
|
||||||
|
std::vector<std::string> Vector() const;
|
||||||
|
|
||||||
|
//! \brief Returns the module’s annotations that are organized as key-value
|
||||||
|
//! pairs, where all keys and values are strings.
|
||||||
|
std::map<std::string, std::string> SimpleMap() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Reades crashreporter_annotations_t::message and
|
||||||
|
// crashreporter_annotations_t::message2 on behalf of Vector().
|
||||||
|
void ReadCrashReporterClientAnnotations(
|
||||||
|
std::vector<std::string>* vector_annotations) const;
|
||||||
|
|
||||||
|
// Reads dyld_error_string on behalf of Vector().
|
||||||
|
void ReadDyldErrorStringAnnotation(
|
||||||
|
std::vector<std::string>* vector_annotations) const;
|
||||||
|
|
||||||
|
// Reads CrashpadInfo::simple_annotations_ on behalf of SimpleMap().
|
||||||
|
void ReadCrashpadSimpleAnnotations(
|
||||||
|
std::map<std::string, std::string>* simple_map_annotations) const;
|
||||||
|
|
||||||
|
std::string name_;
|
||||||
|
ProcessReader* process_reader_; // weak
|
||||||
|
const MachOImageReader* image_reader_; // weak
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(MachOImageAnnotationsReader);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace crashpad
|
||||||
|
|
||||||
|
#endif // CRASHPAD_SNAPSHOT_MAC_MACH_O_IMAGE_ANNOTATIONS_READER_H_
|
334
snapshot/mac/mach_o_image_annotations_reader_test.cc
Normal file
334
snapshot/mac/mach_o_image_annotations_reader_test.cc
Normal file
@ -0,0 +1,334 @@
|
|||||||
|
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "snapshot/mac/mach_o_image_annotations_reader.h"
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <mach/mach.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "base/basictypes.h"
|
||||||
|
#include "client/crashpad_info.h"
|
||||||
|
#include "client/simple_string_dictionary.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "snapshot/mac/process_reader.h"
|
||||||
|
#include "util/file/fd_io.h"
|
||||||
|
#include "util/mac/mac_util.h"
|
||||||
|
#include "util/mach/exc_server_variants.h"
|
||||||
|
#include "util/mach/exception_ports.h"
|
||||||
|
#include "util/mach/mach_message_server.h"
|
||||||
|
#include "util/test/errors.h"
|
||||||
|
#include "util/test/mac/mach_errors.h"
|
||||||
|
#include "util/test/mac/mach_multiprocess.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
namespace test {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class TestMachOImageAnnotationsReader final : public MachMultiprocess,
|
||||||
|
public UniversalMachExcServer {
|
||||||
|
public:
|
||||||
|
enum TestType {
|
||||||
|
// Don’t crash, just test the CrashpadInfo interface.
|
||||||
|
kDontCrash = 0,
|
||||||
|
|
||||||
|
// The child process should crash by calling abort(). The parent verifies
|
||||||
|
// that the system libraries set the expected annotations.
|
||||||
|
kCrashAbort,
|
||||||
|
|
||||||
|
// The child process should crash by setting DYLD_INSERT_LIBRARIES to
|
||||||
|
// contain a nonexistent library. The parent verifies that dyld sets the
|
||||||
|
// expected annotations.
|
||||||
|
kCrashDyld,
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit TestMachOImageAnnotationsReader(TestType test_type)
|
||||||
|
: MachMultiprocess(),
|
||||||
|
UniversalMachExcServer(),
|
||||||
|
test_type_(test_type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~TestMachOImageAnnotationsReader() {}
|
||||||
|
|
||||||
|
// UniversalMachExcServer:
|
||||||
|
kern_return_t CatchMachException(exception_behavior_t behavior,
|
||||||
|
exception_handler_t exception_port,
|
||||||
|
thread_t thread,
|
||||||
|
task_t task,
|
||||||
|
exception_type_t exception,
|
||||||
|
const mach_exception_data_type_t* code,
|
||||||
|
mach_msg_type_number_t code_count,
|
||||||
|
thread_state_flavor_t* flavor,
|
||||||
|
const natural_t* old_state,
|
||||||
|
mach_msg_type_number_t old_state_count,
|
||||||
|
thread_state_t new_state,
|
||||||
|
mach_msg_type_number_t* new_state_count,
|
||||||
|
bool* destroy_complex_request) override {
|
||||||
|
*destroy_complex_request = true;
|
||||||
|
|
||||||
|
EXPECT_EQ(ChildTask(), task);
|
||||||
|
|
||||||
|
ProcessReader process_reader;
|
||||||
|
bool rv = process_reader.Initialize(task);
|
||||||
|
if (!rv) {
|
||||||
|
ADD_FAILURE();
|
||||||
|
} else {
|
||||||
|
const std::vector<ProcessReader::Module>& modules =
|
||||||
|
process_reader.Modules();
|
||||||
|
std::vector<std::string> all_annotations_vector;
|
||||||
|
for (const ProcessReader::Module& module : modules) {
|
||||||
|
MachOImageAnnotationsReader module_annotations_reader(
|
||||||
|
&process_reader, module.reader, module.name);
|
||||||
|
std::vector<std::string> module_annotations_vector =
|
||||||
|
module_annotations_reader.Vector();
|
||||||
|
all_annotations_vector.insert(all_annotations_vector.end(),
|
||||||
|
module_annotations_vector.begin(),
|
||||||
|
module_annotations_vector.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mac OS X 10.6 doesn’t have support for CrashReporter annotations
|
||||||
|
// (CrashReporterClient.h), so don’t look for any special annotations in
|
||||||
|
// that version.
|
||||||
|
int mac_os_x_minor_version = MacOSXMinorVersion();
|
||||||
|
if (mac_os_x_minor_version > 7) {
|
||||||
|
EXPECT_GE(all_annotations_vector.size(), 1u);
|
||||||
|
|
||||||
|
const char* expected_annotation = nullptr;
|
||||||
|
switch (test_type_) {
|
||||||
|
case kCrashAbort:
|
||||||
|
// The child process calls abort(), so the expected annotation
|
||||||
|
// reflects this, with a string set by 10.7.5
|
||||||
|
// Libc-763.13/stdlib/abort-fbsd.c abort(). This string is still
|
||||||
|
// present in 10.9.5 Libc-997.90.3/stdlib/FreeBSD/abort.c abort(),
|
||||||
|
// but because abort() tests to see if a message is already set and
|
||||||
|
// something else in Libc will have set a message, this string is
|
||||||
|
// not the expectation on 10.9 or higher. Instead, after fork(), the
|
||||||
|
// child process has a message indicating that a fork() without
|
||||||
|
// exec() occurred. See 10.9.5 Libc-997.90.3/sys/_libc_fork_child.c
|
||||||
|
// _libc_fork_child().
|
||||||
|
expected_annotation =
|
||||||
|
mac_os_x_minor_version <= 8
|
||||||
|
? "abort() called"
|
||||||
|
: "crashed on child side of fork pre-exec";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kCrashDyld:
|
||||||
|
// This is independent of dyld’s error_string, which is tested
|
||||||
|
// below.
|
||||||
|
expected_annotation = "dyld: launch, loading dependent libraries";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ADD_FAILURE();
|
||||||
|
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) ==
|
||||||
|
expected_annotation) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(found);
|
||||||
|
}
|
||||||
|
|
||||||
|
// dyld exposes its error_string at least as far back as Mac OS X 10.4.
|
||||||
|
if (test_type_ == kCrashDyld) {
|
||||||
|
const char kExpectedAnnotation[] = "could not load inserted library";
|
||||||
|
size_t expected_annotation_length = strlen(kExpectedAnnotation);
|
||||||
|
bool found = false;
|
||||||
|
for (const std::string& annotation : all_annotations_vector) {
|
||||||
|
// Look for the expectation as a leading substring, because the actual
|
||||||
|
// string will contain the library’s pathname and, on Mac OS X 10.9
|
||||||
|
// and later, a reason.
|
||||||
|
if (annotation.substr(0, expected_annotation_length) ==
|
||||||
|
kExpectedAnnotation) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_TRUE(found);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExcServerSuccessfulReturnValue(behavior, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// MachMultiprocess:
|
||||||
|
|
||||||
|
void MachMultiprocessParent() override {
|
||||||
|
ProcessReader process_reader;
|
||||||
|
ASSERT_TRUE(process_reader.Initialize(ChildTask()));
|
||||||
|
|
||||||
|
// Wait for the child process to indicate that it’s done setting up its
|
||||||
|
// annotations via the CrashpadInfo interface.
|
||||||
|
char c;
|
||||||
|
CheckedReadFD(ReadPipeFD(), &c, sizeof(c));
|
||||||
|
|
||||||
|
// Verify the “simple map” annotations set via the CrashpadInfo interface.
|
||||||
|
const std::vector<ProcessReader::Module>& modules =
|
||||||
|
process_reader.Modules();
|
||||||
|
std::map<std::string, std::string> all_annotations_simple_map;
|
||||||
|
for (const ProcessReader::Module& module : modules) {
|
||||||
|
MachOImageAnnotationsReader module_annotations_reader(
|
||||||
|
&process_reader, module.reader, module.name);
|
||||||
|
std::map<std::string, std::string> module_annotations_simple_map =
|
||||||
|
module_annotations_reader.SimpleMap();
|
||||||
|
all_annotations_simple_map.insert(module_annotations_simple_map.begin(),
|
||||||
|
module_annotations_simple_map.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_GE(all_annotations_simple_map.size(), 5u);
|
||||||
|
EXPECT_EQ("crash", all_annotations_simple_map["#TEST# pad"]);
|
||||||
|
EXPECT_EQ("value", all_annotations_simple_map["#TEST# key"]);
|
||||||
|
EXPECT_EQ("y", all_annotations_simple_map["#TEST# x"]);
|
||||||
|
EXPECT_EQ("shorter", all_annotations_simple_map["#TEST# longer"]);
|
||||||
|
EXPECT_EQ("", all_annotations_simple_map["#TEST# empty_value"]);
|
||||||
|
|
||||||
|
// Tell the child process that it’s permitted to crash.
|
||||||
|
CheckedWriteFD(WritePipeFD(), &c, sizeof(c));
|
||||||
|
|
||||||
|
if (test_type_ != kDontCrash) {
|
||||||
|
// Handle the child’s crash. Further validation will be done in
|
||||||
|
// CatchMachException().
|
||||||
|
mach_msg_return_t mr =
|
||||||
|
MachMessageServer::Run(this,
|
||||||
|
LocalPort(),
|
||||||
|
MACH_MSG_OPTION_NONE,
|
||||||
|
MachMessageServer::kOneShot,
|
||||||
|
MachMessageServer::kBlocking,
|
||||||
|
MACH_MSG_TIMEOUT_NONE);
|
||||||
|
EXPECT_EQ(MACH_MSG_SUCCESS, mr)
|
||||||
|
<< MachErrorMessage(mr, "MachMessageServer::Run");
|
||||||
|
|
||||||
|
switch (test_type_) {
|
||||||
|
case kCrashAbort:
|
||||||
|
SetExpectedChildTermination(kTerminationSignal, SIGABRT);
|
||||||
|
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.
|
||||||
|
// 10.9.5 dyld-239.4/src/dyldStartup.s _dyld_fatal_error.
|
||||||
|
SetExpectedChildTermination(kTerminationSignal, SIGTRAP);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
FAIL();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MachMultiprocessChild() override {
|
||||||
|
CrashpadInfo* crashpad_info = CrashpadInfo::GetCrashpadInfo();
|
||||||
|
|
||||||
|
// This is “leaked” to crashpad_info.
|
||||||
|
SimpleStringDictionary* simple_annotations = new SimpleStringDictionary();
|
||||||
|
simple_annotations->SetKeyValue("#TEST# pad", "break");
|
||||||
|
simple_annotations->SetKeyValue("#TEST# key", "value");
|
||||||
|
simple_annotations->SetKeyValue("#TEST# pad", "crash");
|
||||||
|
simple_annotations->SetKeyValue("#TEST# x", "y");
|
||||||
|
simple_annotations->SetKeyValue("#TEST# longer", "shorter");
|
||||||
|
simple_annotations->SetKeyValue("#TEST# empty_value", "");
|
||||||
|
|
||||||
|
crashpad_info->set_simple_annotations(simple_annotations);
|
||||||
|
|
||||||
|
// Tell the parent that the environment has been set up.
|
||||||
|
char c = '\0';
|
||||||
|
CheckedWriteFD(WritePipeFD(), &c, sizeof(c));
|
||||||
|
|
||||||
|
// Wait for the parent to indicate that it’s safe to crash.
|
||||||
|
CheckedReadFD(ReadPipeFD(), &c, sizeof(c));
|
||||||
|
|
||||||
|
// Direct an exception message to the exception server running in the
|
||||||
|
// parent.
|
||||||
|
ExceptionPorts exception_ports(ExceptionPorts::kTargetTypeTask,
|
||||||
|
mach_task_self());
|
||||||
|
ASSERT_TRUE(exception_ports.SetExceptionPort(
|
||||||
|
EXC_MASK_CRASH, RemotePort(), EXCEPTION_DEFAULT, THREAD_STATE_NONE));
|
||||||
|
|
||||||
|
switch (test_type_) {
|
||||||
|
case kDontCrash:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kCrashAbort:
|
||||||
|
abort();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kCrashDyld: {
|
||||||
|
// Set DYLD_INSERT_LIBRARIES to contain a library that does not exist.
|
||||||
|
// Unable to load it, dyld will abort with a fatal error.
|
||||||
|
ASSERT_EQ(
|
||||||
|
0,
|
||||||
|
setenv(
|
||||||
|
"DYLD_INSERT_LIBRARIES", "/var/empty/NoDirectory/NoLibrary", 1))
|
||||||
|
<< ErrnoMessage("setenv");
|
||||||
|
|
||||||
|
// The actual executable doesn’t matter very much, because dyld won’t
|
||||||
|
// ever launch it. It just needs to be an executable that uses dyld as
|
||||||
|
// its LC_LOAD_DYLINKER (all normal executables do). /usr/bin/true is on
|
||||||
|
// every system, so use it.
|
||||||
|
ASSERT_EQ(0, execl("/usr/bin/true", "true", nullptr))
|
||||||
|
<< ErrnoMessage("execl");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TestType test_type_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(TestMachOImageAnnotationsReader);
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(MachOImageAnnotationsReader, DontCrash) {
|
||||||
|
TestMachOImageAnnotationsReader test_mach_o_image_annotations_reader(
|
||||||
|
TestMachOImageAnnotationsReader::kDontCrash);
|
||||||
|
test_mach_o_image_annotations_reader.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MachOImageAnnotationsReader, CrashAbort) {
|
||||||
|
TestMachOImageAnnotationsReader test_mach_o_image_annotations_reader(
|
||||||
|
TestMachOImageAnnotationsReader::kCrashAbort);
|
||||||
|
test_mach_o_image_annotations_reader.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MachOImageAnnotationsReader, CrashDyld) {
|
||||||
|
TestMachOImageAnnotationsReader test_mach_o_image_annotations_reader(
|
||||||
|
TestMachOImageAnnotationsReader::kCrashDyld);
|
||||||
|
test_mach_o_image_annotations_reader.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace test
|
||||||
|
} // namespace crashpad
|
@ -39,6 +39,8 @@ class ProcessReader;
|
|||||||
//! This class is capable of reading both 32-bit (`mach_header`/`MH_MAGIC`) and
|
//! This class is capable of reading both 32-bit (`mach_header`/`MH_MAGIC`) and
|
||||||
//! 64-bit (`mach_header_64`/`MH_MAGIC_64`) images based on the bitness of the
|
//! 64-bit (`mach_header_64`/`MH_MAGIC_64`) images based on the bitness of the
|
||||||
//! remote process.
|
//! remote process.
|
||||||
|
//!
|
||||||
|
//! \sa MachOImageAnnotationsReader
|
||||||
class MachOImageReader {
|
class MachOImageReader {
|
||||||
public:
|
public:
|
||||||
MachOImageReader();
|
MachOImageReader();
|
||||||
|
@ -400,13 +400,14 @@ void ProcessReader::InitializeModules() {
|
|||||||
//
|
//
|
||||||
// TODO(mark): It may be possible to recover from these situations by looking
|
// TODO(mark): It may be possible to recover from these situations by looking
|
||||||
// through memory mappings for Mach-O images.
|
// through memory mappings for Mach-O images.
|
||||||
|
//
|
||||||
|
// Continue along when this situation is detected, because even without any
|
||||||
|
// images in infoArray, dyldImageLoadAddress may be set, and it may be
|
||||||
|
// possible to recover some information from dyld.
|
||||||
if (all_image_infos.infoArrayCount == 0) {
|
if (all_image_infos.infoArrayCount == 0) {
|
||||||
LOG(WARNING) << "all_image_infos.infoArrayCount is zero";
|
LOG(WARNING) << "all_image_infos.infoArrayCount is zero";
|
||||||
return;
|
} else if (!all_image_infos.infoArray) {
|
||||||
}
|
|
||||||
if (!all_image_infos.infoArray) {
|
|
||||||
LOG(WARNING) << "all_image_infos.infoArray is nullptr";
|
LOG(WARNING) << "all_image_infos.infoArray is nullptr";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<process_types::dyld_image_info> image_info_vector(
|
std::vector<process_types::dyld_image_info> image_info_vector(
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
// snapshot/mac/process_types.cc to produce process type struct definitions and
|
// snapshot/mac/process_types.cc to produce process type struct definitions and
|
||||||
// accessors.
|
// accessors.
|
||||||
|
|
||||||
|
#include "snapshot/mac/process_types/crashpad_info.proctype"
|
||||||
#include "snapshot/mac/process_types/crashreporterclient.proctype"
|
#include "snapshot/mac/process_types/crashreporterclient.proctype"
|
||||||
#include "snapshot/mac/process_types/dyld_images.proctype"
|
#include "snapshot/mac/process_types/dyld_images.proctype"
|
||||||
#include "snapshot/mac/process_types/loader.proctype"
|
#include "snapshot/mac/process_types/loader.proctype"
|
||||||
|
34
snapshot/mac/process_types/crashpad_info.proctype
Normal file
34
snapshot/mac/process_types/crashpad_info.proctype
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// The file corresponds to Crashpad’s client/crashpad_info.h.
|
||||||
|
//
|
||||||
|
// This file is intended to be included multiple times in the same translation
|
||||||
|
// unit, so #include guards are intentionally absent.
|
||||||
|
//
|
||||||
|
// This file is included by snapshot/mac/process_types.h and
|
||||||
|
// snapshot/mac/process_types.cc to produce process type struct definitions and
|
||||||
|
// accessors.
|
||||||
|
|
||||||
|
// Client Mach-O images will contain a __DATA,__crashpad_info section formatted
|
||||||
|
// according to this structure.
|
||||||
|
PROCESS_TYPE_STRUCT_BEGIN(CrashpadInfo)
|
||||||
|
PROCESS_TYPE_STRUCT_MEMBER(uint32_t, signature)
|
||||||
|
PROCESS_TYPE_STRUCT_MEMBER(uint32_t, size)
|
||||||
|
PROCESS_TYPE_STRUCT_MEMBER(uint32_t, version)
|
||||||
|
PROCESS_TYPE_STRUCT_MEMBER(uint32_t, padding_0)
|
||||||
|
|
||||||
|
// SimpleStringDictionary*
|
||||||
|
PROCESS_TYPE_STRUCT_MEMBER(Pointer, simple_annotations)
|
||||||
|
PROCESS_TYPE_STRUCT_END(CrashpadInfo)
|
@ -18,6 +18,7 @@
|
|||||||
'target_name': 'snapshot',
|
'target_name': 'snapshot',
|
||||||
'type': 'static_library',
|
'type': 'static_library',
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
|
'../client/client.gyp:client',
|
||||||
'../compat/compat.gyp:compat',
|
'../compat/compat.gyp:compat',
|
||||||
'../third_party/mini_chromium/mini_chromium/base/base.gyp:base',
|
'../third_party/mini_chromium/mini_chromium/base/base.gyp:base',
|
||||||
'../util/util.gyp:util',
|
'../util/util.gyp:util',
|
||||||
@ -34,6 +35,8 @@
|
|||||||
'mac/cpu_context_mac.h',
|
'mac/cpu_context_mac.h',
|
||||||
'mac/exception_snapshot_mac.cc',
|
'mac/exception_snapshot_mac.cc',
|
||||||
'mac/exception_snapshot_mac.h',
|
'mac/exception_snapshot_mac.h',
|
||||||
|
'mac/mach_o_image_annotations_reader.cc',
|
||||||
|
'mac/mach_o_image_annotations_reader.h',
|
||||||
'mac/mach_o_image_reader.cc',
|
'mac/mach_o_image_reader.cc',
|
||||||
'mac/mach_o_image_reader.h',
|
'mac/mach_o_image_reader.h',
|
||||||
'mac/mach_o_image_segment_reader.cc',
|
'mac/mach_o_image_segment_reader.cc',
|
||||||
@ -47,6 +50,7 @@
|
|||||||
'mac/process_types.cc',
|
'mac/process_types.cc',
|
||||||
'mac/process_types.h',
|
'mac/process_types.h',
|
||||||
'mac/process_types/all.proctype',
|
'mac/process_types/all.proctype',
|
||||||
|
'mac/process_types/crashpad_info.proctype',
|
||||||
'mac/process_types/crashreporterclient.proctype',
|
'mac/process_types/crashreporterclient.proctype',
|
||||||
'mac/process_types/custom.cc',
|
'mac/process_types/custom.cc',
|
||||||
'mac/process_types/dyld_images.proctype',
|
'mac/process_types/dyld_images.proctype',
|
||||||
@ -71,6 +75,7 @@
|
|||||||
'type': 'executable',
|
'type': 'executable',
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
'snapshot',
|
'snapshot',
|
||||||
|
'../client/client.gyp:client',
|
||||||
'../compat/compat.gyp:compat',
|
'../compat/compat.gyp:compat',
|
||||||
'../third_party/gtest/gtest.gyp:gtest',
|
'../third_party/gtest/gtest.gyp:gtest',
|
||||||
'../third_party/gtest/gtest.gyp:gtest_main',
|
'../third_party/gtest/gtest.gyp:gtest_main',
|
||||||
@ -83,6 +88,7 @@
|
|||||||
],
|
],
|
||||||
'sources': [
|
'sources': [
|
||||||
'mac/cpu_context_mac_test.cc',
|
'mac/cpu_context_mac_test.cc',
|
||||||
|
'mac/mach_o_image_annotations_reader_test.cc',
|
||||||
'mac/mach_o_image_reader_test.cc',
|
'mac/mach_o_image_reader_test.cc',
|
||||||
'mac/mach_o_image_segment_reader_test.cc',
|
'mac/mach_o_image_segment_reader_test.cc',
|
||||||
'mac/process_reader_test.cc',
|
'mac/process_reader_test.cc',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user