mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-26 23:01:05 +08:00
Add CrashpadInfoReader to read CrashpadInfo via ProcessMemory
Bug: crashpad:30 Change-Id: I295d518ee0eef1fd61e5544cd6bad25827d07a02 Reviewed-on: https://chromium-review.googlesource.com/846025 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
parent
8bbe985004
commit
70563e92f4
@ -100,6 +100,8 @@ static_library("snapshot") {
|
||||
|
||||
if (crashpad_is_linux || crashpad_is_android) {
|
||||
sources += [
|
||||
"crashpad_types/crashpad_info_reader.cc",
|
||||
"crashpad_types/crashpad_info_reader.h",
|
||||
"elf/elf_dynamic_array_reader.cc",
|
||||
"elf/elf_dynamic_array_reader.h",
|
||||
"elf/elf_image_reader.cc",
|
||||
@ -285,6 +287,7 @@ source_set("snapshot_test") {
|
||||
|
||||
if (crashpad_is_linux || crashpad_is_android) {
|
||||
sources += [
|
||||
"crashpad_types/crashpad_info_reader_test.cc",
|
||||
"elf/elf_image_reader_test.cc",
|
||||
"elf/elf_image_reader_test_note.S",
|
||||
"elf/test_exported_symbols.sym",
|
||||
|
187
snapshot/crashpad_types/crashpad_info_reader.cc
Normal file
187
snapshot/crashpad_types/crashpad_info_reader.cc
Normal file
@ -0,0 +1,187 @@
|
||||
// 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 "snapshot/crashpad_types/crashpad_info_reader.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "client/crashpad_info.h"
|
||||
#include "util/linux/traits.h"
|
||||
#include "util/misc/as_underlying_type.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
namespace {
|
||||
|
||||
void UnsetIfNotValidTriState(TriState* value) {
|
||||
switch (AsUnderlyingType(*value)) {
|
||||
case AsUnderlyingType(TriState::kUnset):
|
||||
case AsUnderlyingType(TriState::kEnabled):
|
||||
case AsUnderlyingType(TriState::kDisabled):
|
||||
return;
|
||||
}
|
||||
LOG(WARNING) << "Unsetting invalid TriState " << AsUnderlyingType(*value);
|
||||
*value = TriState::kUnset;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class CrashpadInfoReader::InfoContainer {
|
||||
public:
|
||||
virtual ~InfoContainer() = default;
|
||||
|
||||
virtual bool Read(const ProcessMemoryRange* memory, VMAddress address) = 0;
|
||||
|
||||
protected:
|
||||
InfoContainer() = default;
|
||||
};
|
||||
|
||||
template <class Traits>
|
||||
class CrashpadInfoReader::InfoContainerSpecific : public InfoContainer {
|
||||
public:
|
||||
InfoContainerSpecific() : InfoContainer() {}
|
||||
~InfoContainerSpecific() override = default;
|
||||
|
||||
bool Read(const ProcessMemoryRange* memory, VMAddress address) override {
|
||||
if (!memory->Read(address,
|
||||
offsetof(decltype(info), size) + sizeof(info.size),
|
||||
&info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.signature != CrashpadInfo::kSignature) {
|
||||
LOG(ERROR) << "invalid signature 0x" << std::hex << info.signature;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!memory->Read(address,
|
||||
std::min(VMSize{info.size}, VMSize{sizeof(info)}),
|
||||
&info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.size > sizeof(info)) {
|
||||
LOG(INFO) << "large crashpad info size " << info.size;
|
||||
}
|
||||
|
||||
if (info.version != 1) {
|
||||
LOG(ERROR) << "unexpected version " << info.version;
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(reinterpret_cast<char*>(&info), 0, sizeof(info) - info.size);
|
||||
|
||||
UnsetIfNotValidTriState(&info.crashpad_handler_behavior);
|
||||
UnsetIfNotValidTriState(&info.system_crash_reporter_forwarding);
|
||||
UnsetIfNotValidTriState(&info.gather_indirectly_referenced_memory);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct {
|
||||
uint32_t signature;
|
||||
uint32_t size;
|
||||
uint32_t version;
|
||||
uint32_t indirectly_referenced_memory_cap;
|
||||
uint32_t padding_0;
|
||||
TriState crashpad_handler_behavior;
|
||||
TriState system_crash_reporter_forwarding;
|
||||
TriState gather_indirectly_referenced_memory;
|
||||
uint8_t padding_1;
|
||||
typename Traits::Address extra_memory_ranges;
|
||||
typename Traits::Address simple_annotations;
|
||||
typename Traits::Address user_data_minidump_stream_head;
|
||||
typename Traits::Address annotations_list;
|
||||
} info;
|
||||
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
#define NATIVE_TRAITS Traits64
|
||||
#else
|
||||
#define NATIVE_TRAITS Traits32
|
||||
#endif
|
||||
static_assert(!std::is_same<Traits, NATIVE_TRAITS>::value ||
|
||||
sizeof(info) == sizeof(CrashpadInfo),
|
||||
"CrashpadInfo size mismtach");
|
||||
#undef NATIVE_TRAITS
|
||||
};
|
||||
|
||||
CrashpadInfoReader::CrashpadInfoReader()
|
||||
: container_(), is_64_bit_(false), initialized_() {}
|
||||
|
||||
CrashpadInfoReader::~CrashpadInfoReader() = default;
|
||||
|
||||
bool CrashpadInfoReader::Initialize(const ProcessMemoryRange* memory,
|
||||
VMAddress address) {
|
||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||
|
||||
is_64_bit_ = memory->Is64Bit();
|
||||
|
||||
std::unique_ptr<InfoContainer> new_container;
|
||||
if (is_64_bit_) {
|
||||
new_container = std::make_unique<InfoContainerSpecific<Traits64>>();
|
||||
} else {
|
||||
new_container = std::make_unique<InfoContainerSpecific<Traits32>>();
|
||||
}
|
||||
|
||||
if (!new_container->Read(memory, address)) {
|
||||
return false;
|
||||
}
|
||||
container_ = std::move(new_container);
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
}
|
||||
|
||||
#define GET_MEMBER(name) \
|
||||
(is_64_bit_ \
|
||||
? reinterpret_cast<InfoContainerSpecific<Traits64>*>(container_.get()) \
|
||||
->info.name \
|
||||
: reinterpret_cast<InfoContainerSpecific<Traits32>*>(container_.get()) \
|
||||
->info.name)
|
||||
|
||||
#define DEFINE_GETTER(type, method, member) \
|
||||
type CrashpadInfoReader::method() { \
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_); \
|
||||
return GET_MEMBER(member); \
|
||||
}
|
||||
|
||||
DEFINE_GETTER(TriState, CrashpadHandlerBehavior, crashpad_handler_behavior);
|
||||
|
||||
DEFINE_GETTER(TriState,
|
||||
SystemCrashReporterForwarding,
|
||||
system_crash_reporter_forwarding);
|
||||
|
||||
DEFINE_GETTER(TriState,
|
||||
GatherIndirectlyReferencedMemory,
|
||||
gather_indirectly_referenced_memory);
|
||||
|
||||
DEFINE_GETTER(uint32_t,
|
||||
IndirectlyReferencedMemoryCap,
|
||||
indirectly_referenced_memory_cap);
|
||||
|
||||
DEFINE_GETTER(VMAddress, ExtraMemoryRanges, extra_memory_ranges);
|
||||
|
||||
DEFINE_GETTER(VMAddress, SimpleAnnotations, simple_annotations);
|
||||
|
||||
DEFINE_GETTER(VMAddress, AnnotationsList, annotations_list);
|
||||
|
||||
DEFINE_GETTER(VMAddress,
|
||||
UserDataMinidumpStreamHead,
|
||||
user_data_minidump_stream_head);
|
||||
|
||||
#undef DEFINE_GETTER
|
||||
#undef GET_MEMBER
|
||||
|
||||
} // namespace crashpad
|
75
snapshot/crashpad_types/crashpad_info_reader.h
Normal file
75
snapshot/crashpad_types/crashpad_info_reader.h
Normal file
@ -0,0 +1,75 @@
|
||||
// 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_SNAPSHOT_CRASHPAD_TYPES_CRASHPAD_INFO_READER_H_
|
||||
#define CRASHPAD_SNAPSHOT_CRASHPAD_TYPES_CRASHPAD_INFO_READER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "util/misc/address_types.h"
|
||||
#include "util/misc/initialization_state_dcheck.h"
|
||||
#include "util/misc/tri_state.h"
|
||||
#include "util/process/process_memory_range.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
//! \brief Reads CrashpadInfo structs from another process via a
|
||||
//! ProcessMemoryRange.
|
||||
class CrashpadInfoReader {
|
||||
public:
|
||||
CrashpadInfoReader();
|
||||
~CrashpadInfoReader();
|
||||
|
||||
//! \brief Initializes this object.
|
||||
//!
|
||||
//! This method must be successfully called bfore any other method in this
|
||||
//! class.
|
||||
//!
|
||||
//! \param[in] memory The reader for the remote process.
|
||||
//! \param[in] address The address in the remote process' address space of a
|
||||
//! CrashpadInfo struct.
|
||||
//! \return `true` on success. `false` on failure with a message logged.
|
||||
bool Initialize(const ProcessMemoryRange* memory, VMAddress address);
|
||||
|
||||
//! \{
|
||||
//! \see CrashpadInfo
|
||||
TriState CrashpadHandlerBehavior();
|
||||
TriState SystemCrashReporterForwarding();
|
||||
TriState GatherIndirectlyReferencedMemory();
|
||||
uint32_t IndirectlyReferencedMemoryCap();
|
||||
VMAddress ExtraMemoryRanges();
|
||||
VMAddress SimpleAnnotations();
|
||||
VMAddress AnnotationsList();
|
||||
VMAddress UserDataMinidumpStreamHead();
|
||||
//! \}
|
||||
|
||||
private:
|
||||
class InfoContainer;
|
||||
|
||||
template <typename Traits>
|
||||
class InfoContainerSpecific;
|
||||
|
||||
std::unique_ptr<InfoContainer> container_;
|
||||
bool is_64_bit_;
|
||||
InitializationStateDcheck initialized_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CrashpadInfoReader);
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_SNAPSHOT_CRASHPAD_TYPES_CRASHPAD_INFO_READER_H_
|
132
snapshot/crashpad_types/crashpad_info_reader_test.cc
Normal file
132
snapshot/crashpad_types/crashpad_info_reader_test.cc
Normal file
@ -0,0 +1,132 @@
|
||||
// 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 "snapshot/crashpad_types/crashpad_info_reader.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "client/annotation_list.h"
|
||||
#include "client/crashpad_info.h"
|
||||
#include "client/simple_address_range_bag.h"
|
||||
#include "client/simple_string_dictionary.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/multiprocess.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/misc/from_pointer_cast.h"
|
||||
#include "util/process/process_memory_linux.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
constexpr TriState kCrashpadHandlerBehavior = TriState::kEnabled;
|
||||
constexpr TriState kSystemCrashReporterForwarding = TriState::kDisabled;
|
||||
constexpr TriState kGatherIndirectlyReferencedMemory = TriState::kUnset;
|
||||
|
||||
constexpr uint32_t kIndirectlyReferencedMemoryCap = 42;
|
||||
|
||||
class CrashpadInfoTest {
|
||||
public:
|
||||
CrashpadInfoTest()
|
||||
: extra_memory_(), simple_annotations_(), annotation_list_() {
|
||||
CrashpadInfo* info = CrashpadInfo::GetCrashpadInfo();
|
||||
info->set_extra_memory_ranges(&extra_memory_);
|
||||
info->set_simple_annotations(&simple_annotations_);
|
||||
info->set_annotations_list(&annotation_list_);
|
||||
info->set_crashpad_handler_behavior(kCrashpadHandlerBehavior);
|
||||
info->set_system_crash_reporter_forwarding(kSystemCrashReporterForwarding);
|
||||
info->set_gather_indirectly_referenced_memory(
|
||||
kGatherIndirectlyReferencedMemory, kIndirectlyReferencedMemoryCap);
|
||||
}
|
||||
|
||||
void ExpectCrashpadInfo(pid_t pid, bool is_64_bit) {
|
||||
ProcessMemoryLinux memory;
|
||||
ASSERT_TRUE(memory.Initialize(pid));
|
||||
|
||||
ProcessMemoryRange range;
|
||||
ASSERT_TRUE(range.Initialize(&memory, is_64_bit));
|
||||
|
||||
CrashpadInfo* info = CrashpadInfo::GetCrashpadInfo();
|
||||
|
||||
CrashpadInfoReader reader;
|
||||
ASSERT_TRUE(reader.Initialize(&range, FromPointerCast<VMAddress>(info)));
|
||||
EXPECT_EQ(reader.CrashpadHandlerBehavior(), kCrashpadHandlerBehavior);
|
||||
EXPECT_EQ(reader.SystemCrashReporterForwarding(),
|
||||
kSystemCrashReporterForwarding);
|
||||
EXPECT_EQ(reader.GatherIndirectlyReferencedMemory(),
|
||||
kGatherIndirectlyReferencedMemory);
|
||||
EXPECT_EQ(reader.IndirectlyReferencedMemoryCap(),
|
||||
kIndirectlyReferencedMemoryCap);
|
||||
EXPECT_EQ(reader.ExtraMemoryRanges(),
|
||||
FromPointerCast<VMAddress>(&extra_memory_));
|
||||
EXPECT_EQ(reader.SimpleAnnotations(),
|
||||
FromPointerCast<VMAddress>(info->simple_annotations()));
|
||||
EXPECT_EQ(reader.AnnotationsList(),
|
||||
FromPointerCast<VMAddress>(info->annotations_list()));
|
||||
}
|
||||
|
||||
private:
|
||||
SimpleAddressRangeBag extra_memory_;
|
||||
SimpleStringDictionary simple_annotations_;
|
||||
AnnotationList annotation_list_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CrashpadInfoTest);
|
||||
};
|
||||
|
||||
TEST(CrashpadInfoReader, ReadFromSelf) {
|
||||
CrashpadInfoTest test;
|
||||
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
constexpr bool am_64_bit = true;
|
||||
#else
|
||||
constexpr bool am_64_bit = false;
|
||||
#endif
|
||||
|
||||
test.ExpectCrashpadInfo(getpid(), am_64_bit);
|
||||
}
|
||||
|
||||
class ReadFromChildTest : public Multiprocess {
|
||||
public:
|
||||
ReadFromChildTest() : Multiprocess(), info_test_() {}
|
||||
|
||||
~ReadFromChildTest() = default;
|
||||
|
||||
private:
|
||||
void MultiprocessParent() {
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
constexpr bool am_64_bit = true;
|
||||
#else
|
||||
constexpr bool am_64_bit = false;
|
||||
#endif
|
||||
|
||||
info_test_.ExpectCrashpadInfo(ChildPID(), am_64_bit);
|
||||
}
|
||||
|
||||
void MultiprocessChild() { CheckedReadFileAtEOF(ReadPipeHandle()); }
|
||||
|
||||
CrashpadInfoTest info_test_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ReadFromChildTest);
|
||||
};
|
||||
|
||||
TEST(CrashpadInfoReader, ReadFromChild) {
|
||||
ReadFromChildTest test;
|
||||
test.Run();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
@ -39,6 +39,8 @@
|
||||
'cpu_context.h',
|
||||
'crashpad_info_client_options.cc',
|
||||
'crashpad_info_client_options.h',
|
||||
'crashpad_types/crashpad_info_reader.cc',
|
||||
'crashpad_types/crashpad_info_reader.h',
|
||||
'elf/elf_dynamic_array_reader.cc',
|
||||
'elf/elf_dynamic_array_reader.h',
|
||||
'elf/elf_image_reader.cc',
|
||||
@ -171,6 +173,7 @@
|
||||
}, { # else: OS!="linux" and OS!="android"
|
||||
'sources/': [
|
||||
['exclude', '^elf/'],
|
||||
['exclude', '^crashpad_types/'],
|
||||
],
|
||||
}],
|
||||
['target_arch!="ia32" and target_arch!="x64"', {
|
||||
|
@ -72,6 +72,7 @@
|
||||
'api/module_annotations_win_test.cc',
|
||||
'cpu_context_test.cc',
|
||||
'crashpad_info_client_options_test.cc',
|
||||
'crashpad_types/crashpad_info_reader_test.cc',
|
||||
'elf/elf_image_reader_test.cc',
|
||||
'elf/elf_image_reader_test_note.S',
|
||||
'linux/debug_rendezvous_test.cc',
|
||||
@ -139,6 +140,7 @@
|
||||
}, { # else: OS!="linux" and OS!="android"
|
||||
'sources/': [
|
||||
['exclude', '^elf/'],
|
||||
['exclude', '^crashpad_types/'],
|
||||
],
|
||||
}],
|
||||
],
|
||||
|
@ -24,7 +24,8 @@ namespace crashpad {
|
||||
//! \param[in] from The value to be casted.
|
||||
//! \return \a from casted to its underlying type.
|
||||
template <typename From>
|
||||
typename std::underlying_type<From>::type AsUnderlyingType(From from) {
|
||||
constexpr typename std::underlying_type<From>::type AsUnderlyingType(
|
||||
From from) {
|
||||
return static_cast<typename std::underlying_type<From>::type>(from);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user