mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
Add ModuleSnapshotLinux
Bug: crashpad:30 Change-Id: Ibf1f62b82a4926e1dfd9ad92231bfff44b811d78 Reviewed-on: https://chromium-review.googlesource.com/842187 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
878af9cbbd
commit
fb379a9242
@ -51,17 +51,24 @@ static_assert(std::is_standard_layout<CrashpadInfo>::value,
|
||||
// This may result in a static module initializer in debug-mode builds, but
|
||||
// because it’s POD, no code should need to run to initialize this under
|
||||
// release-mode optimization.
|
||||
|
||||
// Platforms that use ELF objects need to locate this structure via the dynamic
|
||||
// symbol table, so avoid name mangling.
|
||||
#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
__attribute__((
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
// Put the structure in a well-known section name where it can be easily
|
||||
// found without having to consult the symbol table.
|
||||
#if defined(OS_MACOSX)
|
||||
section(SEG_DATA ",crashpad_info"),
|
||||
#elif defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
|
||||
section("crashpad_info"),
|
||||
#else
|
||||
#error Port
|
||||
|
||||
// There's no need to expose this as a public symbol from the symbol table.
|
||||
// All accesses from the outside can locate the well-known section name.
|
||||
visibility("hidden"),
|
||||
#endif
|
||||
|
||||
#if defined(ADDRESS_SANITIZER)
|
||||
@ -74,11 +81,7 @@ __attribute__((
|
||||
#endif // defined(ADDRESS_SANITIZER)
|
||||
|
||||
// The “used” attribute prevents the structure from being dead-stripped.
|
||||
used,
|
||||
|
||||
// There’s no need to expose this as a public symbol from the symbol table.
|
||||
// All accesses from the outside can locate the well-known section name.
|
||||
visibility("hidden")))
|
||||
used))
|
||||
|
||||
#elif defined(OS_WIN)
|
||||
|
||||
@ -93,6 +96,10 @@ __declspec(allocate("CPADinfo"))
|
||||
|
||||
CrashpadInfo g_crashpad_info;
|
||||
|
||||
#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
// static
|
||||
CrashpadInfo* CrashpadInfo::GetCrashpadInfo() {
|
||||
return &g_crashpad_info;
|
||||
|
@ -118,6 +118,8 @@ static_library("snapshot") {
|
||||
"linux/exception_snapshot_linux.h",
|
||||
"linux/memory_snapshot_linux.cc",
|
||||
"linux/memory_snapshot_linux.h",
|
||||
"linux/module_snapshot_linux.cc",
|
||||
"linux/module_snapshot_linux.h",
|
||||
"linux/process_reader.cc",
|
||||
"linux/process_reader.h",
|
||||
"linux/process_snapshot_linux.cc",
|
||||
|
@ -202,6 +202,11 @@ class ElfImageReader {
|
||||
NoteReader::NoteType type,
|
||||
ssize_t max_note_size);
|
||||
|
||||
//! \brief Return a ProcessMemoryRange restricted to the range of this image.
|
||||
//!
|
||||
//! The caller does not take ownership of the returned object.
|
||||
const ProcessMemoryRange* Memory() const;
|
||||
|
||||
private:
|
||||
template <typename PhdrType>
|
||||
class ProgramHeaderTableSpecific;
|
||||
|
188
snapshot/linux/module_snapshot_linux.cc
Normal file
188
snapshot/linux/module_snapshot_linux.cc
Normal file
@ -0,0 +1,188 @@
|
||||
// Copyright 2018 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/linux/module_snapshot_linux.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "snapshot/crashpad_types/image_annotation_reader.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
ModuleSnapshotLinux::ModuleSnapshotLinux()
|
||||
: ModuleSnapshot(),
|
||||
name_(),
|
||||
elf_reader_(nullptr),
|
||||
crashpad_info_(),
|
||||
type_(kModuleTypeUnknown),
|
||||
initialized_() {}
|
||||
|
||||
ModuleSnapshotLinux::~ModuleSnapshotLinux() = default;
|
||||
|
||||
bool ModuleSnapshotLinux::Initialize(
|
||||
const ProcessReader::Module& process_reader_module) {
|
||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||
|
||||
if (!process_reader_module.elf_reader) {
|
||||
LOG(ERROR) << "no elf reader";
|
||||
return false;
|
||||
}
|
||||
|
||||
name_ = process_reader_module.name;
|
||||
elf_reader_ = process_reader_module.elf_reader;
|
||||
type_ = process_reader_module.type;
|
||||
|
||||
VMAddress info_address;
|
||||
VMSize info_size;
|
||||
if (elf_reader_->GetDynamicSymbol(
|
||||
"g_crashpad_info", &info_address, &info_size)) {
|
||||
ProcessMemoryRange range;
|
||||
if (range.Initialize(*elf_reader_->Memory()) &&
|
||||
range.RestrictRange(info_address, info_size)) {
|
||||
auto info = std::make_unique<CrashpadInfoReader>();
|
||||
if (info->Initialize(&range, info_address)) {
|
||||
crashpad_info_ = std::move(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModuleSnapshotLinux::GetCrashpadOptions(
|
||||
CrashpadInfoClientOptions* options) {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
if (!crashpad_info_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
options->crashpad_handler_behavior =
|
||||
crashpad_info_->CrashpadHandlerBehavior();
|
||||
options->system_crash_reporter_forwarding =
|
||||
crashpad_info_->SystemCrashReporterForwarding();
|
||||
options->gather_indirectly_referenced_memory =
|
||||
crashpad_info_->GatherIndirectlyReferencedMemory();
|
||||
options->indirectly_referenced_memory_cap =
|
||||
crashpad_info_->IndirectlyReferencedMemoryCap();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string ModuleSnapshotLinux::Name() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return name_;
|
||||
}
|
||||
|
||||
uint64_t ModuleSnapshotLinux::Address() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return elf_reader_->Address();
|
||||
}
|
||||
|
||||
uint64_t ModuleSnapshotLinux::Size() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return elf_reader_->Size();
|
||||
}
|
||||
|
||||
time_t ModuleSnapshotLinux::Timestamp() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ModuleSnapshotLinux::FileVersion(uint16_t* version_0,
|
||||
uint16_t* version_1,
|
||||
uint16_t* version_2,
|
||||
uint16_t* version_3) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
*version_0 = 0;
|
||||
*version_1 = 0;
|
||||
*version_2 = 0;
|
||||
*version_3 = 0;
|
||||
}
|
||||
|
||||
void ModuleSnapshotLinux::SourceVersion(uint16_t* version_0,
|
||||
uint16_t* version_1,
|
||||
uint16_t* version_2,
|
||||
uint16_t* version_3) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
*version_0 = 0;
|
||||
*version_1 = 0;
|
||||
*version_2 = 0;
|
||||
*version_3 = 0;
|
||||
}
|
||||
|
||||
ModuleSnapshot::ModuleType ModuleSnapshotLinux::GetModuleType() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return type_;
|
||||
}
|
||||
|
||||
void ModuleSnapshotLinux::UUIDAndAge(crashpad::UUID* uuid,
|
||||
uint32_t* age) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
*age = 0;
|
||||
|
||||
std::unique_ptr<ElfImageReader::NoteReader> notes =
|
||||
elf_reader_->NotesWithNameAndType(ELF_NOTE_GNU, NT_GNU_BUILD_ID, 64);
|
||||
std::string desc;
|
||||
notes->NextNote(nullptr, nullptr, &desc);
|
||||
desc.insert(desc.end(), 16 - std::min(desc.size(), size_t{16}), '\0');
|
||||
uuid->InitializeFromBytes(reinterpret_cast<const uint8_t*>(&desc[0]));
|
||||
}
|
||||
|
||||
std::string ModuleSnapshotLinux::DebugFileName() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return base::FilePath(Name()).BaseName().value();
|
||||
}
|
||||
|
||||
std::vector<std::string> ModuleSnapshotLinux::AnnotationsVector() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> ModuleSnapshotLinux::AnnotationsSimpleMap()
|
||||
const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
std::map<std::string, std::string> annotations;
|
||||
if (crashpad_info_ && crashpad_info_->SimpleAnnotations()) {
|
||||
ImageAnnotationReader reader(elf_reader_->Memory());
|
||||
reader.SimpleMap(crashpad_info_->SimpleAnnotations(), &annotations);
|
||||
}
|
||||
return annotations;
|
||||
}
|
||||
|
||||
std::vector<AnnotationSnapshot> ModuleSnapshotLinux::AnnotationObjects() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
std::vector<AnnotationSnapshot> annotations;
|
||||
if (crashpad_info_ && crashpad_info_->AnnotationsList()) {
|
||||
ImageAnnotationReader reader(elf_reader_->Memory());
|
||||
reader.AnnotationsList(crashpad_info_->AnnotationsList(), &annotations);
|
||||
}
|
||||
return annotations;
|
||||
}
|
||||
|
||||
std::set<CheckedRange<uint64_t>> ModuleSnapshotLinux::ExtraMemoryRanges()
|
||||
const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return std::set<CheckedRange<uint64_t>>();
|
||||
}
|
||||
|
||||
std::vector<const UserMinidumpStream*>
|
||||
ModuleSnapshotLinux::CustomMinidumpStreams() const {
|
||||
return std::vector<const UserMinidumpStream*>();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
96
snapshot/linux/module_snapshot_linux.h
Normal file
96
snapshot/linux/module_snapshot_linux.h
Normal file
@ -0,0 +1,96 @@
|
||||
// Copyright 2018 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_LINUX_MODULE_SNAPSHOT_LINUX_H_
|
||||
#define CRASHPAD_SNAPSHOT_LINUX_MODULE_SNAPSHOT_LINUX_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "client/crashpad_info.h"
|
||||
#include "snapshot/crashpad_info_client_options.h"
|
||||
#include "snapshot/crashpad_types/crashpad_info_reader.h"
|
||||
#include "snapshot/elf/elf_image_reader.h"
|
||||
#include "snapshot/linux/process_reader.h"
|
||||
#include "snapshot/module_snapshot.h"
|
||||
#include "util/misc/initialization_state_dcheck.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
namespace internal {
|
||||
|
||||
//! \brief A ModuleSnapshot of a code module (binary image) loaded into a
|
||||
//! running (or crashed) process on a Linux system.
|
||||
class ModuleSnapshotLinux final : public ModuleSnapshot {
|
||||
public:
|
||||
ModuleSnapshotLinux();
|
||||
~ModuleSnapshotLinux() override;
|
||||
|
||||
//! \brief Initializes the object.
|
||||
//!
|
||||
//! \param[in] process_reader_module The module within the ProcessReader for
|
||||
//! which the snapshot should be created.
|
||||
//!
|
||||
//! \return `true` if the snapshot could be created, `false` otherwise with
|
||||
//! an appropriate message logged.
|
||||
bool Initialize(const ProcessReader::Module& process_reader_module);
|
||||
|
||||
//! \brief Returns options from the module’s CrashpadInfo structure.
|
||||
//!
|
||||
//! \param[out] options Options set in the module’s CrashpadInfo structure.
|
||||
//! \return `true` if there were options returned. Otherwise `false`.
|
||||
bool GetCrashpadOptions(CrashpadInfoClientOptions* options);
|
||||
|
||||
// ModuleSnapshot:
|
||||
|
||||
std::string Name() const override;
|
||||
uint64_t Address() const override;
|
||||
uint64_t Size() const override;
|
||||
time_t Timestamp() const override;
|
||||
void FileVersion(uint16_t* version_0,
|
||||
uint16_t* version_1,
|
||||
uint16_t* version_2,
|
||||
uint16_t* version_3) const override;
|
||||
void SourceVersion(uint16_t* version_0,
|
||||
uint16_t* version_1,
|
||||
uint16_t* version_2,
|
||||
uint16_t* version_3) const override;
|
||||
ModuleType GetModuleType() const override;
|
||||
void UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const override;
|
||||
std::string DebugFileName() const override;
|
||||
std::vector<std::string> AnnotationsVector() const override;
|
||||
std::map<std::string, std::string> AnnotationsSimpleMap() const override;
|
||||
std::vector<AnnotationSnapshot> AnnotationObjects() const override;
|
||||
std::set<CheckedRange<uint64_t>> ExtraMemoryRanges() const override;
|
||||
std::vector<const UserMinidumpStream*> CustomMinidumpStreams() const override;
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
ElfImageReader* elf_reader_;
|
||||
std::unique_ptr<CrashpadInfoReader> crashpad_info_;
|
||||
ModuleType type_;
|
||||
InitializationStateDcheck initialized_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ModuleSnapshotLinux);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_SNAPSHOT_LINUX_MODULE_SNAPSHOT_LINUX_H_
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "snapshot/linux/process_reader.h"
|
||||
|
||||
#include <elf.h>
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
@ -26,7 +27,9 @@
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "build/build_config.h"
|
||||
#include "snapshot/linux/debug_rendezvous.h"
|
||||
#include "util/file/directory_reader.h"
|
||||
#include "util/linux/auxiliary_vector.h"
|
||||
#include "util/linux/proc_stat_reader.h"
|
||||
#include "util/misc/as_underlying_type.h"
|
||||
|
||||
@ -166,14 +169,22 @@ void ProcessReader::Thread::InitializeStack(ProcessReader* reader) {
|
||||
}
|
||||
}
|
||||
|
||||
ProcessReader::Module::Module()
|
||||
: name(), elf_reader(nullptr), type(ModuleSnapshot::kModuleTypeUnknown) {}
|
||||
|
||||
ProcessReader::Module::~Module() = default;
|
||||
|
||||
ProcessReader::ProcessReader()
|
||||
: connection_(),
|
||||
process_info_(),
|
||||
memory_map_(),
|
||||
threads_(),
|
||||
modules_(),
|
||||
elf_readers_(),
|
||||
process_memory_(),
|
||||
is_64_bit_(false),
|
||||
initialized_threads_(false),
|
||||
initialized_modules_(false),
|
||||
initialized_() {}
|
||||
|
||||
ProcessReader::~ProcessReader() {}
|
||||
@ -250,6 +261,14 @@ const std::vector<ProcessReader::Thread>& ProcessReader::Threads() {
|
||||
return threads_;
|
||||
}
|
||||
|
||||
const std::vector<ProcessReader::Module>& ProcessReader::Modules() {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
if (!initialized_modules_) {
|
||||
InitializeModules();
|
||||
}
|
||||
return modules_;
|
||||
}
|
||||
|
||||
void ProcessReader::InitializeThreads() {
|
||||
DCHECK(threads_.empty());
|
||||
|
||||
@ -307,4 +326,78 @@ void ProcessReader::InitializeThreads() {
|
||||
DCHECK(main_thread_found);
|
||||
}
|
||||
|
||||
void ProcessReader::InitializeModules() {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
AuxiliaryVector aux;
|
||||
if (!aux.Initialize(ProcessID(), is_64_bit_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
LinuxVMAddress phdrs;
|
||||
if (!aux.GetValue(AT_PHDR, &phdrs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const MemoryMap::Mapping* exe_mapping;
|
||||
if (!(exe_mapping = GetMemoryMap()->FindMapping(phdrs)) &&
|
||||
!(exe_mapping = GetMemoryMap()->FindFileMmapStart(*exe_mapping))) {
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessMemoryRange range;
|
||||
if (!range.Initialize(Memory(), is_64_bit_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto exe_reader = std::make_unique<ElfImageReader>();
|
||||
if (!exe_reader->Initialize(range, exe_mapping->range.Base())) {
|
||||
return;
|
||||
}
|
||||
|
||||
LinuxVMAddress debug_address;
|
||||
if (!exe_reader->GetDebugAddress(&debug_address)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DebugRendezvous debug;
|
||||
if (!debug.Initialize(range, debug_address)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Module exe = {};
|
||||
exe.name = !debug.Executable()->name.empty() ? debug.Executable()->name
|
||||
: exe_mapping->name;
|
||||
exe.elf_reader = exe_reader.get();
|
||||
exe.type = ModuleSnapshot::ModuleType::kModuleTypeExecutable;
|
||||
|
||||
modules_.push_back(exe);
|
||||
elf_readers_.push_back(std::move(exe_reader));
|
||||
|
||||
LinuxVMAddress loader_base = 0;
|
||||
aux.GetValue(AT_BASE, &loader_base);
|
||||
|
||||
for (const DebugRendezvous::LinkEntry& entry : debug.Modules()) {
|
||||
const MemoryMap::Mapping* mapping;
|
||||
if (!(mapping = memory_map_.FindMapping(entry.dynamic_array)) ||
|
||||
!(mapping = memory_map_.FindFileMmapStart(*mapping))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto elf_reader = std::make_unique<ElfImageReader>();
|
||||
if (!elf_reader->Initialize(range, mapping->range.Base())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Module module = {};
|
||||
module.name = !entry.name.empty() ? entry.name : mapping->name;
|
||||
module.elf_reader = elf_reader.get();
|
||||
module.type = loader_base && elf_reader->Address() == loader_base
|
||||
? ModuleSnapshot::kModuleTypeDynamicLoader
|
||||
: ModuleSnapshot::kModuleTypeSharedLibrary;
|
||||
modules_.push_back(module);
|
||||
elf_readers_.push_back(std::move(elf_reader));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -18,9 +18,13 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "snapshot/elf/elf_image_reader.h"
|
||||
#include "snapshot/module_snapshot.h"
|
||||
#include "util/linux/address_types.h"
|
||||
#include "util/linux/memory_map.h"
|
||||
#include "util/linux/ptrace_connection.h"
|
||||
@ -56,6 +60,27 @@ class ProcessReader {
|
||||
void InitializeStack(ProcessReader* reader);
|
||||
};
|
||||
|
||||
//! \brief Contains information about a module loaded into a process.
|
||||
struct Module {
|
||||
Module();
|
||||
~Module();
|
||||
|
||||
//! \brief The pathname used to load the module from disk.
|
||||
std::string name;
|
||||
|
||||
//! \brief An image reader for the module.
|
||||
//!
|
||||
//! The lifetime of this ElfImageReader is scoped to the lifetime of the
|
||||
//! ProcessReader that created it.
|
||||
//!
|
||||
//! This field may be `nullptr` if a reader could not be created for the
|
||||
//! module.
|
||||
ElfImageReader* elf_reader;
|
||||
|
||||
//! \brief The module's type.
|
||||
ModuleSnapshot::ModuleType type;
|
||||
};
|
||||
|
||||
ProcessReader();
|
||||
~ProcessReader();
|
||||
|
||||
@ -107,16 +132,24 @@ class ProcessReader {
|
||||
//! index `0`.
|
||||
const std::vector<Thread>& Threads();
|
||||
|
||||
//! \return The modules loaded in the process. The first element (at index
|
||||
//! `0`) corresponds to the main executable.
|
||||
const std::vector<Module>& Modules();
|
||||
|
||||
private:
|
||||
void InitializeThreads();
|
||||
void InitializeModules();
|
||||
|
||||
PtraceConnection* connection_; // weak
|
||||
ProcessInfo process_info_;
|
||||
MemoryMap memory_map_;
|
||||
std::vector<Thread> threads_;
|
||||
std::vector<Module> modules_;
|
||||
std::vector<std::unique_ptr<ElfImageReader>> elf_readers_;
|
||||
ProcessMemoryLinux process_memory_;
|
||||
bool is_64_bit_;
|
||||
bool initialized_threads_;
|
||||
bool initialized_modules_;
|
||||
InitializationStateDcheck initialized_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ProcessReader);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "snapshot/linux/process_reader.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <link.h>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include <stdlib.h>
|
||||
@ -440,6 +441,89 @@ TEST(ProcessReader, ChildWithSplitStack) {
|
||||
test.Run();
|
||||
}
|
||||
|
||||
int ExpectFindModule(dl_phdr_info* info, size_t size, void* data) {
|
||||
SCOPED_TRACE(
|
||||
base::StringPrintf("module %s at 0x%" PRIx64 " phdrs 0x%" PRIx64,
|
||||
info->dlpi_name,
|
||||
LinuxVMAddress{info->dlpi_addr},
|
||||
FromPointerCast<LinuxVMAddress>(info->dlpi_phdr)));
|
||||
auto modules =
|
||||
reinterpret_cast<const std::vector<ProcessReader::Module>*>(data);
|
||||
|
||||
auto phdr_addr = FromPointerCast<LinuxVMAddress>(info->dlpi_phdr);
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
// Bionic includes a null entry.
|
||||
if (!phdr_addr) {
|
||||
EXPECT_EQ(info->dlpi_name, nullptr);
|
||||
EXPECT_EQ(info->dlpi_addr, 0u);
|
||||
EXPECT_EQ(info->dlpi_phnum, 0u);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO(jperaza): This can use a range map when one is available.
|
||||
bool found = false;
|
||||
for (const auto& module : *modules) {
|
||||
if (module.elf_reader && phdr_addr >= module.elf_reader->Address() &&
|
||||
phdr_addr < module.elf_reader->Address() + module.elf_reader->Size()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(found);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ExpectModulesFromSelf(const std::vector<ProcessReader::Module>& modules) {
|
||||
for (const auto& module : modules) {
|
||||
EXPECT_FALSE(module.name.empty());
|
||||
EXPECT_NE(module.type, ModuleSnapshot::kModuleTypeUnknown);
|
||||
}
|
||||
|
||||
EXPECT_EQ(dl_iterate_phdr(
|
||||
ExpectFindModule,
|
||||
reinterpret_cast<void*>(
|
||||
const_cast<std::vector<ProcessReader::Module>*>(&modules))),
|
||||
0);
|
||||
}
|
||||
|
||||
TEST(ProcessReader, SelfModules) {
|
||||
FakePtraceConnection connection;
|
||||
connection.Initialize(getpid());
|
||||
|
||||
ProcessReader process_reader;
|
||||
ASSERT_TRUE(process_reader.Initialize(&connection));
|
||||
|
||||
ExpectModulesFromSelf(process_reader.Modules());
|
||||
}
|
||||
|
||||
class ChildModuleTest : public Multiprocess {
|
||||
public:
|
||||
ChildModuleTest() : Multiprocess() {}
|
||||
~ChildModuleTest() = default;
|
||||
|
||||
private:
|
||||
void MultiprocessParent() override {
|
||||
DirectPtraceConnection connection;
|
||||
ASSERT_TRUE(connection.Initialize(ChildPID()));
|
||||
|
||||
ProcessReader process_reader;
|
||||
ASSERT_TRUE(process_reader.Initialize(&connection));
|
||||
|
||||
ExpectModulesFromSelf(process_reader.Modules());
|
||||
}
|
||||
|
||||
void MultiprocessChild() override { CheckedReadFileAtEOF(ReadPipeHandle()); }
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ChildModuleTest);
|
||||
};
|
||||
|
||||
TEST(ProcessReader, ChildModules) {
|
||||
ChildModuleTest test;
|
||||
test.Run();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
@ -49,6 +49,7 @@ bool ProcessSnapshotLinux::Initialize(PtraceConnection* connection) {
|
||||
|
||||
system_.Initialize(&process_reader_, &snapshot_time_);
|
||||
InitializeThreads();
|
||||
InitializeModules();
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
@ -136,9 +137,11 @@ std::vector<const ThreadSnapshot*> ProcessSnapshotLinux::Threads() const {
|
||||
|
||||
std::vector<const ModuleSnapshot*> ProcessSnapshotLinux::Modules() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
// TODO(jperaza): do this.
|
||||
LOG(ERROR) << "Not implemented";
|
||||
return std::vector<const ModuleSnapshot*>();
|
||||
std::vector<const ModuleSnapshot*> modules;
|
||||
for (const auto& module : modules_) {
|
||||
modules.push_back(module.get());
|
||||
}
|
||||
return modules;
|
||||
}
|
||||
|
||||
std::vector<UnloadedModuleSnapshot> ProcessSnapshotLinux::UnloadedModules()
|
||||
@ -182,4 +185,13 @@ void ProcessSnapshotLinux::InitializeThreads() {
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessSnapshotLinux::InitializeModules() {
|
||||
for (const ProcessReader::Module& reader_module : process_reader_.Modules()) {
|
||||
auto module = std::make_unique<internal::ModuleSnapshotLinux>();
|
||||
if (module->Initialize(reader_module)) {
|
||||
modules_.push_back(std::move(module));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "snapshot/linux/exception_snapshot_linux.h"
|
||||
#include "snapshot/linux/module_snapshot_linux.h"
|
||||
#include "snapshot/linux/process_reader.h"
|
||||
#include "snapshot/linux/system_snapshot_linux.h"
|
||||
#include "snapshot/linux/thread_snapshot_linux.h"
|
||||
@ -108,12 +109,14 @@ class ProcessSnapshotLinux final : public ProcessSnapshot {
|
||||
|
||||
private:
|
||||
void InitializeThreads();
|
||||
void InitializeModules();
|
||||
|
||||
std::map<std::string, std::string> annotations_simple_map_;
|
||||
timeval snapshot_time_;
|
||||
UUID report_id_;
|
||||
UUID client_id_;
|
||||
std::vector<std::unique_ptr<internal::ThreadSnapshotLinux>> threads_;
|
||||
std::vector<std::unique_ptr<internal::ModuleSnapshotLinux>> modules_;
|
||||
std::unique_ptr<internal::ExceptionSnapshotLinux> exception_;
|
||||
internal::SystemSnapshotLinux system_;
|
||||
ProcessReader process_reader_;
|
||||
|
@ -60,6 +60,8 @@
|
||||
'linux/exception_snapshot_linux.h',
|
||||
'linux/memory_snapshot_linux.cc',
|
||||
'linux/memory_snapshot_linux.h',
|
||||
'linux/module_snapshot_linux.cc',
|
||||
'linux/module_snapshot_linux.h',
|
||||
'linux/process_reader.cc',
|
||||
'linux/process_reader.h',
|
||||
'linux/process_snapshot_linux.cc',
|
||||
|
Loading…
x
Reference in New Issue
Block a user