mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-27 07:14:10 +08:00
mac: Handle _dyld_get_all_image_infos() not being available on 10.13
_dyld_get_all_image_infos() was only used in test code in Crashpad. This addresses two related problems. When running on 10.13 or later, _dyld_get_all_image_infos() is not available. It appears to still be implemented in dyld, but its symbol is now private. This was always known to be an “internal” interface. When it’s not available, fall back to obtaining the address of the process’ dyld_all_image_infos structure by calling task_info(…, TASK_DYLD_INFO, …). Note that this is the same thing that the code being tested does, although the tests are not rendered entirely pointless because the code being tested consumes dyld_all_image_infos through its own implementation of an out-of-process reader interface, while the dyld_all_image_infos data obtained by _dyld_get_all_image_infos() is handled strictly in-process by ordinary memory reads. This is covered by bug 187. When building with the 10.13 SDK, no _dyld_get_all_image_infos symbol is available to link against. In this case, access the symbol strictly at runtime via dlopen() if it may be available, or when expecting to only run on 10.13 and later, don’t even bother looking for this symbol. This is covered by part of bug 188. Bug: crashpad:185, crashpad:187, crashpad:188 Change-Id: Ib283e070faf5d1ec35deee420213b53ec24fb1d3 Reviewed-on: https://chromium-review.googlesource.com/534633 Reviewed-by: Robert Sesek <rsesek@chromium.org>
This commit is contained in:
parent
2851e5cfc8
commit
107fb76317
@ -53,4 +53,10 @@
|
||||
#define MAC_OS_X_VERSION_10_12 101200
|
||||
#endif
|
||||
|
||||
// 10.13 SDK
|
||||
|
||||
#ifndef MAC_OS_X_VERSION_10_13
|
||||
#define MAC_OS_X_VERSION_10_13 101300
|
||||
#endif
|
||||
|
||||
#endif // CRASHPAD_COMPAT_MAC_AVAILABILITYMACROS_H_
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "client/crashpad_info.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/errors.h"
|
||||
#include "test/scoped_module_handle.h"
|
||||
#include "test/test_paths.h"
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
@ -138,48 +139,6 @@ TEST(CrashpadInfoClientOptions, OneModule) {
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
using DlHandle = void*;
|
||||
#elif defined(OS_WIN)
|
||||
using DlHandle = HMODULE;
|
||||
#endif // OS_POSIX
|
||||
|
||||
class ScopedDlHandle {
|
||||
public:
|
||||
explicit ScopedDlHandle(DlHandle dl_handle)
|
||||
: dl_handle_(dl_handle) {
|
||||
}
|
||||
|
||||
~ScopedDlHandle() {
|
||||
if (dl_handle_) {
|
||||
#if defined(OS_POSIX)
|
||||
if (dlclose(dl_handle_) != 0) {
|
||||
LOG(ERROR) << "dlclose: " << dlerror();
|
||||
}
|
||||
#elif defined(OS_WIN)
|
||||
if (!FreeLibrary(dl_handle_))
|
||||
PLOG(ERROR) << "FreeLibrary";
|
||||
#endif // OS_POSIX
|
||||
}
|
||||
}
|
||||
|
||||
bool valid() const { return dl_handle_ != nullptr; }
|
||||
|
||||
template <typename T>
|
||||
T LookUpSymbol(const char* symbol_name) {
|
||||
#if defined(OS_POSIX)
|
||||
return reinterpret_cast<T>(dlsym(dl_handle_, symbol_name));
|
||||
#elif defined(OS_WIN)
|
||||
return reinterpret_cast<T>(GetProcAddress(dl_handle_, symbol_name));
|
||||
#endif // OS_POSIX
|
||||
}
|
||||
|
||||
private:
|
||||
DlHandle dl_handle_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedDlHandle);
|
||||
};
|
||||
|
||||
TEST(CrashpadInfoClientOptions, TwoModules) {
|
||||
// Open the module, which has its own CrashpadInfo structure.
|
||||
#if defined(OS_MACOSX)
|
||||
@ -190,15 +149,15 @@ TEST(CrashpadInfoClientOptions, TwoModules) {
|
||||
base::FilePath module_path = TestPaths::Executable().DirName().Append(
|
||||
FILE_PATH_LITERAL("crashpad_snapshot_test_module") + kDlExtension);
|
||||
#if defined(OS_MACOSX)
|
||||
ScopedDlHandle dl_handle(
|
||||
ScopedModuleHandle module(
|
||||
dlopen(module_path.value().c_str(), RTLD_LAZY | RTLD_LOCAL));
|
||||
ASSERT_TRUE(dl_handle.valid()) << "dlopen " << module_path.value() << ": "
|
||||
<< dlerror();
|
||||
ASSERT_TRUE(module.valid()) << "dlopen " << module_path.value() << ": "
|
||||
<< dlerror();
|
||||
#elif defined(OS_WIN)
|
||||
ScopedDlHandle dl_handle(LoadLibrary(module_path.value().c_str()));
|
||||
ASSERT_TRUE(dl_handle.valid())
|
||||
<< "LoadLibrary " << base::UTF16ToUTF8(module_path.value()) << ": "
|
||||
<< ErrorMessage();
|
||||
ScopedModuleHandle module(LoadLibrary(module_path.value().c_str()));
|
||||
ASSERT_TRUE(module.valid()) << "LoadLibrary "
|
||||
<< base::UTF16ToUTF8(module_path.value()) << ": "
|
||||
<< ErrorMessage();
|
||||
#else
|
||||
#error Port.
|
||||
#endif // OS_MACOSX
|
||||
@ -207,7 +166,7 @@ TEST(CrashpadInfoClientOptions, TwoModules) {
|
||||
// because it runs in the module, it returns the remote module’s CrashpadInfo
|
||||
// structure.
|
||||
CrashpadInfo* (*TestModule_GetCrashpadInfo)() =
|
||||
dl_handle.LookUpSymbol<CrashpadInfo* (*)()>("TestModule_GetCrashpadInfo");
|
||||
module.LookUpSymbol<CrashpadInfo* (*)()>("TestModule_GetCrashpadInfo");
|
||||
ASSERT_TRUE(TestModule_GetCrashpadInfo);
|
||||
|
||||
auto options = SelfProcessSnapshotAndGetCrashpadOptions();
|
||||
|
@ -577,8 +577,7 @@ TEST(MachOImageReader, Self_DyldImages) {
|
||||
|
||||
// Now that all of the modules have been verified, make sure that dyld itself
|
||||
// can be read properly too.
|
||||
const struct dyld_all_image_infos* dyld_image_infos =
|
||||
_dyld_get_all_image_infos();
|
||||
const dyld_all_image_infos* dyld_image_infos = DyldGetAllImageInfos();
|
||||
ASSERT_GE(dyld_image_infos->version, 1u);
|
||||
EXPECT_EQ(dyld_image_infos->infoArrayCount, count);
|
||||
|
||||
|
@ -198,6 +198,46 @@ const std::vector<ProcessReader::Module>& ProcessReader::Modules() {
|
||||
return modules_;
|
||||
}
|
||||
|
||||
mach_vm_address_t ProcessReader::DyldAllImageInfo(
|
||||
mach_vm_size_t* all_image_info_size) {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
task_dyld_info_data_t dyld_info;
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
kern_return_t kr = task_info(
|
||||
task_, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
MACH_LOG(WARNING, kr) << "task_info";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO(mark): Deal with statically linked executables which don’t use dyld.
|
||||
// This may look for the module that matches the executable path in the same
|
||||
// data set that vmmap uses.
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
|
||||
// The task_dyld_info_data_t struct grew in 10.7, adding the format field.
|
||||
// Don’t check this field if it’s not present, which can happen when either
|
||||
// the SDK used at compile time or the kernel at run time are too old and
|
||||
// don’t know about it.
|
||||
if (count >= TASK_DYLD_INFO_COUNT) {
|
||||
const integer_t kExpectedFormat =
|
||||
!Is64Bit() ? TASK_DYLD_ALL_IMAGE_INFO_32 : TASK_DYLD_ALL_IMAGE_INFO_64;
|
||||
if (dyld_info.all_image_info_format != kExpectedFormat) {
|
||||
LOG(WARNING) << "unexpected task_dyld_info_data_t::all_image_info_format "
|
||||
<< dyld_info.all_image_info_format;
|
||||
DCHECK_EQ(dyld_info.all_image_info_format, kExpectedFormat);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (all_image_info_size) {
|
||||
*all_image_info_size = dyld_info.all_image_info_size;
|
||||
}
|
||||
return dyld_info.all_image_info_addr;
|
||||
}
|
||||
|
||||
void ProcessReader::InitializeThreads() {
|
||||
DCHECK(!initialized_threads_);
|
||||
DCHECK(threads_.empty());
|
||||
@ -345,38 +385,12 @@ void ProcessReader::InitializeModules() {
|
||||
|
||||
initialized_modules_ = true;
|
||||
|
||||
task_dyld_info_data_t dyld_info;
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
kern_return_t kr = task_info(
|
||||
task_, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
MACH_LOG(WARNING, kr) << "task_info";
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(mark): Deal with statically linked executables which don’t use dyld.
|
||||
// This may look for the module that matches the executable path in the same
|
||||
// data set that vmmap uses.
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
|
||||
// The task_dyld_info_data_t struct grew in 10.7, adding the format field.
|
||||
// Don’t check this field if it’s not present, which can happen when either
|
||||
// the SDK used at compile time or the kernel at run time are too old and
|
||||
// don’t know about it.
|
||||
if (count >= TASK_DYLD_INFO_COUNT) {
|
||||
const integer_t kExpectedFormat =
|
||||
!Is64Bit() ? TASK_DYLD_ALL_IMAGE_INFO_32 : TASK_DYLD_ALL_IMAGE_INFO_64;
|
||||
if (dyld_info.all_image_info_format != kExpectedFormat) {
|
||||
LOG(WARNING) << "unexpected task_dyld_info_data_t::all_image_info_format "
|
||||
<< dyld_info.all_image_info_format;
|
||||
DCHECK_EQ(dyld_info.all_image_info_format, kExpectedFormat);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
mach_vm_size_t all_image_info_size;
|
||||
mach_vm_address_t all_image_info_addr =
|
||||
DyldAllImageInfo(&all_image_info_size);
|
||||
|
||||
process_types::dyld_all_image_infos all_image_infos;
|
||||
if (!all_image_infos.Read(this, dyld_info.all_image_info_addr)) {
|
||||
if (!all_image_infos.Read(this, all_image_info_addr)) {
|
||||
LOG(WARNING) << "could not read dyld_all_image_infos";
|
||||
return;
|
||||
}
|
||||
@ -390,10 +404,10 @@ void ProcessReader::InitializeModules() {
|
||||
size_t expected_size =
|
||||
process_types::dyld_all_image_infos::ExpectedSizeForVersion(
|
||||
this, all_image_infos.version);
|
||||
if (dyld_info.all_image_info_size < expected_size) {
|
||||
LOG(WARNING) << "small dyld_all_image_infos size "
|
||||
<< dyld_info.all_image_info_size << " < " << expected_size
|
||||
<< " for version " << all_image_infos.version;
|
||||
if (all_image_info_size < expected_size) {
|
||||
LOG(WARNING) << "small dyld_all_image_infos size " << all_image_info_size
|
||||
<< " < " << expected_size << " for version "
|
||||
<< all_image_infos.version;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -150,6 +150,21 @@ class ProcessReader {
|
||||
//! corresponds to the dynamic loader, dyld.
|
||||
const std::vector<Module>& Modules();
|
||||
|
||||
//! \brief Determines the location of the `dyld_all_image_infos` structure in
|
||||
//! the process’ address space.
|
||||
//!
|
||||
//! This function is an internal implementation detail of Modules(), and
|
||||
//! should not normally be used directly. It is exposed solely for use by test
|
||||
//! code.
|
||||
//!
|
||||
//! \param[out] all_image_info_size The size of the `dyld_all_image_infos`
|
||||
//! structure. Optional, may be `nullptr` if not required.
|
||||
//!
|
||||
//! \return The address of the `dyld_all_image_infos` structure in the
|
||||
//! process’ address space, with \a all_image_info_size set appropriately.
|
||||
//! On failure, returns `0` with a message logged.
|
||||
mach_vm_address_t DyldAllImageInfo(mach_vm_size_t* all_image_info_size);
|
||||
|
||||
private:
|
||||
//! Performs lazy initialization of the \a threads_ vector on behalf of
|
||||
//! Threads().
|
||||
|
@ -44,12 +44,13 @@
|
||||
#include "util/stdlib/pointer_container.h"
|
||||
#include "util/synchronization/semaphore.h"
|
||||
|
||||
#if !defined(MAC_OS_X_VERSION_10_10) || \
|
||||
MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
|
||||
extern "C" {
|
||||
// Redeclare a typedef whose availability (OSX 10.10) is newer than the
|
||||
|
||||
// Redeclare a typedef whose availability (OS X 10.10) is newer than the
|
||||
// deployment target.
|
||||
typedef struct _cl_device_id* cl_device_id;
|
||||
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
@ -698,8 +699,7 @@ TEST(ProcessReader, SelfModules) {
|
||||
// is also reported as 0.
|
||||
EXPECT_EQ(modules[index].timestamp, 0);
|
||||
|
||||
const struct dyld_all_image_infos* dyld_image_infos =
|
||||
_dyld_get_all_image_infos();
|
||||
const dyld_all_image_infos* dyld_image_infos = DyldGetAllImageInfos();
|
||||
if (dyld_image_infos->version >= 2) {
|
||||
ASSERT_TRUE(modules[index].reader);
|
||||
EXPECT_EQ(modules[index].reader->Address(),
|
||||
@ -781,8 +781,7 @@ class ProcessReaderModulesChild final : public MachMultiprocess {
|
||||
FileHandle write_handle = WritePipeHandle();
|
||||
|
||||
uint32_t dyld_image_count = _dyld_image_count();
|
||||
const struct dyld_all_image_infos* dyld_image_infos =
|
||||
_dyld_get_all_image_infos();
|
||||
const dyld_all_image_infos* dyld_image_infos = DyldGetAllImageInfos();
|
||||
|
||||
uint32_t write_image_count = dyld_image_count;
|
||||
if (dyld_image_infos->version >= 2) {
|
||||
|
@ -46,8 +46,7 @@ namespace {
|
||||
|
||||
TEST(ProcessTypes, DyldImagesSelf) {
|
||||
// Get the in-process view of dyld_all_image_infos, and check it for sanity.
|
||||
const struct dyld_all_image_infos* self_image_infos =
|
||||
_dyld_get_all_image_infos();
|
||||
const dyld_all_image_infos* self_image_infos = DyldGetAllImageInfos();
|
||||
int mac_os_x_minor_version = MacOSXMinorVersion();
|
||||
if (mac_os_x_minor_version >= 12) {
|
||||
EXPECT_GE(self_image_infos->version, 15u);
|
||||
|
99
test/mac/dyld.cc
Normal file
99
test/mac/dyld.cc
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright 2017 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 "test/mac/dyld.h"
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <dlfcn.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "snapshot/mac/process_reader.h"
|
||||
#include "test/scoped_module_handle.h"
|
||||
#include "util/numeric/safe_assignment.h"
|
||||
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13
|
||||
extern "C" {
|
||||
|
||||
// A non-public dyld API, declared in 10.12.4
|
||||
// dyld-433.5/include/mach-o/dyld_priv.h. The code still exists in 10.13, but
|
||||
// its symbol is no longer public, so it can’t be used there.
|
||||
const dyld_all_image_infos* _dyld_get_all_image_infos()
|
||||
__attribute__((weak_import));
|
||||
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
|
||||
const dyld_all_image_infos* DyldGetAllImageInfos() {
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_13
|
||||
// When building with the pre-10.13 SDK, the weak_import declaration above is
|
||||
// available and a symbol will be present in the SDK to link against. If the
|
||||
// old interface is also available at run time (running on pre-10.13), use it.
|
||||
if (_dyld_get_all_image_infos) {
|
||||
return _dyld_get_all_image_infos();
|
||||
}
|
||||
#elif MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_13
|
||||
// When building with the 10.13 SDK or later, but able to run on pre-10.13,
|
||||
// look for _dyld_get_all_image_infos in the same module that provides
|
||||
// _dyld_image_count. There’s no symbol in the SDK to link against, so this is
|
||||
// a little more involved than the pre-10.13 SDK case above.
|
||||
Dl_info dli;
|
||||
if (!dladdr(reinterpret_cast<void*>(_dyld_image_count), &dli)) {
|
||||
LOG(WARNING) << "dladdr: failed";
|
||||
} else {
|
||||
ScopedModuleHandle module(
|
||||
dlopen(dli.dli_fname, RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD));
|
||||
if (!module.valid()) {
|
||||
LOG(WARNING) << "dlopen: " << dlerror();
|
||||
} else {
|
||||
using DyldGetAllImageInfosType = const dyld_all_image_infos*(*)();
|
||||
const auto _dyld_get_all_image_infos =
|
||||
module.LookUpSymbol<DyldGetAllImageInfosType>(
|
||||
"_dyld_get_all_image_infos");
|
||||
if (_dyld_get_all_image_infos) {
|
||||
return _dyld_get_all_image_infos();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// On 10.13 and later, do it the hard way.
|
||||
ProcessReader process_reader;
|
||||
if (!process_reader.Initialize(mach_task_self())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mach_vm_address_t all_image_info_addr_m =
|
||||
process_reader.DyldAllImageInfo(nullptr);
|
||||
if (!all_image_info_addr_m) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uintptr_t all_image_info_addr_u;
|
||||
if (!AssignIfInRange(&all_image_info_addr_u, all_image_info_addr_m)) {
|
||||
LOG(ERROR) << "all_image_info_addr_m " << all_image_info_addr_m
|
||||
<< " out of range";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<const dyld_all_image_infos*>(all_image_info_addr_u);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
@ -17,13 +17,17 @@
|
||||
|
||||
#include <mach-o/dyld_images.h>
|
||||
|
||||
extern "C" {
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
|
||||
// Returns a pointer to this process’ dyld_all_image_infos structure. This is
|
||||
// implemented as a non-public dyld API, declared in 10.9.2
|
||||
// dyld-239.4/include/mach-o/dyld_priv.h.
|
||||
const struct dyld_all_image_infos* _dyld_get_all_image_infos();
|
||||
//! \brief Calls or emulates the `_dyld_get_all_image_infos()` private/internal
|
||||
//! function.
|
||||
//!
|
||||
//! \return A pointer to this process’ dyld_all_image_infos structure, or
|
||||
//! `nullptr` on failure with a message logged.
|
||||
const dyld_all_image_infos* DyldGetAllImageInfos();
|
||||
|
||||
} // extern "C"
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_TEST_MAC_DYLD_H_
|
||||
|
46
test/scoped_module_handle.cc
Normal file
46
test/scoped_module_handle.cc
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2017 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 "test/scoped_module_handle.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
|
||||
// static
|
||||
void ScopedModuleHandle::Impl::Close(ModuleHandle handle) {
|
||||
#if defined(OS_POSIX)
|
||||
if (dlclose(handle) != 0) {
|
||||
LOG(ERROR) << "dlclose: " << dlerror();
|
||||
}
|
||||
#elif defined(OS_WIN)
|
||||
if (!FreeLibrary(handle)) {
|
||||
PLOG(ERROR) << "FreeLibrary";
|
||||
}
|
||||
#else
|
||||
#error Port
|
||||
#endif
|
||||
}
|
||||
|
||||
ScopedModuleHandle::ScopedModuleHandle(ModuleHandle handle) : handle_(handle) {}
|
||||
|
||||
ScopedModuleHandle::~ScopedModuleHandle() {
|
||||
if (valid()) {
|
||||
Impl::Close(handle_);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
81
test/scoped_module_handle.h
Normal file
81
test/scoped_module_handle.h
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright 2017 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_TEST_SCOPED_MODULE_HANDLE_H_
|
||||
#define CRASHPAD_TEST_SCOPED_MODULE_HANDLE_H_
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#include <dlfcn.h>
|
||||
#elif defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
|
||||
//! \brief Maintains ownership of a loadable module handle, releasing it as
|
||||
//! appropriate on destruction.
|
||||
class ScopedModuleHandle {
|
||||
private:
|
||||
class Impl {
|
||||
public:
|
||||
#if defined(OS_POSIX)
|
||||
using ModuleHandle = void*;
|
||||
|
||||
static void* LookUpSymbol(ModuleHandle handle, const char* symbol_name) {
|
||||
return dlsym(handle, symbol_name);
|
||||
}
|
||||
#elif defined(OS_WIN)
|
||||
using ModuleHandle = HMODULE;
|
||||
|
||||
static void* LookUpSymbol(ModuleHandle handle, const char* symbol_name) {
|
||||
return GetProcAddress(handle, symbol_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void Close(ModuleHandle handle);
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Impl);
|
||||
};
|
||||
|
||||
public:
|
||||
using ModuleHandle = Impl::ModuleHandle;
|
||||
|
||||
explicit ScopedModuleHandle(ModuleHandle handle);
|
||||
~ScopedModuleHandle();
|
||||
|
||||
//! \return `true` if this object manages a valid loadable module handle.
|
||||
bool valid() const { return handle_ != nullptr; }
|
||||
|
||||
//! \return The value of the symbol named by \a symbol_name, or `nullptr` on
|
||||
//! failure.
|
||||
template <typename T>
|
||||
T LookUpSymbol(const char* symbol_name) const {
|
||||
return reinterpret_cast<T>(Impl::LookUpSymbol(handle_, symbol_name));
|
||||
}
|
||||
|
||||
private:
|
||||
ModuleHandle handle_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedModuleHandle);
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_TEST_SCOPED_MODULE_HANDLE_H_
|
@ -22,6 +22,7 @@
|
||||
'type': 'static_library',
|
||||
'dependencies': [
|
||||
'../compat/compat.gyp:crashpad_compat',
|
||||
'../snapshot/snapshot.gyp:crashpad_snapshot',
|
||||
'../third_party/gtest/gtest.gyp:gtest',
|
||||
'../third_party/mini_chromium/mini_chromium.gyp:base',
|
||||
'../util/util.gyp:crashpad_util',
|
||||
@ -37,6 +38,7 @@
|
||||
'gtest_death_check.h',
|
||||
'hex_string.cc',
|
||||
'hex_string.h',
|
||||
'mac/dyld.cc',
|
||||
'mac/dyld.h',
|
||||
'mac/mach_errors.cc',
|
||||
'mac/mach_errors.h',
|
||||
@ -49,6 +51,8 @@
|
||||
'multiprocess_exec_posix.cc',
|
||||
'multiprocess_exec_win.cc',
|
||||
'multiprocess_posix.cc',
|
||||
'scoped_module_handle.cc',
|
||||
'scoped_module_handle.h',
|
||||
'scoped_temp_dir.cc',
|
||||
'scoped_temp_dir.h',
|
||||
'scoped_temp_dir_posix.cc',
|
||||
|
Loading…
x
Reference in New Issue
Block a user