mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-20 18:53:47 +00:00
Merge master 583d1dc3efa9 into doc
This commit is contained in:
commit
59a2e5f621
@ -21,6 +21,7 @@
|
||||
'target_name': 'crashpad_client',
|
||||
'type': 'static_library',
|
||||
'dependencies': [
|
||||
'../compat/compat.gyp:crashpad_compat',
|
||||
'../third_party/mini_chromium/mini_chromium.gyp:base',
|
||||
'../util/util.gyp:crashpad_util',
|
||||
],
|
||||
|
@ -555,6 +555,36 @@ TEST_F(CrashReportDatabaseTest, DeleteReport) {
|
||||
db()->LookUpCrashReport(keep_completed.uuid, &keep_completed));
|
||||
}
|
||||
|
||||
TEST_F(CrashReportDatabaseTest, DeleteReportEmptyingDatabase) {
|
||||
CrashReportDatabase::Report report;
|
||||
CreateCrashReport(&report);
|
||||
|
||||
EXPECT_TRUE(FileExists(report.file_path));
|
||||
|
||||
UploadReport(report.uuid, true, "1");
|
||||
|
||||
EXPECT_EQ(CrashReportDatabase::kNoError,
|
||||
db()->LookUpCrashReport(report.uuid, &report));
|
||||
|
||||
EXPECT_TRUE(FileExists(report.file_path));
|
||||
|
||||
// This causes an empty database to be written, make sure this is handled.
|
||||
EXPECT_EQ(CrashReportDatabase::kNoError, db()->DeleteReport(report.uuid));
|
||||
EXPECT_FALSE(FileExists(report.file_path));
|
||||
}
|
||||
|
||||
TEST_F(CrashReportDatabaseTest, ReadEmptyDatabase) {
|
||||
CrashReportDatabase::Report report;
|
||||
CreateCrashReport(&report);
|
||||
EXPECT_EQ(CrashReportDatabase::kNoError, db()->DeleteReport(report.uuid));
|
||||
|
||||
// Deleting and the creating another report causes an empty database to be
|
||||
// loaded. Make sure this is handled.
|
||||
|
||||
CrashReportDatabase::Report report2;
|
||||
CreateCrashReport(&report2);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include <time.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/numerics/safe_math.h"
|
||||
#include "base/strings/string16.h"
|
||||
@ -416,26 +418,29 @@ void Metadata::Read() {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<MetadataFileReportRecord> records(header.num_records);
|
||||
if (!LoggingReadFile(handle_.get(), &records[0], records_size.ValueOrDie())) {
|
||||
LOG(ERROR) << "failed to read records";
|
||||
return;
|
||||
}
|
||||
|
||||
std::string string_table = ReadRestOfFileAsString(handle_.get());
|
||||
if (string_table.empty() || string_table.back() != '\0') {
|
||||
LOG(ERROR) << "bad string table";
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<ReportDisk> reports;
|
||||
for (const auto& record : records) {
|
||||
if (record.file_path_index >= string_table.size() ||
|
||||
record.id_index >= string_table.size()) {
|
||||
LOG(ERROR) << "invalid string table index";
|
||||
if (header.num_records > 0) {
|
||||
std::vector<MetadataFileReportRecord> records(header.num_records);
|
||||
if (!LoggingReadFile(
|
||||
handle_.get(), &records[0], records_size.ValueOrDie())) {
|
||||
LOG(ERROR) << "failed to read records";
|
||||
return;
|
||||
}
|
||||
reports.push_back(ReportDisk(record, report_dir_, string_table));
|
||||
|
||||
std::string string_table = ReadRestOfFileAsString(handle_.get());
|
||||
if (string_table.empty() || string_table.back() != '\0') {
|
||||
LOG(ERROR) << "bad string table";
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& record : records) {
|
||||
if (record.file_path_index >= string_table.size() ||
|
||||
record.id_index >= string_table.size()) {
|
||||
LOG(ERROR) << "invalid string table index";
|
||||
return;
|
||||
}
|
||||
reports.push_back(ReportDisk(record, report_dir_, string_table));
|
||||
}
|
||||
}
|
||||
reports_.swap(reports);
|
||||
}
|
||||
@ -465,6 +470,9 @@ void Metadata::Write() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (num_records == 0)
|
||||
return;
|
||||
|
||||
// Build the records and string table we're going to write.
|
||||
std::string string_table;
|
||||
std::vector<MetadataFileReportRecord> records;
|
||||
@ -815,7 +823,7 @@ scoped_ptr<CrashReportDatabase> InitializeInternal(
|
||||
scoped_ptr<CrashReportDatabaseWin> database_win(
|
||||
new CrashReportDatabaseWin(path));
|
||||
return database_win->Initialize(may_create)
|
||||
? database_win.Pass()
|
||||
? std::move(database_win)
|
||||
: scoped_ptr<CrashReportDatabaseWin>();
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/mac/mach_logging.h"
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
@ -158,7 +160,7 @@ class HandlerStarter final : public NotifyServer::DefaultInterface {
|
||||
url,
|
||||
annotations,
|
||||
arguments,
|
||||
receive_right.Pass(),
|
||||
std::move(receive_right),
|
||||
handler_restarter.get(),
|
||||
false)) {
|
||||
return base::mac::ScopedMachSendRight();
|
||||
@ -538,7 +540,7 @@ bool CrashpadClient::StartHandler(
|
||||
return false;
|
||||
}
|
||||
|
||||
SetHandlerMachPort(exception_port.Pass());
|
||||
SetHandlerMachPort(std::move(exception_port));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -548,14 +550,14 @@ bool CrashpadClient::SetHandlerMachService(const std::string& service_name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SetHandlerMachPort(exception_port.Pass());
|
||||
SetHandlerMachPort(std::move(exception_port));
|
||||
return true;
|
||||
}
|
||||
|
||||
void CrashpadClient::SetHandlerMachPort(
|
||||
base::mac::ScopedMachSendRight exception_port) {
|
||||
DCHECK(exception_port.is_valid());
|
||||
exception_port_ = exception_port.Pass();
|
||||
exception_port_ = std::move(exception_port);
|
||||
}
|
||||
|
||||
bool CrashpadClient::UseHandler() {
|
||||
|
@ -132,6 +132,18 @@ using ScopedProcThreadAttributeList =
|
||||
base::ScopedGeneric<PPROC_THREAD_ATTRIBUTE_LIST,
|
||||
ScopedProcThreadAttributeListTraits>;
|
||||
|
||||
bool IsInheritableHandle(HANDLE handle) {
|
||||
if (!handle || handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
// File handles (FILE_TYPE_DISK) and pipe handles (FILE_TYPE_PIPE) are known
|
||||
// to be inheritable. Console handles (FILE_TYPE_CHAR) are not inheritable via
|
||||
// PROC_THREAD_ATTRIBUTE_HANDLE_LIST. See
|
||||
// https://crashpad.chromium.org/bug/77.
|
||||
DWORD handle_type = GetFileType(handle);
|
||||
return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE;
|
||||
}
|
||||
|
||||
// Adds |handle| to |handle_list| if it appears valid, and is not already in
|
||||
// |handle_list|.
|
||||
//
|
||||
@ -142,11 +154,12 @@ using ScopedProcThreadAttributeList =
|
||||
// silently not inherit any handles.
|
||||
//
|
||||
// Use this function to add handles with uncertain validities.
|
||||
void AddHandleToListIfValid(std::vector<HANDLE>* handle_list, HANDLE handle) {
|
||||
void AddHandleToListIfValidAndInheritable(std::vector<HANDLE>* handle_list,
|
||||
HANDLE handle) {
|
||||
// There doesn't seem to be any documentation of this, but if there's a handle
|
||||
// duplicated in this list, CreateProcess() fails with
|
||||
// ERROR_INVALID_PARAMETER.
|
||||
if (handle && handle != INVALID_HANDLE_VALUE &&
|
||||
if (IsInheritableHandle(handle) &&
|
||||
std::find(handle_list->begin(), handle_list->end(), handle) ==
|
||||
handle_list->end()) {
|
||||
handle_list->push_back(handle);
|
||||
@ -267,9 +280,12 @@ bool CrashpadClient::StartHandler(
|
||||
|
||||
handle_list.reserve(4);
|
||||
handle_list.push_back(pipe_write);
|
||||
AddHandleToListIfValid(&handle_list, startup_info.StartupInfo.hStdInput);
|
||||
AddHandleToListIfValid(&handle_list, startup_info.StartupInfo.hStdOutput);
|
||||
AddHandleToListIfValid(&handle_list, startup_info.StartupInfo.hStdError);
|
||||
AddHandleToListIfValidAndInheritable(&handle_list,
|
||||
startup_info.StartupInfo.hStdInput);
|
||||
AddHandleToListIfValidAndInheritable(&handle_list,
|
||||
startup_info.StartupInfo.hStdOutput);
|
||||
AddHandleToListIfValidAndInheritable(&handle_list,
|
||||
startup_info.StartupInfo.hStdError);
|
||||
rv = update_proc_thread_attribute(
|
||||
startup_info.lpAttributeList,
|
||||
0,
|
||||
|
@ -235,7 +235,7 @@ Settings::ScopedLockedFileHandle Settings::OpenForWritingAndReadSettings(
|
||||
return ScopedLockedFileHandle();
|
||||
}
|
||||
|
||||
return handle.Pass();
|
||||
return handle;
|
||||
}
|
||||
|
||||
bool Settings::ReadSettings(FileHandle handle,
|
||||
|
@ -22,12 +22,14 @@
|
||||
'type': 'static_library',
|
||||
'sources': [
|
||||
'mac/AvailabilityMacros.h',
|
||||
'mac/kern/exc_resource.h'
|
||||
'mac/kern/exc_resource.h',
|
||||
'mac/mach/mach.h',
|
||||
'mac/mach-o/getsect.cc',
|
||||
'mac/mach-o/getsect.h',
|
||||
'mac/mach-o/loader.h',
|
||||
'mac/sys/resource.h',
|
||||
'non_cxx11_lib/type_traits',
|
||||
'non_cxx11_lib/utility',
|
||||
'non_mac/mach/mach.h',
|
||||
'non_win/dbghelp.h',
|
||||
'non_win/minwinbase.h',
|
||||
@ -50,10 +52,12 @@
|
||||
],
|
||||
'include_dirs': [
|
||||
'mac',
|
||||
'non_cxx11_lib',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'mac',
|
||||
'non_cxx11_lib',
|
||||
],
|
||||
},
|
||||
}],
|
||||
|
37
compat/non_cxx11_lib/type_traits
Normal file
37
compat/non_cxx11_lib/type_traits
Normal file
@ -0,0 +1,37 @@
|
||||
// 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_COMPAT_NON_CXX11_LIB_TYPE_TRAITS_
|
||||
#define CRASHPAD_COMPAT_NON_CXX11_LIB_TYPE_TRAITS_
|
||||
|
||||
#include "util/stdlib/cxx.h"
|
||||
|
||||
#if CXX_LIBRARY_VERSION >= 2011
|
||||
|
||||
#include_next <type_traits>
|
||||
|
||||
#else
|
||||
|
||||
namespace std {
|
||||
|
||||
template <class T>
|
||||
struct remove_reference { using type = T; };
|
||||
template <class T>
|
||||
struct remove_reference<T&> { using type = T; };
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // CXX_LIBRARY_VERSION
|
||||
|
||||
#endif // CRASHPAD_COMPAT_NON_CXX11_LIB_TYPE_TRAITS_
|
46
compat/non_cxx11_lib/utility
Normal file
46
compat/non_cxx11_lib/utility
Normal file
@ -0,0 +1,46 @@
|
||||
// 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_COMPAT_NON_CXX11_LIB_UTILITY_
|
||||
#define CRASHPAD_COMPAT_NON_CXX11_LIB_UTILITY_
|
||||
|
||||
#include_next <utility>
|
||||
|
||||
#include "util/stdlib/cxx.h"
|
||||
|
||||
#if CXX_LIBRARY_VERSION < 2011
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace std {
|
||||
|
||||
template <class T>
|
||||
T&& forward(typename remove_reference<T>::type& t) noexcept {
|
||||
return static_cast<T&&>(t);
|
||||
}
|
||||
template <class T>
|
||||
T&& forward(typename remove_reference<T>::type&& t) noexcept {
|
||||
return static_cast<T&&>(t);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename remove_reference<T>::type&& move(T&& t) noexcept {
|
||||
return static_cast<typename remove_reference<T>::type&&>(t);
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // CXX_LIBRARY_VERSION
|
||||
|
||||
#endif // CRASHPAD_COMPAT_NON_CXX11_LIB_UTILITY_
|
@ -1,5 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2015 The Crashpad Authors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -366,7 +366,7 @@ CrashReportUploadThread::UploadResult CrashReportUploadThread::UploadReport(
|
||||
HTTPHeaders::value_type content_type =
|
||||
http_multipart_builder.GetContentType();
|
||||
http_transport->SetHeader(content_type.first, content_type.second);
|
||||
http_transport->SetBodyStream(http_multipart_builder.GetBodyStream().Pass());
|
||||
http_transport->SetBodyStream(http_multipart_builder.GetBodyStream());
|
||||
// TODO(mark): The timeout should be configurable by the client.
|
||||
http_transport->SetTimeout(60.0); // 1 minute.
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/auto_reset.h"
|
||||
#include "base/files/file_path.h"
|
||||
@ -314,7 +315,7 @@ int HandlerMain(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
ExceptionHandlerServer exception_handler_server(
|
||||
receive_right.Pass(), !options.mach_service.empty());
|
||||
std::move(receive_right), !options.mach_service.empty());
|
||||
base::AutoReset<ExceptionHandlerServer*> reset_g_exception_handler_server(
|
||||
&g_exception_handler_server, &exception_handler_server);
|
||||
|
||||
@ -336,9 +337,12 @@ int HandlerMain(int argc, char* argv[]) {
|
||||
reset_sigterm.reset(&old_sa);
|
||||
}
|
||||
#elif defined(OS_WIN)
|
||||
// Shut down as late as possible relative to programs we're watching.
|
||||
if (!SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY))
|
||||
PLOG(ERROR) << "SetProcessShutdownParameters";
|
||||
|
||||
ExceptionHandlerServer exception_handler_server(!options.pipe_name.empty());
|
||||
|
||||
std::string pipe_name;
|
||||
if (!options.pipe_name.empty()) {
|
||||
exception_handler_server.SetPipeName(base::UTF8ToUTF16(options.pipe_name));
|
||||
} else if (options.handshake_handle != INVALID_HANDLE_VALUE) {
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
#include "handler/mac/exception_handler_server.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/mac/mach_logging.h"
|
||||
#include "util/mach/composite_mach_message_server.h"
|
||||
@ -183,7 +185,7 @@ class ExceptionHandlerServerRun : public UniversalMachExcServer::Interface,
|
||||
ExceptionHandlerServer::ExceptionHandlerServer(
|
||||
base::mac::ScopedMachReceiveRight receive_port,
|
||||
bool launchd)
|
||||
: receive_port_(receive_port.Pass()),
|
||||
: receive_port_(std::move(receive_port)),
|
||||
notify_port_(NewMachPort(MACH_PORT_RIGHT_RECEIVE)),
|
||||
launchd_(launchd) {
|
||||
CHECK(receive_port_.is_valid());
|
||||
|
0
handler/win/z7_test.dll
Normal file → Executable file
0
handler/win/z7_test.dll
Normal file → Executable file
@ -14,6 +14,8 @@
|
||||
|
||||
#include "minidump/minidump_crashpad_info_writer.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "minidump/minidump_module_crashpad_info_writer.h"
|
||||
#include "minidump/minidump_simple_string_dictionary_writer.h"
|
||||
@ -51,14 +53,14 @@ void MinidumpCrashpadInfoWriter::InitializeFromSnapshot(
|
||||
simple_annotations->InitializeFromMap(
|
||||
process_snapshot->AnnotationsSimpleMap());
|
||||
if (simple_annotations->IsUseful()) {
|
||||
SetSimpleAnnotations(simple_annotations.Pass());
|
||||
SetSimpleAnnotations(std::move(simple_annotations));
|
||||
}
|
||||
|
||||
auto modules = make_scoped_ptr(new MinidumpModuleCrashpadInfoListWriter());
|
||||
modules->InitializeFromSnapshot(process_snapshot->Modules());
|
||||
|
||||
if (modules->IsUseful()) {
|
||||
SetModuleList(modules.Pass());
|
||||
SetModuleList(std::move(modules));
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,14 +80,14 @@ void MinidumpCrashpadInfoWriter::SetSimpleAnnotations(
|
||||
scoped_ptr<MinidumpSimpleStringDictionaryWriter> simple_annotations) {
|
||||
DCHECK_EQ(state(), kStateMutable);
|
||||
|
||||
simple_annotations_ = simple_annotations.Pass();
|
||||
simple_annotations_ = std::move(simple_annotations);
|
||||
}
|
||||
|
||||
void MinidumpCrashpadInfoWriter::SetModuleList(
|
||||
scoped_ptr<MinidumpModuleCrashpadInfoListWriter> module_list) {
|
||||
DCHECK_EQ(state(), kStateMutable);
|
||||
|
||||
module_list_ = module_list.Pass();
|
||||
module_list_ = std::move(module_list);
|
||||
}
|
||||
|
||||
bool MinidumpCrashpadInfoWriter::Freeze() {
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "minidump/minidump_extensions.h"
|
||||
@ -67,7 +68,7 @@ TEST(MinidumpCrashpadInfoWriter, Empty) {
|
||||
auto crashpad_info_writer = make_scoped_ptr(new MinidumpCrashpadInfoWriter());
|
||||
EXPECT_FALSE(crashpad_info_writer->IsUseful());
|
||||
|
||||
minidump_file_writer.AddStream(crashpad_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(crashpad_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -102,7 +103,7 @@ TEST(MinidumpCrashpadInfoWriter, ReportAndClientID) {
|
||||
|
||||
EXPECT_TRUE(crashpad_info_writer->IsUseful());
|
||||
|
||||
minidump_file_writer.AddStream(crashpad_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(crashpad_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -137,13 +138,13 @@ TEST(MinidumpCrashpadInfoWriter, SimpleAnnotations) {
|
||||
make_scoped_ptr(new MinidumpSimpleStringDictionaryEntryWriter());
|
||||
simple_string_dictionary_entry_writer->SetKeyValue(kKey, kValue);
|
||||
simple_string_dictionary_writer->AddEntry(
|
||||
simple_string_dictionary_entry_writer.Pass());
|
||||
std::move(simple_string_dictionary_entry_writer));
|
||||
crashpad_info_writer->SetSimpleAnnotations(
|
||||
simple_string_dictionary_writer.Pass());
|
||||
std::move(simple_string_dictionary_writer));
|
||||
|
||||
EXPECT_TRUE(crashpad_info_writer->IsUseful());
|
||||
|
||||
minidump_file_writer.AddStream(crashpad_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(crashpad_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -177,12 +178,13 @@ TEST(MinidumpCrashpadInfoWriter, CrashpadModuleList) {
|
||||
auto module_list_writer =
|
||||
make_scoped_ptr(new MinidumpModuleCrashpadInfoListWriter());
|
||||
auto module_writer = make_scoped_ptr(new MinidumpModuleCrashpadInfoWriter());
|
||||
module_list_writer->AddModule(module_writer.Pass(), kMinidumpModuleListIndex);
|
||||
crashpad_info_writer->SetModuleList(module_list_writer.Pass());
|
||||
module_list_writer->AddModule(std::move(module_writer),
|
||||
kMinidumpModuleListIndex);
|
||||
crashpad_info_writer->SetModuleList(std::move(module_list_writer));
|
||||
|
||||
EXPECT_TRUE(crashpad_info_writer->IsUseful());
|
||||
|
||||
minidump_file_writer.AddStream(crashpad_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(crashpad_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -232,7 +234,7 @@ TEST(MinidumpCrashpadInfoWriter, InitializeFromSnapshot) {
|
||||
auto process_snapshot = make_scoped_ptr(new TestProcessSnapshot());
|
||||
|
||||
auto module_snapshot = make_scoped_ptr(new TestModuleSnapshot());
|
||||
process_snapshot->AddModule(module_snapshot.Pass());
|
||||
process_snapshot->AddModule(std::move(module_snapshot));
|
||||
|
||||
auto info_writer = make_scoped_ptr(new MinidumpCrashpadInfoWriter());
|
||||
info_writer->InitializeFromSnapshot(process_snapshot.get());
|
||||
@ -251,14 +253,14 @@ TEST(MinidumpCrashpadInfoWriter, InitializeFromSnapshot) {
|
||||
module_snapshot.reset(new TestModuleSnapshot());
|
||||
std::vector<std::string> annotations_list(1, std::string(kEntry));
|
||||
module_snapshot->SetAnnotationsVector(annotations_list);
|
||||
process_snapshot->AddModule(module_snapshot.Pass());
|
||||
process_snapshot->AddModule(std::move(module_snapshot));
|
||||
|
||||
info_writer.reset(new MinidumpCrashpadInfoWriter());
|
||||
info_writer->InitializeFromSnapshot(process_snapshot.get());
|
||||
EXPECT_TRUE(info_writer->IsUseful());
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.AddStream(info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/numerics/safe_conversions.h"
|
||||
#include "minidump/minidump_context_writer.h"
|
||||
@ -48,14 +50,14 @@ void MinidumpExceptionWriter::InitializeFromSnapshot(
|
||||
|
||||
scoped_ptr<MinidumpContextWriter> context =
|
||||
MinidumpContextWriter::CreateFromSnapshot(exception_snapshot->Context());
|
||||
SetContext(context.Pass());
|
||||
SetContext(std::move(context));
|
||||
}
|
||||
|
||||
void MinidumpExceptionWriter::SetContext(
|
||||
scoped_ptr<MinidumpContextWriter> context) {
|
||||
DCHECK_EQ(state(), kStateMutable);
|
||||
|
||||
context_ = context.Pass();
|
||||
context_ = std::move(context);
|
||||
}
|
||||
|
||||
void MinidumpExceptionWriter::SetExceptionInformation(
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
@ -104,9 +105,9 @@ TEST(MinidumpExceptionWriter, Minimal) {
|
||||
|
||||
auto context_x86_writer = make_scoped_ptr(new MinidumpContextX86Writer());
|
||||
InitializeMinidumpContextX86(context_x86_writer->context(), kSeed);
|
||||
exception_writer->SetContext(context_x86_writer.Pass());
|
||||
exception_writer->SetContext(std::move(context_x86_writer));
|
||||
|
||||
minidump_file_writer.AddStream(exception_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(exception_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -144,7 +145,7 @@ TEST(MinidumpExceptionWriter, Standard) {
|
||||
|
||||
auto context_x86_writer = make_scoped_ptr(new MinidumpContextX86Writer());
|
||||
InitializeMinidumpContextX86(context_x86_writer->context(), kSeed);
|
||||
exception_writer->SetContext(context_x86_writer.Pass());
|
||||
exception_writer->SetContext(std::move(context_x86_writer));
|
||||
|
||||
exception_writer->SetThreadID(kThreadID);
|
||||
exception_writer->SetExceptionCode(kExceptionCode);
|
||||
@ -165,7 +166,7 @@ TEST(MinidumpExceptionWriter, Standard) {
|
||||
exception_information.push_back(kExceptionInformation2);
|
||||
exception_writer->SetExceptionInformation(exception_information);
|
||||
|
||||
minidump_file_writer.AddStream(exception_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(exception_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -238,7 +239,7 @@ TEST(MinidumpExceptionWriter, InitializeFromSnapshot) {
|
||||
exception_writer->InitializeFromSnapshot(&exception_snapshot, thread_id_map);
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.AddStream(exception_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(exception_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -260,7 +261,7 @@ TEST(MinidumpExceptionWriterDeathTest, NoContext) {
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
auto exception_writer = make_scoped_ptr(new MinidumpExceptionWriter());
|
||||
|
||||
minidump_file_writer.AddStream(exception_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(exception_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_DEATH_CHECK(minidump_file_writer.WriteEverything(&string_file),
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
#include "minidump/minidump_file_writer.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "minidump/minidump_crashpad_info_writer.h"
|
||||
#include "minidump/minidump_exception_writer.h"
|
||||
@ -67,11 +69,11 @@ void MinidumpFileWriter::InitializeFromSnapshot(
|
||||
const SystemSnapshot* system_snapshot = process_snapshot->System();
|
||||
auto system_info = make_scoped_ptr(new MinidumpSystemInfoWriter());
|
||||
system_info->InitializeFromSnapshot(system_snapshot);
|
||||
AddStream(system_info.Pass());
|
||||
AddStream(std::move(system_info));
|
||||
|
||||
auto misc_info = make_scoped_ptr(new MinidumpMiscInfoWriter());
|
||||
misc_info->InitializeFromSnapshot(process_snapshot);
|
||||
AddStream(misc_info.Pass());
|
||||
AddStream(std::move(misc_info));
|
||||
|
||||
auto memory_list = make_scoped_ptr(new MinidumpMemoryListWriter());
|
||||
auto thread_list = make_scoped_ptr(new MinidumpThreadListWriter());
|
||||
@ -79,18 +81,18 @@ void MinidumpFileWriter::InitializeFromSnapshot(
|
||||
MinidumpThreadIDMap thread_id_map;
|
||||
thread_list->InitializeFromSnapshot(process_snapshot->Threads(),
|
||||
&thread_id_map);
|
||||
AddStream(thread_list.Pass());
|
||||
AddStream(std::move(thread_list));
|
||||
|
||||
const ExceptionSnapshot* exception_snapshot = process_snapshot->Exception();
|
||||
if (exception_snapshot) {
|
||||
auto exception = make_scoped_ptr(new MinidumpExceptionWriter());
|
||||
exception->InitializeFromSnapshot(exception_snapshot, thread_id_map);
|
||||
AddStream(exception.Pass());
|
||||
AddStream(std::move(exception));
|
||||
}
|
||||
|
||||
auto module_list = make_scoped_ptr(new MinidumpModuleListWriter());
|
||||
module_list->InitializeFromSnapshot(process_snapshot->Modules());
|
||||
AddStream(module_list.Pass());
|
||||
AddStream(std::move(module_list));
|
||||
|
||||
auto crashpad_info = make_scoped_ptr(new MinidumpCrashpadInfoWriter());
|
||||
crashpad_info->InitializeFromSnapshot(process_snapshot);
|
||||
@ -98,7 +100,7 @@ void MinidumpFileWriter::InitializeFromSnapshot(
|
||||
// Since the MinidumpCrashpadInfo stream is an extension, it’s safe to not add
|
||||
// it to the minidump file if it wouldn’t carry any useful information.
|
||||
if (crashpad_info->IsUseful()) {
|
||||
AddStream(crashpad_info.Pass());
|
||||
AddStream(std::move(crashpad_info));
|
||||
}
|
||||
|
||||
std::vector<const MemoryMapRegionSnapshot*> memory_map_snapshot =
|
||||
@ -106,19 +108,19 @@ void MinidumpFileWriter::InitializeFromSnapshot(
|
||||
if (!memory_map_snapshot.empty()) {
|
||||
auto memory_info_list = make_scoped_ptr(new MinidumpMemoryInfoListWriter());
|
||||
memory_info_list->InitializeFromSnapshot(memory_map_snapshot);
|
||||
AddStream(memory_info_list.Pass());
|
||||
AddStream(std::move(memory_info_list));
|
||||
}
|
||||
|
||||
std::vector<HandleSnapshot> handles_snapshot = process_snapshot->Handles();
|
||||
if (!handles_snapshot.empty()) {
|
||||
auto handle_data_writer = make_scoped_ptr(new MinidumpHandleDataWriter());
|
||||
handle_data_writer->InitializeFromSnapshot(handles_snapshot);
|
||||
AddStream(handle_data_writer.Pass());
|
||||
AddStream(std::move(handle_data_writer));
|
||||
}
|
||||
|
||||
memory_list->AddFromSnapshot(process_snapshot->ExtraMemory());
|
||||
|
||||
AddStream(memory_list.Pass());
|
||||
AddStream(std::move(memory_list));
|
||||
}
|
||||
|
||||
void MinidumpFileWriter::SetTimestamp(time_t timestamp) {
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <dbghelp.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
@ -96,7 +97,7 @@ TEST(MinidumpFileWriter, OneStream) {
|
||||
const uint8_t kStreamValue = 0x5a;
|
||||
auto stream =
|
||||
make_scoped_ptr(new TestStream(kStreamType, kStreamSize, kStreamValue));
|
||||
minidump_file.AddStream(stream.Pass());
|
||||
minidump_file.AddStream(std::move(stream));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file.WriteEverything(&string_file));
|
||||
@ -135,7 +136,7 @@ TEST(MinidumpFileWriter, ThreeStreams) {
|
||||
const uint8_t kStream0Value = 0x5a;
|
||||
auto stream0 = make_scoped_ptr(
|
||||
new TestStream(kStream0Type, kStream0Size, kStream0Value));
|
||||
minidump_file.AddStream(stream0.Pass());
|
||||
minidump_file.AddStream(std::move(stream0));
|
||||
|
||||
// Make the second stream’s type be a smaller quantity than the first stream’s
|
||||
// to test that the streams show up in the order that they were added, not in
|
||||
@ -145,14 +146,14 @@ TEST(MinidumpFileWriter, ThreeStreams) {
|
||||
const uint8_t kStream1Value = 0xa5;
|
||||
auto stream1 = make_scoped_ptr(
|
||||
new TestStream(kStream1Type, kStream1Size, kStream1Value));
|
||||
minidump_file.AddStream(stream1.Pass());
|
||||
minidump_file.AddStream(std::move(stream1));
|
||||
|
||||
const size_t kStream2Size = 1;
|
||||
const MinidumpStreamType kStream2Type = static_cast<MinidumpStreamType>(0x7e);
|
||||
const uint8_t kStream2Value = 0x36;
|
||||
auto stream2 = make_scoped_ptr(
|
||||
new TestStream(kStream2Type, kStream2Size, kStream2Value));
|
||||
minidump_file.AddStream(stream2.Pass());
|
||||
minidump_file.AddStream(std::move(stream2));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file.WriteEverything(&string_file));
|
||||
@ -219,7 +220,7 @@ TEST(MinidumpFileWriter, ZeroLengthStream) {
|
||||
const size_t kStreamSize = 0;
|
||||
const MinidumpStreamType kStreamType = static_cast<MinidumpStreamType>(0x4d);
|
||||
auto stream = make_scoped_ptr(new TestStream(kStreamType, kStreamSize, 0));
|
||||
minidump_file.AddStream(stream.Pass());
|
||||
minidump_file.AddStream(std::move(stream));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file.WriteEverything(&string_file));
|
||||
@ -251,7 +252,7 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_Basic) {
|
||||
auto system_snapshot = make_scoped_ptr(new TestSystemSnapshot());
|
||||
system_snapshot->SetCPUArchitecture(kCPUArchitectureX86_64);
|
||||
system_snapshot->SetOperatingSystem(SystemSnapshot::kOperatingSystemMacOSX);
|
||||
process_snapshot.SetSystem(system_snapshot.Pass());
|
||||
process_snapshot.SetSystem(std::move(system_snapshot));
|
||||
|
||||
auto peb_snapshot = make_scoped_ptr(new TestMemorySnapshot());
|
||||
const uint64_t kPebAddress = 0x07f90000;
|
||||
@ -259,7 +260,7 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_Basic) {
|
||||
const size_t kPebSize = 0x280;
|
||||
peb_snapshot->SetSize(kPebSize);
|
||||
peb_snapshot->SetValue('p');
|
||||
process_snapshot.AddExtraMemory(peb_snapshot.Pass());
|
||||
process_snapshot.AddExtraMemory(std::move(peb_snapshot));
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.InitializeFromSnapshot(&process_snapshot);
|
||||
@ -315,22 +316,22 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_Exception) {
|
||||
auto system_snapshot = make_scoped_ptr(new TestSystemSnapshot());
|
||||
system_snapshot->SetCPUArchitecture(kCPUArchitectureX86_64);
|
||||
system_snapshot->SetOperatingSystem(SystemSnapshot::kOperatingSystemMacOSX);
|
||||
process_snapshot.SetSystem(system_snapshot.Pass());
|
||||
process_snapshot.SetSystem(std::move(system_snapshot));
|
||||
|
||||
auto thread_snapshot = make_scoped_ptr(new TestThreadSnapshot());
|
||||
InitializeCPUContextX86_64(thread_snapshot->MutableContext(), 5);
|
||||
process_snapshot.AddThread(thread_snapshot.Pass());
|
||||
process_snapshot.AddThread(std::move(thread_snapshot));
|
||||
|
||||
auto exception_snapshot = make_scoped_ptr(new TestExceptionSnapshot());
|
||||
InitializeCPUContextX86_64(exception_snapshot->MutableContext(), 11);
|
||||
process_snapshot.SetException(exception_snapshot.Pass());
|
||||
process_snapshot.SetException(std::move(exception_snapshot));
|
||||
|
||||
// The module does not have anything that needs to be represented in a
|
||||
// MinidumpModuleCrashpadInfo structure, so no such structure is expected to
|
||||
// be present, which will in turn suppress the addition of a
|
||||
// MinidumpCrashpadInfo stream.
|
||||
auto module_snapshot = make_scoped_ptr(new TestModuleSnapshot());
|
||||
process_snapshot.AddModule(module_snapshot.Pass());
|
||||
process_snapshot.AddModule(std::move(module_snapshot));
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.InitializeFromSnapshot(&process_snapshot);
|
||||
@ -379,22 +380,22 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_CrashpadInfo) {
|
||||
auto system_snapshot = make_scoped_ptr(new TestSystemSnapshot());
|
||||
system_snapshot->SetCPUArchitecture(kCPUArchitectureX86_64);
|
||||
system_snapshot->SetOperatingSystem(SystemSnapshot::kOperatingSystemMacOSX);
|
||||
process_snapshot.SetSystem(system_snapshot.Pass());
|
||||
process_snapshot.SetSystem(std::move(system_snapshot));
|
||||
|
||||
auto thread_snapshot = make_scoped_ptr(new TestThreadSnapshot());
|
||||
InitializeCPUContextX86_64(thread_snapshot->MutableContext(), 5);
|
||||
process_snapshot.AddThread(thread_snapshot.Pass());
|
||||
process_snapshot.AddThread(std::move(thread_snapshot));
|
||||
|
||||
auto exception_snapshot = make_scoped_ptr(new TestExceptionSnapshot());
|
||||
InitializeCPUContextX86_64(exception_snapshot->MutableContext(), 11);
|
||||
process_snapshot.SetException(exception_snapshot.Pass());
|
||||
process_snapshot.SetException(std::move(exception_snapshot));
|
||||
|
||||
// The module needs an annotation for the MinidumpCrashpadInfo stream to be
|
||||
// considered useful and be included.
|
||||
auto module_snapshot = make_scoped_ptr(new TestModuleSnapshot());
|
||||
std::vector<std::string> annotations_list(1, std::string("annotation"));
|
||||
module_snapshot->SetAnnotationsVector(annotations_list);
|
||||
process_snapshot.AddModule(module_snapshot.Pass());
|
||||
process_snapshot.AddModule(std::move(module_snapshot));
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.InitializeFromSnapshot(&process_snapshot);
|
||||
@ -445,7 +446,7 @@ TEST(MinidumpFileWriterDeathTest, SameStreamType) {
|
||||
const uint8_t kStream0Value = 0x5a;
|
||||
auto stream0 = make_scoped_ptr(
|
||||
new TestStream(kStream0Type, kStream0Size, kStream0Value));
|
||||
minidump_file.AddStream(stream0.Pass());
|
||||
minidump_file.AddStream(std::move(stream0));
|
||||
|
||||
// It is an error to add a second stream of the same type.
|
||||
const size_t kStream1Size = 3;
|
||||
@ -453,7 +454,7 @@ TEST(MinidumpFileWriterDeathTest, SameStreamType) {
|
||||
const uint8_t kStream1Value = 0xa5;
|
||||
auto stream1 = make_scoped_ptr(
|
||||
new TestStream(kStream1Type, kStream1Size, kStream1Value));
|
||||
ASSERT_DEATH_CHECK(minidump_file.AddStream(stream1.Pass()),
|
||||
ASSERT_DEATH_CHECK(minidump_file.AddStream(std::move(stream1)),
|
||||
"already present");
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "minidump/minidump_handle_writer.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "gtest/gtest.h"
|
||||
@ -57,7 +58,7 @@ void GetHandleDataStream(
|
||||
TEST(MinidumpHandleDataWriter, Empty) {
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
auto handle_data_writer = make_scoped_ptr(new MinidumpHandleDataWriter());
|
||||
minidump_file_writer.AddStream(handle_data_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(handle_data_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -90,7 +91,7 @@ TEST(MinidumpHandleDataWriter, OneHandle) {
|
||||
|
||||
handle_data_writer->InitializeFromSnapshot(snapshot);
|
||||
|
||||
minidump_file_writer.AddStream(handle_data_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(handle_data_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -148,7 +149,7 @@ TEST(MinidumpHandleDataWriter, RepeatedTypeName) {
|
||||
|
||||
handle_data_writer->InitializeFromSnapshot(snapshot);
|
||||
|
||||
minidump_file_writer.AddStream(handle_data_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(handle_data_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "minidump/minidump_memory_info_writer.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "minidump/minidump_file_writer.h"
|
||||
@ -58,7 +59,7 @@ TEST(MinidumpMemoryInfoWriter, Empty) {
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
auto memory_info_list_writer =
|
||||
make_scoped_ptr(new MinidumpMemoryInfoListWriter());
|
||||
minidump_file_writer.AddStream(memory_info_list_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(memory_info_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -95,7 +96,7 @@ TEST(MinidumpMemoryInfoWriter, OneRegion) {
|
||||
memory_map.push_back(memory_map_region.get());
|
||||
memory_info_list_writer->InitializeFromSnapshot(memory_map);
|
||||
|
||||
minidump_file_writer.AddStream(memory_info_list_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(memory_info_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
#include "minidump/minidump_memory_writer.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/auto_reset.h"
|
||||
#include "base/logging.h"
|
||||
#include "snapshot/memory_snapshot.h"
|
||||
@ -177,7 +179,7 @@ void MinidumpMemoryListWriter::AddFromSnapshot(
|
||||
for (const MemorySnapshot* memory_snapshot : memory_snapshots) {
|
||||
scoped_ptr<MinidumpMemoryWriter> memory =
|
||||
MinidumpMemoryWriter::CreateFromSnapshot(memory_snapshot);
|
||||
AddMemory(memory.Pass());
|
||||
AddMemory(std::move(memory));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include <dbghelp.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/format_macros.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
@ -80,7 +82,7 @@ TEST(MinidumpMemoryWriter, EmptyMemoryList) {
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
auto memory_list_writer = make_scoped_ptr(new MinidumpMemoryListWriter());
|
||||
|
||||
minidump_file_writer.AddStream(memory_list_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(memory_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -106,9 +108,9 @@ TEST(MinidumpMemoryWriter, OneMemoryRegion) {
|
||||
|
||||
auto memory_writer = make_scoped_ptr(
|
||||
new TestMinidumpMemoryWriter(kBaseAddress, kSize, kValue));
|
||||
memory_list_writer->AddMemory(memory_writer.Pass());
|
||||
memory_list_writer->AddMemory(std::move(memory_writer));
|
||||
|
||||
minidump_file_writer.AddStream(memory_list_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(memory_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -144,12 +146,12 @@ TEST(MinidumpMemoryWriter, TwoMemoryRegions) {
|
||||
|
||||
auto memory_writer_0 = make_scoped_ptr(
|
||||
new TestMinidumpMemoryWriter(kBaseAddress0, kSize0, kValue0));
|
||||
memory_list_writer->AddMemory(memory_writer_0.Pass());
|
||||
memory_list_writer->AddMemory(std::move(memory_writer_0));
|
||||
auto memory_writer_1 = make_scoped_ptr(
|
||||
new TestMinidumpMemoryWriter(kBaseAddress1, kSize1, kValue1));
|
||||
memory_list_writer->AddMemory(memory_writer_1.Pass());
|
||||
memory_list_writer->AddMemory(std::move(memory_writer_1));
|
||||
|
||||
minidump_file_writer.AddStream(memory_list_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(memory_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -248,7 +250,7 @@ TEST(MinidumpMemoryWriter, ExtraMemory) {
|
||||
auto memory_list_writer = make_scoped_ptr(new MinidumpMemoryListWriter());
|
||||
memory_list_writer->AddExtraMemory(test_memory_stream->memory());
|
||||
|
||||
minidump_file_writer.AddStream(test_memory_stream.Pass());
|
||||
minidump_file_writer.AddStream(std::move(test_memory_stream));
|
||||
|
||||
const uint64_t kBaseAddress1 = 0x2000;
|
||||
const size_t kSize1 = 0x0400;
|
||||
@ -256,9 +258,9 @@ TEST(MinidumpMemoryWriter, ExtraMemory) {
|
||||
|
||||
auto memory_writer = make_scoped_ptr(
|
||||
new TestMinidumpMemoryWriter(kBaseAddress1, kSize1, kValue1));
|
||||
memory_list_writer->AddMemory(memory_writer.Pass());
|
||||
memory_list_writer->AddMemory(std::move(memory_writer));
|
||||
|
||||
minidump_file_writer.AddStream(memory_list_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(memory_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -336,7 +338,7 @@ TEST(MinidumpMemoryWriter, AddFromSnapshot) {
|
||||
memory_list_writer->AddFromSnapshot(memory_snapshots);
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.AddStream(memory_list_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(memory_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/compiler_specific.h"
|
||||
@ -168,7 +169,7 @@ TEST(MinidumpMiscInfoWriter, Empty) {
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
auto misc_info_writer = make_scoped_ptr(new MinidumpMiscInfoWriter());
|
||||
|
||||
minidump_file_writer.AddStream(misc_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(misc_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -189,7 +190,7 @@ TEST(MinidumpMiscInfoWriter, ProcessId) {
|
||||
|
||||
misc_info_writer->SetProcessID(kProcessId);
|
||||
|
||||
minidump_file_writer.AddStream(misc_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(misc_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -215,7 +216,7 @@ TEST(MinidumpMiscInfoWriter, ProcessTimes) {
|
||||
misc_info_writer->SetProcessTimes(
|
||||
kProcessCreateTime, kProcessUserTime, kProcessKernelTime);
|
||||
|
||||
minidump_file_writer.AddStream(misc_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(misc_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -248,7 +249,7 @@ TEST(MinidumpMiscInfoWriter, ProcessorPowerInfo) {
|
||||
kProcessorMaxIdleState,
|
||||
kProcessorCurrentIdleState);
|
||||
|
||||
minidump_file_writer.AddStream(misc_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(misc_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -275,7 +276,7 @@ TEST(MinidumpMiscInfoWriter, ProcessIntegrityLevel) {
|
||||
|
||||
misc_info_writer->SetProcessIntegrityLevel(kProcessIntegrityLevel);
|
||||
|
||||
minidump_file_writer.AddStream(misc_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(misc_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -298,7 +299,7 @@ TEST(MinidumpMiscInfoWriter, ProcessExecuteFlags) {
|
||||
|
||||
misc_info_writer->SetProcessExecuteFlags(kProcessExecuteFlags);
|
||||
|
||||
minidump_file_writer.AddStream(misc_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(misc_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -321,7 +322,7 @@ TEST(MinidumpMiscInfoWriter, ProtectedProcess) {
|
||||
|
||||
misc_info_writer->SetProtectedProcess(kProtectedProcess);
|
||||
|
||||
minidump_file_writer.AddStream(misc_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(misc_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -358,7 +359,7 @@ TEST(MinidumpMiscInfoWriter, TimeZone) {
|
||||
kDaylightDate,
|
||||
kDaylightBias);
|
||||
|
||||
minidump_file_writer.AddStream(misc_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(misc_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -419,7 +420,7 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) {
|
||||
kSystemTimeZero,
|
||||
kDaylightBias);
|
||||
|
||||
minidump_file_writer.AddStream(misc_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(misc_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -460,7 +461,7 @@ TEST(MinidumpMiscInfoWriter, BuildStrings) {
|
||||
|
||||
misc_info_writer->SetBuildString(kBuildString, kDebugBuildString);
|
||||
|
||||
minidump_file_writer.AddStream(misc_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(misc_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -497,7 +498,7 @@ TEST(MinidumpMiscInfoWriter, BuildStringsOverflow) {
|
||||
|
||||
misc_info_writer->SetBuildString(build_string, debug_build_string);
|
||||
|
||||
minidump_file_writer.AddStream(misc_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(misc_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -567,7 +568,7 @@ TEST(MinidumpMiscInfoWriter, Everything) {
|
||||
kDaylightBias);
|
||||
misc_info_writer->SetBuildString(kBuildString, kDebugBuildString);
|
||||
|
||||
minidump_file_writer.AddStream(misc_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(misc_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -701,13 +702,13 @@ TEST(MinidumpMiscInfoWriter, InitializeFromSnapshot) {
|
||||
system_snapshot->SetOSVersionFull(kOSVersionFull);
|
||||
system_snapshot->SetMachineDescription(kMachineDescription);
|
||||
|
||||
process_snapshot.SetSystem(system_snapshot.Pass());
|
||||
process_snapshot.SetSystem(std::move(system_snapshot));
|
||||
|
||||
auto misc_info_writer = make_scoped_ptr(new MinidumpMiscInfoWriter());
|
||||
misc_info_writer->InitializeFromSnapshot(&process_snapshot);
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.AddStream(misc_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(misc_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "minidump/minidump_simple_string_dictionary_writer.h"
|
||||
#include "snapshot/module_snapshot.h"
|
||||
@ -44,7 +46,7 @@ void MinidumpModuleCrashpadInfoWriter::InitializeFromSnapshot(
|
||||
auto list_annotations = make_scoped_ptr(new MinidumpUTF8StringListWriter());
|
||||
list_annotations->InitializeFromVector(module_snapshot->AnnotationsVector());
|
||||
if (list_annotations->IsUseful()) {
|
||||
SetListAnnotations(list_annotations.Pass());
|
||||
SetListAnnotations(std::move(list_annotations));
|
||||
}
|
||||
|
||||
auto simple_annotations =
|
||||
@ -52,7 +54,7 @@ void MinidumpModuleCrashpadInfoWriter::InitializeFromSnapshot(
|
||||
simple_annotations->InitializeFromMap(
|
||||
module_snapshot->AnnotationsSimpleMap());
|
||||
if (simple_annotations->IsUseful()) {
|
||||
SetSimpleAnnotations(simple_annotations.Pass());
|
||||
SetSimpleAnnotations(std::move(simple_annotations));
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,14 +62,14 @@ void MinidumpModuleCrashpadInfoWriter::SetListAnnotations(
|
||||
scoped_ptr<MinidumpUTF8StringListWriter> list_annotations) {
|
||||
DCHECK_EQ(state(), kStateMutable);
|
||||
|
||||
list_annotations_ = list_annotations.Pass();
|
||||
list_annotations_ = std::move(list_annotations);
|
||||
}
|
||||
|
||||
void MinidumpModuleCrashpadInfoWriter::SetSimpleAnnotations(
|
||||
scoped_ptr<MinidumpSimpleStringDictionaryWriter> simple_annotations) {
|
||||
DCHECK_EQ(state(), kStateMutable);
|
||||
|
||||
simple_annotations_ = simple_annotations.Pass();
|
||||
simple_annotations_ = std::move(simple_annotations);
|
||||
}
|
||||
|
||||
bool MinidumpModuleCrashpadInfoWriter::IsUseful() const {
|
||||
@ -144,7 +146,7 @@ void MinidumpModuleCrashpadInfoListWriter::InitializeFromSnapshot(
|
||||
auto module = make_scoped_ptr(new MinidumpModuleCrashpadInfoWriter());
|
||||
module->InitializeFromSnapshot(module_snapshot);
|
||||
if (module->IsUseful()) {
|
||||
AddModule(module.Pass(), index);
|
||||
AddModule(std::move(module), index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "minidump/minidump_extensions.h"
|
||||
#include "minidump/minidump_simple_string_dictionary_writer.h"
|
||||
@ -77,7 +79,7 @@ TEST(MinidumpModuleCrashpadInfoWriter, EmptyModule) {
|
||||
make_scoped_ptr(new MinidumpModuleCrashpadInfoListWriter());
|
||||
auto module_writer = make_scoped_ptr(new MinidumpModuleCrashpadInfoWriter());
|
||||
EXPECT_FALSE(module_writer->IsUseful());
|
||||
module_list_writer->AddModule(module_writer.Pass(), 0);
|
||||
module_list_writer->AddModule(std::move(module_writer), 0);
|
||||
|
||||
EXPECT_TRUE(module_list_writer->IsUseful());
|
||||
|
||||
@ -119,17 +121,19 @@ TEST(MinidumpModuleCrashpadInfoWriter, FullModule) {
|
||||
auto module_writer = make_scoped_ptr(new MinidumpModuleCrashpadInfoWriter());
|
||||
auto string_list_writer = make_scoped_ptr(new MinidumpUTF8StringListWriter());
|
||||
string_list_writer->InitializeFromVector(vector);
|
||||
module_writer->SetListAnnotations(string_list_writer.Pass());
|
||||
module_writer->SetListAnnotations(std::move(string_list_writer));
|
||||
auto simple_string_dictionary_writer =
|
||||
make_scoped_ptr(new MinidumpSimpleStringDictionaryWriter());
|
||||
auto simple_string_dictionary_entry_writer =
|
||||
make_scoped_ptr(new MinidumpSimpleStringDictionaryEntryWriter());
|
||||
simple_string_dictionary_entry_writer->SetKeyValue(kKey, kValue);
|
||||
simple_string_dictionary_writer->AddEntry(
|
||||
simple_string_dictionary_entry_writer.Pass());
|
||||
module_writer->SetSimpleAnnotations(simple_string_dictionary_writer.Pass());
|
||||
std::move(simple_string_dictionary_entry_writer));
|
||||
module_writer->SetSimpleAnnotations(
|
||||
std::move(simple_string_dictionary_writer));
|
||||
EXPECT_TRUE(module_writer->IsUseful());
|
||||
module_list_writer->AddModule(module_writer.Pass(), kMinidumpModuleListIndex);
|
||||
module_list_writer->AddModule(std::move(module_writer),
|
||||
kMinidumpModuleListIndex);
|
||||
|
||||
EXPECT_TRUE(module_list_writer->IsUseful());
|
||||
|
||||
@ -211,17 +215,17 @@ TEST(MinidumpModuleCrashpadInfoWriter, ThreeModules) {
|
||||
make_scoped_ptr(new MinidumpSimpleStringDictionaryEntryWriter());
|
||||
simple_string_dictionary_entry_writer_0->SetKeyValue(kKey0, kValue0);
|
||||
simple_string_dictionary_writer_0->AddEntry(
|
||||
simple_string_dictionary_entry_writer_0.Pass());
|
||||
std::move(simple_string_dictionary_entry_writer_0));
|
||||
module_writer_0->SetSimpleAnnotations(
|
||||
simple_string_dictionary_writer_0.Pass());
|
||||
std::move(simple_string_dictionary_writer_0));
|
||||
EXPECT_TRUE(module_writer_0->IsUseful());
|
||||
module_list_writer->AddModule(module_writer_0.Pass(),
|
||||
module_list_writer->AddModule(std::move(module_writer_0),
|
||||
kMinidumpModuleListIndex0);
|
||||
|
||||
auto module_writer_1 =
|
||||
make_scoped_ptr(new MinidumpModuleCrashpadInfoWriter());
|
||||
EXPECT_FALSE(module_writer_1->IsUseful());
|
||||
module_list_writer->AddModule(module_writer_1.Pass(),
|
||||
module_list_writer->AddModule(std::move(module_writer_1),
|
||||
kMinidumpModuleListIndex1);
|
||||
|
||||
auto module_writer_2 =
|
||||
@ -232,16 +236,16 @@ TEST(MinidumpModuleCrashpadInfoWriter, ThreeModules) {
|
||||
make_scoped_ptr(new MinidumpSimpleStringDictionaryEntryWriter());
|
||||
simple_string_dictionary_entry_writer_2a->SetKeyValue(kKey2A, kValue2A);
|
||||
simple_string_dictionary_writer_2->AddEntry(
|
||||
simple_string_dictionary_entry_writer_2a.Pass());
|
||||
std::move(simple_string_dictionary_entry_writer_2a));
|
||||
auto simple_string_dictionary_entry_writer_2b =
|
||||
make_scoped_ptr(new MinidumpSimpleStringDictionaryEntryWriter());
|
||||
simple_string_dictionary_entry_writer_2b->SetKeyValue(kKey2B, kValue2B);
|
||||
simple_string_dictionary_writer_2->AddEntry(
|
||||
simple_string_dictionary_entry_writer_2b.Pass());
|
||||
std::move(simple_string_dictionary_entry_writer_2b));
|
||||
module_writer_2->SetSimpleAnnotations(
|
||||
simple_string_dictionary_writer_2.Pass());
|
||||
std::move(simple_string_dictionary_writer_2));
|
||||
EXPECT_TRUE(module_writer_2->IsUseful());
|
||||
module_list_writer->AddModule(module_writer_2.Pass(),
|
||||
module_list_writer->AddModule(std::move(module_writer_2),
|
||||
kMinidumpModuleListIndex2);
|
||||
|
||||
EXPECT_TRUE(module_list_writer->IsUseful());
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/numerics/safe_conversions.h"
|
||||
@ -244,7 +245,7 @@ void MinidumpModuleWriter::InitializeFromSnapshot(
|
||||
auto codeview_record =
|
||||
make_scoped_ptr(new MinidumpModuleCodeViewRecordPDB70Writer());
|
||||
codeview_record->InitializeFromSnapshot(module_snapshot);
|
||||
SetCodeViewRecord(codeview_record.Pass());
|
||||
SetCodeViewRecord(std::move(codeview_record));
|
||||
}
|
||||
|
||||
const MINIDUMP_MODULE* MinidumpModuleWriter::MinidumpModule() const {
|
||||
@ -266,14 +267,14 @@ void MinidumpModuleWriter::SetCodeViewRecord(
|
||||
scoped_ptr<MinidumpModuleCodeViewRecordWriter> codeview_record) {
|
||||
DCHECK_EQ(state(), kStateMutable);
|
||||
|
||||
codeview_record_ = codeview_record.Pass();
|
||||
codeview_record_ = std::move(codeview_record);
|
||||
}
|
||||
|
||||
void MinidumpModuleWriter::SetMiscDebugRecord(
|
||||
scoped_ptr<MinidumpModuleMiscDebugRecordWriter> misc_debug_record) {
|
||||
DCHECK_EQ(state(), kStateMutable);
|
||||
|
||||
misc_debug_record_ = misc_debug_record.Pass();
|
||||
misc_debug_record_ = std::move(misc_debug_record);
|
||||
}
|
||||
|
||||
void MinidumpModuleWriter::SetTimestamp(time_t timestamp) {
|
||||
@ -385,7 +386,7 @@ void MinidumpModuleListWriter::InitializeFromSnapshot(
|
||||
for (const ModuleSnapshot* module_snapshot : module_snapshots) {
|
||||
auto module = make_scoped_ptr(new MinidumpModuleWriter());
|
||||
module->InitializeFromSnapshot(module_snapshot);
|
||||
AddModule(module.Pass());
|
||||
AddModule(std::move(module));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/format_macros.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
@ -68,7 +70,7 @@ TEST(MinidumpModuleWriter, EmptyModuleList) {
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
auto module_list_writer = make_scoped_ptr(new MinidumpModuleListWriter());
|
||||
|
||||
minidump_file_writer.AddStream(module_list_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(module_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -276,8 +278,8 @@ TEST(MinidumpModuleWriter, EmptyModule) {
|
||||
auto module_writer = make_scoped_ptr(new MinidumpModuleWriter());
|
||||
module_writer->SetName(kModuleName);
|
||||
|
||||
module_list_writer->AddModule(module_writer.Pass());
|
||||
minidump_file_writer.AddStream(module_list_writer.Pass());
|
||||
module_list_writer->AddModule(std::move(module_writer));
|
||||
minidump_file_writer.AddStream(std::move(module_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -359,16 +361,16 @@ TEST(MinidumpModuleWriter, OneModule) {
|
||||
make_scoped_ptr(new MinidumpModuleCodeViewRecordPDB70Writer());
|
||||
codeview_pdb70_writer->SetPDBName(kPDBName);
|
||||
codeview_pdb70_writer->SetUUIDAndAge(pdb_uuid, kPDBAge);
|
||||
module_writer->SetCodeViewRecord(codeview_pdb70_writer.Pass());
|
||||
module_writer->SetCodeViewRecord(std::move(codeview_pdb70_writer));
|
||||
|
||||
auto misc_debug_writer =
|
||||
make_scoped_ptr(new MinidumpModuleMiscDebugRecordWriter());
|
||||
misc_debug_writer->SetDataType(kDebugType);
|
||||
misc_debug_writer->SetData(kDebugName, kDebugUTF16);
|
||||
module_writer->SetMiscDebugRecord(misc_debug_writer.Pass());
|
||||
module_writer->SetMiscDebugRecord(std::move(misc_debug_writer));
|
||||
|
||||
module_list_writer->AddModule(module_writer.Pass());
|
||||
minidump_file_writer.AddStream(module_list_writer.Pass());
|
||||
module_list_writer->AddModule(std::move(module_writer));
|
||||
minidump_file_writer.AddStream(std::move(module_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -434,16 +436,16 @@ TEST(MinidumpModuleWriter, OneModule_CodeViewUsesPDB20_MiscUsesUTF16) {
|
||||
make_scoped_ptr(new MinidumpModuleCodeViewRecordPDB20Writer());
|
||||
codeview_pdb20_writer->SetPDBName(kPDBName);
|
||||
codeview_pdb20_writer->SetTimestampAndAge(kPDBTimestamp, kPDBAge);
|
||||
module_writer->SetCodeViewRecord(codeview_pdb20_writer.Pass());
|
||||
module_writer->SetCodeViewRecord(std::move(codeview_pdb20_writer));
|
||||
|
||||
auto misc_debug_writer =
|
||||
make_scoped_ptr(new MinidumpModuleMiscDebugRecordWriter());
|
||||
misc_debug_writer->SetDataType(kDebugType);
|
||||
misc_debug_writer->SetData(kDebugName, kDebugUTF16);
|
||||
module_writer->SetMiscDebugRecord(misc_debug_writer.Pass());
|
||||
module_writer->SetMiscDebugRecord(std::move(misc_debug_writer));
|
||||
|
||||
module_list_writer->AddModule(module_writer.Pass());
|
||||
minidump_file_writer.AddStream(module_list_writer.Pass());
|
||||
module_list_writer->AddModule(std::move(module_writer));
|
||||
minidump_file_writer.AddStream(std::move(module_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -511,16 +513,16 @@ TEST(MinidumpModuleWriter, ThreeModules) {
|
||||
make_scoped_ptr(new MinidumpModuleCodeViewRecordPDB70Writer());
|
||||
codeview_pdb70_writer_0->SetPDBName(kPDBName0);
|
||||
codeview_pdb70_writer_0->SetUUIDAndAge(pdb_uuid_0, kPDBAge0);
|
||||
module_writer_0->SetCodeViewRecord(codeview_pdb70_writer_0.Pass());
|
||||
module_writer_0->SetCodeViewRecord(std::move(codeview_pdb70_writer_0));
|
||||
|
||||
module_list_writer->AddModule(module_writer_0.Pass());
|
||||
module_list_writer->AddModule(std::move(module_writer_0));
|
||||
|
||||
auto module_writer_1 = make_scoped_ptr(new MinidumpModuleWriter());
|
||||
module_writer_1->SetName(kModuleName1);
|
||||
module_writer_1->SetImageBaseAddress(kModuleBase1);
|
||||
module_writer_1->SetImageSize(kModuleSize1);
|
||||
|
||||
module_list_writer->AddModule(module_writer_1.Pass());
|
||||
module_list_writer->AddModule(std::move(module_writer_1));
|
||||
|
||||
auto module_writer_2 = make_scoped_ptr(new MinidumpModuleWriter());
|
||||
module_writer_2->SetName(kModuleName2);
|
||||
@ -531,11 +533,11 @@ TEST(MinidumpModuleWriter, ThreeModules) {
|
||||
make_scoped_ptr(new MinidumpModuleCodeViewRecordPDB20Writer());
|
||||
codeview_pdb70_writer_2->SetPDBName(kPDBName2);
|
||||
codeview_pdb70_writer_2->SetTimestampAndAge(kPDBTimestamp2, kPDBAge2);
|
||||
module_writer_2->SetCodeViewRecord(codeview_pdb70_writer_2.Pass());
|
||||
module_writer_2->SetCodeViewRecord(std::move(codeview_pdb70_writer_2));
|
||||
|
||||
module_list_writer->AddModule(module_writer_2.Pass());
|
||||
module_list_writer->AddModule(std::move(module_writer_2));
|
||||
|
||||
minidump_file_writer.AddStream(module_list_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(module_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -728,7 +730,7 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) {
|
||||
module_list_writer->InitializeFromSnapshot(module_snapshots);
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.AddStream(module_list_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(module_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -759,8 +761,8 @@ TEST(MinidumpModuleWriterDeathTest, NoModuleName) {
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
auto module_list_writer = make_scoped_ptr(new MinidumpModuleListWriter());
|
||||
auto module_writer = make_scoped_ptr(new MinidumpModuleWriter());
|
||||
module_list_writer->AddModule(module_writer.Pass());
|
||||
minidump_file_writer.AddStream(module_list_writer.Pass());
|
||||
module_list_writer->AddModule(std::move(module_writer));
|
||||
minidump_file_writer.AddStream(std::move(module_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_DEATH_CHECK(minidump_file_writer.WriteEverything(&string_file),
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
#include "minidump/minidump_rva_list_writer.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/format_macros.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "gtest/gtest.h"
|
||||
@ -32,7 +34,7 @@ class TestMinidumpRVAListWriter final : public internal::MinidumpRVAListWriter {
|
||||
|
||||
void AddChild(uint32_t value) {
|
||||
auto child = make_scoped_ptr(new TestUInt32MinidumpWritable(value));
|
||||
MinidumpRVAListWriter::AddChild(child.Pass());
|
||||
MinidumpRVAListWriter::AddChild(std::move(child));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
#include "minidump/minidump_simple_string_dictionary_writer.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "util/file/file_writer.h"
|
||||
@ -109,7 +111,7 @@ void MinidumpSimpleStringDictionaryWriter::InitializeFromMap(
|
||||
auto entry =
|
||||
make_scoped_ptr(new MinidumpSimpleStringDictionaryEntryWriter());
|
||||
entry->SetKeyValue(iterator.first, iterator.second);
|
||||
AddEntry(entry.Pass());
|
||||
AddEntry(std::move(entry));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "minidump/minidump_extensions.h"
|
||||
@ -62,7 +63,7 @@ TEST(MinidumpSimpleStringDictionaryWriter, EmptyKeyValue) {
|
||||
MinidumpSimpleStringDictionaryWriter dictionary_writer;
|
||||
auto entry_writer =
|
||||
make_scoped_ptr(new MinidumpSimpleStringDictionaryEntryWriter());
|
||||
dictionary_writer.AddEntry(entry_writer.Pass());
|
||||
dictionary_writer.AddEntry(std::move(entry_writer));
|
||||
|
||||
EXPECT_TRUE(dictionary_writer.IsUseful());
|
||||
|
||||
@ -96,7 +97,7 @@ TEST(MinidumpSimpleStringDictionaryWriter, OneKeyValue) {
|
||||
auto entry_writer =
|
||||
make_scoped_ptr(new MinidumpSimpleStringDictionaryEntryWriter());
|
||||
entry_writer->SetKeyValue(kKey, kValue);
|
||||
dictionary_writer.AddEntry(entry_writer.Pass());
|
||||
dictionary_writer.AddEntry(std::move(entry_writer));
|
||||
|
||||
EXPECT_TRUE(dictionary_writer.IsUseful());
|
||||
|
||||
@ -134,15 +135,15 @@ TEST(MinidumpSimpleStringDictionaryWriter, ThreeKeysValues) {
|
||||
auto entry_writer_0 =
|
||||
make_scoped_ptr(new MinidumpSimpleStringDictionaryEntryWriter());
|
||||
entry_writer_0->SetKeyValue(kKey0, kValue0);
|
||||
dictionary_writer.AddEntry(entry_writer_0.Pass());
|
||||
dictionary_writer.AddEntry(std::move(entry_writer_0));
|
||||
auto entry_writer_1 =
|
||||
make_scoped_ptr(new MinidumpSimpleStringDictionaryEntryWriter());
|
||||
entry_writer_1->SetKeyValue(kKey1, kValue1);
|
||||
dictionary_writer.AddEntry(entry_writer_1.Pass());
|
||||
dictionary_writer.AddEntry(std::move(entry_writer_1));
|
||||
auto entry_writer_2 =
|
||||
make_scoped_ptr(new MinidumpSimpleStringDictionaryEntryWriter());
|
||||
entry_writer_2->SetKeyValue(kKey2, kValue2);
|
||||
dictionary_writer.AddEntry(entry_writer_2.Pass());
|
||||
dictionary_writer.AddEntry(std::move(entry_writer_2));
|
||||
|
||||
EXPECT_TRUE(dictionary_writer.IsUseful());
|
||||
|
||||
@ -202,11 +203,11 @@ TEST(MinidumpSimpleStringDictionaryWriter, DuplicateKeyValue) {
|
||||
auto entry_writer_0 =
|
||||
make_scoped_ptr(new MinidumpSimpleStringDictionaryEntryWriter());
|
||||
entry_writer_0->SetKeyValue(kKey, kValue0);
|
||||
dictionary_writer.AddEntry(entry_writer_0.Pass());
|
||||
dictionary_writer.AddEntry(std::move(entry_writer_0));
|
||||
auto entry_writer_1 =
|
||||
make_scoped_ptr(new MinidumpSimpleStringDictionaryEntryWriter());
|
||||
entry_writer_1->SetKeyValue(kKey, kValue1);
|
||||
dictionary_writer.AddEntry(entry_writer_1.Pass());
|
||||
dictionary_writer.AddEntry(std::move(entry_writer_1));
|
||||
|
||||
EXPECT_TRUE(dictionary_writer.IsUseful());
|
||||
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "minidump/minidump_writer_util.h"
|
||||
#include "util/file/file_writer.h"
|
||||
@ -121,7 +123,7 @@ void MinidumpStringListWriter<MinidumpStringWriterType>::AddStringUTF8(
|
||||
const std::string& string_utf8) {
|
||||
auto string_writer = make_scoped_ptr(new MinidumpStringWriterType());
|
||||
string_writer->SetUTF8(string_utf8);
|
||||
AddChild(string_writer.Pass());
|
||||
AddChild(std::move(string_writer));
|
||||
}
|
||||
|
||||
template <typename MinidumpStringWriterType>
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "gtest/gtest.h"
|
||||
@ -83,7 +84,7 @@ TEST(MinidumpSystemInfoWriter, Empty) {
|
||||
|
||||
system_info_writer->SetCSDVersion(std::string());
|
||||
|
||||
minidump_file_writer.AddStream(system_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(system_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -154,7 +155,7 @@ TEST(MinidumpSystemInfoWriter, X86_Win) {
|
||||
system_info_writer->SetCPUX86VersionAndFeatures(kCPUVersion, kCPUFeatures);
|
||||
system_info_writer->SetCPUX86AMDExtendedFeatures(kAMDFeatures);
|
||||
|
||||
minidump_file_writer.AddStream(system_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(system_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -214,7 +215,7 @@ TEST(MinidumpSystemInfoWriter, AMD64_Mac) {
|
||||
system_info_writer->SetCSDVersion(kCSDVersion);
|
||||
system_info_writer->SetCPUOtherFeatures(kCPUFeatures[0], kCPUFeatures[1]);
|
||||
|
||||
minidump_file_writer.AddStream(system_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(system_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -256,7 +257,7 @@ TEST(MinidumpSystemInfoWriter, X86_CPUVendorFromRegisters) {
|
||||
kCPUVendor[0], kCPUVendor[1], kCPUVendor[2]);
|
||||
system_info_writer->SetCSDVersion(std::string());
|
||||
|
||||
minidump_file_writer.AddStream(system_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(system_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -336,7 +337,7 @@ TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_X86) {
|
||||
system_info_writer->InitializeFromSnapshot(&system_snapshot);
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.AddStream(system_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(system_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -431,7 +432,7 @@ TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_AMD64) {
|
||||
system_info_writer->InitializeFromSnapshot(&system_snapshot);
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.AddStream(system_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(system_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -469,7 +470,7 @@ TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_AMD64) {
|
||||
TEST(MinidumpSystemInfoWriterDeathTest, NoCSDVersion) {
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
auto system_info_writer = make_scoped_ptr(new MinidumpSystemInfoWriter());
|
||||
minidump_file_writer.AddStream(system_info_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(system_info_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_DEATH_CHECK(minidump_file_writer.WriteEverything(&string_file),
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "minidump/minidump_context_writer.h"
|
||||
#include "minidump/minidump_memory_writer.h"
|
||||
@ -52,12 +54,12 @@ void MinidumpThreadWriter::InitializeFromSnapshot(
|
||||
if (stack_snapshot && stack_snapshot->Size() > 0) {
|
||||
scoped_ptr<MinidumpMemoryWriter> stack =
|
||||
MinidumpMemoryWriter::CreateFromSnapshot(stack_snapshot);
|
||||
SetStack(stack.Pass());
|
||||
SetStack(std::move(stack));
|
||||
}
|
||||
|
||||
scoped_ptr<MinidumpContextWriter> context =
|
||||
MinidumpContextWriter::CreateFromSnapshot(thread_snapshot->Context());
|
||||
SetContext(context.Pass());
|
||||
SetContext(std::move(context));
|
||||
}
|
||||
|
||||
const MINIDUMP_THREAD* MinidumpThreadWriter::MinidumpThread() const {
|
||||
@ -69,14 +71,14 @@ const MINIDUMP_THREAD* MinidumpThreadWriter::MinidumpThread() const {
|
||||
void MinidumpThreadWriter::SetStack(scoped_ptr<MinidumpMemoryWriter> stack) {
|
||||
DCHECK_EQ(state(), kStateMutable);
|
||||
|
||||
stack_ = stack.Pass();
|
||||
stack_ = std::move(stack);
|
||||
}
|
||||
|
||||
void MinidumpThreadWriter::SetContext(
|
||||
scoped_ptr<MinidumpContextWriter> context) {
|
||||
DCHECK_EQ(state(), kStateMutable);
|
||||
|
||||
context_ = context.Pass();
|
||||
context_ = std::move(context);
|
||||
}
|
||||
|
||||
bool MinidumpThreadWriter::Freeze() {
|
||||
@ -148,7 +150,7 @@ void MinidumpThreadListWriter::InitializeFromSnapshot(
|
||||
for (const ThreadSnapshot* thread_snapshot : thread_snapshots) {
|
||||
auto thread = make_scoped_ptr(new MinidumpThreadWriter());
|
||||
thread->InitializeFromSnapshot(thread_snapshot, thread_id_map);
|
||||
AddThread(thread.Pass());
|
||||
AddThread(std::move(thread));
|
||||
}
|
||||
|
||||
// Do this in a separate loop to keep the thread stacks earlier in the dump,
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/format_macros.h"
|
||||
@ -83,7 +84,7 @@ TEST(MinidumpThreadWriter, EmptyThreadList) {
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
auto thread_list_writer = make_scoped_ptr(new MinidumpThreadListWriter());
|
||||
|
||||
minidump_file_writer.AddStream(thread_list_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(thread_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -160,10 +161,10 @@ TEST(MinidumpThreadWriter, OneThread_x86_NoStack) {
|
||||
|
||||
auto context_x86_writer = make_scoped_ptr(new MinidumpContextX86Writer());
|
||||
InitializeMinidumpContextX86(context_x86_writer->context(), kSeed);
|
||||
thread_writer->SetContext(context_x86_writer.Pass());
|
||||
thread_writer->SetContext(std::move(context_x86_writer));
|
||||
|
||||
thread_list_writer->AddThread(thread_writer.Pass());
|
||||
minidump_file_writer.AddStream(thread_list_writer.Pass());
|
||||
thread_list_writer->AddThread(std::move(thread_writer));
|
||||
minidump_file_writer.AddStream(std::move(thread_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -222,15 +223,15 @@ TEST(MinidumpThreadWriter, OneThread_AMD64_Stack) {
|
||||
|
||||
auto memory_writer = make_scoped_ptr(
|
||||
new TestMinidumpMemoryWriter(kMemoryBase, kMemorySize, kMemoryValue));
|
||||
thread_writer->SetStack(memory_writer.Pass());
|
||||
thread_writer->SetStack(std::move(memory_writer));
|
||||
|
||||
MSVC_SUPPRESS_WARNING(4316); // Object allocated on heap may not be aligned.
|
||||
auto context_amd64_writer = make_scoped_ptr(new MinidumpContextAMD64Writer());
|
||||
InitializeMinidumpContextAMD64(context_amd64_writer->context(), kSeed);
|
||||
thread_writer->SetContext(context_amd64_writer.Pass());
|
||||
thread_writer->SetContext(std::move(context_amd64_writer));
|
||||
|
||||
thread_list_writer->AddThread(thread_writer.Pass());
|
||||
minidump_file_writer.AddStream(thread_list_writer.Pass());
|
||||
thread_list_writer->AddThread(std::move(thread_writer));
|
||||
minidump_file_writer.AddStream(std::move(thread_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -300,13 +301,13 @@ TEST(MinidumpThreadWriter, ThreeThreads_x86_MemoryList) {
|
||||
|
||||
auto memory_writer_0 = make_scoped_ptr(
|
||||
new TestMinidumpMemoryWriter(kMemoryBase0, kMemorySize0, kMemoryValue0));
|
||||
thread_writer_0->SetStack(memory_writer_0.Pass());
|
||||
thread_writer_0->SetStack(std::move(memory_writer_0));
|
||||
|
||||
auto context_x86_writer_0 = make_scoped_ptr(new MinidumpContextX86Writer());
|
||||
InitializeMinidumpContextX86(context_x86_writer_0->context(), kSeed0);
|
||||
thread_writer_0->SetContext(context_x86_writer_0.Pass());
|
||||
thread_writer_0->SetContext(std::move(context_x86_writer_0));
|
||||
|
||||
thread_list_writer->AddThread(thread_writer_0.Pass());
|
||||
thread_list_writer->AddThread(std::move(thread_writer_0));
|
||||
|
||||
const uint32_t kThreadID1 = 2222222;
|
||||
const uint32_t kSuspendCount1 = 222222;
|
||||
@ -327,13 +328,13 @@ TEST(MinidumpThreadWriter, ThreeThreads_x86_MemoryList) {
|
||||
|
||||
auto memory_writer_1 = make_scoped_ptr(
|
||||
new TestMinidumpMemoryWriter(kMemoryBase1, kMemorySize1, kMemoryValue1));
|
||||
thread_writer_1->SetStack(memory_writer_1.Pass());
|
||||
thread_writer_1->SetStack(std::move(memory_writer_1));
|
||||
|
||||
auto context_x86_writer_1 = make_scoped_ptr(new MinidumpContextX86Writer());
|
||||
InitializeMinidumpContextX86(context_x86_writer_1->context(), kSeed1);
|
||||
thread_writer_1->SetContext(context_x86_writer_1.Pass());
|
||||
thread_writer_1->SetContext(std::move(context_x86_writer_1));
|
||||
|
||||
thread_list_writer->AddThread(thread_writer_1.Pass());
|
||||
thread_list_writer->AddThread(std::move(thread_writer_1));
|
||||
|
||||
const uint32_t kThreadID2 = 3333333;
|
||||
const uint32_t kSuspendCount2 = 333333;
|
||||
@ -354,16 +355,16 @@ TEST(MinidumpThreadWriter, ThreeThreads_x86_MemoryList) {
|
||||
|
||||
auto memory_writer_2 = make_scoped_ptr(
|
||||
new TestMinidumpMemoryWriter(kMemoryBase2, kMemorySize2, kMemoryValue2));
|
||||
thread_writer_2->SetStack(memory_writer_2.Pass());
|
||||
thread_writer_2->SetStack(std::move(memory_writer_2));
|
||||
|
||||
auto context_x86_writer_2 = make_scoped_ptr(new MinidumpContextX86Writer());
|
||||
InitializeMinidumpContextX86(context_x86_writer_2->context(), kSeed2);
|
||||
thread_writer_2->SetContext(context_x86_writer_2.Pass());
|
||||
thread_writer_2->SetContext(std::move(context_x86_writer_2));
|
||||
|
||||
thread_list_writer->AddThread(thread_writer_2.Pass());
|
||||
thread_list_writer->AddThread(std::move(thread_writer_2));
|
||||
|
||||
minidump_file_writer.AddStream(thread_list_writer.Pass());
|
||||
minidump_file_writer.AddStream(memory_list_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(thread_list_writer));
|
||||
minidump_file_writer.AddStream(std::move(memory_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -600,7 +601,7 @@ void RunInitializeFromSnapshotTest(bool thread_id_collision) {
|
||||
expect_threads[index].Stack.StartOfMemoryRange);
|
||||
memory_snapshot->SetSize(expect_threads[index].Stack.Memory.DataSize);
|
||||
memory_snapshot->SetValue(memory_values[index]);
|
||||
thread_snapshot->SetStack(memory_snapshot.Pass());
|
||||
thread_snapshot->SetStack(std::move(memory_snapshot));
|
||||
}
|
||||
|
||||
Traits::InitializeCPUContext(thread_snapshot->MutableContext(),
|
||||
@ -610,7 +611,7 @@ void RunInitializeFromSnapshotTest(bool thread_id_collision) {
|
||||
teb_snapshot->SetAddress(expect_threads[index].Teb);
|
||||
teb_snapshot->SetSize(kTebSize);
|
||||
teb_snapshot->SetValue(static_cast<char>('t' + index));
|
||||
thread_snapshot->AddExtraMemory(teb_snapshot.Pass());
|
||||
thread_snapshot->AddExtraMemory(std::move(teb_snapshot));
|
||||
|
||||
thread_snapshots.push_back(thread_snapshot);
|
||||
}
|
||||
@ -622,8 +623,8 @@ void RunInitializeFromSnapshotTest(bool thread_id_collision) {
|
||||
thread_list_writer->InitializeFromSnapshot(thread_snapshots, &thread_id_map);
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.AddStream(thread_list_writer.Pass());
|
||||
minidump_file_writer.AddStream(memory_list_writer.Pass());
|
||||
minidump_file_writer.AddStream(std::move(thread_list_writer));
|
||||
minidump_file_writer.AddStream(std::move(memory_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
|
||||
@ -700,8 +701,8 @@ TEST(MinidumpThreadWriterDeathTest, NoContext) {
|
||||
|
||||
auto thread_writer = make_scoped_ptr(new MinidumpThreadWriter());
|
||||
|
||||
thread_list_writer->AddThread(thread_writer.Pass());
|
||||
minidump_file_writer.AddStream(thread_list_writer.Pass());
|
||||
thread_list_writer->AddThread(std::move(thread_writer));
|
||||
minidump_file_writer.AddStream(std::move(thread_list_writer));
|
||||
|
||||
StringFile string_file;
|
||||
ASSERT_DEATH_CHECK(minidump_file_writer.WriteEverything(&string_file),
|
||||
|
@ -23,7 +23,7 @@
|
||||
#define PACKAGE_NAME "Crashpad"
|
||||
#define PACKAGE_STRING PACKAGE_NAME " " PACKAGE_VERSION
|
||||
#define PACKAGE_TARNAME "crashpad"
|
||||
#define PACKAGE_VERSION "0.7.0"
|
||||
#define PACKAGE_VERSION "0.8.0"
|
||||
#define PACKAGE_URL "https://crashpad.chromium.org/"
|
||||
|
||||
#endif // CRASHPAD_PACKAGE_H_
|
||||
|
@ -103,10 +103,14 @@
|
||||
'win/pe_image_annotations_reader.h',
|
||||
'win/pe_image_reader.cc',
|
||||
'win/pe_image_reader.h',
|
||||
'win/pe_image_resource_reader.cc',
|
||||
'win/pe_image_resource_reader.h',
|
||||
'win/process_reader_win.cc',
|
||||
'win/process_reader_win.h',
|
||||
'win/process_snapshot_win.cc',
|
||||
'win/process_snapshot_win.h',
|
||||
'win/process_subrange_reader.cc',
|
||||
'win/process_subrange_reader.h',
|
||||
'win/system_snapshot_win.cc',
|
||||
'win/system_snapshot_win.h',
|
||||
'win/thread_snapshot_win.cc',
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
@ -71,7 +72,9 @@ class TestProcessSnapshot final : public ProcessSnapshot {
|
||||
//!
|
||||
//! \param[in] system The system snapshot that System() will return. The
|
||||
//! TestProcessSnapshot object takes ownership of \a system.
|
||||
void SetSystem(scoped_ptr<SystemSnapshot> system) { system_ = system.Pass(); }
|
||||
void SetSystem(scoped_ptr<SystemSnapshot> system) {
|
||||
system_ = std::move(system);
|
||||
}
|
||||
|
||||
//! \brief Adds a thread snapshot to be returned by Threads().
|
||||
//!
|
||||
@ -94,7 +97,7 @@ class TestProcessSnapshot final : public ProcessSnapshot {
|
||||
//! \param[in] exception The exception snapshot that Exception() will return.
|
||||
//! The TestProcessSnapshot object takes ownership of \a exception.
|
||||
void SetException(scoped_ptr<ExceptionSnapshot> exception) {
|
||||
exception_ = exception.Pass();
|
||||
exception_ = std::move(exception);
|
||||
}
|
||||
|
||||
//! \brief Adds a memory map region snapshot to be returned by MemoryMap().
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
@ -55,7 +56,7 @@ class TestThreadSnapshot final : public ThreadSnapshot {
|
||||
//!
|
||||
//! \param[in] stack The memory region that Stack() will return. The
|
||||
//! TestThreadSnapshot object takes ownership of \a stack.
|
||||
void SetStack(scoped_ptr<MemorySnapshot> stack) { stack_ = stack.Pass(); }
|
||||
void SetStack(scoped_ptr<MemorySnapshot> stack) { stack_ = std::move(stack); }
|
||||
|
||||
void SetThreadID(uint64_t thread_id) { thread_id_ = thread_id; }
|
||||
void SetSuspendCount(int suspend_count) { suspend_count_ = suspend_count; }
|
||||
|
14
snapshot/win/end_to_end_test.py
Normal file → Executable file
14
snapshot/win/end_to_end_test.py
Normal file → Executable file
@ -221,12 +221,14 @@ def RunTests(cdb_path,
|
||||
out.Check('LastStatusValue: \(NTSTATUS\) 0xc000000f - {File Not Found} The '
|
||||
'file %hs does not exist.', '!gle gets last ntstatus')
|
||||
|
||||
out = CdbRun(cdb_path, dump_path, '!locks')
|
||||
out.Check(r'CritSec crashy_program!crashpad::`anonymous namespace\'::'
|
||||
r'g_test_critical_section', 'lock was captured')
|
||||
if platform.win32_ver()[0] != '7':
|
||||
# We can't allocate CRITICAL_SECTIONs with .DebugInfo on Win 7.
|
||||
out.Check(r'\*\*\* Locked', 'lock debug info was captured, and is locked')
|
||||
if False:
|
||||
# TODO(scottmg): Re-enable when we grab ntdll!RtlCriticalSectionList.
|
||||
out = CdbRun(cdb_path, dump_path, '!locks')
|
||||
out.Check(r'CritSec crashy_program!crashpad::`anonymous namespace\'::'
|
||||
r'g_test_critical_section', 'lock was captured')
|
||||
if platform.win32_ver()[0] != '7':
|
||||
# We can't allocate CRITICAL_SECTIONs with .DebugInfo on Win 7.
|
||||
out.Check(r'\*\*\* Locked', 'lock debug info was captured, and is locked')
|
||||
|
||||
out = CdbRun(cdb_path, dump_path, '!handle')
|
||||
out.Check(r'\d+ Handles', 'captured handles')
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "snapshot/win/pe_image_reader.h"
|
||||
#include "util/misc/tri_state.h"
|
||||
#include "util/misc/uuid.h"
|
||||
#include "util/win/module_version.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
@ -210,7 +209,7 @@ const VS_FIXEDFILEINFO* ModuleSnapshotWin::VSFixedFileInfo() const {
|
||||
|
||||
if (initialized_vs_fixed_file_info_.is_uninitialized()) {
|
||||
initialized_vs_fixed_file_info_.set_invalid();
|
||||
if (GetModuleVersionAndType(base::FilePath(name_), &vs_fixed_file_info_)) {
|
||||
if (pe_image_reader_->VSFixedFileInfo(&vs_fixed_file_info_)) {
|
||||
initialized_vs_fixed_file_info_.set_valid();
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,8 @@
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "client/crashpad_info.h"
|
||||
#include "snapshot/win/process_reader_win.h"
|
||||
#include "snapshot/win/pe_image_resource_reader.h"
|
||||
#include "util/misc/pdb_structures.h"
|
||||
#include "util/win/process_structs.h"
|
||||
|
||||
@ -28,13 +27,6 @@ namespace crashpad {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string RangeToString(const CheckedWinAddressRange& range) {
|
||||
return base::StringPrintf("[0x%llx + 0x%llx (%s)]",
|
||||
range.Base(),
|
||||
range.Size(),
|
||||
range.Is64Bit() ? "64" : "32");
|
||||
}
|
||||
|
||||
// Map from Traits to an IMAGE_NT_HEADERSxx.
|
||||
template <class Traits>
|
||||
struct NtHeadersForTraits;
|
||||
@ -52,9 +44,7 @@ struct NtHeadersForTraits<process_types::internal::Traits64> {
|
||||
} // namespace
|
||||
|
||||
PEImageReader::PEImageReader()
|
||||
: process_reader_(nullptr),
|
||||
module_range_(),
|
||||
module_name_(),
|
||||
: module_subrange_reader_(),
|
||||
initialized_() {
|
||||
}
|
||||
|
||||
@ -67,14 +57,10 @@ bool PEImageReader::Initialize(ProcessReaderWin* process_reader,
|
||||
const std::string& module_name) {
|
||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||
|
||||
process_reader_ = process_reader;
|
||||
module_range_.SetRange(process_reader_->Is64Bit(), address, size);
|
||||
if (!module_range_.IsValid()) {
|
||||
LOG(WARNING) << "invalid module range for " << module_name << ": "
|
||||
<< RangeToString(module_range_);
|
||||
if (!module_subrange_reader_.Initialize(
|
||||
process_reader, address, size, module_name)) {
|
||||
return false;
|
||||
}
|
||||
module_name_ = module_name;
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
@ -86,41 +72,41 @@ bool PEImageReader::GetCrashpadInfo(
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
IMAGE_SECTION_HEADER section;
|
||||
if (!GetSectionByName<NtHeadersForTraits<Traits>::type>("CPADinfo", §ion))
|
||||
if (!GetSectionByName<typename NtHeadersForTraits<Traits>::type>("CPADinfo",
|
||||
§ion)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (section.Misc.VirtualSize < sizeof(process_types::CrashpadInfo<Traits>)) {
|
||||
LOG(WARNING) << "small crashpad info section size "
|
||||
<< section.Misc.VirtualSize << ", " << module_name_;
|
||||
<< section.Misc.VirtualSize << ", "
|
||||
<< module_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
WinVMAddress crashpad_info_address = Address() + section.VirtualAddress;
|
||||
CheckedWinAddressRange crashpad_info_range(process_reader_->Is64Bit(),
|
||||
crashpad_info_address,
|
||||
section.Misc.VirtualSize);
|
||||
if (!crashpad_info_range.IsValid()) {
|
||||
LOG(WARNING) << "invalid range for crashpad info: "
|
||||
<< RangeToString(crashpad_info_range);
|
||||
ProcessSubrangeReader crashpad_info_subrange_reader;
|
||||
const WinVMAddress crashpad_info_address = Address() + section.VirtualAddress;
|
||||
if (!crashpad_info_subrange_reader.InitializeSubrange(
|
||||
module_subrange_reader_,
|
||||
crashpad_info_address,
|
||||
section.Misc.VirtualSize,
|
||||
"crashpad_info")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!module_range_.ContainsRange(crashpad_info_range)) {
|
||||
LOG(WARNING) << "crashpad info does not fall inside module "
|
||||
<< module_name_;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!process_reader_->ReadMemory(crashpad_info_address,
|
||||
sizeof(process_types::CrashpadInfo<Traits>),
|
||||
crashpad_info)) {
|
||||
LOG(WARNING) << "could not read crashpad info " << module_name_;
|
||||
if (!crashpad_info_subrange_reader.ReadMemory(
|
||||
crashpad_info_address,
|
||||
sizeof(process_types::CrashpadInfo<Traits>),
|
||||
crashpad_info)) {
|
||||
LOG(WARNING) << "could not read crashpad info from "
|
||||
<< module_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (crashpad_info->signature != CrashpadInfo::kSignature ||
|
||||
crashpad_info->version < 1) {
|
||||
LOG(WARNING) << "unexpected crashpad info data " << module_name_;
|
||||
LOG(WARNING) << "unexpected crashpad info data in "
|
||||
<< module_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -130,46 +116,23 @@ bool PEImageReader::GetCrashpadInfo(
|
||||
bool PEImageReader::DebugDirectoryInformation(UUID* uuid,
|
||||
DWORD* age,
|
||||
std::string* pdbname) const {
|
||||
if (process_reader_->Is64Bit()) {
|
||||
return ReadDebugDirectoryInformation<IMAGE_NT_HEADERS64>(
|
||||
uuid, age, pdbname);
|
||||
} else {
|
||||
return ReadDebugDirectoryInformation<IMAGE_NT_HEADERS32>(
|
||||
uuid, age, pdbname);
|
||||
}
|
||||
}
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
template <class NtHeadersType>
|
||||
bool PEImageReader::ReadDebugDirectoryInformation(UUID* uuid,
|
||||
DWORD* age,
|
||||
std::string* pdbname) const {
|
||||
NtHeadersType nt_headers;
|
||||
if (!ReadNtHeaders(&nt_headers, nullptr))
|
||||
IMAGE_DATA_DIRECTORY data_directory;
|
||||
if (!ImageDataDirectoryEntry(IMAGE_DIRECTORY_ENTRY_DEBUG, &data_directory))
|
||||
return false;
|
||||
|
||||
if (nt_headers.FileHeader.SizeOfOptionalHeader <
|
||||
offsetof(decltype(nt_headers.OptionalHeader),
|
||||
DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]) +
|
||||
sizeof(nt_headers.OptionalHeader
|
||||
.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]) ||
|
||||
nt_headers.OptionalHeader.NumberOfRvaAndSizes <=
|
||||
IMAGE_DIRECTORY_ENTRY_DEBUG) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const IMAGE_DATA_DIRECTORY& data_directory =
|
||||
nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
|
||||
if (data_directory.VirtualAddress == 0 || data_directory.Size == 0)
|
||||
return false;
|
||||
IMAGE_DEBUG_DIRECTORY debug_directory;
|
||||
if (data_directory.Size % sizeof(debug_directory) != 0)
|
||||
return false;
|
||||
for (size_t offset = 0; offset < data_directory.Size;
|
||||
offset += sizeof(debug_directory)) {
|
||||
if (!CheckedReadMemory(Address() + data_directory.VirtualAddress + offset,
|
||||
sizeof(debug_directory),
|
||||
&debug_directory)) {
|
||||
LOG(WARNING) << "could not read data directory";
|
||||
if (!module_subrange_reader_.ReadMemory(
|
||||
Address() + data_directory.VirtualAddress + offset,
|
||||
sizeof(debug_directory),
|
||||
&debug_directory)) {
|
||||
LOG(WARNING) << "could not read data directory from "
|
||||
<< module_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -178,21 +141,25 @@ bool PEImageReader::ReadDebugDirectoryInformation(UUID* uuid,
|
||||
|
||||
if (debug_directory.AddressOfRawData) {
|
||||
if (debug_directory.SizeOfData < sizeof(CodeViewRecordPDB70)) {
|
||||
LOG(WARNING) << "CodeView debug entry of unexpected size";
|
||||
LOG(WARNING) << "CodeView debug entry of unexpected size in "
|
||||
<< module_subrange_reader_.name();
|
||||
continue;
|
||||
}
|
||||
|
||||
scoped_ptr<char[]> data(new char[debug_directory.SizeOfData]);
|
||||
if (!CheckedReadMemory(Address() + debug_directory.AddressOfRawData,
|
||||
debug_directory.SizeOfData,
|
||||
data.get())) {
|
||||
LOG(WARNING) << "could not read debug directory";
|
||||
if (!module_subrange_reader_.ReadMemory(
|
||||
Address() + debug_directory.AddressOfRawData,
|
||||
debug_directory.SizeOfData,
|
||||
data.get())) {
|
||||
LOG(WARNING) << "could not read debug directory from "
|
||||
<< module_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*reinterpret_cast<DWORD*>(data.get()) !=
|
||||
CodeViewRecordPDB70::kSignature) {
|
||||
LOG(WARNING) << "encountered non-7.0 CodeView debug record";
|
||||
LOG(WARNING) << "encountered non-7.0 CodeView debug record in "
|
||||
<< module_subrange_reader_.name();
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -216,29 +183,120 @@ bool PEImageReader::ReadDebugDirectoryInformation(UUID* uuid,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PEImageReader::VSFixedFileInfo(
|
||||
VS_FIXEDFILEINFO* vs_fixed_file_info) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
IMAGE_DATA_DIRECTORY data_directory;
|
||||
if (!ImageDataDirectoryEntry(IMAGE_DIRECTORY_ENTRY_RESOURCE,
|
||||
&data_directory)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PEImageResourceReader resource_reader;
|
||||
if (!resource_reader.Initialize(module_subrange_reader_, data_directory)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WinVMAddress address;
|
||||
WinVMSize size;
|
||||
if (!resource_reader.FindResourceByID(
|
||||
reinterpret_cast<uint16_t>(VS_FILE_INFO), // RT_VERSION
|
||||
VS_VERSION_INFO,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
|
||||
&address,
|
||||
&size,
|
||||
nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This structure is not declared anywhere in the SDK, but is documented at
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms647001.aspx.
|
||||
struct VS_VERSIONINFO {
|
||||
WORD wLength;
|
||||
WORD wValueLength;
|
||||
WORD wType;
|
||||
|
||||
// The structure documentation on MSDN doesn’t show the [16], but it does
|
||||
// say that it’s supposed to be L"VS_VERSION_INFO", which is is in fact a
|
||||
// 16-character string (including its NUL terminator).
|
||||
WCHAR szKey[16];
|
||||
|
||||
WORD Padding1;
|
||||
VS_FIXEDFILEINFO Value;
|
||||
|
||||
// Don’t include Children or the Padding2 that precedes it, because they may
|
||||
// not be present.
|
||||
// WORD Padding2;
|
||||
// WORD Children;
|
||||
};
|
||||
VS_VERSIONINFO version_info;
|
||||
|
||||
if (size < sizeof(version_info)) {
|
||||
LOG(WARNING) << "version info size " << size
|
||||
<< " too small for structure of size " << sizeof(version_info)
|
||||
<< " in " << module_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!module_subrange_reader_.ReadMemory(
|
||||
address, sizeof(version_info), &version_info)) {
|
||||
LOG(WARNING) << "could not read version info from "
|
||||
<< module_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (version_info.wLength < sizeof(version_info) ||
|
||||
version_info.wValueLength != sizeof(version_info.Value) ||
|
||||
version_info.wType != 0 ||
|
||||
wcsncmp(version_info.szKey,
|
||||
L"VS_VERSION_INFO",
|
||||
arraysize(version_info.szKey)) != 0) {
|
||||
LOG(WARNING) << "unexpected VS_VERSIONINFO in "
|
||||
<< module_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (version_info.Value.dwSignature != VS_FFI_SIGNATURE ||
|
||||
version_info.Value.dwStrucVersion != VS_FFI_STRUCVERSION) {
|
||||
LOG(WARNING) << "unexpected VS_FIXEDFILEINFO in "
|
||||
<< module_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
*vs_fixed_file_info = version_info.Value;
|
||||
vs_fixed_file_info->dwFileFlags &= vs_fixed_file_info->dwFileFlagsMask;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class NtHeadersType>
|
||||
bool PEImageReader::ReadNtHeaders(NtHeadersType* nt_headers,
|
||||
WinVMAddress* nt_headers_address) const {
|
||||
IMAGE_DOS_HEADER dos_header;
|
||||
if (!CheckedReadMemory(Address(), sizeof(IMAGE_DOS_HEADER), &dos_header)) {
|
||||
LOG(WARNING) << "could not read dos header of " << module_name_;
|
||||
if (!module_subrange_reader_.ReadMemory(
|
||||
Address(), sizeof(IMAGE_DOS_HEADER), &dos_header)) {
|
||||
LOG(WARNING) << "could not read dos header from "
|
||||
<< module_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
LOG(WARNING) << "invalid e_magic in dos header of " << module_name_;
|
||||
LOG(WARNING) << "invalid e_magic in dos header of "
|
||||
<< module_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
WinVMAddress local_nt_headers_address = Address() + dos_header.e_lfanew;
|
||||
if (!CheckedReadMemory(
|
||||
if (!module_subrange_reader_.ReadMemory(
|
||||
local_nt_headers_address, sizeof(NtHeadersType), nt_headers)) {
|
||||
LOG(WARNING) << "could not read nt headers of " << module_name_;
|
||||
LOG(WARNING) << "could not read nt headers from "
|
||||
<< module_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nt_headers->Signature != IMAGE_NT_SIGNATURE) {
|
||||
LOG(WARNING) << "invalid signature in nt headers of " << module_name_;
|
||||
LOG(WARNING) << "invalid signature in nt headers of "
|
||||
<< module_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -267,9 +325,10 @@ bool PEImageReader::GetSectionByName(const std::string& name,
|
||||
for (DWORD i = 0; i < nt_headers.FileHeader.NumberOfSections; ++i) {
|
||||
WinVMAddress section_address =
|
||||
first_section_address + sizeof(IMAGE_SECTION_HEADER) * i;
|
||||
if (!CheckedReadMemory(
|
||||
if (!module_subrange_reader_.ReadMemory(
|
||||
section_address, sizeof(IMAGE_SECTION_HEADER), section)) {
|
||||
LOG(WARNING) << "could not read section " << i << " of " << module_name_;
|
||||
LOG(WARNING) << "could not read section " << i << " from "
|
||||
<< module_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
if (strncmp(reinterpret_cast<const char*>(section->Name),
|
||||
@ -282,20 +341,36 @@ bool PEImageReader::GetSectionByName(const std::string& name,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PEImageReader::CheckedReadMemory(WinVMAddress address,
|
||||
WinVMSize size,
|
||||
void* into) const {
|
||||
CheckedWinAddressRange read_range(process_reader_->Is64Bit(), address, size);
|
||||
if (!read_range.IsValid()) {
|
||||
LOG(WARNING) << "invalid read range: " << RangeToString(read_range);
|
||||
bool PEImageReader::ImageDataDirectoryEntry(size_t index,
|
||||
IMAGE_DATA_DIRECTORY* entry) const {
|
||||
bool rv;
|
||||
if (module_subrange_reader_.Is64Bit()) {
|
||||
rv = ImageDataDirectoryEntryT<IMAGE_NT_HEADERS64>(index, entry);
|
||||
} else {
|
||||
rv = ImageDataDirectoryEntryT<IMAGE_NT_HEADERS32>(index, entry);
|
||||
}
|
||||
|
||||
return rv && entry->VirtualAddress != 0 && entry->Size != 0;
|
||||
}
|
||||
|
||||
template <class NtHeadersType>
|
||||
bool PEImageReader::ImageDataDirectoryEntryT(
|
||||
size_t index,
|
||||
IMAGE_DATA_DIRECTORY* entry) const {
|
||||
NtHeadersType nt_headers;
|
||||
if (!ReadNtHeaders(&nt_headers, nullptr)) {
|
||||
return false;
|
||||
}
|
||||
if (!module_range_.ContainsRange(read_range)) {
|
||||
LOG(WARNING) << "attempt to read outside of module " << module_name_
|
||||
<< " at range: " << RangeToString(read_range);
|
||||
|
||||
if (nt_headers.FileHeader.SizeOfOptionalHeader <
|
||||
offsetof(decltype(nt_headers.OptionalHeader), DataDirectory[index]) +
|
||||
sizeof(nt_headers.OptionalHeader.DataDirectory[index]) ||
|
||||
nt_headers.OptionalHeader.NumberOfRvaAndSizes <= index) {
|
||||
return false;
|
||||
}
|
||||
return process_reader_->ReadMemory(address, size, into);
|
||||
|
||||
*entry = nt_headers.OptionalHeader.DataDirectory[index];
|
||||
return true;
|
||||
}
|
||||
|
||||
// Explicit instantiations with the only 2 valid template arguments to avoid
|
||||
|
@ -20,10 +20,10 @@
|
||||
#include <string>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "snapshot/win/process_subrange_reader.h"
|
||||
#include "util/misc/initialization_state_dcheck.h"
|
||||
#include "util/misc/uuid.h"
|
||||
#include "util/win/address_types.h"
|
||||
#include "util/win/checked_win_address_range.h"
|
||||
#include "util/win/process_structs.h"
|
||||
|
||||
namespace crashpad {
|
||||
@ -51,6 +51,7 @@ struct CrashpadInfo {
|
||||
//! bitness of the remote process.
|
||||
//!
|
||||
//! \sa PEImageAnnotationsReader
|
||||
//! \sa PEImageResourceReader
|
||||
class PEImageReader {
|
||||
public:
|
||||
PEImageReader();
|
||||
@ -65,8 +66,8 @@ class PEImageReader {
|
||||
//! \param[in] address The address, in the remote process' address space,
|
||||
//! where the `IMAGE_DOS_HEADER` is located.
|
||||
//! \param[in] size The size of the image.
|
||||
//! \param[in] name The module's name, a string to be used in logged messages.
|
||||
//! This string is for diagnostic purposes.
|
||||
//! \param[in] module_name The module's name, a string to be used in logged
|
||||
//! messages. This string is for diagnostic purposes.
|
||||
//!
|
||||
//! \return `true` if the image was read successfully, `false` otherwise, with
|
||||
//! an appropriate message logged.
|
||||
@ -78,12 +79,12 @@ class PEImageReader {
|
||||
//! \brief Returns the image's load address.
|
||||
//!
|
||||
//! This is the value passed as \a address to Initialize().
|
||||
WinVMAddress Address() const { return module_range_.Base(); }
|
||||
WinVMAddress Address() const { return module_subrange_reader_.Base(); }
|
||||
|
||||
//! \brief Returns the image's size.
|
||||
//!
|
||||
//! This is the value passed as \a size to Initialize().
|
||||
WinVMSize Size() const { return module_range_.Size(); }
|
||||
WinVMSize Size() const { return module_subrange_reader_.Size(); }
|
||||
|
||||
//! \brief Obtains the module's CrashpadInfo structure.
|
||||
//!
|
||||
@ -100,25 +101,34 @@ class PEImageReader {
|
||||
//! \param[out] age The age field for the pdb (the number of times it's been
|
||||
//! relinked).
|
||||
//! \param[out] pdbname Name of the pdb file.
|
||||
//! \return `true` on success, or `false` if the module has no debug directory
|
||||
//! entry.
|
||||
bool DebugDirectoryInformation(UUID* uuid,
|
||||
DWORD* age,
|
||||
std::string* pdbname) const;
|
||||
|
||||
private:
|
||||
//! \brief Implementation helper for DebugDirectoryInformation() templated by
|
||||
//! `IMAGE_NT_HEADERS` type for different bitnesses.
|
||||
//!
|
||||
//! \return `true` on success, with the parameters set appropriately. `false`
|
||||
//! on failure. This method may return `false` without logging anything in
|
||||
//! the case of a module that does not contain relevant debugging
|
||||
//! information but is otherwise properly structured.
|
||||
template <class NtHeadersType>
|
||||
bool ReadDebugDirectoryInformation(UUID* uuid,
|
||||
DWORD* age,
|
||||
std::string* pdbname) const;
|
||||
bool DebugDirectoryInformation(UUID* uuid,
|
||||
DWORD* age,
|
||||
std::string* pdbname) const;
|
||||
|
||||
//! \brief Obtains the module’s `VS_FIXEDFILEINFO`, containing its version and
|
||||
//! type information.
|
||||
//!
|
||||
//! The data obtained from this method should be equivalent to what could be
|
||||
//! obtained by calling GetModuleVersionAndType(). Avoiding that function
|
||||
//! ensures that the data in the module loaded into the remote process will be
|
||||
//! used as-is, without the risks associated with loading the module into the
|
||||
//! reading process.
|
||||
//!
|
||||
//! \param[out] vs_fixed_file_info The VS_FIXEDFILEINFO on success.
|
||||
//! VS_FIXEDFILEINFO::dwFileFlags will have been masked with
|
||||
//! VS_FIXEDFILEINFO::dwFileFlagsMask already.
|
||||
//!
|
||||
//! \return `true` on success. `false` if the module does not contain this
|
||||
//! information, without logging any messages. `false` on failure, with
|
||||
//! a message logged.
|
||||
bool VSFixedFileInfo(VS_FIXEDFILEINFO* vs_fixed_file_info) const;
|
||||
|
||||
private:
|
||||
//! \brief Reads the `IMAGE_NT_HEADERS` from the beginning of the image.
|
||||
//!
|
||||
//! \param[out] nt_headers The contents of the templated NtHeadersType
|
||||
@ -139,18 +149,25 @@ class PEImageReader {
|
||||
bool GetSectionByName(const std::string& name,
|
||||
IMAGE_SECTION_HEADER* section) const;
|
||||
|
||||
//! \brief Reads memory from target process, first checking whether the range
|
||||
//! requested falls inside module_range_.
|
||||
//! \brief Finds the `IMAGE_DATA_DIRECTORY` in
|
||||
//! `IMAGE_OPTIONAL_HEADER::DataDirectory` at the specified \a index.
|
||||
//!
|
||||
//! \return `true` on success, with \a into filled out, otherwise `false` and
|
||||
//! a message will be logged.
|
||||
bool CheckedReadMemory(WinVMAddress address,
|
||||
WinVMSize size,
|
||||
void* into) const;
|
||||
//! \param[in] index An `IMAGE_DIRECTORY_ENTRY_*` constant specifying the
|
||||
//! data to be returned.
|
||||
//! \param[out] entry The `IMAGE_DATA_DIRECTORY` found within the module.
|
||||
//!
|
||||
//! \return `true` on success, with \a entry set appropriately. `false` if the
|
||||
//! module does not contain the specified information, without logging a
|
||||
//! message. `false` on failure, with a message logged.
|
||||
bool ImageDataDirectoryEntry(size_t index, IMAGE_DATA_DIRECTORY* entry) const;
|
||||
|
||||
ProcessReaderWin* process_reader_; // weak
|
||||
CheckedWinAddressRange module_range_;
|
||||
std::string module_name_;
|
||||
//! \brief A templatized helper for ImageDataDirectoryEntry() to account for
|
||||
//! differences in \a NtHeadersType.
|
||||
template <class NtHeadersType>
|
||||
bool ImageDataDirectoryEntryT(size_t index,
|
||||
IMAGE_DATA_DIRECTORY* entry) const;
|
||||
|
||||
ProcessSubrangeReader module_subrange_reader_;
|
||||
InitializationStateDcheck initialized_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PEImageReader);
|
||||
|
@ -17,9 +17,14 @@
|
||||
#define PSAPI_VERSION 1
|
||||
#include <psapi.h>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "snapshot/win/process_reader_win.h"
|
||||
#include "test/errors.h"
|
||||
#include "util/win/get_function.h"
|
||||
#include "util/win/module_version.h"
|
||||
#include "util/win/process_info.h"
|
||||
|
||||
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||
|
||||
@ -28,9 +33,9 @@ namespace test {
|
||||
namespace {
|
||||
|
||||
BOOL CrashpadGetModuleInformation(HANDLE process,
|
||||
HMODULE module,
|
||||
MODULEINFO* module_info,
|
||||
DWORD cb) {
|
||||
HMODULE module,
|
||||
MODULEINFO* module_info,
|
||||
DWORD cb) {
|
||||
static const auto get_module_information =
|
||||
GET_FUNCTION_REQUIRED(L"psapi.dll", ::GetModuleInformation);
|
||||
return get_module_information(process, module, module_info, cb);
|
||||
@ -44,9 +49,10 @@ TEST(PEImageReader, DebugDirectory) {
|
||||
HMODULE self = reinterpret_cast<HMODULE>(&__ImageBase);
|
||||
MODULEINFO module_info;
|
||||
ASSERT_TRUE(CrashpadGetModuleInformation(
|
||||
GetCurrentProcess(), self, &module_info, sizeof(module_info)));
|
||||
GetCurrentProcess(), self, &module_info, sizeof(module_info)))
|
||||
<< ErrorMessage("GetModuleInformation");
|
||||
EXPECT_EQ(self, module_info.lpBaseOfDll);
|
||||
EXPECT_TRUE(pe_image_reader.Initialize(&process_reader,
|
||||
ASSERT_TRUE(pe_image_reader.Initialize(&process_reader,
|
||||
reinterpret_cast<WinVMAddress>(self),
|
||||
module_info.SizeOfImage,
|
||||
"self"));
|
||||
@ -61,6 +67,107 @@ TEST(PEImageReader, DebugDirectory) {
|
||||
pdbname.compare(pdbname.size() - suffix.size(), suffix.size(), suffix));
|
||||
}
|
||||
|
||||
void TestVSFixedFileInfo(ProcessReaderWin* process_reader,
|
||||
const ProcessInfo::Module& module,
|
||||
bool known_dll) {
|
||||
PEImageReader pe_image_reader;
|
||||
ASSERT_TRUE(pe_image_reader.Initialize(process_reader,
|
||||
module.dll_base,
|
||||
module.size,
|
||||
base::UTF16ToUTF8(module.name)));
|
||||
|
||||
VS_FIXEDFILEINFO observed;
|
||||
const bool observed_rv = pe_image_reader.VSFixedFileInfo(&observed);
|
||||
ASSERT_TRUE(observed_rv || !known_dll);
|
||||
|
||||
if (observed_rv) {
|
||||
EXPECT_EQ(VS_FFI_SIGNATURE, observed.dwSignature);
|
||||
EXPECT_EQ(VS_FFI_STRUCVERSION, observed.dwStrucVersion);
|
||||
EXPECT_EQ(0, observed.dwFileFlags & ~observed.dwFileFlagsMask);
|
||||
EXPECT_EQ(VOS_NT_WINDOWS32, observed.dwFileOS);
|
||||
if (known_dll) {
|
||||
EXPECT_EQ(VFT_DLL, observed.dwFileType);
|
||||
} else {
|
||||
EXPECT_TRUE(observed.dwFileType == VFT_APP ||
|
||||
observed.dwFileType == VFT_DLL);
|
||||
}
|
||||
}
|
||||
|
||||
base::FilePath module_path(module.name);
|
||||
|
||||
const DWORD version = GetVersion();
|
||||
const int major_version = LOBYTE(LOWORD(version));
|
||||
const int minor_version = HIBYTE(LOWORD(version));
|
||||
if (major_version > 6 || (major_version == 6 && minor_version >= 2)) {
|
||||
// Windows 8 or later.
|
||||
//
|
||||
// Use BaseName() to ensure that GetModuleVersionAndType() finds the
|
||||
// already-loaded module with the specified name. Otherwise, dwFileVersionMS
|
||||
// may not match. This appears to be related to the changes made in Windows
|
||||
// 8.1 to GetVersion() and GetVersionEx() for non-manifested applications
|
||||
module_path = module_path.BaseName();
|
||||
}
|
||||
|
||||
VS_FIXEDFILEINFO expected;
|
||||
const bool expected_rv = GetModuleVersionAndType(module_path, &expected);
|
||||
ASSERT_TRUE(expected_rv || !known_dll);
|
||||
|
||||
EXPECT_EQ(expected_rv, observed_rv);
|
||||
|
||||
if (observed_rv && expected_rv) {
|
||||
EXPECT_EQ(expected.dwSignature, observed.dwSignature);
|
||||
EXPECT_EQ(expected.dwStrucVersion, observed.dwStrucVersion);
|
||||
EXPECT_EQ(expected.dwFileVersionMS, observed.dwFileVersionMS);
|
||||
EXPECT_EQ(expected.dwFileVersionLS, observed.dwFileVersionLS);
|
||||
EXPECT_EQ(expected.dwProductVersionMS, observed.dwProductVersionMS);
|
||||
EXPECT_EQ(expected.dwProductVersionLS, observed.dwProductVersionLS);
|
||||
EXPECT_EQ(expected.dwFileFlagsMask, observed.dwFileFlagsMask);
|
||||
EXPECT_EQ(expected.dwFileFlags, observed.dwFileFlags);
|
||||
EXPECT_EQ(expected.dwFileOS, observed.dwFileOS);
|
||||
EXPECT_EQ(expected.dwFileType, observed.dwFileType);
|
||||
EXPECT_EQ(expected.dwFileSubtype, observed.dwFileSubtype);
|
||||
EXPECT_EQ(expected.dwFileDateMS, observed.dwFileDateMS);
|
||||
EXPECT_EQ(expected.dwFileDateLS, observed.dwFileDateLS);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PEImageReader, VSFixedFileInfo_OneModule) {
|
||||
ProcessReaderWin process_reader;
|
||||
ASSERT_TRUE(process_reader.Initialize(GetCurrentProcess(),
|
||||
ProcessSuspensionState::kRunning));
|
||||
|
||||
const wchar_t kModuleName[] = L"kernel32.dll";
|
||||
const HMODULE module_handle = GetModuleHandle(kModuleName);
|
||||
ASSERT_TRUE(module_handle) << ErrorMessage("GetModuleHandle");
|
||||
|
||||
MODULEINFO module_info;
|
||||
ASSERT_TRUE(CrashpadGetModuleInformation(
|
||||
GetCurrentProcess(), module_handle, &module_info, sizeof(module_info)))
|
||||
<< ErrorMessage("GetModuleInformation");
|
||||
EXPECT_EQ(module_handle, module_info.lpBaseOfDll);
|
||||
|
||||
ProcessInfo::Module module;
|
||||
module.name = kModuleName;
|
||||
module.dll_base = reinterpret_cast<WinVMAddress>(module_info.lpBaseOfDll);
|
||||
module.size = module_info.SizeOfImage;
|
||||
|
||||
TestVSFixedFileInfo(&process_reader, module, true);
|
||||
}
|
||||
|
||||
TEST(PEImageReader, VSFixedFileInfo_AllModules) {
|
||||
ProcessReaderWin process_reader;
|
||||
ASSERT_TRUE(process_reader.Initialize(GetCurrentProcess(),
|
||||
ProcessSuspensionState::kRunning));
|
||||
|
||||
const std::vector<ProcessInfo::Module>& modules = process_reader.Modules();
|
||||
EXPECT_GT(modules.size(), 2u);
|
||||
|
||||
for (const auto& module : modules) {
|
||||
SCOPED_TRACE(base::UTF16ToUTF8(module.name));
|
||||
TestVSFixedFileInfo(&process_reader, module, false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
279
snapshot/win/pe_image_resource_reader.cc
Normal file
279
snapshot/win/pe_image_resource_reader.cc
Normal file
@ -0,0 +1,279 @@
|
||||
// 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/win/pe_image_resource_reader.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void AddLanguageAndNeutralSublanguage(std::vector<uint16_t>* languages,
|
||||
uint16_t language) {
|
||||
languages->push_back(language);
|
||||
if (SUBLANGID(language) != SUBLANG_NEUTRAL) {
|
||||
languages->push_back(MAKELANGID(PRIMARYLANGID(language), SUBLANG_NEUTRAL));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
PEImageResourceReader::PEImageResourceReader()
|
||||
: resources_subrange_reader_(),
|
||||
module_base_(0),
|
||||
initialized_() {
|
||||
}
|
||||
|
||||
PEImageResourceReader::~PEImageResourceReader() {}
|
||||
|
||||
bool PEImageResourceReader::Initialize(
|
||||
const ProcessSubrangeReader& module_subrange_reader,
|
||||
const IMAGE_DATA_DIRECTORY& resources_directory_entry) {
|
||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||
|
||||
module_base_ = module_subrange_reader.Base();
|
||||
|
||||
if (!resources_subrange_reader_.InitializeSubrange(
|
||||
module_subrange_reader,
|
||||
module_base_ + resources_directory_entry.VirtualAddress,
|
||||
resources_directory_entry.Size,
|
||||
"resources")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PEImageResourceReader::FindResourceByID(uint16_t type,
|
||||
uint16_t name,
|
||||
uint16_t language,
|
||||
WinVMAddress* address,
|
||||
WinVMSize* size,
|
||||
uint32_t* code_page) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
// The root resource directory is at the beginning of the resources area
|
||||
// within the module.
|
||||
const uint32_t name_directory_offset =
|
||||
GetEntryFromResourceDirectoryByID(0, type, true);
|
||||
if (!name_directory_offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t language_directory_offset =
|
||||
GetEntryFromResourceDirectoryByID(name_directory_offset, name, true);
|
||||
if (!language_directory_offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The definition of IMAGE_RESOURCE_DIRECTORY_ENTRY in <winnt.h> has a comment
|
||||
// saying that its offsets are relative to “the resource directory of the data
|
||||
// associated with this directory entry”. That could be interpreted to mean
|
||||
// that language_directory_offset is relative to name_directory_offset, since
|
||||
// the language directory entry is found within the name directory. This is
|
||||
// not correct. All resource offsets are relative to the resources area within
|
||||
// the module.
|
||||
const uint32_t data_offset = GetEntryFromResourceDirectoryByLanguage(
|
||||
language_directory_offset, language);
|
||||
if (!data_offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IMAGE_RESOURCE_DATA_ENTRY data_entry;
|
||||
if (!resources_subrange_reader_.ReadMemory(
|
||||
resources_subrange_reader_.Base() + data_offset,
|
||||
sizeof(data_entry),
|
||||
&data_entry)) {
|
||||
LOG(WARNING) << "could not read resource data entry from "
|
||||
<< resources_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
// The definition of IMAGE_RESOURCE_DATA_ENTRY in <winnt.h> has a comment
|
||||
// saying that OffsetToData is relative to the beginning of the resource data.
|
||||
// This is not correct. It’s module-relative.
|
||||
*address = module_base_ + data_entry.OffsetToData;
|
||||
*size = data_entry.Size;
|
||||
if (code_page) {
|
||||
*code_page = data_entry.CodePage;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t PEImageResourceReader::GetEntryFromResourceDirectoryByID(
|
||||
uint32_t language_directory_offset,
|
||||
uint16_t id,
|
||||
bool want_subdirectory) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY> entries_by_id;
|
||||
if (!ReadResourceDirectory(
|
||||
language_directory_offset, nullptr, nullptr, &entries_by_id)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto entry_it =
|
||||
std::find_if(entries_by_id.begin(),
|
||||
entries_by_id.end(),
|
||||
[id](const IMAGE_RESOURCE_DIRECTORY_ENTRY& entry) {
|
||||
return !entry.NameIsString && entry.Id == id;
|
||||
});
|
||||
if (entry_it != entries_by_id.end()) {
|
||||
if ((entry_it->DataIsDirectory != 0) != want_subdirectory) {
|
||||
LOG(WARNING) << "expected " << (want_subdirectory ? "" : "non-")
|
||||
<< "directory for entry id " << id << " in "
|
||||
<< resources_subrange_reader_.name();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return entry_it->DataIsDirectory ? entry_it->OffsetToDirectory
|
||||
: entry_it->OffsetToData;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t PEImageResourceReader::GetEntryFromResourceDirectoryByLanguage(
|
||||
uint32_t resource_directory_offset,
|
||||
uint16_t language) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY> entries_by_language;
|
||||
if (!ReadResourceDirectory(
|
||||
resource_directory_offset, nullptr, nullptr, &entries_by_language)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (entries_by_language.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/cc194810.aspx
|
||||
//
|
||||
// TODO(mark): It seems like FindResourceEx() might do something more complex.
|
||||
// It would be best to mimic its behavior.
|
||||
std::vector<uint16_t> try_languages;
|
||||
if (PRIMARYLANGID(language) != LANG_NEUTRAL) {
|
||||
AddLanguageAndNeutralSublanguage(&try_languages, language);
|
||||
} else {
|
||||
if (SUBLANGID(language) != SUBLANG_SYS_DEFAULT) {
|
||||
AddLanguageAndNeutralSublanguage(&try_languages,
|
||||
LANGIDFROMLCID(GetThreadLocale()));
|
||||
AddLanguageAndNeutralSublanguage(&try_languages,
|
||||
LANGIDFROMLCID(GetUserDefaultLCID()));
|
||||
}
|
||||
if (SUBLANGID(language) != SUBLANG_DEFAULT) {
|
||||
AddLanguageAndNeutralSublanguage(&try_languages,
|
||||
LANGIDFROMLCID(GetSystemDefaultLCID()));
|
||||
}
|
||||
}
|
||||
|
||||
try_languages.push_back(MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
|
||||
try_languages.push_back(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT));
|
||||
|
||||
for (const auto try_language : try_languages) {
|
||||
const auto entry_it = std::find_if(
|
||||
entries_by_language.begin(),
|
||||
entries_by_language.end(),
|
||||
[try_language](const IMAGE_RESOURCE_DIRECTORY_ENTRY& entry) {
|
||||
return !entry.NameIsString && entry.Id == try_language;
|
||||
});
|
||||
if (entry_it != entries_by_language.end()) {
|
||||
if (entry_it->DataIsDirectory) {
|
||||
LOG(WARNING) << "expected non-directory for entry language "
|
||||
<< try_language << " in "
|
||||
<< resources_subrange_reader_.name();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return entry_it->OffsetToData;
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to the first entry in the list.
|
||||
const auto& entry = entries_by_language.front();
|
||||
if (entry.DataIsDirectory) {
|
||||
LOG(WARNING) << "expected non-directory for entry in "
|
||||
<< resources_subrange_reader_.name();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return entry.OffsetToData;
|
||||
}
|
||||
|
||||
bool PEImageResourceReader::ReadResourceDirectory(
|
||||
uint32_t resource_directory_offset,
|
||||
IMAGE_RESOURCE_DIRECTORY* resource_directory,
|
||||
std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY>* named_entries,
|
||||
std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY>* id_entries) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
// resource_directory is optional, but it’s still needed locally even if the
|
||||
// caller isn’t interested in it.
|
||||
scoped_ptr<IMAGE_RESOURCE_DIRECTORY> local_resource_directory;
|
||||
if (!resource_directory) {
|
||||
local_resource_directory.reset(new IMAGE_RESOURCE_DIRECTORY);
|
||||
resource_directory = local_resource_directory.get();
|
||||
}
|
||||
|
||||
const WinVMAddress address =
|
||||
resources_subrange_reader_.Base() + resource_directory_offset;
|
||||
|
||||
if (!resources_subrange_reader_.ReadMemory(
|
||||
address, sizeof(*resource_directory), resource_directory)) {
|
||||
LOG(WARNING) << "could not read resource directory from "
|
||||
<< resources_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (named_entries) {
|
||||
named_entries->clear();
|
||||
named_entries->resize(resource_directory->NumberOfNamedEntries);
|
||||
if (!named_entries->empty() &&
|
||||
!resources_subrange_reader_.ReadMemory(
|
||||
address + sizeof(*resource_directory),
|
||||
named_entries->size() * sizeof((*named_entries)[0]),
|
||||
&(*named_entries)[0])) {
|
||||
LOG(WARNING) << "could not read resource directory named entries from "
|
||||
<< resources_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (id_entries) {
|
||||
id_entries->clear();
|
||||
id_entries->resize(resource_directory->NumberOfIdEntries);
|
||||
if (!id_entries->empty() &&
|
||||
!resources_subrange_reader_.ReadMemory(
|
||||
address + sizeof(*resource_directory) +
|
||||
resource_directory->NumberOfNamedEntries *
|
||||
sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY),
|
||||
id_entries->size() * sizeof((*id_entries)[0]),
|
||||
&(*id_entries)[0])) {
|
||||
LOG(WARNING) << "could not read resource directory ID entries from "
|
||||
<< resources_subrange_reader_.name();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
179
snapshot/win/pe_image_resource_reader.h
Normal file
179
snapshot/win/pe_image_resource_reader.h
Normal file
@ -0,0 +1,179 @@
|
||||
// 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_WIN_PE_IMAGE_RESOURCE_READER_H_
|
||||
#define CRASHPAD_SNAPSHOT_WIN_PE_IMAGE_RESOURCE_READER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "snapshot/win/process_subrange_reader.h"
|
||||
#include "util/misc/initialization_state_dcheck.h"
|
||||
#include "util/win/address_types.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
//! \brief A reader for resources stored in PE images mapped into another
|
||||
//! process.
|
||||
//!
|
||||
//! \sa PEImageReader
|
||||
class PEImageResourceReader {
|
||||
public:
|
||||
PEImageResourceReader();
|
||||
~PEImageResourceReader();
|
||||
|
||||
//! \brief Initializes the resource reader.
|
||||
//!
|
||||
//! \param[in] module_subrange_reader The reader for the module.
|
||||
//! \param[in] resources_directory_entry The module’s `IMAGE_DATA_DIRECTORY`
|
||||
//! for its resources area. This is taken from the module’s
|
||||
//! `IMAGE_OPTIONAL_HEADER::DataDirectory` at index
|
||||
//! `IMAGE_DIRECTORY_ENTRY_RESOURCE`.
|
||||
//!
|
||||
//! \return `true` on success, `false` on failure with a message logged.
|
||||
bool Initialize(const ProcessSubrangeReader& module_subrange_reader,
|
||||
const IMAGE_DATA_DIRECTORY& resources_directory_entry);
|
||||
|
||||
//! \brief Locates a resource in a module by its ID.
|
||||
//!
|
||||
//! This method is similar to `FindResourceEx()`, but it operates on modules
|
||||
//! loaded in a remote process’ address space. It is not necessary to
|
||||
//! `LoadLibrary()` a module into a process in order to use this method.
|
||||
//!
|
||||
//! No support is provided at present for locating resources by \a type or \a
|
||||
//! name using strings as opposed to integer identifiers.
|
||||
//!
|
||||
//! Languages are scanned in the order determined by
|
||||
//! GetEntryFromResourceDirectoryByLanguage().
|
||||
//!
|
||||
//! \param[in] type The integer identifier of the resource type, as in the
|
||||
//! `lpType` parameter of `FindResourceEx()`.
|
||||
//! \param[in] name The integer identifier of the resource, as in the `lpName`
|
||||
//! parameter of `FindResourceEx()`.
|
||||
//! \param[in] language The language of the resource, as in the `wLanguage`
|
||||
//! parameter of `FindResourceEx()`.
|
||||
//! \param[out] address The address, in the remote process’ address space, of
|
||||
//! the resource data.
|
||||
//! \param[out] size The size of the resource data.
|
||||
//! \param[out] code_page The code page used to encode textual resource data.
|
||||
//! This parameter is optional.
|
||||
//!
|
||||
//! \return `true` on success, with the out parameters set appropriately.
|
||||
//! `false` if the resource was not found, without logging any messages.
|
||||
//! `false` on failure, with a message logged.
|
||||
bool FindResourceByID(uint16_t type,
|
||||
uint16_t name,
|
||||
uint16_t language,
|
||||
WinVMAddress* address,
|
||||
WinVMSize* size,
|
||||
uint32_t* code_page) const;
|
||||
|
||||
private:
|
||||
//! \brief Locates a resource directory entry within a resource directory by
|
||||
//! integer ID.
|
||||
//!
|
||||
//! \param[in] resource_directory_offset The offset, in the module’s resources
|
||||
//! area, of the resource directory to search.
|
||||
//! \param[in] id The integer identifier of the resource to search for.
|
||||
//! \param[in] want_subdirectory `true` if the resource directory entry is
|
||||
//! expected to be a resource directory itself, `false` otherwise.
|
||||
//!
|
||||
//! \return The offset, in the module’s resources area, of the entry that was
|
||||
//! found. On failure, `0`. `0` is technically a valid offset, but it
|
||||
//! corresponds to the root resource directory, which should never be the
|
||||
//! offset of another resource directory entry. If \a id was not found,
|
||||
//! `0` will be returned without logging anything. For other failures, a
|
||||
//! message will be logged.
|
||||
uint32_t GetEntryFromResourceDirectoryByID(uint32_t resource_directory_offset,
|
||||
uint16_t id,
|
||||
bool want_subdirectory) const;
|
||||
|
||||
//! \brief Locates a resource directory entry within a resource directory by
|
||||
//! language.
|
||||
//!
|
||||
//! This method is similar to GetEntryFromResourceDirectoryByID() with \a
|
||||
//! want_subdirectory set to `false`. Attempts are made to locate the resource
|
||||
//! by using these languages:
|
||||
//! <ul>
|
||||
//! <li>If \a language is `LANG_NEUTRAL`:</li>
|
||||
//! <ul>
|
||||
//! <li>Unless `SUBLANG_SYS_DEFAULT` is specified, the language of the
|
||||
//! thread’s locale, with its normal sublanguage and with
|
||||
//! `SUBLANG_NEUTRAL`.</li>
|
||||
//! <li>Unless `SUBLANG_SYS_DEFAULT` is specified, the language of the
|
||||
//! user’s default locale, with its normal sublanguage and with
|
||||
//! `SUBLANG_NEUTRAL`.</li>
|
||||
//! <li>Unless `SUBLANG_DEFAULT` is specified, the language of the
|
||||
//! system’s default locale, with its normal sublanguage and with
|
||||
//! `SUBLANG_NEUTRAL`.</li>
|
||||
//! </ul>
|
||||
//! <li>If \a language is not `LANG_NEUTRAL`:</li>
|
||||
//! <ul>
|
||||
//! <li>\a language</li>
|
||||
//! <li>\a language, with `SUBLANG_NEUTRAL`</li>
|
||||
//! </ul>
|
||||
//! <li>`LANG_NEUTRAL` with `SUBLANG_NEUTRAL`</li>
|
||||
//! <li>`LANG_ENGLISH` with `SUBLANG_DEFAULT`</li>
|
||||
//! <li>If none of the above match, the first language found</li>
|
||||
//! </ul>
|
||||
//!
|
||||
//! If only a specific language is desired without any fallbacks, call
|
||||
//! GetEntryFromResourceDirectoryByID() with the language directory’s offset
|
||||
//! instead, passing the desired language in the \a id parameter, and `false`
|
||||
//! for \a want_subdirectory.
|
||||
//!
|
||||
//! \param[in] language_directory_offset The offset, in the module’s resources
|
||||
//! area, of the resource directory to search.
|
||||
//! \param[in] language The language of the resource to search for.
|
||||
//!
|
||||
//! \return The return value is as in GetEntryFromResourceDirectoryByID().
|
||||
uint32_t GetEntryFromResourceDirectoryByLanguage(
|
||||
uint32_t language_directory_offset,
|
||||
uint16_t language) const;
|
||||
|
||||
//! \brief Reads a resource directory.
|
||||
//!
|
||||
//! \param[in] resource_directory_offset The offset, in the module’s resources
|
||||
//! area, of the resource directory to read.
|
||||
//! \param[out] resource_directory The `IMAGE_RESOURCE_DIRECTORY` structure.
|
||||
//! This parameter is optional.
|
||||
//! \param[out] named_entries A vector of \a
|
||||
//! resource_directory->NumberOfNamedEntries
|
||||
//! `IMAGE_RESOURCE_DIRECTORY_ENTRY` items that follow the resource
|
||||
//! directory. This parameter is optional.
|
||||
//! \param[out] id_entries A vector of \a
|
||||
//! resource_directory->NumberOfIdEntries `IMAGE_RESOURCE_DIRECTORY_ENTRY`
|
||||
//! items that follow the named entries. This parameter is optional.
|
||||
//!
|
||||
//! \return `true` on success, with the out parameters set appropriately.
|
||||
//! `false` on failure with a message logged.
|
||||
bool ReadResourceDirectory(
|
||||
uint32_t resource_directory_offset,
|
||||
IMAGE_RESOURCE_DIRECTORY* resource_directory,
|
||||
std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY>* named_entries,
|
||||
std::vector<IMAGE_RESOURCE_DIRECTORY_ENTRY>* id_entries) const;
|
||||
|
||||
ProcessSubrangeReader resources_subrange_reader_;
|
||||
WinVMAddress module_base_;
|
||||
InitializationStateDcheck initialized_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PEImageResourceReader);
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_SNAPSHOT_WIN_PE_IMAGE_RESOURCE_READER_H_
|
@ -136,7 +136,7 @@ bool FillThreadContextAndSuspendCount(HANDLE thread_handle,
|
||||
CaptureContext(&thread->context.native);
|
||||
} else {
|
||||
DWORD previous_suspend_count = SuspendThread(thread_handle);
|
||||
if (previous_suspend_count == -1) {
|
||||
if (previous_suspend_count == static_cast<DWORD>(-1)) {
|
||||
PLOG(ERROR) << "SuspendThread";
|
||||
return false;
|
||||
}
|
||||
|
@ -326,15 +326,16 @@ void ProcessSnapshotWin::InitializePebData(
|
||||
DetermineSizeOfEnvironmentBlock(process_parameters.Environment),
|
||||
&extra_memory_);
|
||||
|
||||
// Walk the loader lock which is directly referenced by the PEB. It may or may
|
||||
// not have a .DebugInfo list, but doesn't on more recent OSs (it does on
|
||||
// Vista). If it does, then we may walk the lock list more than once, but
|
||||
// AddMemorySnapshot() will take care of deduplicating the added regions.
|
||||
ReadLocks<Traits>(peb_data.LoaderLock, &extra_memory_);
|
||||
// Walk the loader lock which is directly referenced by the PEB.
|
||||
ReadLock<Traits>(peb_data.LoaderLock, &extra_memory_);
|
||||
|
||||
// Traverse the locks with valid .DebugInfo if a starting point was supplied.
|
||||
if (debug_critical_section_address)
|
||||
ReadLocks<Traits>(debug_critical_section_address, &extra_memory_);
|
||||
// TODO(scottmg): Use debug_critical_section_address to walk the list of
|
||||
// locks (see history of this file for walking code). In some configurations
|
||||
// this can walk many thousands of locks, so we may want to get some
|
||||
// annotation from the client for which locks to grab. Unfortunately, without
|
||||
// walking the list, the !locks command in windbg won't work because it
|
||||
// requires the lock pointed to by ntdll!RtlCriticalSectionList, which we
|
||||
// won't have captured.
|
||||
}
|
||||
|
||||
void ProcessSnapshotWin::AddMemorySnapshot(
|
||||
@ -380,9 +381,9 @@ void ProcessSnapshotWin::AddMemorySnapshotForLdrLIST_ENTRY(
|
||||
PointerVector<internal::MemorySnapshotWin>* into) {
|
||||
// Walk the doubly-linked list of entries, adding the list memory itself, as
|
||||
// well as pointed-to strings.
|
||||
Traits::Pointer last = le.Blink;
|
||||
typename Traits::Pointer last = le.Blink;
|
||||
process_types::LDR_DATA_TABLE_ENTRY<Traits> entry;
|
||||
Traits::Pointer cur = le.Flink;
|
||||
typename Traits::Pointer cur = le.Flink;
|
||||
for (;;) {
|
||||
// |cur| is the pointer to LIST_ENTRY embedded in the LDR_DATA_TABLE_ENTRY.
|
||||
// So we need to offset back to the beginning of the structure.
|
||||
@ -425,7 +426,7 @@ WinVMSize ProcessSnapshotWin::DetermineSizeOfEnvironmentBlock(
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void ProcessSnapshotWin::ReadLocks(
|
||||
void ProcessSnapshotWin::ReadLock(
|
||||
WinVMAddress start,
|
||||
PointerVector<internal::MemorySnapshotWin>* into) {
|
||||
// We're walking the RTL_CRITICAL_SECTION_DEBUG ProcessLocksList, but starting
|
||||
@ -439,82 +440,17 @@ void ProcessSnapshotWin::ReadLocks(
|
||||
return;
|
||||
}
|
||||
|
||||
AddMemorySnapshot(
|
||||
start, sizeof(process_types::RTL_CRITICAL_SECTION<Traits>), into);
|
||||
|
||||
const decltype(critical_section.DebugInfo) kInvalid =
|
||||
static_cast<decltype(critical_section.DebugInfo)>(-1);
|
||||
if (critical_section.DebugInfo == kInvalid)
|
||||
return;
|
||||
|
||||
const WinVMAddress start_address_backward = critical_section.DebugInfo;
|
||||
WinVMAddress current_address = start_address_backward;
|
||||
WinVMAddress last_good_address;
|
||||
|
||||
// Typically, this seems to be a circular list, but it's not clear that it
|
||||
// always is, so follow Blink fields back to the head (or where we started)
|
||||
// before following Flink to capture memory.
|
||||
do {
|
||||
last_good_address = current_address;
|
||||
// Read the RTL_CRITICAL_SECTION_DEBUG structure to get ProcessLocksList.
|
||||
process_types::RTL_CRITICAL_SECTION_DEBUG<Traits> critical_section_debug;
|
||||
if (!process_reader_.ReadMemory(current_address,
|
||||
sizeof(critical_section_debug),
|
||||
&critical_section_debug)) {
|
||||
LOG(ERROR) << "failed to read RTL_CRITICAL_SECTION_DEBUG";
|
||||
return;
|
||||
}
|
||||
|
||||
if (critical_section_debug.ProcessLocksList.Blink == 0) {
|
||||
// At the head of the list.
|
||||
break;
|
||||
}
|
||||
|
||||
// Move to the previous RTL_CRITICAL_SECTION_DEBUG by walking
|
||||
// ProcessLocksList.Blink.
|
||||
current_address =
|
||||
critical_section_debug.ProcessLocksList.Blink -
|
||||
offsetof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>,
|
||||
ProcessLocksList);
|
||||
} while (current_address != start_address_backward &&
|
||||
current_address != kInvalid);
|
||||
|
||||
if (current_address == kInvalid) {
|
||||
// Unexpectedly encountered a bad record, so step back one.
|
||||
current_address = last_good_address;
|
||||
}
|
||||
|
||||
const WinVMAddress start_address_forward = current_address;
|
||||
|
||||
// current_address is now the head of the list, walk Flink to add the whole
|
||||
// list.
|
||||
do {
|
||||
// Read the RTL_CRITICAL_SECTION_DEBUG structure to get ProcessLocksList.
|
||||
process_types::RTL_CRITICAL_SECTION_DEBUG<Traits> critical_section_debug;
|
||||
if (!process_reader_.ReadMemory(current_address,
|
||||
sizeof(critical_section_debug),
|
||||
&critical_section_debug)) {
|
||||
LOG(ERROR) << "failed to read RTL_CRITICAL_SECTION_DEBUG";
|
||||
return;
|
||||
}
|
||||
|
||||
// Add both RTL_CRITICAL_SECTION_DEBUG and RTL_CRITICAL_SECTION to the extra
|
||||
// memory to be saved.
|
||||
AddMemorySnapshot(current_address,
|
||||
sizeof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>),
|
||||
into);
|
||||
AddMemorySnapshot(critical_section_debug.CriticalSection,
|
||||
sizeof(process_types::RTL_CRITICAL_SECTION<Traits>),
|
||||
into);
|
||||
|
||||
if (critical_section_debug.ProcessLocksList.Flink == 0)
|
||||
break;
|
||||
|
||||
// Move to the next RTL_CRITICAL_SECTION_DEBUG by walking
|
||||
// ProcessLocksList.Flink.
|
||||
current_address =
|
||||
critical_section_debug.ProcessLocksList.Flink -
|
||||
offsetof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>,
|
||||
ProcessLocksList);
|
||||
} while (current_address != start_address_forward &&
|
||||
current_address != kInvalid);
|
||||
AddMemorySnapshot(critical_section.DebugInfo,
|
||||
sizeof(process_types::RTL_CRITICAL_SECTION_DEBUG<Traits>),
|
||||
into);
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -168,13 +168,11 @@ class ProcessSnapshotWin final : public ProcessSnapshot {
|
||||
WinVMSize DetermineSizeOfEnvironmentBlock(
|
||||
WinVMAddress start_of_environment_block);
|
||||
|
||||
// Starting from the address of a CRITICAL_SECTION, walks the doubly-linked
|
||||
// list stored in RTL_CRITICAL_SECTION.DebugInfo.ProcessLocksList adding both
|
||||
// the RTL_CRITICAL_SECTION and the RTL_CRITICAL_SECTION_DEBUG memory blocks
|
||||
// to the snapshot.
|
||||
// Starting from the address of a CRITICAL_SECTION, add a lock and, if valid,
|
||||
// its .DebugInfo field to the snapshot.
|
||||
template <class Traits>
|
||||
void ReadLocks(WinVMAddress start,
|
||||
PointerVector<internal::MemorySnapshotWin>* into);
|
||||
void ReadLock(WinVMAddress start,
|
||||
PointerVector<internal::MemorySnapshotWin>* into);
|
||||
|
||||
internal::SystemSnapshotWin system_;
|
||||
PointerVector<internal::MemorySnapshotWin> extra_memory_;
|
||||
|
104
snapshot/win/process_subrange_reader.cc
Normal file
104
snapshot/win/process_subrange_reader.cc
Normal file
@ -0,0 +1,104 @@
|
||||
// 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/win/process_subrange_reader.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "snapshot/win/process_reader_win.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
ProcessSubrangeReader::ProcessSubrangeReader()
|
||||
: name_(),
|
||||
range_(),
|
||||
process_reader_(nullptr) {
|
||||
}
|
||||
|
||||
ProcessSubrangeReader::~ProcessSubrangeReader() {
|
||||
}
|
||||
|
||||
bool ProcessSubrangeReader::Initialize(ProcessReaderWin* process_reader,
|
||||
WinVMAddress base,
|
||||
WinVMSize size,
|
||||
const std::string& name) {
|
||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||
|
||||
if (!InitializeInternal(process_reader, base, size, name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProcessSubrangeReader::InitializeSubrange(
|
||||
const ProcessSubrangeReader& that,
|
||||
WinVMAddress base,
|
||||
WinVMSize size,
|
||||
const std::string& sub_name) {
|
||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||
INITIALIZATION_STATE_DCHECK_VALID(that.initialized_);
|
||||
|
||||
if (!InitializeInternal(
|
||||
that.process_reader_, base, size, that.name_ + " " + sub_name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!that.range_.ContainsRange(range_)) {
|
||||
LOG(WARNING) << "range " << range_.AsString() << " outside of range "
|
||||
<< that.range_.AsString() << " for " << name_;
|
||||
return false;
|
||||
}
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProcessSubrangeReader::ReadMemory(WinVMAddress address,
|
||||
WinVMSize size,
|
||||
void* into) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
CheckedWinAddressRange read_range(process_reader_->Is64Bit(), address, size);
|
||||
if (!read_range.IsValid()) {
|
||||
LOG(WARNING) << "invalid read range " << read_range.AsString();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!range_.ContainsRange(read_range)) {
|
||||
LOG(WARNING) << "attempt to read outside of " << name_ << " range "
|
||||
<< range_.AsString() << " at range " << read_range.AsString();
|
||||
return false;
|
||||
}
|
||||
|
||||
return process_reader_->ReadMemory(address, size, into);
|
||||
}
|
||||
|
||||
bool ProcessSubrangeReader::InitializeInternal(ProcessReaderWin* process_reader,
|
||||
WinVMAddress base,
|
||||
WinVMSize size,
|
||||
const std::string& name) {
|
||||
range_.SetRange(process_reader->Is64Bit(), base, size);
|
||||
if (!range_.IsValid()) {
|
||||
LOG(WARNING) << "invalid range " << range_.AsString() << " for " << name;
|
||||
return false;
|
||||
}
|
||||
|
||||
name_ = name;
|
||||
process_reader_ = process_reader;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
114
snapshot/win/process_subrange_reader.h
Normal file
114
snapshot/win/process_subrange_reader.h
Normal file
@ -0,0 +1,114 @@
|
||||
// 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_WIN_PROCESS_SUBRANGE_READER_WIN_H_
|
||||
#define CRASHPAD_SNAPSHOT_WIN_PROCESS_SUBRANGE_READER_WIN_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "util/misc/initialization_state_dcheck.h"
|
||||
#include "util/win/address_types.h"
|
||||
#include "util/win/checked_win_address_range.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
class ProcessReaderWin;
|
||||
|
||||
//! \brief A wrapper for ProcessReaderWin that only allows a specific subrange
|
||||
//! to be read from.
|
||||
//!
|
||||
//! This class is useful to restrict reads to a specific address range, such as
|
||||
//! the address range occupied by a loaded module, or a specific section within
|
||||
//! a module.
|
||||
class ProcessSubrangeReader {
|
||||
public:
|
||||
ProcessSubrangeReader();
|
||||
~ProcessSubrangeReader();
|
||||
|
||||
//! \brief Initializes the object.
|
||||
//!
|
||||
//! \param[in] process_reader A reader for a remote process.
|
||||
//! \param[in] base The base address for the range that reads should be
|
||||
//! restricted to.
|
||||
//! \param[in] size The size of the range that reads should be restricted to.
|
||||
//! \param[in] name The range’s name, a string to be used in logged messages.
|
||||
//! This string is for diagnostic purposes.
|
||||
//!
|
||||
//! \return `true` on success, `false` on failure with a message logged. The
|
||||
//! other methods in this class must not be called unless this method or
|
||||
//! InitializeSubrange() has returned true.
|
||||
bool Initialize(ProcessReaderWin* process_reader,
|
||||
WinVMAddress base,
|
||||
WinVMSize size,
|
||||
const std::string& name);
|
||||
|
||||
//! \brief Initializes the object to a subrange of an existing
|
||||
//! ProcessSubrangeReader.
|
||||
//!
|
||||
//! The subrange identified by \a base and \a size must be contained within
|
||||
//! the subrange in \a that.
|
||||
//!
|
||||
//! \param[in] that The existing ProcessSubrangeReader to base the new object
|
||||
//! on.
|
||||
//! \param[in] base The base address for the range that reads should be
|
||||
//! restricted to.
|
||||
//! \param[in] size The size of the range that reads should be restricted to.
|
||||
//! \param[in] sub_name A description of the subrange, which will be appended
|
||||
//! to the \a name in \a that and used in logged messages. This string is
|
||||
//! for diagnostic purposes.
|
||||
//!
|
||||
//! \return `true` on success, `false` on failure with a message logged. The
|
||||
//! other methods in this class must not be called unless this method or
|
||||
//! Initialize() has returned true.
|
||||
bool InitializeSubrange(const ProcessSubrangeReader& that,
|
||||
WinVMAddress base,
|
||||
WinVMSize size,
|
||||
const std::string& sub_name);
|
||||
|
||||
bool Is64Bit() const { return range_.Is64Bit(); }
|
||||
WinVMAddress Base() const { return range_.Base(); }
|
||||
WinVMAddress Size() const { return range_.Size(); }
|
||||
const std::string& name() const { return name_; }
|
||||
|
||||
//! \brief Reads memory from the remote process.
|
||||
//!
|
||||
//! The range specified by \a address and \a size must be contained within
|
||||
//! the range that this object is permitted to read.
|
||||
//!
|
||||
//! \param[in] address The address to read from.
|
||||
//! \param[in] size The size of data to read, in bytes.
|
||||
//! \param[out] into The buffer to read data into.
|
||||
//!
|
||||
//! \return `true` on success, `false` on failure with a message logged.
|
||||
bool ReadMemory(WinVMAddress address, WinVMSize size, void* into) const;
|
||||
|
||||
private:
|
||||
// Common helper for Initialize() and InitializeSubrange().
|
||||
bool InitializeInternal(ProcessReaderWin* process_reader,
|
||||
WinVMAddress base,
|
||||
WinVMSize size,
|
||||
const std::string& name);
|
||||
|
||||
std::string name_;
|
||||
CheckedWinAddressRange range_;
|
||||
ProcessReaderWin* process_reader_; // weak
|
||||
InitializationStateDcheck initialized_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ProcessSubrangeReader);
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_SNAPSHOT_WIN_PROCESS_SUBRANGE_READER_WIN_H_
|
@ -86,35 +86,37 @@ void SystemSnapshotWin::Initialize(ProcessReaderWin* process_reader) {
|
||||
|
||||
process_reader_ = process_reader;
|
||||
|
||||
// We use both GetVersionEx and VerQueryValue. GetVersionEx is not trustworthy
|
||||
// after Windows 8 (depending on the application manifest) so its data is used
|
||||
// only to fill the os_server_ field, and the rest comes from the version
|
||||
// We use both GetVersionEx() and GetModuleVersionAndType() (which uses
|
||||
// VerQueryValue() internally). GetVersionEx() is not trustworthy after
|
||||
// Windows 8 (depending on the application manifest) so its data is used only
|
||||
// to fill the os_server_ field, and the rest comes from the version
|
||||
// information stamped on kernel32.dll.
|
||||
OSVERSIONINFOEX version_info = {sizeof(version_info)};
|
||||
if (!GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info))) {
|
||||
PLOG(WARNING) << "GetVersionEx";
|
||||
} else {
|
||||
const wchar_t kSystemDll[] = L"kernel32.dll";
|
||||
VS_FIXEDFILEINFO ffi;
|
||||
if (GetModuleVersionAndType(base::FilePath(kSystemDll), &ffi)) {
|
||||
std::string flags_string = GetStringForFileFlags(ffi.dwFileFlags);
|
||||
os_server_ = version_info.wProductType != VER_NT_WORKSTATION;
|
||||
std::string os_name = GetStringForFileOS(ffi.dwFileOS);
|
||||
os_version_major_ = ffi.dwFileVersionMS >> 16;
|
||||
os_version_minor_ = ffi.dwFileVersionMS & 0xffff;
|
||||
os_version_bugfix_ = ffi.dwFileVersionLS >> 16;
|
||||
os_version_build_ =
|
||||
base::StringPrintf("%d", ffi.dwFileVersionLS & 0xffff);
|
||||
os_version_full_ = base::StringPrintf(
|
||||
"%s %d.%d.%d.%s%s",
|
||||
os_name.c_str(),
|
||||
os_version_major_,
|
||||
os_version_minor_,
|
||||
os_version_bugfix_,
|
||||
os_version_build_.c_str(),
|
||||
flags_string.empty() ? "" : (std::string(" (") + flags_string + ")")
|
||||
.c_str());
|
||||
}
|
||||
os_server_ = version_info.wProductType != VER_NT_WORKSTATION;
|
||||
}
|
||||
|
||||
const wchar_t kSystemDll[] = L"kernel32.dll";
|
||||
VS_FIXEDFILEINFO ffi;
|
||||
if (GetModuleVersionAndType(base::FilePath(kSystemDll), &ffi)) {
|
||||
std::string flags_string = GetStringForFileFlags(ffi.dwFileFlags);
|
||||
std::string os_name = GetStringForFileOS(ffi.dwFileOS);
|
||||
os_version_major_ = ffi.dwFileVersionMS >> 16;
|
||||
os_version_minor_ = ffi.dwFileVersionMS & 0xffff;
|
||||
os_version_bugfix_ = ffi.dwFileVersionLS >> 16;
|
||||
os_version_build_ =
|
||||
base::StringPrintf("%d", ffi.dwFileVersionLS & 0xffff);
|
||||
os_version_full_ = base::StringPrintf(
|
||||
"%s %d.%d.%d.%s%s",
|
||||
os_name.c_str(),
|
||||
os_version_major_,
|
||||
os_version_minor_,
|
||||
os_version_bugfix_,
|
||||
os_version_build_.c_str(),
|
||||
flags_string.empty() ? "" : (std::string(" (") + flags_string + ")")
|
||||
.c_str());
|
||||
}
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
|
@ -207,7 +207,7 @@ void MachMultiprocess::MultiprocessParent() {
|
||||
}
|
||||
|
||||
void MachMultiprocess::MultiprocessChild() {
|
||||
ScopedForbidReturn forbid_return;;
|
||||
ScopedForbidReturn forbid_return;
|
||||
|
||||
// local_port is not valid in the forked child process.
|
||||
ignore_result(info_->local_port.release());
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <shellapi.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
@ -125,8 +126,8 @@ bool CreateInheritablePipe(ScopedFileHANDLE* read_handle,
|
||||
if (!write_inheritable && !UnsetHandleInheritance(temp_write.get()))
|
||||
return false;
|
||||
|
||||
*read_handle = temp_read.Pass();
|
||||
*write_handle = temp_write.Pass();
|
||||
*read_handle = std::move(temp_read);
|
||||
*write_handle = std::move(temp_write);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -212,7 +213,7 @@ scoped_ptr<WinChildProcess::Handles> WinChildProcess::Launch() {
|
||||
return scoped_ptr<Handles>();
|
||||
}
|
||||
|
||||
return handles_for_parent.Pass();
|
||||
return std::move(handles_for_parent);
|
||||
}
|
||||
|
||||
FileHandle WinChildProcess::ReadPipeHandle() const {
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <time.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
@ -552,7 +553,7 @@ int DatabaseUtilMain(int argc, char* argv[]) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
file_reader = file_path_reader.Pass();
|
||||
file_reader = std::move(file_path_reader);
|
||||
}
|
||||
|
||||
CrashReportDatabase::NewReport* new_report;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/mac/mach_logging.h"
|
||||
@ -352,30 +353,30 @@ ChildPortHandshake::~ChildPortHandshake() {
|
||||
|
||||
base::ScopedFD ChildPortHandshake::ClientReadFD() {
|
||||
DCHECK(client_read_fd_.is_valid());
|
||||
return client_read_fd_.Pass();
|
||||
return std::move(client_read_fd_);
|
||||
}
|
||||
|
||||
base::ScopedFD ChildPortHandshake::ServerWriteFD() {
|
||||
DCHECK(server_write_fd_.is_valid());
|
||||
return server_write_fd_.Pass();
|
||||
return std::move(server_write_fd_);
|
||||
}
|
||||
|
||||
mach_port_t ChildPortHandshake::RunServer(PortRightType port_right_type) {
|
||||
client_read_fd_.reset();
|
||||
return RunServerForFD(server_write_fd_.Pass(), port_right_type);
|
||||
return RunServerForFD(std::move(server_write_fd_), port_right_type);
|
||||
}
|
||||
|
||||
bool ChildPortHandshake::RunClient(mach_port_t port,
|
||||
mach_msg_type_name_t right_type) {
|
||||
server_write_fd_.reset();
|
||||
return RunClientForFD(client_read_fd_.Pass(), port, right_type);
|
||||
return RunClientForFD(std::move(client_read_fd_), port, right_type);
|
||||
}
|
||||
|
||||
// static
|
||||
mach_port_t ChildPortHandshake::RunServerForFD(base::ScopedFD server_write_fd,
|
||||
PortRightType port_right_type) {
|
||||
ChildPortHandshakeServer server;
|
||||
return server.RunServer(server_write_fd.Pass(), port_right_type);
|
||||
return server.RunServer(std::move(server_write_fd), port_right_type);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -138,7 +138,7 @@ class ChildPortHandshakeTest;
|
||||
//! // Obtain a receive right from the parent process.
|
||||
//! base::mac::ScopedMachReceiveRight receive_right(
|
||||
//! ChildPortHandshake::RunServerForFD(
|
||||
//! server_write_fd.Pass(),
|
||||
//! std::move(server_write_fd),
|
||||
//! ChildPortHandshake::PortRightType::kReceiveRight));
|
||||
//! }
|
||||
//! \endcode
|
||||
|
@ -445,7 +445,7 @@ bool IsAddressMapped(vm_address_t address) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ADD_FAILURE() << MachErrorMessage(kr, "vm_region_64");;
|
||||
ADD_FAILURE() << MachErrorMessage(kr, "vm_region_64");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
#include "util/net/http_transport.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "util/net/http_body.h"
|
||||
|
||||
namespace crashpad {
|
||||
@ -43,7 +45,7 @@ void HTTPTransport::SetHeader(const std::string& header,
|
||||
}
|
||||
|
||||
void HTTPTransport::SetBodyStream(scoped_ptr<HTTPBodyStream> stream) {
|
||||
body_stream_ = stream.Pass();
|
||||
body_stream_ = std::move(stream);
|
||||
}
|
||||
|
||||
void HTTPTransport::SetTimeout(double timeout) {
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
@ -51,7 +52,7 @@ class HTTPTransportTestFixture : public MultiprocessExec {
|
||||
RequestValidator request_validator)
|
||||
: MultiprocessExec(),
|
||||
headers_(headers),
|
||||
body_stream_(body_stream.Pass()),
|
||||
body_stream_(std::move(body_stream)),
|
||||
response_code_(http_response_code),
|
||||
request_validator_(request_validator) {
|
||||
base::FilePath server_path = Paths::TestDataRoot().Append(
|
||||
@ -102,7 +103,7 @@ class HTTPTransportTestFixture : public MultiprocessExec {
|
||||
for (const auto& pair : headers_) {
|
||||
transport->SetHeader(pair.first, pair.second);
|
||||
}
|
||||
transport->SetBodyStream(body_stream_.Pass());
|
||||
transport->SetBodyStream(std::move(body_stream_));
|
||||
|
||||
std::string response_body;
|
||||
bool success = transport->ExecuteSynchronously(&response_body);
|
||||
@ -270,8 +271,8 @@ TEST(HTTPTransport, UnchunkedPlainText) {
|
||||
headers[kContentType] = kTextPlain;
|
||||
headers[kContentLength] = base::StringPrintf("%" PRIuS, strlen(kTextBody));
|
||||
|
||||
HTTPTransportTestFixture test(headers, body_stream.Pass(), 200,
|
||||
&UnchunkedPlainText);
|
||||
HTTPTransportTestFixture test(
|
||||
headers, std::move(body_stream), 200, &UnchunkedPlainText);
|
||||
test.Run();
|
||||
}
|
||||
|
||||
@ -291,7 +292,10 @@ void RunUpload33k(bool has_content_length) {
|
||||
headers[kContentLength] =
|
||||
base::StringPrintf("%" PRIuS, request_string.size());
|
||||
}
|
||||
HTTPTransportTestFixture test(headers, body_stream.Pass(), 200,
|
||||
HTTPTransportTestFixture test(
|
||||
headers,
|
||||
std::move(body_stream),
|
||||
200,
|
||||
[](HTTPTransportTestFixture* fixture, const std::string& request) {
|
||||
size_t body_start = request.rfind("\r\n");
|
||||
EXPECT_EQ(33 * 1024u + 2, request.size() - body_start);
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
#include "util/numeric/checked_address_range.h"
|
||||
|
||||
#include "base/strings/stringprintf.h"
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#include <mach/mach.h>
|
||||
#elif defined(OS_WIN)
|
||||
@ -109,6 +111,12 @@ bool CheckedAddressRangeGeneric<ValueType, SizeType>::ContainsRange(
|
||||
: range_32_.ContainsRange(that.range_32_);
|
||||
}
|
||||
|
||||
template <class ValueType, class SizeType>
|
||||
std::string CheckedAddressRangeGeneric<ValueType, SizeType>::AsString() const {
|
||||
return base::StringPrintf(
|
||||
"0x%llx + 0x%llx (%s)", Base(), Size(), Is64Bit() ? "64" : "32");
|
||||
}
|
||||
|
||||
// Explicit instantiations for the cases we use.
|
||||
#if defined(OS_MACOSX)
|
||||
template class CheckedAddressRangeGeneric<mach_vm_address_t, mach_vm_size_t>;
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "util/numeric/checked_range.h"
|
||||
|
||||
@ -108,6 +110,12 @@ class CheckedAddressRangeGeneric {
|
||||
//! CheckedAddressRangeGeneric objects involved.
|
||||
bool ContainsRange(const CheckedAddressRangeGeneric& that) const;
|
||||
|
||||
//! \brief Returns a string describing the address range.
|
||||
//!
|
||||
//! The string will be formatted as `"0x123 + 0x45 (64)"`, where the
|
||||
//! individual components are the address, size, and bitness.
|
||||
std::string AsString() const;
|
||||
|
||||
private:
|
||||
#if defined(COMPILER_MSVC)
|
||||
// MSVC cannot handle a union containing CheckedRange (with constructor, etc.)
|
||||
|
78
util/stdlib/aligned_allocator.cc
Normal file
78
util/stdlib/aligned_allocator.cc
Normal file
@ -0,0 +1,78 @@
|
||||
// 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 "util/stdlib/aligned_allocator.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#include <stdlib.h>
|
||||
#elif defined(OS_WIN)
|
||||
#include <malloc.h>
|
||||
#include <xutility>
|
||||
#endif // OS_POSIX
|
||||
|
||||
namespace {
|
||||
|
||||
// Throws std::bad_alloc() by calling an internal function provided by the C++
|
||||
// library to do so. This works even if C++ exceptions are disabled, causing
|
||||
// program termination if uncaught.
|
||||
void ThrowBadAlloc() {
|
||||
#if defined(OS_POSIX)
|
||||
// This works with both libc++ and libstdc++.
|
||||
std::__throw_bad_alloc();
|
||||
#elif defined(OS_WIN)
|
||||
std::_Xbad_alloc();
|
||||
#endif // OS_POSIX
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
void* AlignedAllocate(size_t alignment, size_t size) {
|
||||
#if defined(OS_POSIX)
|
||||
// posix_memalign() requires that alignment be at least sizeof(void*), so the
|
||||
// power-of-2 check needs to happen before potentially changing the alignment.
|
||||
if (alignment == 0 || alignment & (alignment - 1)) {
|
||||
ThrowBadAlloc();
|
||||
}
|
||||
|
||||
void* pointer;
|
||||
if (posix_memalign(&pointer, std::max(alignment, sizeof(void*)), size) != 0) {
|
||||
ThrowBadAlloc();
|
||||
}
|
||||
#elif defined(OS_WIN)
|
||||
void* pointer = _aligned_malloc(size, alignment);
|
||||
if (pointer == nullptr) {
|
||||
ThrowBadAlloc();
|
||||
}
|
||||
#endif // OS_POSIX
|
||||
|
||||
return pointer;
|
||||
}
|
||||
|
||||
void AlignedFree(void* pointer) {
|
||||
#if defined(OS_POSIX)
|
||||
free(pointer);
|
||||
#elif defined(OS_WIN)
|
||||
_aligned_free(pointer);
|
||||
#endif // OS_POSIX
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
140
util/stdlib/aligned_allocator.h
Normal file
140
util/stdlib/aligned_allocator.h
Normal file
@ -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.
|
||||
|
||||
#ifndef CRASHPAD_UTIL_STDLIB_ALIGNED_ALLOCATOR_H_
|
||||
#define CRASHPAD_UTIL_STDLIB_ALIGNED_ALLOCATOR_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "build/build_config.h"
|
||||
#include "util/stdlib/cxx.h"
|
||||
|
||||
#if defined(COMPILER_MSVC) && _MSC_VER < 1900
|
||||
#define CRASHPAD_NOEXCEPT _NOEXCEPT
|
||||
#else
|
||||
#define CRASHPAD_NOEXCEPT noexcept
|
||||
#endif
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
//! \brief Allocates memory with the specified alignment constraint.
|
||||
//!
|
||||
//! This function wraps `posix_memalign()` or `_aligned_malloc()`. Memory
|
||||
//! allocated by this function must be released by AlignFree().
|
||||
void* AlignedAllocate(size_t alignment, size_t size);
|
||||
|
||||
//! \brief Frees memory allocated by AlignedAllocate().
|
||||
//!
|
||||
//! This function wraps `free()` or `_aligned_free()`.
|
||||
void AlignedFree(void* pointer);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
//! \brief A standard allocator that aligns its allocations as requested,
|
||||
//! suitable for use as an allocator in standard containers.
|
||||
//!
|
||||
//! This is similar to `std::allocator<T>`, with the addition of an alignment
|
||||
//! guarantee. \a Alignment must be a power of 2. If \a Alignment is not
|
||||
//! specified, the default alignment for type \a T is used.
|
||||
template <class T, size_t Alignment = ALIGNOF(T)>
|
||||
struct AlignedAllocator {
|
||||
public:
|
||||
using value_type = T;
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
template <class U>
|
||||
struct rebind {
|
||||
using other = AlignedAllocator<U, Alignment>;
|
||||
};
|
||||
|
||||
AlignedAllocator() CRASHPAD_NOEXCEPT {}
|
||||
AlignedAllocator(const AlignedAllocator& other) CRASHPAD_NOEXCEPT {}
|
||||
|
||||
template <typename U>
|
||||
AlignedAllocator(const AlignedAllocator<U, Alignment>& other)
|
||||
CRASHPAD_NOEXCEPT {}
|
||||
|
||||
~AlignedAllocator() {}
|
||||
|
||||
pointer address(reference x) const CRASHPAD_NOEXCEPT { return &x; }
|
||||
const_pointer address(const_reference x) const CRASHPAD_NOEXCEPT {
|
||||
return &x;
|
||||
}
|
||||
|
||||
pointer allocate(size_type n, std::allocator<void>::const_pointer hint = 0) {
|
||||
return reinterpret_cast<pointer>(
|
||||
internal::AlignedAllocate(Alignment, sizeof(value_type) * n));
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type n) { internal::AlignedFree(p); }
|
||||
|
||||
size_type max_size() const CRASHPAD_NOEXCEPT {
|
||||
return std::numeric_limits<size_type>::max() / sizeof(value_type);
|
||||
}
|
||||
|
||||
#if CXX_LIBRARY_VERSION < 2011
|
||||
void construct(pointer p, const T& val) {
|
||||
new (reinterpret_cast<void*>(p)) T(val);
|
||||
}
|
||||
#else
|
||||
template <class U, class... Args>
|
||||
void construct(U* p, Args&&... args) {
|
||||
new (reinterpret_cast<void*>(p)) U(std::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class U>
|
||||
void destroy(U* p) {
|
||||
p->~U();
|
||||
}
|
||||
};
|
||||
|
||||
template <class T1, class T2, size_t Alignment>
|
||||
bool operator==(const AlignedAllocator<T1, Alignment>& lhs,
|
||||
const AlignedAllocator<T2, Alignment>& rhs) CRASHPAD_NOEXCEPT {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T1, class T2, size_t Alignment>
|
||||
bool operator!=(const AlignedAllocator<T1, Alignment>& lhs,
|
||||
const AlignedAllocator<T2, Alignment>& rhs) CRASHPAD_NOEXCEPT {
|
||||
return false;
|
||||
}
|
||||
|
||||
//! \brief A `std::vector` using AlignedAllocator.
|
||||
//!
|
||||
//! This is similar to `std::vector<T>`, with the addition of an alignment
|
||||
//! guarantee. \a Alignment must be a power of 2. If \a Alignment is not
|
||||
//! specified, the default alignment for type \a T is used.
|
||||
template <typename T, size_t Alignment = ALIGNOF(T)>
|
||||
using AlignedVector = std::vector<T, AlignedAllocator<T, Alignment>>;
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#undef CRASHPAD_NOEXCEPT
|
||||
|
||||
#endif // CRASHPAD_UTIL_STDLIB_ALIGNED_ALLOCATOR_H_
|
117
util/stdlib/aligned_allocator_test.cc
Normal file
117
util/stdlib/aligned_allocator_test.cc
Normal file
@ -0,0 +1,117 @@
|
||||
// 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 "util/stdlib/aligned_allocator.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
bool IsAligned(void* pointer, size_t alignment) {
|
||||
uintptr_t address = reinterpret_cast<uintptr_t>(pointer);
|
||||
return (address & (alignment - 1)) == 0;
|
||||
}
|
||||
|
||||
TEST(AlignedAllocator, AlignedVector) {
|
||||
// Test a structure with natural alignment.
|
||||
struct NaturalAlignedStruct {
|
||||
int i;
|
||||
};
|
||||
|
||||
AlignedVector<NaturalAlignedStruct> natural_aligned_vector;
|
||||
natural_aligned_vector.push_back(NaturalAlignedStruct());
|
||||
EXPECT_TRUE(
|
||||
IsAligned(&natural_aligned_vector[0], ALIGNOF(NaturalAlignedStruct)));
|
||||
|
||||
natural_aligned_vector.resize(3);
|
||||
EXPECT_TRUE(
|
||||
IsAligned(&natural_aligned_vector[0], ALIGNOF(NaturalAlignedStruct)));
|
||||
EXPECT_TRUE(
|
||||
IsAligned(&natural_aligned_vector[1], ALIGNOF(NaturalAlignedStruct)));
|
||||
EXPECT_TRUE(
|
||||
IsAligned(&natural_aligned_vector[2], ALIGNOF(NaturalAlignedStruct)));
|
||||
|
||||
// Test a structure that declares its own alignment.
|
||||
struct ALIGNAS(32) AlignedStruct {
|
||||
int i;
|
||||
};
|
||||
ASSERT_EQ(32u, ALIGNOF(AlignedStruct));
|
||||
|
||||
AlignedVector<AlignedStruct> aligned_vector;
|
||||
aligned_vector.push_back(AlignedStruct());
|
||||
EXPECT_TRUE(IsAligned(&aligned_vector[0], ALIGNOF(AlignedStruct)));
|
||||
|
||||
aligned_vector.resize(3);
|
||||
EXPECT_TRUE(IsAligned(&aligned_vector[0], ALIGNOF(AlignedStruct)));
|
||||
EXPECT_TRUE(IsAligned(&aligned_vector[1], ALIGNOF(AlignedStruct)));
|
||||
EXPECT_TRUE(IsAligned(&aligned_vector[2], ALIGNOF(AlignedStruct)));
|
||||
|
||||
// Try a custom alignment. Since the structure itself doesn’t specify an
|
||||
// alignment constraint, only the base address will be aligned to the
|
||||
// requested boundary.
|
||||
AlignedVector<NaturalAlignedStruct, 64> custom_aligned_vector;
|
||||
custom_aligned_vector.push_back(NaturalAlignedStruct());
|
||||
EXPECT_TRUE(IsAligned(&custom_aligned_vector[0], 64));
|
||||
|
||||
// Try a structure with a pretty big alignment request.
|
||||
struct ALIGNAS(1024) BigAlignedStruct {
|
||||
int i;
|
||||
};
|
||||
ASSERT_EQ(1024u, ALIGNOF(BigAlignedStruct));
|
||||
|
||||
AlignedVector<BigAlignedStruct> big_aligned_vector;
|
||||
big_aligned_vector.push_back(BigAlignedStruct());
|
||||
EXPECT_TRUE(IsAligned(&big_aligned_vector[0], ALIGNOF(BigAlignedStruct)));
|
||||
|
||||
big_aligned_vector.resize(3);
|
||||
EXPECT_TRUE(IsAligned(&big_aligned_vector[0], ALIGNOF(BigAlignedStruct)));
|
||||
EXPECT_TRUE(IsAligned(&big_aligned_vector[1], ALIGNOF(BigAlignedStruct)));
|
||||
EXPECT_TRUE(IsAligned(&big_aligned_vector[2], ALIGNOF(BigAlignedStruct)));
|
||||
}
|
||||
|
||||
void BadAlignmentTest() {
|
||||
#if defined(OS_WIN)
|
||||
// Suppress the assertion MessageBox() normally displayed by the CRT in debug
|
||||
// mode.
|
||||
int previous = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
|
||||
|
||||
// In release mode, _CrtSetReportMode() is #defined to ((int)0), so |previous|
|
||||
// would appear unused.
|
||||
ALLOW_UNUSED_LOCAL(previous);
|
||||
#endif
|
||||
|
||||
// Alignment constraints must be powers of 2. 7 is not valid.
|
||||
AlignedVector<int, 7> bad_aligned_vector;
|
||||
bad_aligned_vector.push_back(0);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
_CrtSetReportMode(_CRT_ASSERT, previous);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(AlignedAllocatorDeathTest, BadAlignment) {
|
||||
ASSERT_DEATH(BadAlignmentTest(), "");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
@ -128,6 +128,8 @@
|
||||
'posix/process_info_mac.cc',
|
||||
'posix/symbolic_constants_posix.cc',
|
||||
'posix/symbolic_constants_posix.h',
|
||||
'stdlib/aligned_allocator.cc',
|
||||
'stdlib/aligned_allocator.h',
|
||||
'stdlib/cxx.h',
|
||||
'stdlib/map_insert.h',
|
||||
'stdlib/objc.h',
|
||||
|
@ -72,6 +72,7 @@
|
||||
'numeric/int128_test.cc',
|
||||
'posix/process_info_test.cc',
|
||||
'posix/symbolic_constants_posix_test.cc',
|
||||
'stdlib/aligned_allocator_test.cc',
|
||||
'stdlib/map_insert_test.cc',
|
||||
'stdlib/string_number_conversion_test.cc',
|
||||
'stdlib/strlcpy_test.cc',
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include <sddl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/numerics/safe_conversions.h"
|
||||
#include "base/rand_util.h"
|
||||
@ -179,7 +181,7 @@ class ClientData {
|
||||
CreateEvent(nullptr, false /* auto reset */, false, nullptr)),
|
||||
non_crash_dump_completed_event_(
|
||||
CreateEvent(nullptr, false /* auto reset */, false, nullptr)),
|
||||
process_(process.Pass()),
|
||||
process_(std::move(process)),
|
||||
crash_exception_information_address_(
|
||||
crash_exception_information_address),
|
||||
non_crash_exception_information_address_(
|
||||
@ -346,7 +348,7 @@ std::wstring ExceptionHandlerServer::CreatePipe() {
|
||||
void ExceptionHandlerServer::Run(Delegate* delegate) {
|
||||
uint64_t shutdown_token = base::RandUint64();
|
||||
ScopedKernelHANDLE thread_handles[kPipeInstances];
|
||||
for (int i = 0; i < arraysize(thread_handles); ++i) {
|
||||
for (size_t i = 0; i < arraysize(thread_handles); ++i) {
|
||||
HANDLE pipe;
|
||||
if (first_pipe_instance_.is_valid()) {
|
||||
pipe = first_pipe_instance_.release();
|
||||
@ -398,7 +400,7 @@ void ExceptionHandlerServer::Run(Delegate* delegate) {
|
||||
}
|
||||
|
||||
// Signal to the named pipe instances that they should terminate.
|
||||
for (int i = 0; i < arraysize(thread_handles); ++i) {
|
||||
for (size_t i = 0; i < arraysize(thread_handles); ++i) {
|
||||
ClientToServerMessage message;
|
||||
memset(&message, 0, sizeof(message));
|
||||
message.type = ClientToServerMessage::kShutdown;
|
||||
|
@ -24,9 +24,15 @@ namespace crashpad {
|
||||
//! \brief Retrieve the type and version information from a given module (exe,
|
||||
//! dll, etc.)
|
||||
//!
|
||||
//! This function calls `GetFileVersionInfo()`, which can implicitly call
|
||||
//! `LoadLibrary()` to load \a path into the calling process. Do not call this
|
||||
//! function on an untrusted module, because there is a risk of executing the
|
||||
//! module’s code.
|
||||
//!
|
||||
//! \param[in] path The path to the module to be inspected.
|
||||
//! \param[out] vs_fixedfileinfo The `VS_FIXEDFILEINFO` on success.
|
||||
//! `dwFileFlags` will have been masked with `dwFileFlagsMask` already.
|
||||
//! \param[out] vs_fixedfileinfo The VS_FIXEDFILEINFO on success.
|
||||
//! VS_FIXEDFILEINFO::dwFileFlags will have been masked with
|
||||
//! VS_FIXEDFILEINFO::dwFileFlagsMask already.
|
||||
//!
|
||||
//! \return `true` on success, or `false` on failure with a message logged. If
|
||||
//! the module has no `VERSIONINFO` resource, `false` will be returned
|
||||
|
@ -150,11 +150,11 @@ scoped_ptr<uint8_t[]> QueryObject(
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
NTSTATUS_LOG(ERROR, status) << "NtQueryObject";
|
||||
return scoped_ptr<uint8_t[]>();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DCHECK_GE(return_length, minimum_size);
|
||||
return buffer.Pass();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -224,7 +224,7 @@ bool ReadProcessData(HANDLE process,
|
||||
ProcessInfo* process_info) {
|
||||
typename Traits::Pointer peb_address;
|
||||
if (!AssignIfInRange(&peb_address, peb_address_vmaddr)) {
|
||||
LOG(ERROR) << base::StringPrintf("peb address 0x%x out of range",
|
||||
LOG(ERROR) << base::StringPrintf("peb address 0x%llx out of range",
|
||||
peb_address_vmaddr);
|
||||
return false;
|
||||
}
|
||||
@ -589,7 +589,8 @@ bool ProcessInfo::Modules(std::vector<Module>* modules) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<MEMORY_BASIC_INFORMATION64>& ProcessInfo::MemoryInfo() const {
|
||||
const ProcessInfo::MemoryBasicInformation64Vector& ProcessInfo::MemoryInfo()
|
||||
const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return memory_info_;
|
||||
}
|
||||
@ -629,11 +630,11 @@ const std::vector<ProcessInfo::Handle>& ProcessInfo::Handles() const {
|
||||
|
||||
std::vector<CheckedRange<WinVMAddress, WinVMSize>> GetReadableRangesOfMemoryMap(
|
||||
const CheckedRange<WinVMAddress, WinVMSize>& range,
|
||||
const std::vector<MEMORY_BASIC_INFORMATION64>& memory_info) {
|
||||
const ProcessInfo::MemoryBasicInformation64Vector& memory_info) {
|
||||
using Range = CheckedRange<WinVMAddress, WinVMSize>;
|
||||
|
||||
// Find all the ranges that overlap the target range, maintaining their order.
|
||||
std::vector<MEMORY_BASIC_INFORMATION64> overlapping;
|
||||
ProcessInfo::MemoryBasicInformation64Vector overlapping;
|
||||
for (const auto& mi : memory_info) {
|
||||
static_assert(base::is_same<decltype(mi.BaseAddress), WinVMAddress>::value,
|
||||
"expected range address to be WinVMAddress");
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "base/basictypes.h"
|
||||
#include "util/misc/initialization_state_dcheck.h"
|
||||
#include "util/numeric/checked_range.h"
|
||||
#include "util/stdlib/aligned_allocator.h"
|
||||
#include "util/win/address_types.h"
|
||||
|
||||
namespace crashpad {
|
||||
@ -32,6 +33,10 @@ namespace crashpad {
|
||||
//! primarily of information stored in the Process Environment Block.
|
||||
class ProcessInfo {
|
||||
public:
|
||||
//! \brief The return type of MemoryInfo(), for convenience.
|
||||
using MemoryBasicInformation64Vector =
|
||||
AlignedVector<MEMORY_BASIC_INFORMATION64>;
|
||||
|
||||
//! \brief Contains information about a module loaded into a process.
|
||||
struct Module {
|
||||
Module();
|
||||
@ -124,7 +129,7 @@ class ProcessInfo {
|
||||
bool Modules(std::vector<Module>* modules) const;
|
||||
|
||||
//! \brief Retrieves information about all pages mapped into the process.
|
||||
const std::vector<MEMORY_BASIC_INFORMATION64>& MemoryInfo() const;
|
||||
const MemoryBasicInformation64Vector& MemoryInfo() const;
|
||||
|
||||
//! \brief Given a range to be read from the target process, returns a vector
|
||||
//! of ranges, representing the readable portions of the original range.
|
||||
@ -174,7 +179,19 @@ class ProcessInfo {
|
||||
WinVMAddress peb_address_;
|
||||
WinVMSize peb_size_;
|
||||
std::vector<Module> modules_;
|
||||
std::vector<MEMORY_BASIC_INFORMATION64> memory_info_;
|
||||
|
||||
// memory_info_ is a MemoryBasicInformation64Vector instead of a
|
||||
// std::vector<MEMORY_BASIC_INFORMATION64> because MEMORY_BASIC_INFORMATION64
|
||||
// is declared with __declspec(align(16)), but std::vector<> does not maintain
|
||||
// this alignment on 32-bit x86. clang-cl (but not MSVC cl) takes advantage of
|
||||
// the presumed alignment and emits SSE instructions that require aligned
|
||||
// storage. clang-cl should relax (unfortunately), but in the mean time, this
|
||||
// provides aligned storage. See https://crbug.com/564691 and
|
||||
// http://llvm.org/PR25779.
|
||||
//
|
||||
// TODO(mark): Remove this workaround when http://llvm.org/PR25779 is fixed
|
||||
// and the fix is present in the clang-cl that compiles this code.
|
||||
MemoryBasicInformation64Vector memory_info_;
|
||||
|
||||
// Handles() is logically const, but updates this member on first retrieval.
|
||||
// See https://crashpad.chromium.org/bug/9.
|
||||
@ -195,7 +212,7 @@ class ProcessInfo {
|
||||
//! ProcessInfo::GetReadableRanges().
|
||||
std::vector<CheckedRange<WinVMAddress, WinVMSize>> GetReadableRangesOfMemoryMap(
|
||||
const CheckedRange<WinVMAddress, WinVMSize>& range,
|
||||
const std::vector<MEMORY_BASIC_INFORMATION64>& memory_info);
|
||||
const ProcessInfo::MemoryBasicInformation64Vector& memory_info);
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
|
@ -59,7 +59,7 @@ void VerifyAddressInInCodePage(const ProcessInfo& process_info,
|
||||
WinVMAddress code_address) {
|
||||
// Make sure the child code address is an code page address with the right
|
||||
// information.
|
||||
const std::vector<MEMORY_BASIC_INFORMATION64>& memory_info =
|
||||
const ProcessInfo::MemoryBasicInformation64Vector& memory_info =
|
||||
process_info.MemoryInfo();
|
||||
bool found_region = false;
|
||||
for (const auto& mi : memory_info) {
|
||||
@ -199,7 +199,7 @@ TEST(ProcessInfo, OtherProcessWOW64) {
|
||||
#endif // ARCH_CPU_64_BITS
|
||||
|
||||
TEST(ProcessInfo, AccessibleRangesNone) {
|
||||
std::vector<MEMORY_BASIC_INFORMATION64> memory_info;
|
||||
ProcessInfo::MemoryBasicInformation64Vector memory_info;
|
||||
MEMORY_BASIC_INFORMATION64 mbi = {0};
|
||||
|
||||
mbi.BaseAddress = 0;
|
||||
@ -215,7 +215,7 @@ TEST(ProcessInfo, AccessibleRangesNone) {
|
||||
}
|
||||
|
||||
TEST(ProcessInfo, AccessibleRangesOneInside) {
|
||||
std::vector<MEMORY_BASIC_INFORMATION64> memory_info;
|
||||
ProcessInfo::MemoryBasicInformation64Vector memory_info;
|
||||
MEMORY_BASIC_INFORMATION64 mbi = {0};
|
||||
|
||||
mbi.BaseAddress = 0;
|
||||
@ -233,7 +233,7 @@ TEST(ProcessInfo, AccessibleRangesOneInside) {
|
||||
}
|
||||
|
||||
TEST(ProcessInfo, AccessibleRangesOneTruncatedSize) {
|
||||
std::vector<MEMORY_BASIC_INFORMATION64> memory_info;
|
||||
ProcessInfo::MemoryBasicInformation64Vector memory_info;
|
||||
MEMORY_BASIC_INFORMATION64 mbi = {0};
|
||||
|
||||
mbi.BaseAddress = 0;
|
||||
@ -256,7 +256,7 @@ TEST(ProcessInfo, AccessibleRangesOneTruncatedSize) {
|
||||
}
|
||||
|
||||
TEST(ProcessInfo, AccessibleRangesOneMovedStart) {
|
||||
std::vector<MEMORY_BASIC_INFORMATION64> memory_info;
|
||||
ProcessInfo::MemoryBasicInformation64Vector memory_info;
|
||||
MEMORY_BASIC_INFORMATION64 mbi = {0};
|
||||
|
||||
mbi.BaseAddress = 0;
|
||||
@ -279,7 +279,7 @@ TEST(ProcessInfo, AccessibleRangesOneMovedStart) {
|
||||
}
|
||||
|
||||
TEST(ProcessInfo, ReserveIsInaccessible) {
|
||||
std::vector<MEMORY_BASIC_INFORMATION64> memory_info;
|
||||
ProcessInfo::MemoryBasicInformation64Vector memory_info;
|
||||
MEMORY_BASIC_INFORMATION64 mbi = {0};
|
||||
|
||||
mbi.BaseAddress = 0;
|
||||
@ -302,7 +302,7 @@ TEST(ProcessInfo, ReserveIsInaccessible) {
|
||||
}
|
||||
|
||||
TEST(ProcessInfo, PageGuardIsInaccessible) {
|
||||
std::vector<MEMORY_BASIC_INFORMATION64> memory_info;
|
||||
ProcessInfo::MemoryBasicInformation64Vector memory_info;
|
||||
MEMORY_BASIC_INFORMATION64 mbi = {0};
|
||||
|
||||
mbi.BaseAddress = 0;
|
||||
@ -327,7 +327,7 @@ TEST(ProcessInfo, PageGuardIsInaccessible) {
|
||||
}
|
||||
|
||||
TEST(ProcessInfo, PageNoAccessIsInaccessible) {
|
||||
std::vector<MEMORY_BASIC_INFORMATION64> memory_info;
|
||||
ProcessInfo::MemoryBasicInformation64Vector memory_info;
|
||||
MEMORY_BASIC_INFORMATION64 mbi = {0};
|
||||
|
||||
mbi.BaseAddress = 0;
|
||||
@ -352,7 +352,7 @@ TEST(ProcessInfo, PageNoAccessIsInaccessible) {
|
||||
}
|
||||
|
||||
TEST(ProcessInfo, AccessibleRangesCoalesced) {
|
||||
std::vector<MEMORY_BASIC_INFORMATION64> memory_info;
|
||||
ProcessInfo::MemoryBasicInformation64Vector memory_info;
|
||||
MEMORY_BASIC_INFORMATION64 mbi = {0};
|
||||
|
||||
mbi.BaseAddress = 0;
|
||||
@ -380,7 +380,7 @@ TEST(ProcessInfo, AccessibleRangesCoalesced) {
|
||||
}
|
||||
|
||||
TEST(ProcessInfo, AccessibleRangesMiddleUnavailable) {
|
||||
std::vector<MEMORY_BASIC_INFORMATION64> memory_info;
|
||||
ProcessInfo::MemoryBasicInformation64Vector memory_info;
|
||||
MEMORY_BASIC_INFORMATION64 mbi = {0};
|
||||
|
||||
mbi.BaseAddress = 0;
|
||||
@ -410,7 +410,7 @@ TEST(ProcessInfo, AccessibleRangesMiddleUnavailable) {
|
||||
}
|
||||
|
||||
TEST(ProcessInfo, RequestedBeforeMap) {
|
||||
std::vector<MEMORY_BASIC_INFORMATION64> memory_info;
|
||||
ProcessInfo::MemoryBasicInformation64Vector memory_info;
|
||||
MEMORY_BASIC_INFORMATION64 mbi = {0};
|
||||
|
||||
mbi.BaseAddress = 10;
|
||||
@ -428,7 +428,7 @@ TEST(ProcessInfo, RequestedBeforeMap) {
|
||||
}
|
||||
|
||||
TEST(ProcessInfo, RequestedAfterMap) {
|
||||
std::vector<MEMORY_BASIC_INFORMATION64> memory_info;
|
||||
ProcessInfo::MemoryBasicInformation64Vector memory_info;
|
||||
MEMORY_BASIC_INFORMATION64 mbi = {0};
|
||||
|
||||
mbi.BaseAddress = 10;
|
||||
|
Loading…
x
Reference in New Issue
Block a user