mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-27 07:14:10 +08:00
linux: Add ElfImageReader to read ELF images via ProcessMemory
Bug: crashpad:30 Change-Id: Id2a6a1868103b0f4374816e58aab365a977b010d Reviewed-on: https://chromium-review.googlesource.com/508836 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
parent
1c87c92932
commit
4224be41d7
38
compat/android/elf.h
Normal file
38
compat/android/elf.h
Normal file
@ -0,0 +1,38 @@
|
||||
// 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_COMPAT_ANDROID_ELF_H_
|
||||
#define CRASHPAD_COMPAT_ANDROID_ELF_H_
|
||||
|
||||
#include_next <elf.h>
|
||||
|
||||
#if !defined(ELF32_ST_VISIBILITY)
|
||||
#define ELF32_ST_VISIBILITY(other) ((other) & 0x3)
|
||||
#endif
|
||||
|
||||
#if !defined(ELF64_ST_VISIBILITY)
|
||||
#define ELF64_ST_VISIBILITY(other) ELF32_ST_VISIBILITY(other)
|
||||
#endif
|
||||
|
||||
// Android 5.0.0 (API 21) NDK
|
||||
|
||||
#if !defined(STT_COMMON)
|
||||
#define STT_COMMON 5
|
||||
#endif
|
||||
|
||||
#if !defined(STT_TLS)
|
||||
#define STT_TLS 6
|
||||
#endif
|
||||
|
||||
#endif // CRASHPAD_COMPAT_ANDROID_ELF_H_
|
75
snapshot/linux/elf_dynamic_array_reader.cc
Normal file
75
snapshot/linux/elf_dynamic_array_reader.cc
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.
|
||||
|
||||
#include "snapshot/linux/elf_dynamic_array_reader.h"
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
#include "util/stdlib/map_insert.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename DynType>
|
||||
bool Read(const ProcessMemoryRange& memory,
|
||||
LinuxVMAddress address,
|
||||
LinuxVMSize size,
|
||||
std::map<uint64_t, uint64_t>* values) {
|
||||
std::map<uint64_t, uint64_t> local_values;
|
||||
|
||||
while (size > 0) {
|
||||
DynType entry;
|
||||
if (!memory.Read(address, sizeof(entry), &entry)) {
|
||||
return false;
|
||||
}
|
||||
size -= sizeof(entry);
|
||||
address += sizeof(entry);
|
||||
|
||||
switch (entry.d_tag) {
|
||||
case DT_NULL:
|
||||
values->swap(local_values);
|
||||
if (size != 0) {
|
||||
LOG(WARNING) << size << " trailing bytes not read";
|
||||
}
|
||||
return true;
|
||||
case DT_NEEDED:
|
||||
// Skip these entries for now.
|
||||
break;
|
||||
default:
|
||||
if (!MapInsertOrReplace(
|
||||
&local_values, entry.d_tag, entry.d_un.d_val, nullptr)) {
|
||||
LOG(ERROR) << "duplicate dynamic array entry";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG(ERROR) << "missing DT_NULL";
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ElfDynamicArrayReader::ElfDynamicArrayReader() : values_() {}
|
||||
|
||||
ElfDynamicArrayReader::~ElfDynamicArrayReader() {}
|
||||
|
||||
bool ElfDynamicArrayReader::Initialize(const ProcessMemoryRange& memory,
|
||||
LinuxVMAddress address,
|
||||
LinuxVMSize size) {
|
||||
return memory.Is64Bit() ? Read<Elf64_Dyn>(memory, address, size, &values_)
|
||||
: Read<Elf32_Dyn>(memory, address, size, &values_);
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
73
snapshot/linux/elf_dynamic_array_reader.h
Normal file
73
snapshot/linux/elf_dynamic_array_reader.h
Normal file
@ -0,0 +1,73 @@
|
||||
// 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_LINUX_ELF_DYNAMIC_ARRAY_READER_H_
|
||||
#define CRASHPAD_SNAPSHOT_LINUX_ELF_DYNAMIC_ARRAY_READER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "util/linux/address_types.h"
|
||||
#include "util/linux/process_memory_range.h"
|
||||
#include "util/misc/reinterpret_bytes.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
//! \brief A reader for ELF dynamic arrays mapped into another process.
|
||||
class ElfDynamicArrayReader {
|
||||
public:
|
||||
ElfDynamicArrayReader();
|
||||
~ElfDynamicArrayReader();
|
||||
|
||||
//! \brief Initializes the reader.
|
||||
//!
|
||||
//! This method must be called once on an object and must be successfully
|
||||
//! called before any other method in this class may be called.
|
||||
//!
|
||||
//! \param[in] memory A memory reader for the remote process.
|
||||
//! \param[in] address The address in the remote process' address space where
|
||||
//! the ELF dynamic table is loaded.
|
||||
//! \param[in] size The maximum number of bytes to read.
|
||||
bool Initialize(const ProcessMemoryRange& memory,
|
||||
LinuxVMAddress address,
|
||||
LinuxVMSize size);
|
||||
|
||||
//! \brief Retrieve a value from the array.
|
||||
//!
|
||||
//! \param[in] tag Specifies which value should be retrieved. The possible
|
||||
//! values for this parameter are the `DT_*` values from `<elf.h>`.
|
||||
//! \param[out] value The value, casted to an appropriate type, if found.
|
||||
//! \return `true` if the value is found.
|
||||
template <typename V>
|
||||
bool GetValue(uint64_t tag, V* value) {
|
||||
auto iter = values_.find(tag);
|
||||
if (iter == values_.end()) {
|
||||
LOG(ERROR) << "tag not found";
|
||||
return false;
|
||||
}
|
||||
return ReinterpretBytes(iter->second, value);
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<uint64_t, uint64_t> values_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ElfDynamicArrayReader);
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_SNAPSHOT_LINUX_ELF_DYNAMIC_ARRAY_READER_H_
|
468
snapshot/linux/elf_image_reader.cc
Normal file
468
snapshot/linux/elf_image_reader.cc
Normal file
@ -0,0 +1,468 @@
|
||||
// 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/linux/elf_image_reader.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
class ElfImageReader::ProgramHeaderTable {
|
||||
public:
|
||||
virtual ~ProgramHeaderTable() {}
|
||||
|
||||
virtual bool VerifyLoadSegments() const = 0;
|
||||
virtual size_t Size() const = 0;
|
||||
virtual bool GetDynamicSegment(LinuxVMAddress* address,
|
||||
LinuxVMSize* size) const = 0;
|
||||
virtual bool GetPreferredElfHeaderAddress(LinuxVMAddress* address) const = 0;
|
||||
virtual bool GetPreferredLoadedMemoryRange(LinuxVMAddress* address,
|
||||
LinuxVMSize* size) const = 0;
|
||||
|
||||
protected:
|
||||
ProgramHeaderTable() {}
|
||||
};
|
||||
|
||||
template <typename PhdrType>
|
||||
class ElfImageReader::ProgramHeaderTableSpecific
|
||||
: public ElfImageReader::ProgramHeaderTable {
|
||||
public:
|
||||
ProgramHeaderTableSpecific<PhdrType>() {}
|
||||
~ProgramHeaderTableSpecific<PhdrType>() {}
|
||||
|
||||
bool Initialize(const ProcessMemoryRange& memory,
|
||||
LinuxVMAddress address,
|
||||
LinuxVMSize num_segments) {
|
||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||
table_.resize(num_segments);
|
||||
if (!memory.Read(address, sizeof(PhdrType) * num_segments, table_.data())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!VerifyLoadSegments()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VerifyLoadSegments() const override {
|
||||
constexpr bool is_64_bit = std::is_same<PhdrType, Elf64_Phdr>::value;
|
||||
LinuxVMAddress last_vaddr;
|
||||
bool load_found = false;
|
||||
for (const auto& header : table_) {
|
||||
if (header.p_type == PT_LOAD) {
|
||||
CheckedLinuxAddressRange load_range(
|
||||
is_64_bit, header.p_vaddr, header.p_memsz);
|
||||
|
||||
if (!load_range.IsValid()) {
|
||||
LOG(ERROR) << "bad load range";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (load_found && header.p_vaddr <= last_vaddr) {
|
||||
LOG(ERROR) << "out of order load segments";
|
||||
return false;
|
||||
}
|
||||
load_found = true;
|
||||
last_vaddr = header.p_vaddr;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t Size() const override { return sizeof(PhdrType) * table_.size(); }
|
||||
|
||||
bool GetPreferredElfHeaderAddress(LinuxVMAddress* address) const override {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
for (const auto& header : table_) {
|
||||
if (header.p_type == PT_LOAD && header.p_offset == 0) {
|
||||
*address = header.p_vaddr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
LOG(ERROR) << "no preferred header address";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetPreferredLoadedMemoryRange(LinuxVMAddress* base,
|
||||
LinuxVMSize* size) const override {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
LinuxVMAddress preferred_base = 0;
|
||||
LinuxVMAddress preferred_end = 0;
|
||||
bool load_found = false;
|
||||
for (const auto& header : table_) {
|
||||
if (header.p_type == PT_LOAD) {
|
||||
if (!load_found) {
|
||||
preferred_base = header.p_vaddr;
|
||||
load_found = true;
|
||||
}
|
||||
preferred_end = header.p_vaddr + header.p_memsz;
|
||||
}
|
||||
}
|
||||
if (load_found) {
|
||||
*base = preferred_base;
|
||||
*size = preferred_end - preferred_base;
|
||||
return true;
|
||||
}
|
||||
LOG(ERROR) << "no load segments";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetDynamicSegment(LinuxVMAddress* address,
|
||||
LinuxVMSize* size) const override {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
const PhdrType* phdr;
|
||||
if (!GetProgramHeader(PT_DYNAMIC, &phdr)) {
|
||||
return false;
|
||||
}
|
||||
*address = phdr->p_vaddr;
|
||||
*size = phdr->p_memsz;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetProgramHeader(uint32_t type, const PhdrType** header_out) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
for (const auto& header : table_) {
|
||||
if (header.p_type == type) {
|
||||
*header_out = &header;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<PhdrType> table_;
|
||||
InitializationStateDcheck initialized_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ProgramHeaderTableSpecific<PhdrType>);
|
||||
};
|
||||
|
||||
ElfImageReader::ElfImageReader()
|
||||
: header_64_(),
|
||||
ehdr_address_(0),
|
||||
load_bias_(0),
|
||||
memory_(),
|
||||
program_headers_(),
|
||||
dynamic_array_(),
|
||||
symbol_table_(),
|
||||
initialized_(),
|
||||
dynamic_array_initialized_(),
|
||||
symbol_table_initialized_() {}
|
||||
|
||||
ElfImageReader::~ElfImageReader() {}
|
||||
|
||||
bool ElfImageReader::Initialize(const ProcessMemoryRange& memory,
|
||||
LinuxVMAddress address) {
|
||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||
ehdr_address_ = address;
|
||||
if (!memory_.Initialize(memory)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t e_ident[EI_NIDENT];
|
||||
if (!memory_.Read(ehdr_address_, EI_NIDENT, e_ident)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 ||
|
||||
e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3) {
|
||||
LOG(ERROR) << "Incorrect ELF magic number";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(memory_.Is64Bit() && e_ident[EI_CLASS] == ELFCLASS64) &&
|
||||
!(!memory_.Is64Bit() && e_ident[EI_CLASS] == ELFCLASS32)) {
|
||||
LOG(ERROR) << "unexpected bitness";
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(ARCH_CPU_LITTLE_ENDIAN)
|
||||
constexpr uint8_t expected_encoding = ELFDATA2LSB;
|
||||
#elif defined(ARCH_CPU_BIG_ENDIAN)
|
||||
constexpr uint8_t expected_encoding = ELFDATA2MSB;
|
||||
#endif
|
||||
if (e_ident[EI_DATA] != expected_encoding) {
|
||||
LOG(ERROR) << "unexpected encoding";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (e_ident[EI_VERSION] != EV_CURRENT) {
|
||||
LOG(ERROR) << "unexpected version";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(memory_.Is64Bit()
|
||||
? memory_.Read(ehdr_address_, sizeof(header_64_), &header_64_)
|
||||
: memory_.Read(ehdr_address_, sizeof(header_32_), &header_32_))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#define VERIFY_HEADER(header) \
|
||||
do { \
|
||||
if (header.e_type != ET_EXEC && header.e_type != ET_DYN) { \
|
||||
LOG(ERROR) << "unexpected image type"; \
|
||||
return false; \
|
||||
} \
|
||||
if (header.e_version != EV_CURRENT) { \
|
||||
LOG(ERROR) << "unexpected version"; \
|
||||
return false; \
|
||||
} \
|
||||
if (header.e_ehsize != sizeof(header)) { \
|
||||
LOG(ERROR) << "unexpected header size"; \
|
||||
return false; \
|
||||
} \
|
||||
} while (false);
|
||||
|
||||
if (memory_.Is64Bit()) {
|
||||
VERIFY_HEADER(header_64_);
|
||||
} else {
|
||||
VERIFY_HEADER(header_32_);
|
||||
}
|
||||
|
||||
if (!InitializeProgramHeaders()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LinuxVMAddress preferred_ehdr_address;
|
||||
if (!program_headers_.get()->GetPreferredElfHeaderAddress(
|
||||
&preferred_ehdr_address)) {
|
||||
return false;
|
||||
}
|
||||
load_bias_ = ehdr_address_ - preferred_ehdr_address;
|
||||
|
||||
LinuxVMAddress base_address;
|
||||
LinuxVMSize loaded_size;
|
||||
if (!program_headers_.get()->GetPreferredLoadedMemoryRange(&base_address,
|
||||
&loaded_size)) {
|
||||
return false;
|
||||
}
|
||||
base_address += load_bias_;
|
||||
|
||||
if (!memory_.RestrictRange(base_address, loaded_size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LinuxVMSize ehdr_size;
|
||||
LinuxVMAddress phdr_address;
|
||||
if (memory_.Is64Bit()) {
|
||||
ehdr_size = sizeof(header_64_);
|
||||
phdr_address = ehdr_address_ + header_64_.e_phoff;
|
||||
} else {
|
||||
ehdr_size = sizeof(header_32_);
|
||||
phdr_address = ehdr_address_ + header_32_.e_phoff;
|
||||
}
|
||||
|
||||
CheckedLinuxAddressRange range(memory_.Is64Bit(), base_address, loaded_size);
|
||||
if (!range.ContainsRange(CheckedLinuxAddressRange(
|
||||
memory_.Is64Bit(), ehdr_address_, ehdr_size))) {
|
||||
LOG(ERROR) << "ehdr out of range";
|
||||
return false;
|
||||
}
|
||||
if (!range.ContainsRange(CheckedLinuxAddressRange(
|
||||
memory.Is64Bit(), phdr_address, program_headers_->Size()))) {
|
||||
LOG(ERROR) << "phdrs out of range";
|
||||
return false;
|
||||
}
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t ElfImageReader::FileType() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return memory_.Is64Bit() ? header_64_.e_type : header_32_.e_type;
|
||||
}
|
||||
|
||||
bool ElfImageReader::GetDynamicSymbol(const std::string& name,
|
||||
LinuxVMAddress* address,
|
||||
LinuxVMSize* size) {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
if (!InitializeDynamicSymbolTable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ElfSymbolTableReader::SymbolInformation info;
|
||||
if (!symbol_table_->GetSymbol(name, &info)) {
|
||||
return false;
|
||||
}
|
||||
if (info.shndx == SHN_UNDEF || info.shndx == SHN_COMMON) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (info.binding) {
|
||||
case STB_GLOBAL:
|
||||
case STB_WEAK:
|
||||
break;
|
||||
|
||||
case STB_LOCAL:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (info.type) {
|
||||
case STT_OBJECT:
|
||||
case STT_FUNC:
|
||||
break;
|
||||
|
||||
case STT_COMMON:
|
||||
case STT_NOTYPE:
|
||||
case STT_SECTION:
|
||||
case STT_FILE:
|
||||
case STT_TLS:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.shndx != SHN_ABS) {
|
||||
info.address += GetLoadBias();
|
||||
}
|
||||
|
||||
*address = info.address;
|
||||
*size = info.size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ElfImageReader::ReadDynamicStringTableAtOffset(LinuxVMSize offset,
|
||||
std::string* string) {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
if (!InitializeDynamicArray()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LinuxVMAddress string_table_address;
|
||||
LinuxVMSize string_table_size;
|
||||
if (!GetAddressFromDynamicArray(DT_STRTAB, &string_table_address) ||
|
||||
!dynamic_array_->GetValue(DT_STRSZ, &string_table_size)) {
|
||||
LOG(ERROR) << "missing string table info";
|
||||
return false;
|
||||
}
|
||||
if (offset >= string_table_size) {
|
||||
LOG(ERROR) << "bad offset";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!memory_.ReadCStringSizeLimited(
|
||||
string_table_address + offset, string_table_size - offset, string)) {
|
||||
LOG(ERROR) << "missing nul-terminator";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ElfImageReader::GetDebugAddress(LinuxVMAddress* debug) {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
if (!InitializeDynamicArray()) {
|
||||
return false;
|
||||
}
|
||||
return GetAddressFromDynamicArray(DT_DEBUG, debug);
|
||||
}
|
||||
|
||||
bool ElfImageReader::InitializeProgramHeaders() {
|
||||
#define INITIALIZE_PROGRAM_HEADERS(PhdrType, header) \
|
||||
do { \
|
||||
if (header.e_phentsize != sizeof(PhdrType)) { \
|
||||
LOG(ERROR) << "unexpected phdr size"; \
|
||||
return false; \
|
||||
} \
|
||||
auto phdrs = new ProgramHeaderTableSpecific<PhdrType>(); \
|
||||
program_headers_.reset(phdrs); \
|
||||
if (!phdrs->Initialize( \
|
||||
memory_, ehdr_address_ + header.e_phoff, header.e_phnum)) { \
|
||||
return false; \
|
||||
} \
|
||||
} while (false);
|
||||
|
||||
if (memory_.Is64Bit()) {
|
||||
INITIALIZE_PROGRAM_HEADERS(Elf64_Phdr, header_64_);
|
||||
} else {
|
||||
INITIALIZE_PROGRAM_HEADERS(Elf32_Phdr, header_32_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ElfImageReader::InitializeDynamicArray() {
|
||||
if (dynamic_array_initialized_.is_valid()) {
|
||||
return true;
|
||||
}
|
||||
if (!dynamic_array_initialized_.is_uninitialized()) {
|
||||
return false;
|
||||
}
|
||||
dynamic_array_initialized_.set_invalid();
|
||||
|
||||
LinuxVMAddress dyn_segment_address;
|
||||
LinuxVMSize dyn_segment_size;
|
||||
if (!program_headers_.get()->GetDynamicSegment(&dyn_segment_address,
|
||||
&dyn_segment_size)) {
|
||||
LOG(ERROR) << "no dynamic segment";
|
||||
return false;
|
||||
}
|
||||
dyn_segment_address += GetLoadBias();
|
||||
|
||||
dynamic_array_.reset(new ElfDynamicArrayReader());
|
||||
if (!dynamic_array_->Initialize(
|
||||
memory_, dyn_segment_address, dyn_segment_size)) {
|
||||
return false;
|
||||
}
|
||||
dynamic_array_initialized_.set_valid();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ElfImageReader::InitializeDynamicSymbolTable() {
|
||||
if (symbol_table_initialized_.is_valid()) {
|
||||
return true;
|
||||
}
|
||||
if (!symbol_table_initialized_.is_uninitialized()) {
|
||||
return false;
|
||||
}
|
||||
symbol_table_initialized_.set_invalid();
|
||||
|
||||
if (!InitializeDynamicArray()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LinuxVMAddress symbol_table_address;
|
||||
if (!GetAddressFromDynamicArray(DT_SYMTAB, &symbol_table_address)) {
|
||||
LOG(ERROR) << "no symbol table";
|
||||
return false;
|
||||
}
|
||||
|
||||
symbol_table_.reset(
|
||||
new ElfSymbolTableReader(&memory_, this, symbol_table_address));
|
||||
symbol_table_initialized_.set_valid();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ElfImageReader::GetAddressFromDynamicArray(uint64_t tag,
|
||||
LinuxVMAddress* address) {
|
||||
if (!dynamic_array_->GetValue(tag, address)) {
|
||||
return false;
|
||||
}
|
||||
#if defined(OS_ANDROID)
|
||||
// The GNU loader updates the dynamic array according to the load bias while
|
||||
// the Android loader only updates the debug address.
|
||||
if (tag != DT_DEBUG) {
|
||||
*address += GetLoadBias();
|
||||
}
|
||||
#endif // OS_ANDROID
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
120
snapshot/linux/elf_image_reader.h
Normal file
120
snapshot/linux/elf_image_reader.h
Normal file
@ -0,0 +1,120 @@
|
||||
// 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_LINUX_ELF_IMAGE_READER_H_
|
||||
#define CRASHPAD_SNAPSHOT_LINUX_ELF_IMAGE_READER_H_
|
||||
|
||||
#include <elf.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "util/linux/address_types.h"
|
||||
#include "snapshot/linux/elf_dynamic_array_reader.h"
|
||||
#include "snapshot/linux/elf_symbol_table_reader.h"
|
||||
#include "util/linux/process_memory_range.h"
|
||||
#include "util/misc/initialization_state.h"
|
||||
#include "util/misc/initialization_state_dcheck.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
//! \brief A reader for ELF images mapped into another process.
|
||||
//!
|
||||
//! This class is capable of reading both 32-bit and 64-bit images.
|
||||
class ElfImageReader {
|
||||
public:
|
||||
ElfImageReader();
|
||||
~ElfImageReader();
|
||||
|
||||
//! \brief Initializes the reader.
|
||||
//!
|
||||
//! This method must be called once on an object and must be successfully
|
||||
//! called before any other method in this class may be called.
|
||||
//!
|
||||
//! \param[in] memory A memory reader for the remote process.
|
||||
//! \param[in] address The address in the remote process' address space where
|
||||
//! the ELF image is loaded.
|
||||
bool Initialize(const ProcessMemoryRange& memory, LinuxVMAddress address);
|
||||
|
||||
//! \brief Returns the file type for the image.
|
||||
//!
|
||||
//! Possible values include `ET_EXEC` or `ET_DYN` from `<elf.h>`.
|
||||
uint16_t FileType() const;
|
||||
|
||||
//! \brief Returns the load bias for the image.
|
||||
//!
|
||||
//! The load bias is the actual load address minus the preferred load address.
|
||||
LinuxVMOffset GetLoadBias() const { return load_bias_; }
|
||||
|
||||
//! \brief Reads information from the dynamic symbol table about the symbol
|
||||
//! identified by \a name.
|
||||
//!
|
||||
//! \param[in] name The name of the symbol to search for.
|
||||
//! \param[out] address The address of the symbol in the target process'
|
||||
//! address space, if found.
|
||||
//! \param[out] size The size of the symbol, if found.
|
||||
//! \return `true` if the symbol was found.
|
||||
bool GetDynamicSymbol(const std::string& name,
|
||||
LinuxVMAddress* address,
|
||||
LinuxVMSize* size);
|
||||
|
||||
//! \brief Reads a `NUL`-terminated C string from this image's dynamic string
|
||||
//! table.
|
||||
//!
|
||||
//! \param[in] offset the byte offset in the string table to start reading.
|
||||
//! \param[out] string the string read.
|
||||
//! \return `true` on success. Otherwise `false` with a message logged.
|
||||
bool ReadDynamicStringTableAtOffset(LinuxVMSize offset, std::string* string);
|
||||
|
||||
//! \brief Determine the debug address.
|
||||
//!
|
||||
//! The debug address is a pointer to an `r_debug` struct defined in
|
||||
//! `<link.h>`.
|
||||
//!
|
||||
//! \param[out] debug the debug address, if found.
|
||||
//! \return `true` if the debug address was found.
|
||||
bool GetDebugAddress(LinuxVMAddress* debug);
|
||||
|
||||
private:
|
||||
class ProgramHeaderTable;
|
||||
template <typename PhdrType>
|
||||
class ProgramHeaderTableSpecific;
|
||||
|
||||
bool InitializeProgramHeaders();
|
||||
bool InitializeDynamicArray();
|
||||
bool InitializeDynamicSymbolTable();
|
||||
bool GetAddressFromDynamicArray(uint64_t tag, LinuxVMAddress* address);
|
||||
|
||||
union {
|
||||
Elf32_Ehdr header_32_;
|
||||
Elf64_Ehdr header_64_;
|
||||
};
|
||||
LinuxVMAddress ehdr_address_;
|
||||
LinuxVMOffset load_bias_;
|
||||
ProcessMemoryRange memory_;
|
||||
std::unique_ptr<ProgramHeaderTable> program_headers_;
|
||||
std::unique_ptr<ElfDynamicArrayReader> dynamic_array_;
|
||||
std::unique_ptr<ElfSymbolTableReader> symbol_table_;
|
||||
InitializationStateDcheck initialized_;
|
||||
InitializationState dynamic_array_initialized_;
|
||||
InitializationState symbol_table_initialized_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ElfImageReader);
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_SNAPSHOT_LINUX_ELF_IMAGE_READER_H_
|
154
snapshot/linux/elf_image_reader_test.cc
Normal file
154
snapshot/linux/elf_image_reader_test.cc
Normal file
@ -0,0 +1,154 @@
|
||||
// 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/linux/elf_image_reader.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/multiprocess.h"
|
||||
#include "util/file/file_io.h"
|
||||
#include "util/linux/address_types.h"
|
||||
#include "util/linux/auxiliary_vector.h"
|
||||
#include "util/linux/memory_map.h"
|
||||
#include "util/misc/from_pointer_cast.h"
|
||||
|
||||
extern "C" {
|
||||
__attribute__((visibility("default"))) void
|
||||
ElfImageReaderTestExportedSymbol(){};
|
||||
} // extern "C"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
void LocateExecutable(pid_t pid, bool is_64_bit, LinuxVMAddress* elf_address) {
|
||||
AuxiliaryVector aux;
|
||||
ASSERT_TRUE(aux.Initialize(pid, is_64_bit));
|
||||
|
||||
LinuxVMAddress phdrs;
|
||||
ASSERT_TRUE(aux.GetValue(AT_PHDR, &phdrs));
|
||||
|
||||
MemoryMap memory_map;
|
||||
ASSERT_TRUE(memory_map.Initialize(pid));
|
||||
const MemoryMap::Mapping* exe_mapping = memory_map.FindMapping(phdrs);
|
||||
ASSERT_TRUE(exe_mapping);
|
||||
*elf_address = exe_mapping->range.Base();
|
||||
}
|
||||
|
||||
void ExpectElfImageWithSymbol(pid_t pid,
|
||||
LinuxVMAddress address,
|
||||
bool is_64_bit,
|
||||
std::string symbol_name,
|
||||
LinuxVMAddress expected_symbol_address) {
|
||||
ProcessMemory memory;
|
||||
ASSERT_TRUE(memory.Initialize(pid));
|
||||
ProcessMemoryRange range;
|
||||
ASSERT_TRUE(range.Initialize(&memory, is_64_bit));
|
||||
|
||||
ElfImageReader reader;
|
||||
ASSERT_TRUE(reader.Initialize(range, address));
|
||||
|
||||
LinuxVMAddress symbol_address;
|
||||
LinuxVMSize symbol_size;
|
||||
ASSERT_TRUE(
|
||||
reader.GetDynamicSymbol(symbol_name, &symbol_address, &symbol_size));
|
||||
EXPECT_EQ(symbol_address, expected_symbol_address);
|
||||
|
||||
EXPECT_FALSE(
|
||||
reader.GetDynamicSymbol("notasymbol", &symbol_address, &symbol_size));
|
||||
}
|
||||
|
||||
void ReadThisExecutableInTarget(pid_t pid) {
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
constexpr bool am_64_bit = true;
|
||||
#else
|
||||
constexpr bool am_64_bit = false;
|
||||
#endif // ARCH_CPU_64_BITS
|
||||
|
||||
LinuxVMAddress elf_address;
|
||||
LocateExecutable(pid, am_64_bit, &elf_address);
|
||||
|
||||
ExpectElfImageWithSymbol(
|
||||
pid,
|
||||
elf_address,
|
||||
am_64_bit,
|
||||
"ElfImageReaderTestExportedSymbol",
|
||||
FromPointerCast<LinuxVMAddress>(ElfImageReaderTestExportedSymbol));
|
||||
}
|
||||
|
||||
// Assumes that libc is loaded at the same address in this process as in the
|
||||
// target, which it is for the fork test below.
|
||||
void ReadLibcInTarget(pid_t pid) {
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
constexpr bool am_64_bit = true;
|
||||
#else
|
||||
constexpr bool am_64_bit = false;
|
||||
#endif // ARCH_CPU_64_BITS
|
||||
|
||||
Dl_info info;
|
||||
ASSERT_TRUE(dladdr(reinterpret_cast<void*>(getpid), &info)) << "dladdr:"
|
||||
<< dlerror();
|
||||
LinuxVMAddress elf_address = FromPointerCast<LinuxVMAddress>(info.dli_fbase);
|
||||
|
||||
ExpectElfImageWithSymbol(pid,
|
||||
elf_address,
|
||||
am_64_bit,
|
||||
"getpid",
|
||||
FromPointerCast<LinuxVMAddress>(getpid));
|
||||
}
|
||||
|
||||
class ReadExecutableChildTest : public Multiprocess {
|
||||
public:
|
||||
ReadExecutableChildTest() : Multiprocess() {}
|
||||
~ReadExecutableChildTest() {}
|
||||
|
||||
private:
|
||||
void MultiprocessParent() { ReadThisExecutableInTarget(ChildPID()); }
|
||||
void MultiprocessChild() { CheckedReadFileAtEOF(ReadPipeHandle()); }
|
||||
};
|
||||
|
||||
TEST(ElfImageReader, MainExecutableSelf) {
|
||||
ReadThisExecutableInTarget(getpid());
|
||||
}
|
||||
|
||||
TEST(ElfImageReader, MainExecutableChild) {
|
||||
ReadExecutableChildTest test;
|
||||
test.Run();
|
||||
}
|
||||
|
||||
TEST(ElfImageReader, OneModuleSelf) {
|
||||
ReadLibcInTarget(getpid());
|
||||
}
|
||||
|
||||
class ReadLibcChildTest : public Multiprocess {
|
||||
public:
|
||||
ReadLibcChildTest() : Multiprocess() {}
|
||||
~ReadLibcChildTest() {}
|
||||
|
||||
private:
|
||||
void MultiprocessParent() { ReadLibcInTarget(ChildPID()); }
|
||||
void MultiprocessChild() { CheckedReadFileAtEOF(ReadPipeHandle()); }
|
||||
};
|
||||
|
||||
TEST(ElfImageReader, OneModuleChild) {
|
||||
ReadLibcChildTest test;
|
||||
test.Run();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
87
snapshot/linux/elf_symbol_table_reader.cc
Normal file
87
snapshot/linux/elf_symbol_table_reader.cc
Normal file
@ -0,0 +1,87 @@
|
||||
// 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/linux/elf_symbol_table_reader.h"
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "snapshot/linux/elf_image_reader.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
namespace {
|
||||
|
||||
uint8_t GetBinding(const Elf32_Sym& sym) {
|
||||
return ELF32_ST_BIND(sym.st_info);
|
||||
}
|
||||
|
||||
uint8_t GetBinding(const Elf64_Sym& sym) {
|
||||
return ELF64_ST_BIND(sym.st_info);
|
||||
}
|
||||
|
||||
uint8_t GetType(const Elf32_Sym& sym) {
|
||||
return ELF32_ST_TYPE(sym.st_info);
|
||||
}
|
||||
|
||||
uint8_t GetType(const Elf64_Sym& sym) {
|
||||
return ELF64_ST_TYPE(sym.st_info);
|
||||
}
|
||||
|
||||
uint8_t GetVisibility(const Elf32_Sym& sym) {
|
||||
return ELF32_ST_VISIBILITY(sym.st_other);
|
||||
}
|
||||
|
||||
uint8_t GetVisibility(const Elf64_Sym& sym) {
|
||||
return ELF64_ST_VISIBILITY(sym.st_other);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ElfSymbolTableReader::ElfSymbolTableReader(const ProcessMemoryRange* memory,
|
||||
ElfImageReader* elf_reader,
|
||||
LinuxVMAddress address)
|
||||
: memory_(memory), elf_reader_(elf_reader), base_address_(address) {}
|
||||
|
||||
ElfSymbolTableReader::~ElfSymbolTableReader() {}
|
||||
|
||||
bool ElfSymbolTableReader::GetSymbol(const std::string& name,
|
||||
SymbolInformation* info) {
|
||||
return memory_->Is64Bit() ? ScanSymbolTable<Elf64_Sym>(name, info)
|
||||
: ScanSymbolTable<Elf32_Sym>(name, info);
|
||||
}
|
||||
|
||||
template <typename SymEnt>
|
||||
bool ElfSymbolTableReader::ScanSymbolTable(const std::string& name,
|
||||
SymbolInformation* info_out) {
|
||||
LinuxVMAddress address = base_address_;
|
||||
SymEnt entry;
|
||||
std::string string;
|
||||
while (memory_->Read(address, sizeof(entry), &entry) &&
|
||||
elf_reader_->ReadDynamicStringTableAtOffset(entry.st_name, &string)) {
|
||||
if (string == name) {
|
||||
info_out->address = entry.st_value;
|
||||
info_out->size = entry.st_size;
|
||||
info_out->shndx = entry.st_shndx;
|
||||
info_out->binding = GetBinding(entry);
|
||||
info_out->type = GetType(entry);
|
||||
info_out->visibility = GetVisibility(entry);
|
||||
return true;
|
||||
}
|
||||
address += sizeof(entry);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
87
snapshot/linux/elf_symbol_table_reader.h
Normal file
87
snapshot/linux/elf_symbol_table_reader.h
Normal file
@ -0,0 +1,87 @@
|
||||
// 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_LINUX_ELF_SYMBOL_TABLE_READER_H_
|
||||
#define CRASHPAD_SNAPSHOT_LINUX_ELF_SYMBOL_TABLE_READER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "util/linux/address_types.h"
|
||||
#include "util/linux/process_memory_range.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
class ElfImageReader;
|
||||
|
||||
//! \brief A reader for symbol tables in ELF images mapped into another process.
|
||||
class ElfSymbolTableReader {
|
||||
public:
|
||||
//! \brief Information about a symbol in a module's symbol table.
|
||||
struct SymbolInformation {
|
||||
//! \brief The address of the symbol as it exists in the symbol table, not
|
||||
//! adjusted for any load bias.
|
||||
LinuxVMAddress address;
|
||||
|
||||
//! \brief The size of the symbol.
|
||||
LinuxVMSize size;
|
||||
|
||||
//! \brief The section index that the symbol definition is in relation to.
|
||||
uint16_t shndx;
|
||||
|
||||
//! \brief Specifies the type of symbol. Possible values include
|
||||
//! `STT_OBJECT`, `STT_FUNC`, etc.
|
||||
uint8_t type;
|
||||
|
||||
//! \brief Specifies the default scope at which a symbol takes precedence.
|
||||
//! Possible values include `STB_LOCAL`, `STB_GLOBAL`, `STB_WEAK`, or
|
||||
//! OS/processor specific values.
|
||||
uint8_t binding;
|
||||
|
||||
//! \brief Together with binding, can limit the visibility of a symbol to
|
||||
//! the module that defines it. Possible values include `STV_DEFAULT`,
|
||||
//! `STV_INTERNAL`, `STV_HIDDEN`, and `STV_PROTECTED`.
|
||||
uint8_t visibility;
|
||||
};
|
||||
|
||||
// TODO(jperaza): Support using .hash and .gnu.hash sections to improve symbol
|
||||
// lookup.
|
||||
ElfSymbolTableReader(const ProcessMemoryRange* memory,
|
||||
ElfImageReader* elf_reader,
|
||||
LinuxVMAddress address);
|
||||
~ElfSymbolTableReader();
|
||||
|
||||
//! \brief Lookup information about a symbol.
|
||||
//!
|
||||
//! \param[in] name The name of the symbol to search for.
|
||||
//! \param[out] info The symbol information, if found.
|
||||
//! \return `true` if the symbol is found.
|
||||
bool GetSymbol(const std::string& name, SymbolInformation* info);
|
||||
|
||||
private:
|
||||
template <typename SymEnt>
|
||||
bool ScanSymbolTable(const std::string& name, SymbolInformation* info);
|
||||
|
||||
const ProcessMemoryRange* const memory_; // weak
|
||||
ElfImageReader* const elf_reader_; // weak
|
||||
const LinuxVMAddress base_address_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ElfSymbolTableReader);
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_SNAPSHOT_LINUX_ELF_SYMBOL_TABLE_READER_H_
|
18
snapshot/linux/test_exported_symbols.sym
Normal file
18
snapshot/linux/test_exported_symbols.sym
Normal file
@ -0,0 +1,18 @@
|
||||
# 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.
|
||||
|
||||
# This symbol is used by elf_image_reader_test.cc.
|
||||
{
|
||||
ElfImageReaderTestExportedSymbol;
|
||||
};
|
@ -40,6 +40,12 @@
|
||||
'exception_snapshot.h',
|
||||
'handle_snapshot.cc',
|
||||
'handle_snapshot.h',
|
||||
'linux/elf_dynamic_array_reader.cc',
|
||||
'linux/elf_dynamic_array_reader.h',
|
||||
'linux/elf_image_reader.cc',
|
||||
'linux/elf_image_reader.h',
|
||||
'linux/elf_symbol_table_reader.cc',
|
||||
'linux/elf_symbol_table_reader.h',
|
||||
'mac/cpu_context_mac.cc',
|
||||
'mac/cpu_context_mac.h',
|
||||
'mac/exception_snapshot_mac.cc',
|
||||
@ -136,7 +142,14 @@
|
||||
'capture_memory.h',
|
||||
],
|
||||
}],
|
||||
]
|
||||
],
|
||||
'target_conditions': [
|
||||
['OS=="android"', {
|
||||
'sources/': [
|
||||
['include', '^linux/'],
|
||||
],
|
||||
}],
|
||||
],
|
||||
},
|
||||
{
|
||||
'variables': {
|
||||
|
@ -70,6 +70,7 @@
|
||||
'cpu_context_test.cc',
|
||||
'crashpad_info_client_options_test.cc',
|
||||
'api/module_annotations_win_test.cc',
|
||||
'linux/elf_image_reader_test.cc',
|
||||
'mac/cpu_context_mac_test.cc',
|
||||
'mac/mach_o_image_annotations_reader_test.cc',
|
||||
'mac/mach_o_image_reader_test.cc',
|
||||
@ -111,6 +112,27 @@
|
||||
'sources!': [
|
||||
'crashpad_info_client_options_test.cc',
|
||||
],
|
||||
'copies': [{
|
||||
'destination': '<(PRODUCT_DIR)',
|
||||
'files': [
|
||||
'linux/test_exported_symbols.sym',
|
||||
],
|
||||
}],
|
||||
'ldflags': [
|
||||
'-Wl,--dynamic-list=test_exported_symbols.sym',
|
||||
],
|
||||
'link_settings': {
|
||||
'libraries': [
|
||||
'-ldl',
|
||||
],
|
||||
},
|
||||
}],
|
||||
],
|
||||
'target_conditions': [
|
||||
['OS=="android"', {
|
||||
'sources/': [
|
||||
['include', '^linux/'],
|
||||
],
|
||||
}],
|
||||
],
|
||||
},
|
||||
|
@ -27,6 +27,10 @@ using LinuxVMAddress = uint64_t;
|
||||
//! LinuxVMAddress), potentially across bitness.
|
||||
using LinuxVMSize = uint64_t;
|
||||
|
||||
//! \brief Type used to represent an offset from a LinuxVMAddress, potentially
|
||||
//! across bitness.
|
||||
using LinuxVMOffset = int64_t;
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_LINUX_ADDRESS_TYPES_H_
|
||||
|
Loading…
x
Reference in New Issue
Block a user