Adding an API to read module annotations in snapshot.gyp

Kasko needs a way to read crash keys from out of process. This API
reuses the functionality of PEImageAnnotationsReader.

Change-Id: I2f3bbc358212e6f50235183e9dbb4e5a2cf989cf

This is a reupload of https://codereview.chromium.org/1586433003/ but
for gerrit.

Change-Id: I2f3bbc358212e6f50235183e9dbb4e5a2cf989cf
Reviewed-on: https://chromium-review.googlesource.com/322550
Reviewed-by: Scott Graham <scottmg@chromium.org>
Tested-by: Scott Graham <scottmg@chromium.org>
Reviewed-by: Scott Graham <scottmg@google.com>
This commit is contained in:
Patrick Monette 2016-01-18 15:05:20 -05:00 committed by Scott Graham
parent 2e44832850
commit 4794225f22
10 changed files with 273 additions and 11 deletions

View File

@ -0,0 +1,53 @@
// Copyright 2016 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/api/module_annotations_win.h"
#include "snapshot/win/pe_image_annotations_reader.h"
#include "snapshot/win/pe_image_reader.h"
#include "snapshot/win/process_reader_win.h"
#include "util/win/get_module_information.h"
namespace crashpad {
bool ReadModuleAnnotations(HANDLE process,
HMODULE module,
std::map<std::string, std::string>* annotations) {
ProcessReaderWin process_reader;
if (!process_reader.Initialize(process, ProcessSuspensionState::kRunning))
return false;
MODULEINFO module_info;
if (!CrashpadGetModuleInformation(
process, module, &module_info, sizeof(module_info))) {
PLOG(ERROR) << "CrashpadGetModuleInformation";
return false;
}
PEImageReader image_reader;
if (!image_reader.Initialize(
&process_reader,
reinterpret_cast<crashpad::WinVMAddress>(module_info.lpBaseOfDll),
module_info.SizeOfImage,
""))
return false;
PEImageAnnotationsReader annotations_reader(
&process_reader, &image_reader, L"");
*annotations = annotations_reader.SimpleMap();
return true;
}
} // namespace crashpad

View File

@ -0,0 +1,42 @@
// Copyright 2016 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_API_MODULE_ANNOTATIONS_WIN_H_
#define CRASHPAD_SNAPSHOT_API_MODULE_ANNOTATIONS_WIN_H_
#include <windows.h>
#include <map>
#include <string>
namespace crashpad {
//! \brief Reads the module annotations from another process.
//!
//! \param[in] process The handle to the process that hosts the \a module.
//! Requires PROCESS_QUERY_INFORMATION and PROCESS_VM_READ accesses.
//! \param[in] module The handle to the module from which the \a annotations
//! will be read. This module should be loaded in the target process.
//! \param[out] annotations The map that will be filled with the annotations.
//! Remains unchanged if the function returns 'false'.
//!
//! \return `true` if the annotations could be read succesfully, even if the
//! module doesn't contain any annotations.
bool ReadModuleAnnotations(HANDLE process,
HMODULE module,
std::map<std::string, std::string>* annotations);
} // namespace crashpad
#endif // CRASHPAD_SNAPSHOT_API_MODULE_ANNOTATIONS_WIN_H_

View File

@ -0,0 +1,83 @@
// Copyright 2016 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/api/module_annotations_win.h"
#include "client/crashpad_info.h"
#include "gtest/gtest.h"
#include "test/win/win_multiprocess.h"
#include "util/file/file_io.h"
namespace crashpad {
namespace test {
namespace {
class ModuleAnnotationsMultiprocessTest final : public WinMultiprocess {
private:
void WinMultiprocessParent() override {
// Read the child executable module.
HMODULE module = nullptr;
CheckedReadFile(ReadPipeHandle(), &module, sizeof(module));
// Reopen the child process with necessary access.
HANDLE process_handle =
OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE,
GetProcessId(ChildProcess()));
EXPECT_TRUE(process_handle);
// Read the module annotations in the child process and verify them.
std::map<std::string, std::string> annotations;
ASSERT_TRUE(ReadModuleAnnotations(process_handle, module, &annotations));
EXPECT_GE(annotations.size(), 3u);
EXPECT_EQ("value", annotations["#APITEST# key"]);
EXPECT_EQ("y", annotations["#APITEST# x"]);
EXPECT_EQ("", annotations["#APITEST# empty_value"]);
// Signal the child process to terminate.
char c = ' ';
CheckedWriteFile(WritePipeHandle(), &c, sizeof(c));
}
void WinMultiprocessChild() override {
// Set some test annotations.
crashpad::CrashpadInfo* crashpad_info =
crashpad::CrashpadInfo::GetCrashpadInfo();
crashpad::SimpleStringDictionary* simple_annotations =
new crashpad::SimpleStringDictionary();
simple_annotations->SetKeyValue("#APITEST# key", "value");
simple_annotations->SetKeyValue("#APITEST# x", "y");
simple_annotations->SetKeyValue("#APITEST# empty_value", "");
crashpad_info->set_simple_annotations(simple_annotations);
// Send the executable module.
HMODULE module = GetModuleHandle(nullptr);
CheckedWriteFile(WritePipeHandle(), &module, sizeof(module));
// Wait until a signal from the parent process to terminate.
char c;
CheckedReadFile(ReadPipeHandle(), &c, sizeof(c));
}
};
TEST(ModuleAnnotationsWin, ReadAnnotations) {
WinMultiprocess::Run<ModuleAnnotationsMultiprocessTest>();
}
} // namespace
} // namespace test
} // namespace crashpad

View File

@ -129,5 +129,32 @@
}],
]
},
{
'variables': {
'conditions': [
['OS == "win"', {
'snapshot_api_target_type%': 'static_library',
}, {
# There are no source files except on Windows.
'snapshot_api_target_type%': 'none',
}],
],
},
'target_name': 'crashpad_snapshot_api',
'type': '<(snapshot_api_target_type)',
'dependencies': [
'crashpad_snapshot',
'../compat/compat.gyp:crashpad_compat',
'../third_party/mini_chromium/mini_chromium.gyp:base',
'../util/util.gyp:crashpad_util',
],
'include_dirs': [
'..',
],
'sources': [
'api/module_annotations_win.cc',
'api/module_annotations_win.h',
],
},
],
}

View File

@ -54,6 +54,7 @@
'dependencies': [
'crashpad_snapshot_test_module',
'snapshot.gyp:crashpad_snapshot',
'snapshot.gyp:crashpad_snapshot_api',
'../client/client.gyp:crashpad_client',
'../compat/compat.gyp:crashpad_compat',
'../test/test.gyp:crashpad_test',
@ -68,6 +69,7 @@
'sources': [
'cpu_context_test.cc',
'crashpad_info_client_options_test.cc',
'api/module_annotations_win_test.cc',
'mac/cpu_context_mac_test.cc',
'mac/mach_o_image_annotations_reader_test.cc',
'mac/mach_o_image_reader_test.cc',

View File

@ -31,7 +31,6 @@
#include "snapshot/win/process_reader_win.h"
#include "test/paths.h"
#include "test/win/child_launcher.h"
#include "test/win/win_multiprocess.h"
#include "util/file/file_io.h"
#include "util/win/process_info.h"

View File

@ -22,7 +22,7 @@
#include "gtest/gtest.h"
#include "snapshot/win/process_reader_win.h"
#include "test/errors.h"
#include "util/win/get_function.h"
#include "util/win/get_module_information.h"
#include "util/win/module_version.h"
#include "util/win/process_info.h"
@ -32,15 +32,6 @@ namespace crashpad {
namespace test {
namespace {
BOOL CrashpadGetModuleInformation(HANDLE process,
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);
}
TEST(PEImageReader, DebugDirectory) {
PEImageReader pe_image_reader;
ProcessReaderWin process_reader;

View File

@ -166,6 +166,8 @@
'win/exception_handler_server.h',
'win/get_function.cc',
'win/get_function.h',
'win/get_module_information.cc',
'win/get_module_information.h',
'win/handle.cc',
'win/handle.h',
'win/module_version.cc',

View File

@ -0,0 +1,30 @@
// Copyright 2016 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/win/get_module_information.h"
#include "util/win/get_function.h"
namespace crashpad {
BOOL CrashpadGetModuleInformation(HANDLE process,
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);
}
} // namespace crashpad

View File

@ -0,0 +1,33 @@
// Copyright 2016 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_WIN_GET_MODULE_INFORMATION_H_
#define CRASHPAD_UTIL_WIN_GET_MODULE_INFORMATION_H_
#include <windows.h>
#define PSAPI_VERSION 1
#include <psapi.h>
namespace crashpad {
//! \brief Proxy function for `GetModuleInformation()`.
BOOL CrashpadGetModuleInformation(HANDLE process,
HMODULE module,
MODULEINFO* module_info,
DWORD cb);
} // namespace crashpad
#endif // CRASHPAD_UTIL_WIN_GET_MODULE_INFORMATION_H_