diff --git a/snapshot/mac/process_snapshot_mac.cc b/snapshot/mac/process_snapshot_mac.cc index dd462a90..767c75a0 100644 --- a/snapshot/mac/process_snapshot_mac.cc +++ b/snapshot/mac/process_snapshot_mac.cc @@ -107,6 +107,7 @@ void ProcessSnapshotMac::ProcessCPUTimes(timeval* user_time, const std::map& ProcessSnapshotMac::AnnotationsSimpleMap() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); return annotations_simple_map_; } diff --git a/snapshot/minidump/minidump_simple_string_dictionary_reader.cc b/snapshot/minidump/minidump_simple_string_dictionary_reader.cc new file mode 100644 index 00000000..685266d7 --- /dev/null +++ b/snapshot/minidump/minidump_simple_string_dictionary_reader.cc @@ -0,0 +1,89 @@ +// 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. + +#include "snapshot/minidump/minidump_simple_string_dictionary_reader.h" + +#include +#include + +#include "base/logging.h" +#include "minidump/minidump_extensions.h" +#include "snapshot/minidump/minidump_string_reader.h" + +namespace crashpad { +namespace internal { + +bool ReadMinidumpSimpleStringDictionary( + FileReaderInterface* file_reader, + const MINIDUMP_LOCATION_DESCRIPTOR& location, + std::map* dictionary) { + if (location.Rva == 0) { + dictionary->clear(); + return true; + } + + if (location.DataSize < sizeof(MinidumpSimpleStringDictionary)) { + LOG(ERROR) << "simple_string_dictionary size mismatch"; + return false; + } + + if (!file_reader->SeekSet(location.Rva)) { + return false; + } + + uint32_t entry_count; + if (!file_reader->ReadExactly(&entry_count, sizeof(entry_count))) { + return false; + } + + if (location.DataSize != + entry_count * sizeof(MinidumpSimpleStringDictionaryEntry)) { + LOG(ERROR) << "simple_string_dictionary size mismatch"; + return false; + } + + std::vector entries(entry_count); + if (!file_reader->ReadExactly(&entries[0], + entry_count * sizeof(entries[0]))) { + return false; + } + + std::map local_dictionary; + for (const MinidumpSimpleStringDictionaryEntry& entry : entries) { + std::string key; + if (!ReadMinidumpUTF8String(file_reader, entry.key, &key)) { + // Not a hard error, keep trying. + continue; + } + + std::string value; + if (!ReadMinidumpUTF8String(file_reader, entry.value, &value)) { + // Not a hard error, keep trying. + continue; + } + + if (local_dictionary.find(key) != local_dictionary.end()) { + LOG(WARNING) << "duplicate key " << key << ", discarding value " << value; + continue; + } + + local_dictionary.insert(std::make_pair(key, value)); + } + + dictionary->swap(local_dictionary); + return true; +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/minidump/minidump_simple_string_dictionary_reader.h b/snapshot/minidump/minidump_simple_string_dictionary_reader.h new file mode 100644 index 00000000..65b7cba8 --- /dev/null +++ b/snapshot/minidump/minidump_simple_string_dictionary_reader.h @@ -0,0 +1,44 @@ +// 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. + +#ifndef CRASHPAD_SNAPSHOT_MINIDUMP_MINIDUMP_SIMPLE_STRING_DICTIONARY_READER_H_ +#define CRASHPAD_SNAPSHOT_MINIDUMP_MINIDUMP_SIMPLE_STRING_DICTIONARY_READER_H_ + +#include +#include + +#include +#include + +#include "util/file/file_reader.h" + +namespace crashpad { +namespace internal { + +//! \brief Reads a MinidumpSimpleStringDictionary from a minidump file \a +//! location in \a file_reader, and returns it in \a dictionary. +//! +//! \return `true` on success, with \a dictionary set by replacing its contents. +//! `false` on failure, with a message logged. If any individual strings +//! cannot be read, or if any duplicate keys are found, it is not considered +//! an error, although a message will be logged. +bool ReadMinidumpSimpleStringDictionary( + FileReaderInterface* file_reader, + const MINIDUMP_LOCATION_DESCRIPTOR& location, + std::map* dictionary); + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_MINIDUMP_MINIDUMP_SIMPLE_STRING_DICTIONARY_READER_H_ diff --git a/snapshot/minidump/minidump_string_reader.cc b/snapshot/minidump/minidump_string_reader.cc new file mode 100644 index 00000000..6ea36089 --- /dev/null +++ b/snapshot/minidump/minidump_string_reader.cc @@ -0,0 +1,50 @@ +// 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. + +#include "snapshot/minidump/minidump_string_reader.h" + +#include "base/logging.h" +#include "minidump/minidump_extensions.h" + +namespace crashpad { +namespace internal { + +bool ReadMinidumpUTF8String(FileReaderInterface* file_reader, + RVA rva, + std::string* string) { + if (rva == 0) { + string->clear(); + return true; + } + + if (!file_reader->SeekSet(rva)) { + return false; + } + + uint32_t string_size; + if (!file_reader->ReadExactly(&string_size, sizeof(string_size))) { + return false; + } + + std::string local_string(string_size, '\0'); + if (!file_reader->ReadExactly(&local_string[0], string_size)) { + return false; + } + + string->swap(local_string); + return true; +} + +} // namespace internal +} // namespace crashpad diff --git a/snapshot/minidump/minidump_string_reader.h b/snapshot/minidump/minidump_string_reader.h new file mode 100644 index 00000000..e5667ec2 --- /dev/null +++ b/snapshot/minidump/minidump_string_reader.h @@ -0,0 +1,40 @@ +// 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. + +#ifndef CRASHPAD_SNAPSHOT_MINIDUMP_MINIDUMP_STRING_READER_H_ +#define CRASHPAD_SNAPSHOT_MINIDUMP_MINIDUMP_STRING_READER_H_ + +#include +#include + +#include + +#include "util/file/file_reader.h" + +namespace crashpad { +namespace internal { + +//! \brief Reads a MinidumpUTF8String from a minidump file at offset \a rva in +//! \a file_reader, and returns it in \a string. +//! +//! \return `true` on success, with \a string set. `false` on failure, with a +//! message logged. +bool ReadMinidumpUTF8String(FileReaderInterface* file_reader, + RVA rva, + std::string* string); + +} // namespace internal +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_MINIDUMP_MINIDUMP_STRING_READER_H_ diff --git a/snapshot/minidump/process_snapshot_minidump.cc b/snapshot/minidump/process_snapshot_minidump.cc new file mode 100644 index 00000000..a882c7cd --- /dev/null +++ b/snapshot/minidump/process_snapshot_minidump.cc @@ -0,0 +1,189 @@ +// 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. + +#include "snapshot/minidump/process_snapshot_minidump.h" + +#include "util/file/file_io.h" +#include "snapshot/minidump/minidump_simple_string_dictionary_reader.h" + +namespace crashpad { + +ProcessSnapshotMinidump::ProcessSnapshotMinidump() + : ProcessSnapshot(), + header_(), + stream_directory_(), + stream_map_(), + crashpad_info_(), + annotations_simple_map_(), + file_reader_(nullptr), + initialized_() { +} + +ProcessSnapshotMinidump::~ProcessSnapshotMinidump() { +} + +bool ProcessSnapshotMinidump::Initialize(FileReaderInterface* file_reader) { + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); + + file_reader_ = file_reader; + + if (!file_reader_->SeekSet(0)) { + return false; + } + + if (!file_reader_->ReadExactly(&header_, sizeof(header_))) { + return false; + } + + if (header_.Signature != MINIDUMP_SIGNATURE) { + LOG(ERROR) << "minidump signature mismatch"; + return false; + } + + if (header_.Version != MINIDUMP_VERSION) { + LOG(ERROR) << "minidump version mismatch"; + return false; + } + + if (!file_reader->SeekSet(header_.StreamDirectoryRva)) { + return false; + } + + stream_directory_.resize(header_.NumberOfStreams); + if (!file_reader_->ReadExactly( + &stream_directory_[0], + header_.NumberOfStreams * sizeof(stream_directory_[0]))) { + return false; + } + + for (const MINIDUMP_DIRECTORY& directory : stream_directory_) { + const MinidumpStreamType stream_type = + static_cast(directory.StreamType); + if (stream_map_.find(stream_type) != stream_map_.end()) { + LOG(ERROR) << "duplicate streams for type " << directory.StreamType; + return false; + } + + stream_map_[stream_type] = &directory.Location; + } + + INITIALIZATION_STATE_SET_VALID(initialized_); + + InitializeCrashpadInfo(); + + return true; +} + +pid_t ProcessSnapshotMinidump::ProcessID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); + return 0; +} + +pid_t ProcessSnapshotMinidump::ParentProcessID() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); + return 0; +} + +void ProcessSnapshotMinidump::SnapshotTime(timeval* snapshot_time) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); + snapshot_time->tv_sec = 0; + snapshot_time->tv_usec = 0; +} + +void ProcessSnapshotMinidump::ProcessStartTime(timeval* start_time) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); + start_time->tv_sec = 0; + start_time->tv_usec = 0; +} + +void ProcessSnapshotMinidump::ProcessCPUTimes(timeval* user_time, + timeval* system_time) const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); + user_time->tv_sec = 0; + user_time->tv_usec = 0; + system_time->tv_sec = 0; + system_time->tv_usec = 0; +} + +const std::map& +ProcessSnapshotMinidump::AnnotationsSimpleMap() const { + // TODO(mark): This method should not be const, although the interface + // currently imposes this requirement. Making it non-const would allow + // annotations_simple_map_ to be lazily constructed: InitializeCrashpadInfo() + // could be called here, and from other locations that require it, rather than + // calling it from Initialize(). + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + return annotations_simple_map_; +} + +const SystemSnapshot* ProcessSnapshotMinidump::System() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); + return nullptr; +} + +std::vector ProcessSnapshotMinidump::Threads() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); + return std::vector(); +} + +std::vector ProcessSnapshotMinidump::Modules() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); + return std::vector(); +} + +const ExceptionSnapshot* ProcessSnapshotMinidump::Exception() const { + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + NOTREACHED(); + return nullptr; +} + +void ProcessSnapshotMinidump::InitializeCrashpadInfo() { + const auto& it = stream_map_.find(kMinidumpStreamTypeCrashpadInfo); + if (it == stream_map_.end()) { + return; + } + + if (it->second->DataSize < sizeof(crashpad_info_)) { + LOG(ERROR) << "crashpad_info size mismatch"; + return; + } + + if (!file_reader_->SeekSet(it->second->Rva)) { + return; + } + + if (!file_reader_->ReadExactly(&crashpad_info_, sizeof(crashpad_info_))) { + return; + } + + if (crashpad_info_.version != MinidumpCrashpadInfo::kVersion) { + LOG(ERROR) << "crashpad_info version mismatch"; + return; + } + + internal::ReadMinidumpSimpleStringDictionary( + file_reader_, + crashpad_info_.simple_annotations, + &annotations_simple_map_); +} + +} // namespace crashpad diff --git a/snapshot/minidump/process_snapshot_minidump.h b/snapshot/minidump/process_snapshot_minidump.h new file mode 100644 index 00000000..9a7f84af --- /dev/null +++ b/snapshot/minidump/process_snapshot_minidump.h @@ -0,0 +1,85 @@ +// 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. + +#ifndef CRASHPAD_SNAPSHOT_MINIDUMP_PROCESS_SNAPSHOT_MINIDUMP_H_ +#define CRASHPAD_SNAPSHOT_MINIDUMP_PROCESS_SNAPSHOT_MINIDUMP_H_ + +#include +#include +#include + +#include +#include +#include + +#include "base/basictypes.h" +#include "minidump/minidump_extensions.h" +#include "snapshot/exception_snapshot.h" +#include "snapshot/module_snapshot.h" +#include "snapshot/process_snapshot.h" +#include "snapshot/system_snapshot.h" +#include "snapshot/thread_snapshot.h" +#include "util/file/file_reader.h" +#include "util/misc/initialization_state_dcheck.h" + +namespace crashpad { + +//! \brief A ProcessSnapshot based on a minidump file. +class ProcessSnapshotMinidump final : public ProcessSnapshot { + public: + ProcessSnapshotMinidump(); + ~ProcessSnapshotMinidump() override; + + //! \brief Initializes the object. + //! + //! \param[in] file_reader A file reader corresponding to a minidump file. + //! The file reader must support seeking. + //! + //! \return `true` if the snapshot could be created, `false` otherwise with + //! an appropriate message logged. + bool Initialize(FileReaderInterface* file_reader); + + // ProcessSnapshot: + + pid_t ProcessID() const override; + pid_t ParentProcessID() const override; + void SnapshotTime(timeval* snapshot_time) const override; + void ProcessStartTime(timeval* start_time) const override; + void ProcessCPUTimes(timeval* user_time, timeval* system_time) const override; + const std::map& AnnotationsSimpleMap() + const override; + const SystemSnapshot* System() const override; + std::vector Threads() const override; + std::vector Modules() const override; + const ExceptionSnapshot* Exception() const override; + + private: + // Initializes data carried in a MinidumpCrashpadInfo stream on behalf of + // Initialize(). + void InitializeCrashpadInfo(); + + MINIDUMP_HEADER header_; + std::vector stream_directory_; + std::map stream_map_; + MinidumpCrashpadInfo crashpad_info_; + std::map annotations_simple_map_; + FileReaderInterface* file_reader_; // weak + InitializationStateDcheck initialized_; + + DISALLOW_COPY_AND_ASSIGN(ProcessSnapshotMinidump); +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_MINIDUMP_PROCESS_SNAPSHOT_MINIDUMP_H_ diff --git a/snapshot/minidump/process_snapshot_minidump_test.cc b/snapshot/minidump/process_snapshot_minidump_test.cc new file mode 100644 index 00000000..fcd40d4c --- /dev/null +++ b/snapshot/minidump/process_snapshot_minidump_test.cc @@ -0,0 +1,140 @@ +// 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. + +#include "snapshot/minidump/process_snapshot_minidump.h" + +#include +#include +#include + +#include "base/memory/scoped_ptr.h" +#include "gtest/gtest.h" +#include "util/file/string_file.h" + +namespace crashpad { +namespace test { +namespace { + +TEST(ProcessSnapshotMinidump, EmptyFile) { + StringFile string_file; + ProcessSnapshotMinidump process_snapshot; + + EXPECT_FALSE(process_snapshot.Initialize(&string_file)); +} + +TEST(ProcessSnapshotMinidump, InvalidSignatureAndVersion) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + ProcessSnapshotMinidump process_snapshot; + EXPECT_FALSE(process_snapshot.Initialize(&string_file)); +} + +TEST(ProcessSnapshotMinidump, Empty) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + ProcessSnapshotMinidump process_snapshot; + EXPECT_TRUE(process_snapshot.Initialize(&string_file)); +} + +TEST(ProcessSnapshotMinidump, AnnotationsSimpleMap) { + StringFile string_file; + + MINIDUMP_HEADER header = {}; + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + MinidumpSimpleStringDictionaryEntry entry0 = {}; + entry0.key = static_cast(string_file.SeekGet()); + const char kKey0[] = "the first key"; + uint32_t string_size = strlen(kKey0); + EXPECT_TRUE(string_file.Write(&string_size, sizeof(string_size))); + EXPECT_TRUE(string_file.Write(kKey0, sizeof(kKey0))); + + entry0.value = static_cast(string_file.SeekGet()); + const char kValue0[] = "THE FIRST VALUE EVER!"; + string_size = strlen(kValue0); + EXPECT_TRUE(string_file.Write(&string_size, sizeof(string_size))); + EXPECT_TRUE(string_file.Write(kValue0, sizeof(kValue0))); + + MinidumpSimpleStringDictionaryEntry entry1 = {}; + entry1.key = static_cast(string_file.SeekGet()); + const char kKey1[] = "2key"; + string_size = strlen(kKey1); + EXPECT_TRUE(string_file.Write(&string_size, sizeof(string_size))); + EXPECT_TRUE(string_file.Write(kKey1, sizeof(kKey1))); + + entry1.value = static_cast(string_file.SeekGet()); + const char kValue1[] = "a lowly second value"; + string_size = strlen(kValue1); + EXPECT_TRUE(string_file.Write(&string_size, sizeof(string_size))); + EXPECT_TRUE(string_file.Write(kValue1, sizeof(kValue1))); + + MinidumpCrashpadInfo crashpad_info = {}; + crashpad_info.version = MinidumpCrashpadInfo::kVersion; + + crashpad_info.simple_annotations.Rva = + static_cast(string_file.SeekGet()); + uint32_t simple_string_dictionary_entries = 2; + EXPECT_TRUE(string_file.Write(&simple_string_dictionary_entries, + sizeof(simple_string_dictionary_entries))); + EXPECT_TRUE(string_file.Write(&entry0, sizeof(entry0))); + EXPECT_TRUE(string_file.Write(&entry1, sizeof(entry1))); + crashpad_info.simple_annotations.DataSize = + simple_string_dictionary_entries * + sizeof(MinidumpSimpleStringDictionaryEntry); + + MINIDUMP_DIRECTORY crashpad_info_directory = {}; + crashpad_info_directory.StreamType = kMinidumpStreamTypeCrashpadInfo; + crashpad_info_directory.Location.Rva = + static_cast(string_file.SeekGet()); + EXPECT_TRUE(string_file.Write(&crashpad_info, sizeof(crashpad_info))); + crashpad_info_directory.Location.DataSize = sizeof(crashpad_info); + + header.StreamDirectoryRva = static_cast(string_file.SeekGet()); + EXPECT_TRUE(string_file.Write(&crashpad_info_directory, + sizeof(crashpad_info_directory))); + + header.Signature = MINIDUMP_SIGNATURE; + header.Version = MINIDUMP_VERSION; + header.NumberOfStreams = 1; + EXPECT_TRUE(string_file.SeekSet(0)); + EXPECT_TRUE(string_file.Write(&header, sizeof(header))); + + ProcessSnapshotMinidump process_snapshot; + EXPECT_TRUE(process_snapshot.Initialize(&string_file)); + + const auto annotations_simple_map = process_snapshot.AnnotationsSimpleMap(); + EXPECT_EQ(2u, annotations_simple_map.size()); + + auto it = annotations_simple_map.find(kKey0); + ASSERT_NE(it, annotations_simple_map.end()); + EXPECT_EQ(kValue0, it->second); + + it = annotations_simple_map.find(kKey1); + ASSERT_NE(it, annotations_simple_map.end()); + EXPECT_EQ(kValue1, it->second); +} + +} // namespace +} // namespace test +} // namespace crashpad diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp index 894fd061..0ec007b1 100644 --- a/snapshot/snapshot.gyp +++ b/snapshot/snapshot.gyp @@ -67,6 +67,12 @@ 'mac/system_snapshot_mac.h', 'mac/thread_snapshot_mac.cc', 'mac/thread_snapshot_mac.h', + 'minidump/minidump_simple_string_dictionary_reader.cc', + 'minidump/minidump_simple_string_dictionary_reader.h', + 'minidump/minidump_string_reader.cc', + 'minidump/minidump_string_reader.h', + 'minidump/process_snapshot_minidump.cc', + 'minidump/process_snapshot_minidump.h', 'memory_snapshot.h', 'module_snapshot.h', 'process_snapshot.h', @@ -128,6 +134,7 @@ 'mac/process_reader_test.cc', 'mac/process_types_test.cc', 'mac/system_snapshot_mac_test.cc', + 'minidump/process_snapshot_minidump_test.cc', ], }, ],