Merge changes I53c2c560,I7d845ac5,I8b11d923

* changes:
  unwindstack: rename Memory::ReadPartially to Read.
  unwindstack: rename Memory::Read to ReadFully.
  unwindstack: add Memory::ReadPartially.
This commit is contained in:
Treehugger Robot 2017-12-02 00:12:21 +00:00 committed by Gerrit Code Review
commit b4fda18d83
20 changed files with 418 additions and 279 deletions

View File

@ -27,7 +27,7 @@
namespace unwindstack {
bool DwarfMemory::ReadBytes(void* dst, size_t num_bytes) {
if (!memory_->Read(cur_offset_, dst, num_bytes)) {
if (!memory_->ReadFully(cur_offset_, dst, num_bytes)) {
return false;
}
cur_offset_ += num_bytes;

View File

@ -141,7 +141,7 @@ bool DwarfOp<AddressType>::op_deref() {
// Read the address and dereference it.
AddressType addr = StackPop();
AddressType value;
if (!regular_memory()->Read(addr, &value, sizeof(value))) {
if (!regular_memory()->ReadFully(addr, &value, sizeof(value))) {
last_error_ = DWARF_ERROR_MEMORY_INVALID;
return false;
}
@ -159,7 +159,7 @@ bool DwarfOp<AddressType>::op_deref_size() {
// Read the address and dereference it.
AddressType addr = StackPop();
AddressType value = 0;
if (!regular_memory()->Read(addr, &value, bytes_to_read)) {
if (!regular_memory()->ReadFully(addr, &value, bytes_to_read)) {
last_error_ = DWARF_ERROR_MEMORY_INVALID;
return false;
}

View File

@ -142,7 +142,7 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me
return false;
}
if (loc->type == DWARF_LOCATION_EXPRESSION) {
if (!regular_memory->Read(value, &cfa, sizeof(AddressType))) {
if (!regular_memory->ReadFully(value, &cfa, sizeof(AddressType))) {
last_error_ = DWARF_ERROR_MEMORY_INVALID;
return false;
}
@ -175,7 +175,8 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me
const DwarfLocation* loc = &entry.second;
switch (loc->type) {
case DWARF_LOCATION_OFFSET:
if (!regular_memory->Read(cfa + loc->values[0], &(*cur_regs)[reg], sizeof(AddressType))) {
if (!regular_memory->ReadFully(cfa + loc->values[0], &(*cur_regs)[reg],
sizeof(AddressType))) {
last_error_ = DWARF_ERROR_MEMORY_INVALID;
return false;
}
@ -210,7 +211,7 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me
return false;
}
if (loc->type == DWARF_LOCATION_EXPRESSION) {
if (!regular_memory->Read(value, &(*cur_regs)[reg], sizeof(AddressType))) {
if (!regular_memory->ReadFully(value, &(*cur_regs)[reg], sizeof(AddressType))) {
last_error_ = DWARF_ERROR_MEMORY_INVALID;
return false;
}

View File

@ -136,7 +136,7 @@ bool Elf::IsValidElf(Memory* memory) {
// Verify that this is a valid elf file.
uint8_t e_ident[SELFMAG + 1];
if (!memory->Read(0, e_ident, SELFMAG)) {
if (!memory->ReadFully(0, e_ident, SELFMAG)) {
return false;
}
@ -156,7 +156,7 @@ void Elf::GetInfo(Memory* memory, bool* valid, uint64_t* size) {
// Now read the section header information.
uint8_t class_type;
if (!memory->Read(EI_CLASS, &class_type, 1)) {
if (!memory->ReadFully(EI_CLASS, &class_type, 1)) {
return;
}
if (class_type == ELFCLASS32) {
@ -174,12 +174,12 @@ ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) {
}
std::unique_ptr<ElfInterface> interface;
if (!memory->Read(EI_CLASS, &class_type_, 1)) {
if (!memory->ReadFully(EI_CLASS, &class_type_, 1)) {
return nullptr;
}
if (class_type_ == ELFCLASS32) {
Elf32_Half e_machine;
if (!memory->Read(EI_NIDENT + sizeof(Elf32_Half), &e_machine, sizeof(e_machine))) {
if (!memory->ReadFully(EI_NIDENT + sizeof(Elf32_Half), &e_machine, sizeof(e_machine))) {
return nullptr;
}
@ -200,7 +200,7 @@ ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) {
}
} else if (class_type_ == ELFCLASS64) {
Elf64_Half e_machine;
if (!memory->Read(EI_NIDENT + sizeof(Elf64_Half), &e_machine, sizeof(e_machine))) {
if (!memory->ReadFully(EI_NIDENT + sizeof(Elf64_Half), &e_machine, sizeof(e_machine))) {
return nullptr;
}
if (e_machine != EM_AARCH64 && e_machine != EM_X86_64) {

View File

@ -53,7 +53,7 @@ Memory* ElfInterface::CreateGnuDebugdataMemory() {
Crc64GenerateTable();
std::vector<uint8_t> src(gnu_debugdata_size_);
if (!memory_->Read(gnu_debugdata_offset_, src.data(), gnu_debugdata_size_)) {
if (!memory_->ReadFully(gnu_debugdata_offset_, src.data(), gnu_debugdata_size_)) {
gnu_debugdata_offset_ = 0;
gnu_debugdata_size_ = static_cast<uint64_t>(-1);
return nullptr;
@ -131,7 +131,7 @@ void ElfInterface::InitHeadersWithTemplate() {
template <typename EhdrType, typename PhdrType, typename ShdrType>
bool ElfInterface::ReadAllHeaders(uint64_t* load_bias) {
EhdrType ehdr;
if (!memory_->Read(0, &ehdr, sizeof(ehdr))) {
if (!memory_->ReadFully(0, &ehdr, sizeof(ehdr))) {
return false;
}
@ -242,7 +242,7 @@ bool ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
}
if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
if (!memory_->Read(offset, &shdr, sizeof(shdr))) {
if (!memory_->ReadFully(offset, &shdr, sizeof(shdr))) {
return false;
}
// Need to go get the information about the section that contains
@ -324,7 +324,7 @@ bool ElfInterface::GetSonameWithTemplate(std::string* soname) {
uint64_t offset = dynamic_offset_;
uint64_t max_offset = offset + dynamic_size_;
for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
if (!memory_->Read(offset, &dyn, sizeof(dyn))) {
if (!memory_->ReadFully(offset, &dyn, sizeof(dyn))) {
return false;
}
@ -388,7 +388,7 @@ bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* f
template <typename EhdrType>
void ElfInterface::GetMaxSizeWithTemplate(Memory* memory, uint64_t* size) {
EhdrType ehdr;
if (!memory->Read(0, &ehdr, sizeof(ehdr))) {
if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
return;
}
if (ehdr.e_shnum == 0) {

View File

@ -102,7 +102,7 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
if (!(flags & PROT_READ)) {
return nullptr;
}
return new MemoryRange(process_memory, start, end);
return new MemoryRange(process_memory, start, end - start, 0);
}
Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata) {

View File

@ -32,14 +32,69 @@
#include "Check.h"
static size_t ProcessVmRead(pid_t pid, void* dst, uint64_t remote_src, size_t len) {
struct iovec dst_iov = {
.iov_base = dst,
.iov_len = len,
};
// Split up the remote read across page boundaries.
// From the manpage:
// A partial read/write may result if one of the remote_iov elements points to an invalid
// memory region in the remote process.
//
// Partial transfers apply at the granularity of iovec elements. These system calls won't
// perform a partial transfer that splits a single iovec element.
constexpr size_t kMaxIovecs = 64;
struct iovec src_iovs[kMaxIovecs];
size_t iovecs_used = 0;
uint64_t cur = remote_src;
while (len > 0) {
if (iovecs_used == kMaxIovecs) {
errno = EINVAL;
return 0;
}
// struct iovec uses void* for iov_base.
if (cur >= UINTPTR_MAX) {
errno = EFAULT;
return 0;
}
src_iovs[iovecs_used].iov_base = reinterpret_cast<void*>(cur);
uintptr_t misalignment = cur & (getpagesize() - 1);
size_t iov_len = getpagesize() - misalignment;
iov_len = std::min(iov_len, len);
len -= iov_len;
if (__builtin_add_overflow(cur, iov_len, &cur)) {
errno = EFAULT;
return 0;
}
src_iovs[iovecs_used].iov_len = iov_len;
++iovecs_used;
}
ssize_t rc = process_vm_readv(pid, &dst_iov, 1, src_iovs, iovecs_used, 0);
return rc == -1 ? 0 : rc;
}
namespace unwindstack {
bool Memory::ReadFully(uint64_t addr, void* dst, size_t size) {
size_t rc = Read(addr, dst, size);
return rc == size;
}
bool Memory::ReadString(uint64_t addr, std::string* string, uint64_t max_read) {
string->clear();
uint64_t bytes_read = 0;
while (bytes_read < max_read) {
uint8_t value;
if (!Read(addr, &value, sizeof(value))) {
if (!ReadFully(addr, &value, sizeof(value))) {
return false;
}
if (value == '\0') {
@ -59,16 +114,17 @@ std::shared_ptr<Memory> Memory::CreateProcessMemory(pid_t pid) {
return std::shared_ptr<Memory>(new MemoryRemote(pid));
}
bool MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
uint64_t last_read_byte;
if (__builtin_add_overflow(size, addr, &last_read_byte)) {
return false;
size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
if (addr >= raw_.size()) {
return 0;
}
if (last_read_byte > raw_.size()) {
return false;
}
memcpy(dst, &raw_[addr], size);
return true;
size_t bytes_left = raw_.size() - static_cast<size_t>(addr);
const unsigned char* actual_base = static_cast<const unsigned char*>(raw_.data()) + addr;
size_t actual_len = std::min(bytes_left, size);
memcpy(dst, actual_base, actual_len);
return actual_len;
}
uint8_t* MemoryBuffer::GetPtr(size_t offset) {
@ -129,145 +185,77 @@ bool MemoryFileAtOffset::Init(const std::string& file, uint64_t offset, uint64_t
return true;
}
bool MemoryFileAtOffset::Read(uint64_t addr, void* dst, size_t size) {
uint64_t max_size;
if (__builtin_add_overflow(addr, size, &max_size) || max_size > size_) {
return false;
size_t MemoryFileAtOffset::Read(uint64_t addr, void* dst, size_t size) {
if (addr >= size_) {
return 0;
}
memcpy(dst, &data_[addr], size);
return true;
size_t bytes_left = size_ - static_cast<size_t>(addr);
const unsigned char* actual_base = static_cast<const unsigned char*>(data_) + addr;
size_t actual_len = std::min(bytes_left, size);
memcpy(dst, actual_base, actual_len);
return actual_len;
}
bool MemoryRemote::PtraceRead(uint64_t addr, long* value) {
#if !defined(__LP64__)
// Cannot read an address greater than 32 bits.
if (addr > UINT32_MAX) {
return false;
}
#endif
// ptrace() returns -1 and sets errno when the operation fails.
// To disambiguate -1 from a valid result, we clear errno beforehand.
errno = 0;
*value = ptrace(PTRACE_PEEKTEXT, pid_, reinterpret_cast<void*>(addr), nullptr);
if (*value == -1 && errno) {
return false;
}
return true;
size_t MemoryRemote::Read(uint64_t addr, void* dst, size_t size) {
return ProcessVmRead(pid_, dst, addr, size);
}
bool MemoryRemote::Read(uint64_t addr, void* dst, size_t bytes) {
// Make sure that there is no overflow.
uint64_t max_size;
if (__builtin_add_overflow(addr, bytes, &max_size)) {
return false;
}
size_t bytes_read = 0;
long data;
size_t align_bytes = addr & (sizeof(long) - 1);
if (align_bytes != 0) {
if (!PtraceRead(addr & ~(sizeof(long) - 1), &data)) {
return false;
}
size_t copy_bytes = std::min(sizeof(long) - align_bytes, bytes);
memcpy(dst, reinterpret_cast<uint8_t*>(&data) + align_bytes, copy_bytes);
addr += copy_bytes;
dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + copy_bytes);
bytes -= copy_bytes;
bytes_read += copy_bytes;
}
for (size_t i = 0; i < bytes / sizeof(long); i++) {
if (!PtraceRead(addr, &data)) {
return false;
}
memcpy(dst, &data, sizeof(long));
dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
addr += sizeof(long);
bytes_read += sizeof(long);
}
size_t left_over = bytes & (sizeof(long) - 1);
if (left_over) {
if (!PtraceRead(addr, &data)) {
return false;
}
memcpy(dst, &data, left_over);
bytes_read += left_over;
}
return true;
size_t MemoryLocal::Read(uint64_t addr, void* dst, size_t size) {
return ProcessVmRead(getpid(), dst, addr, size);
}
bool MemoryLocal::Read(uint64_t addr, void* dst, size_t size) {
// Make sure that there is no overflow.
uint64_t max_size;
if (__builtin_add_overflow(addr, size, &max_size)) {
return false;
MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
uint64_t offset)
: memory_(memory), begin_(begin), length_(length), offset_(offset) {}
size_t MemoryRange::Read(uint64_t addr, void* dst, size_t size) {
if (addr < offset_) {
return 0;
}
// The process_vm_readv call will not always work on remote
// processes, so only use it for reads from the current pid.
// Use this method to avoid crashes if an address is invalid since
// unwind data could try to access any part of the address space.
struct iovec local_io;
local_io.iov_base = dst;
local_io.iov_len = size;
struct iovec remote_io;
remote_io.iov_base = reinterpret_cast<void*>(static_cast<uintptr_t>(addr));
remote_io.iov_len = size;
ssize_t bytes_read = process_vm_readv(getpid(), &local_io, 1, &remote_io, 1, 0);
if (bytes_read == -1) {
return false;
uint64_t read_offset = addr - offset_;
if (read_offset >= length_) {
return 0;
}
return static_cast<size_t>(bytes_read) == size;
uint64_t read_length = std::min(static_cast<uint64_t>(size), length_ - read_offset);
uint64_t read_addr;
if (__builtin_add_overflow(read_offset, begin_, &read_addr)) {
return 0;
}
return memory_->Read(read_addr, dst, read_length);
}
bool MemoryOffline::Init(const std::string& file, uint64_t offset) {
if (!MemoryFileAtOffset::Init(file, offset)) {
auto memory_file = std::make_shared<MemoryFileAtOffset>();
if (!memory_file->Init(file, offset)) {
return false;
}
// The first uint64_t value is the start of memory.
if (!MemoryFileAtOffset::Read(0, &start_, sizeof(start_))) {
uint64_t start;
if (!memory_file->ReadFully(0, &start, sizeof(start))) {
return false;
}
// Subtract the first 64 bit value from the total size.
size_ -= sizeof(start_);
uint64_t size = memory_file->Size();
if (__builtin_sub_overflow(size, sizeof(start), &size)) {
return false;
}
memory_ = std::make_unique<MemoryRange>(memory_file, sizeof(start), size, start);
return true;
}
bool MemoryOffline::Read(uint64_t addr, void* dst, size_t size) {
uint64_t max_size;
if (__builtin_add_overflow(addr, size, &max_size)) {
return false;
size_t MemoryOffline::Read(uint64_t addr, void* dst, size_t size) {
if (!memory_) {
return 0;
}
uint64_t real_size;
if (__builtin_add_overflow(start_, offset_, &real_size) ||
__builtin_add_overflow(real_size, size_, &real_size)) {
return false;
}
if (addr < start_ || max_size > real_size) {
return false;
}
memcpy(dst, &data_[addr + offset_ - start_ + sizeof(start_)], size);
return true;
}
MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t end)
: memory_(memory), begin_(begin), length_(end - begin) {
CHECK(end > begin);
}
bool MemoryRange::Read(uint64_t addr, void* dst, size_t size) {
uint64_t max_read;
if (__builtin_add_overflow(addr, size, &max_read) || max_read > length_) {
return false;
}
// The check above guarantees that addr + begin_ will not overflow.
return memory_->Read(addr + begin_, dst, size);
return memory_->Read(addr, dst, size);
}
} // namespace unwindstack

View File

@ -58,7 +58,7 @@ uint64_t RegsArm::GetAdjustedPc(uint64_t rel_pc, Elf* elf) {
if (adjusted_rel_pc & 1) {
// This is a thumb instruction, it could be 2 or 4 bytes.
uint32_t value;
if (rel_pc < 5 || !elf->memory()->Read(adjusted_rel_pc - 5, &value, sizeof(value)) ||
if (rel_pc < 5 || !elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
(value & 0xe000f000) != 0xe000f000) {
return rel_pc - 2;
}
@ -193,7 +193,7 @@ void RegsX86::SetFromRaw() {
bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) {
// Attempt to get the return address from the top of the stack.
uint32_t new_pc;
if (!process_memory->Read(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
return false;
}
@ -240,7 +240,7 @@ void RegsX86_64::SetFromRaw() {
bool RegsX86_64::SetPcFromReturnAddress(Memory* process_memory) {
// Attempt to get the return address from the top of the stack.
uint64_t new_pc;
if (!process_memory->Read(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) {
return false;
}
@ -474,7 +474,7 @@ bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_mem
Memory* elf_memory = elf->memory();
// Read from elf memory since it is usually more expensive to read from
// process memory.
if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
return false;
}
@ -493,7 +493,7 @@ bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_mem
// Form 3 (thumb):
// 0x77 0x27 movs r7, #77
// 0x00 0xdf svc 0
if (!process_memory->Read(sp(), &data, sizeof(data))) {
if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
return false;
}
if (data == 0x5ac3c35a) {
@ -517,7 +517,7 @@ bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_mem
// Form 3 (thumb):
// 0xad 0x27 movs r7, #ad
// 0x00 0xdf svc 0
if (!process_memory->Read(sp(), &data, sizeof(data))) {
if (!process_memory->ReadFully(sp(), &data, sizeof(data))) {
return false;
}
if (data == sp() + 8) {
@ -532,7 +532,7 @@ bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_mem
return false;
}
if (!process_memory->Read(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
if (!process_memory->ReadFully(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
return false;
}
SetFromRaw();
@ -544,7 +544,7 @@ bool RegsArm64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_m
Memory* elf_memory = elf->memory();
// Read from elf memory since it is usually more expensive to read from
// process memory.
if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
return false;
}
@ -557,8 +557,8 @@ bool RegsArm64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_m
}
// SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
if (!process_memory->Read(sp() + 0x80 + 0xb0 + 0x08, regs_.data(),
sizeof(uint64_t) * ARM64_REG_LAST)) {
if (!process_memory->ReadFully(sp() + 0x80 + 0xb0 + 0x08, regs_.data(),
sizeof(uint64_t) * ARM64_REG_LAST)) {
return false;
}
@ -571,7 +571,7 @@ bool RegsX86::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_mem
Memory* elf_memory = elf->memory();
// Read from elf memory since it is usually more expensive to read from
// process memory.
if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
return false;
}
@ -587,7 +587,7 @@ bool RegsX86::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_mem
// int signum
// struct sigcontext (same format as mcontext)
struct x86_mcontext_t context;
if (!process_memory->Read(sp() + 4, &context, sizeof(context))) {
if (!process_memory->ReadFully(sp() + 4, &context, sizeof(context))) {
return false;
}
regs_[X86_REG_EBP] = context.ebp;
@ -613,12 +613,12 @@ bool RegsX86::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_mem
// Get the location of the sigcontext data.
uint32_t ptr;
if (!process_memory->Read(sp() + 8, &ptr, sizeof(ptr))) {
if (!process_memory->ReadFully(sp() + 8, &ptr, sizeof(ptr))) {
return false;
}
// Only read the portion of the data structure we care about.
x86_ucontext_t x86_ucontext;
if (!process_memory->Read(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
if (!process_memory->ReadFully(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
return false;
}
SetFromUcontext(&x86_ucontext);
@ -632,12 +632,12 @@ bool RegsX86_64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_
Memory* elf_memory = elf->memory();
// Read from elf memory since it is usually more expensive to read from
// process memory.
if (!elf_memory->Read(rel_pc, &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
return false;
}
uint16_t data2;
if (!elf_memory->Read(rel_pc + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
if (!elf_memory->ReadFully(rel_pc + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
return false;
}
@ -649,7 +649,8 @@ bool RegsX86_64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_
// Read the mcontext data from the stack.
// sp points to the ucontext data structure, read only the mcontext part.
x86_64_ucontext_t x86_64_ucontext;
if (!process_memory->Read(sp() + 0x28, &x86_64_ucontext.uc_mcontext, sizeof(x86_64_mcontext_t))) {
if (!process_memory->ReadFully(sp() + 0x28, &x86_64_ucontext.uc_mcontext,
sizeof(x86_64_mcontext_t))) {
return false;
}
SetFromUcontext(&x86_64_ucontext);

View File

@ -71,7 +71,7 @@ bool Symbols::GetName(uint64_t addr, uint64_t load_bias, Memory* elf_memory, std
bool return_value = false;
while (cur_offset_ + entry_size_ <= end_) {
SymType entry;
if (!elf_memory->Read(cur_offset_, &entry, sizeof(entry))) {
if (!elf_memory->ReadFully(cur_offset_, &entry, sizeof(entry))) {
// Stop all processing, something looks like it is corrupted.
cur_offset_ = UINT64_MAX;
return false;

View File

@ -36,7 +36,9 @@ class Memory {
virtual bool ReadString(uint64_t addr, std::string* string, uint64_t max_read = UINT64_MAX);
virtual bool Read(uint64_t addr, void* dst, size_t size) = 0;
virtual size_t Read(uint64_t addr, void* dst, size_t size) = 0;
bool ReadFully(uint64_t addr, void* dst, size_t size);
inline bool ReadField(uint64_t addr, void* start, void* field, size_t size) {
if (reinterpret_cast<uintptr_t>(field) < reinterpret_cast<uintptr_t>(start)) {
@ -47,12 +49,16 @@ class Memory {
return false;
}
// The read will check if offset + size overflows.
return Read(offset, field, size);
return ReadFully(offset, field, size);
}
inline bool Read32(uint64_t addr, uint32_t* dst) { return Read(addr, dst, sizeof(uint32_t)); }
inline bool Read32(uint64_t addr, uint32_t* dst) {
return ReadFully(addr, dst, sizeof(uint32_t));
}
inline bool Read64(uint64_t addr, uint64_t* dst) { return Read(addr, dst, sizeof(uint64_t)); }
inline bool Read64(uint64_t addr, uint64_t* dst) {
return ReadFully(addr, dst, sizeof(uint64_t));
}
};
class MemoryBuffer : public Memory {
@ -60,7 +66,7 @@ class MemoryBuffer : public Memory {
MemoryBuffer() = default;
virtual ~MemoryBuffer() = default;
bool Read(uint64_t addr, void* dst, size_t size) override;
size_t Read(uint64_t addr, void* dst, size_t size) override;
uint8_t* GetPtr(size_t offset);
@ -79,7 +85,9 @@ class MemoryFileAtOffset : public Memory {
bool Init(const std::string& file, uint64_t offset, uint64_t size = UINT64_MAX);
bool Read(uint64_t addr, void* dst, size_t size) override;
size_t Read(uint64_t addr, void* dst, size_t size) override;
size_t Size() { return size_; }
void Clear();
@ -89,31 +97,15 @@ class MemoryFileAtOffset : public Memory {
uint8_t* data_ = nullptr;
};
class MemoryOffline : public MemoryFileAtOffset {
public:
MemoryOffline() = default;
virtual ~MemoryOffline() = default;
bool Init(const std::string& file, uint64_t offset);
bool Read(uint64_t addr, void* dst, size_t size) override;
private:
uint64_t start_;
};
class MemoryRemote : public Memory {
public:
MemoryRemote(pid_t pid) : pid_(pid) {}
virtual ~MemoryRemote() = default;
bool Read(uint64_t addr, void* dst, size_t size) override;
size_t Read(uint64_t addr, void* dst, size_t size) override;
pid_t pid() { return pid_; }
protected:
virtual bool PtraceRead(uint64_t addr, long* value);
private:
pid_t pid_;
};
@ -123,20 +115,38 @@ class MemoryLocal : public Memory {
MemoryLocal() = default;
virtual ~MemoryLocal() = default;
bool Read(uint64_t addr, void* dst, size_t size) override;
size_t Read(uint64_t addr, void* dst, size_t size) override;
};
// MemoryRange maps one address range onto another.
// The range [src_begin, src_begin + length) in the underlying Memory is mapped onto offset,
// such that range.read(offset) is equivalent to underlying.read(src_begin).
class MemoryRange : public Memory {
public:
MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t end);
MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
uint64_t offset);
virtual ~MemoryRange() = default;
bool Read(uint64_t addr, void* dst, size_t size) override;
size_t Read(uint64_t addr, void* dst, size_t size) override;
private:
std::shared_ptr<Memory> memory_;
uint64_t begin_;
uint64_t length_;
uint64_t offset_;
};
class MemoryOffline : public Memory {
public:
MemoryOffline() = default;
virtual ~MemoryOffline() = default;
bool Init(const std::string& file, uint64_t offset);
size_t Read(uint64_t addr, void* dst, size_t size) override;
private:
std::unique_ptr<MemoryRange> memory_;
};
} // namespace unwindstack

View File

@ -120,14 +120,14 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
// Read the entire file.
std::vector<uint8_t> buffer(1024);
ASSERT_TRUE(memory->Read(0, buffer.data(), 1024));
ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 1024));
ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0);
ASSERT_EQ(ELFCLASS32, buffer[EI_CLASS]);
for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) {
ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
}
ASSERT_FALSE(memory->Read(1024, buffer.data(), 1));
ASSERT_FALSE(memory->ReadFully(1024, buffer.data(), 1));
}
// Verify that if the offset is non-zero and there is an elf at that
@ -141,14 +141,14 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
// Read the valid part of the file.
std::vector<uint8_t> buffer(0x100);
ASSERT_TRUE(memory->Read(0, buffer.data(), 0x100));
ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 0x100));
ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0);
ASSERT_EQ(ELFCLASS64, buffer[EI_CLASS]);
for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) {
ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
}
ASSERT_FALSE(memory->Read(0x100, buffer.data(), 1));
ASSERT_FALSE(memory->ReadFully(0x100, buffer.data(), 1));
}
// Verify that if the offset is non-zero and there is an elf at that
@ -164,11 +164,11 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_e
// Verify the memory is a valid elf.
uint8_t e_ident[SELFMAG + 1];
ASSERT_TRUE(memory->Read(0, e_ident, SELFMAG));
ASSERT_TRUE(memory->ReadFully(0, e_ident, SELFMAG));
ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG));
// Read past the end of what would normally be the size of the map.
ASSERT_TRUE(memory->Read(0x1000, e_ident, 1));
ASSERT_TRUE(memory->ReadFully(0x1000, e_ident, 1));
}
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
@ -180,11 +180,11 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_e
// Verify the memory is a valid elf.
uint8_t e_ident[SELFMAG + 1];
ASSERT_TRUE(memory->Read(0, e_ident, SELFMAG));
ASSERT_TRUE(memory->ReadFully(0, e_ident, SELFMAG));
ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG));
// Read past the end of what would normally be the size of the map.
ASSERT_TRUE(memory->Read(0x1000, e_ident, 1));
ASSERT_TRUE(memory->ReadFully(0x1000, e_ident, 1));
}
// Verify that device file names will never result in Memory object creation.
@ -221,13 +221,13 @@ TEST_F(MapInfoCreateMemoryTest, process_memory) {
ASSERT_TRUE(memory.get() != nullptr);
memset(buffer.data(), 0, buffer.size());
ASSERT_TRUE(memory->Read(0, buffer.data(), buffer.size()));
ASSERT_TRUE(memory->ReadFully(0, buffer.data(), buffer.size()));
for (size_t i = 0; i < buffer.size(); i++) {
ASSERT_EQ(i % 256, buffer[i]) << "Failed at byte " << i;
}
// Try to read outside of the map size.
ASSERT_FALSE(memory->Read(buffer.size(), buffer.data(), 1));
ASSERT_FALSE(memory->ReadFully(buffer.size(), buffer.data(), 1));
}
} // namespace unwindstack

View File

@ -216,13 +216,13 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
// Read the entire file.
memset(buffer.data(), 0, buffer.size());
ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), buffer.size()));
ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), buffer.size()));
ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
}
ASSERT_FALSE(elf->memory()->Read(buffer.size(), buffer.data(), 1));
ASSERT_FALSE(elf->memory()->ReadFully(buffer.size(), buffer.data(), 1));
}
// Verify that if the offset is non-zero and there is an elf at that
@ -244,13 +244,13 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
ASSERT_EQ(0U, info.elf_offset);
// Read the valid part of the file.
ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000));
ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
for (size_t i = sizeof(ehdr); i < 0x1000; i++) {
ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
}
ASSERT_FALSE(elf->memory()->Read(0x1000, buffer.data(), 1));
ASSERT_FALSE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
}
// Verify that if the offset is non-zero and there is an elf at that
@ -278,11 +278,11 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32)
// Verify the memory is a valid elf.
memset(buffer.data(), 0, buffer.size());
ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000));
ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
// Read past the end of what would normally be the size of the map.
ASSERT_TRUE(elf->memory()->Read(0x1000, buffer.data(), 1));
ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
}
TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
@ -306,11 +306,11 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64)
// Verify the memory is a valid elf.
memset(buffer.data(), 0, buffer.size());
ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000));
ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
// Read past the end of what would normally be the size of the map.
ASSERT_TRUE(elf->memory()->Read(0x1000, buffer.data(), 1));
ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
}
TEST_F(MapInfoGetElfTest, process_memory_not_read_only) {

View File

@ -36,7 +36,7 @@ class MemoryBufferTest : public ::testing::Test {
TEST_F(MemoryBufferTest, empty) {
ASSERT_EQ(0U, memory_->Size());
std::vector<uint8_t> buffer(1024);
ASSERT_FALSE(memory_->Read(0, buffer.data(), 1));
ASSERT_FALSE(memory_->ReadFully(0, buffer.data(), 1));
ASSERT_EQ(nullptr, memory_->GetPtr(0));
ASSERT_EQ(nullptr, memory_->GetPtr(1));
}
@ -55,7 +55,7 @@ TEST_F(MemoryBufferTest, write_read) {
}
std::vector<uint8_t> buffer(memory_->Size());
ASSERT_TRUE(memory_->Read(0, buffer.data(), buffer.size()));
ASSERT_TRUE(memory_->ReadFully(0, buffer.data(), buffer.size()));
for (size_t i = 0; i < buffer.size(); i++) {
ASSERT_EQ(i, buffer[i]) << "Failed at byte " << i;
}
@ -64,18 +64,38 @@ TEST_F(MemoryBufferTest, write_read) {
TEST_F(MemoryBufferTest, read_failures) {
memory_->Resize(100);
std::vector<uint8_t> buffer(200);
ASSERT_FALSE(memory_->Read(0, buffer.data(), 101));
ASSERT_FALSE(memory_->Read(100, buffer.data(), 1));
ASSERT_FALSE(memory_->Read(101, buffer.data(), 2));
ASSERT_FALSE(memory_->Read(99, buffer.data(), 2));
ASSERT_TRUE(memory_->Read(99, buffer.data(), 1));
ASSERT_FALSE(memory_->ReadFully(0, buffer.data(), 101));
ASSERT_FALSE(memory_->ReadFully(100, buffer.data(), 1));
ASSERT_FALSE(memory_->ReadFully(101, buffer.data(), 2));
ASSERT_FALSE(memory_->ReadFully(99, buffer.data(), 2));
ASSERT_TRUE(memory_->ReadFully(99, buffer.data(), 1));
}
TEST_F(MemoryBufferTest, read_failure_overflow) {
memory_->Resize(100);
std::vector<uint8_t> buffer(200);
ASSERT_FALSE(memory_->Read(UINT64_MAX - 100, buffer.data(), 200));
ASSERT_FALSE(memory_->ReadFully(UINT64_MAX - 100, buffer.data(), 200));
}
TEST_F(MemoryBufferTest, Read) {
memory_->Resize(256);
ASSERT_EQ(256U, memory_->Size());
ASSERT_TRUE(memory_->GetPtr(0) != nullptr);
ASSERT_TRUE(memory_->GetPtr(1) != nullptr);
ASSERT_TRUE(memory_->GetPtr(255) != nullptr);
ASSERT_TRUE(memory_->GetPtr(256) == nullptr);
uint8_t* data = memory_->GetPtr(0);
for (size_t i = 0; i < memory_->Size(); i++) {
data[i] = i;
}
std::vector<uint8_t> buffer(memory_->Size());
ASSERT_EQ(128U, memory_->Read(128, buffer.data(), buffer.size()));
for (size_t i = 0; i < 128; i++) {
ASSERT_EQ(128 + i, buffer[i]) << "Failed at byte " << i;
}
}
} // namespace unwindstack

View File

@ -35,16 +35,16 @@ void MemoryFake::SetMemory(uint64_t addr, const void* memory, size_t length) {
}
}
bool MemoryFake::Read(uint64_t addr, void* memory, size_t size) {
size_t MemoryFake::Read(uint64_t addr, void* memory, size_t size) {
uint8_t* dst = reinterpret_cast<uint8_t*>(memory);
for (size_t i = 0; i < size; i++, addr++) {
auto value = data_.find(addr);
if (value == data_.end()) {
return false;
return i;
}
dst[i] = value->second;
}
return true;
return size;
}
} // namespace unwindstack

View File

@ -32,7 +32,7 @@ class MemoryFake : public Memory {
MemoryFake() = default;
virtual ~MemoryFake() = default;
bool Read(uint64_t addr, void* buffer, size_t size) override;
size_t Read(uint64_t addr, void* buffer, size_t size) override;
void SetMemory(uint64_t addr, const void* memory, size_t length);
@ -71,21 +71,9 @@ class MemoryFakeAlwaysReadZero : public Memory {
MemoryFakeAlwaysReadZero() = default;
virtual ~MemoryFakeAlwaysReadZero() = default;
bool Read(uint64_t, void* buffer, size_t size) override {
size_t Read(uint64_t, void* buffer, size_t size) override {
memset(buffer, 0, size);
return true;
}
};
class MemoryFakeRemote : public MemoryRemote {
public:
MemoryFakeRemote() : MemoryRemote(0) {}
virtual ~MemoryFakeRemote() = default;
protected:
bool PtraceRead(uint64_t, long* value) override {
*value = 0;
return true;
return size;
}
};

View File

@ -49,7 +49,7 @@ TEST_F(MemoryFileTest, init_offset_0) {
ASSERT_TRUE(memory_.Init(tf_->path, 0));
std::vector<char> buffer(11);
ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
buffer[10] = '\0';
ASSERT_STREQ("0123456789", buffer.data());
}
@ -59,7 +59,7 @@ TEST_F(MemoryFileTest, init_offset_non_zero) {
ASSERT_TRUE(memory_.Init(tf_->path, 10));
std::vector<char> buffer(11);
ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
buffer[10] = '\0';
ASSERT_STREQ("abcdefghij", buffer.data());
}
@ -75,7 +75,7 @@ TEST_F(MemoryFileTest, init_offset_non_zero_larger_than_pagesize) {
ASSERT_TRUE(memory_.Init(tf_->path, pagesize + 15));
std::vector<char> buffer(9);
ASSERT_TRUE(memory_.Read(0, buffer.data(), 8));
ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 8));
buffer[8] = '\0';
ASSERT_STREQ("abcdefgh", buffer.data());
}
@ -91,7 +91,7 @@ TEST_F(MemoryFileTest, init_offset_pagesize_aligned) {
ASSERT_TRUE(memory_.Init(tf_->path, 2 * pagesize));
std::vector<char> buffer(11);
ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
buffer[10] = '\0';
std::string expected_str;
for (size_t i = 0; i < 5; i++) {
@ -112,7 +112,7 @@ TEST_F(MemoryFileTest, init_offset_pagesize_aligned_plus_extra) {
ASSERT_TRUE(memory_.Init(tf_->path, 2 * pagesize + 10));
std::vector<char> buffer(11);
ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
buffer[10] = '\0';
std::string expected_str;
for (size_t i = 0; i < 5; i++) {
@ -149,19 +149,19 @@ TEST_F(MemoryFileTest, read_error) {
std::vector<char> buffer(100);
// Read before init.
ASSERT_FALSE(memory_.Read(0, buffer.data(), 10));
ASSERT_FALSE(memory_.ReadFully(0, buffer.data(), 10));
ASSERT_TRUE(memory_.Init(tf_->path, 0));
ASSERT_FALSE(memory_.Read(10000, buffer.data(), 10));
ASSERT_FALSE(memory_.Read(5000, buffer.data(), 10));
ASSERT_FALSE(memory_.Read(4990, buffer.data(), 11));
ASSERT_TRUE(memory_.Read(4990, buffer.data(), 10));
ASSERT_FALSE(memory_.Read(4999, buffer.data(), 2));
ASSERT_TRUE(memory_.Read(4999, buffer.data(), 1));
ASSERT_FALSE(memory_.ReadFully(10000, buffer.data(), 10));
ASSERT_FALSE(memory_.ReadFully(5000, buffer.data(), 10));
ASSERT_FALSE(memory_.ReadFully(4990, buffer.data(), 11));
ASSERT_TRUE(memory_.ReadFully(4990, buffer.data(), 10));
ASSERT_FALSE(memory_.ReadFully(4999, buffer.data(), 2));
ASSERT_TRUE(memory_.ReadFully(4999, buffer.data(), 1));
// Check that overflow fails properly.
ASSERT_FALSE(memory_.Read(UINT64_MAX - 100, buffer.data(), 200));
ASSERT_FALSE(memory_.ReadFully(UINT64_MAX - 100, buffer.data(), 200));
}
TEST_F(MemoryFileTest, read_past_file_within_mapping) {
@ -178,7 +178,8 @@ TEST_F(MemoryFileTest, read_past_file_within_mapping) {
for (size_t i = 0; i < 100; i++) {
uint8_t value;
ASSERT_FALSE(memory_.Read(buffer.size() + i, &value, 1)) << "Should have failed at value " << i;
ASSERT_FALSE(memory_.ReadFully(buffer.size() + i, &value, 1))
<< "Should have failed at value " << i;
}
}
@ -195,8 +196,8 @@ TEST_F(MemoryFileTest, map_partial_offset_aligned) {
std::vector<uint8_t> read_buffer(pagesize * 2);
// Make sure that reading after mapped data is a failure.
ASSERT_FALSE(memory_.Read(pagesize * 2, read_buffer.data(), 1));
ASSERT_TRUE(memory_.Read(0, read_buffer.data(), pagesize * 2));
ASSERT_FALSE(memory_.ReadFully(pagesize * 2, read_buffer.data(), 1));
ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize * 2));
for (size_t i = 0; i < pagesize; i++) {
ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
}
@ -219,8 +220,8 @@ TEST_F(MemoryFileTest, map_partial_offset_unaligned) {
std::vector<uint8_t> read_buffer(pagesize * 2);
// Make sure that reading after mapped data is a failure.
ASSERT_FALSE(memory_.Read(pagesize * 2, read_buffer.data(), 1));
ASSERT_TRUE(memory_.Read(0, read_buffer.data(), pagesize * 2));
ASSERT_FALSE(memory_.ReadFully(pagesize * 2, read_buffer.data(), 1));
ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize * 2));
for (size_t i = 0; i < pagesize - 0x100; i++) {
ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
}
@ -245,8 +246,8 @@ TEST_F(MemoryFileTest, map_overflow) {
ASSERT_TRUE(memory_.Init(tf_->path, pagesize + 0x100, UINT64_MAX));
std::vector<uint8_t> read_buffer(pagesize * 10);
ASSERT_FALSE(memory_.Read(pagesize * 9 - 0x100 + 1, read_buffer.data(), 1));
ASSERT_TRUE(memory_.Read(0, read_buffer.data(), pagesize * 9 - 0x100));
ASSERT_FALSE(memory_.ReadFully(pagesize * 9 - 0x100 + 1, read_buffer.data(), 1));
ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize * 9 - 0x100));
}
TEST_F(MemoryFileTest, init_reinit) {
@ -259,14 +260,14 @@ TEST_F(MemoryFileTest, init_reinit) {
ASSERT_TRUE(memory_.Init(tf_->path, 0));
std::vector<uint8_t> read_buffer(buffer.size());
ASSERT_TRUE(memory_.Read(0, read_buffer.data(), pagesize));
ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize));
for (size_t i = 0; i < pagesize; i++) {
ASSERT_EQ(1, read_buffer[i]) << "Failed at byte " << i;
}
// Now reinit.
ASSERT_TRUE(memory_.Init(tf_->path, pagesize));
ASSERT_TRUE(memory_.Read(0, read_buffer.data(), pagesize));
ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize));
for (size_t i = 0; i < pagesize; i++) {
ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
}

View File

@ -16,6 +16,7 @@
#include <stdint.h>
#include <string.h>
#include <sys/mman.h>
#include <vector>
@ -32,14 +33,14 @@ TEST(MemoryLocalTest, read) {
MemoryLocal local;
std::vector<uint8_t> dst(1024);
ASSERT_TRUE(local.Read(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024));
ASSERT_TRUE(local.ReadFully(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024));
ASSERT_EQ(0, memcmp(src.data(), dst.data(), 1024));
for (size_t i = 0; i < 1024; i++) {
ASSERT_EQ(0x4cU, dst[i]);
}
memset(src.data(), 0x23, 512);
ASSERT_TRUE(local.Read(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024));
ASSERT_TRUE(local.ReadFully(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024));
ASSERT_EQ(0, memcmp(src.data(), dst.data(), 1024));
for (size_t i = 0; i < 512; i++) {
ASSERT_EQ(0x23U, dst[i]);
@ -53,8 +54,8 @@ TEST(MemoryLocalTest, read_illegal) {
MemoryLocal local;
std::vector<uint8_t> dst(100);
ASSERT_FALSE(local.Read(0, dst.data(), 1));
ASSERT_FALSE(local.Read(0, dst.data(), 100));
ASSERT_FALSE(local.ReadFully(0, dst.data(), 1));
ASSERT_FALSE(local.ReadFully(0, dst.data(), 100));
}
TEST(MemoryLocalTest, read_overflow) {
@ -64,7 +65,47 @@ TEST(MemoryLocalTest, read_overflow) {
// version will always go through the overflow check.
std::vector<uint8_t> dst(100);
uint64_t value;
ASSERT_FALSE(local.Read(reinterpret_cast<uint64_t>(&value), dst.data(), SIZE_MAX));
ASSERT_FALSE(local.ReadFully(reinterpret_cast<uint64_t>(&value), dst.data(), SIZE_MAX));
}
TEST(MemoryLocalTest, Read) {
char* mapping = static_cast<char*>(
mmap(nullptr, 2 * getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
ASSERT_NE(MAP_FAILED, mapping);
mprotect(mapping + getpagesize(), getpagesize(), PROT_NONE);
memset(mapping + getpagesize() - 1024, 0x4c, 1024);
MemoryLocal local;
std::vector<uint8_t> dst(4096);
ASSERT_EQ(1024U, local.Read(reinterpret_cast<uint64_t>(mapping + getpagesize() - 1024),
dst.data(), 4096));
for (size_t i = 0; i < 1024; i++) {
ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
}
ASSERT_EQ(0, munmap(mapping, 2 * getpagesize()));
}
TEST(MemoryLocalTest, read_hole) {
void* mapping =
mmap(nullptr, 3 * 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
ASSERT_NE(MAP_FAILED, mapping);
memset(mapping, 0xFF, 3 * 4096);
mprotect(static_cast<char*>(mapping) + 4096, 4096, PROT_NONE);
MemoryLocal local;
std::vector<uint8_t> dst(4096 * 3, 0xCC);
ASSERT_EQ(4096U, local.Read(reinterpret_cast<uintptr_t>(mapping), dst.data(), 4096 * 3));
for (size_t i = 0; i < 4096; ++i) {
ASSERT_EQ(0xFF, dst[i]);
}
for (size_t i = 4096; i < 4096 * 3; ++i) {
ASSERT_EQ(0xCC, dst[i]);
}
ASSERT_EQ(0, munmap(mapping, 3 * 4096));
}
} // namespace unwindstack

View File

@ -35,10 +35,10 @@ TEST(MemoryRangeTest, read) {
std::shared_ptr<Memory> process_memory(memory_fake);
memory_fake->SetMemory(9001, src);
MemoryRange range(process_memory, 9001, 9001 + src.size());
MemoryRange range(process_memory, 9001, src.size(), 0);
std::vector<uint8_t> dst(1024);
ASSERT_TRUE(range.Read(0, dst.data(), src.size()));
ASSERT_TRUE(range.ReadFully(0, dst.data(), src.size()));
for (size_t i = 0; i < 1024; i++) {
ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
}
@ -51,29 +51,44 @@ TEST(MemoryRangeTest, read_near_limit) {
std::shared_ptr<Memory> process_memory(memory_fake);
memory_fake->SetMemory(1000, src);
MemoryRange range(process_memory, 1000, 2024);
MemoryRange range(process_memory, 1000, 1024, 0);
std::vector<uint8_t> dst(1024);
ASSERT_TRUE(range.Read(1020, dst.data(), 4));
ASSERT_TRUE(range.ReadFully(1020, dst.data(), 4));
for (size_t i = 0; i < 4; i++) {
ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
}
// Verify that reads outside of the range will fail.
ASSERT_FALSE(range.Read(1020, dst.data(), 5));
ASSERT_FALSE(range.Read(1024, dst.data(), 1));
ASSERT_FALSE(range.Read(1024, dst.data(), 1024));
ASSERT_FALSE(range.ReadFully(1020, dst.data(), 5));
ASSERT_FALSE(range.ReadFully(1024, dst.data(), 1));
ASSERT_FALSE(range.ReadFully(1024, dst.data(), 1024));
// Verify that reading up to the end works.
ASSERT_TRUE(range.Read(1020, dst.data(), 4));
ASSERT_TRUE(range.ReadFully(1020, dst.data(), 4));
}
TEST(MemoryRangeTest, read_overflow) {
std::vector<uint8_t> buffer(100);
std::shared_ptr<Memory> process_memory(new MemoryFakeAlwaysReadZero);
std::unique_ptr<MemoryRange> overflow(new MemoryRange(process_memory, 100, 200));
ASSERT_FALSE(overflow->Read(UINT64_MAX - 10, buffer.data(), 100));
std::unique_ptr<MemoryRange> overflow(new MemoryRange(process_memory, 100, 200, 0));
ASSERT_FALSE(overflow->ReadFully(UINT64_MAX - 10, buffer.data(), 100));
}
TEST(MemoryRangeTest, Read) {
std::vector<uint8_t> src(4096);
memset(src.data(), 0x4c, 4096);
MemoryFake* memory_fake = new MemoryFake;
std::shared_ptr<Memory> process_memory(memory_fake);
memory_fake->SetMemory(1000, src);
MemoryRange range(process_memory, 1000, 1024, 0);
std::vector<uint8_t> dst(1024);
ASSERT_EQ(4U, range.Read(1020, dst.data(), 1024));
for (size_t i = 0; i < 4; i++) {
ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
}
}
} // namespace unwindstack

View File

@ -71,7 +71,7 @@ TEST_F(MemoryRemoteTest, read) {
MemoryRemote remote(pid);
std::vector<uint8_t> dst(1024);
ASSERT_TRUE(remote.Read(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024));
ASSERT_TRUE(remote.ReadFully(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024));
for (size_t i = 0; i < 1024; i++) {
ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
}
@ -79,6 +79,39 @@ TEST_F(MemoryRemoteTest, read) {
ASSERT_TRUE(Detach(pid));
}
TEST_F(MemoryRemoteTest, Read) {
char* mapping = static_cast<char*>(
mmap(nullptr, 2 * getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
ASSERT_NE(MAP_FAILED, mapping);
mprotect(mapping + getpagesize(), getpagesize(), PROT_NONE);
memset(mapping + getpagesize() - 1024, 0x4c, 1024);
pid_t pid;
if ((pid = fork()) == 0) {
while (true)
;
exit(1);
}
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
ASSERT_TRUE(Attach(pid));
MemoryRemote remote(pid);
std::vector<uint8_t> dst(4096);
ASSERT_EQ(1024U, remote.Read(reinterpret_cast<uint64_t>(mapping + getpagesize() - 1024),
dst.data(), 4096));
for (size_t i = 0; i < 1024; i++) {
ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
}
ASSERT_TRUE(Detach(pid));
ASSERT_EQ(0, munmap(mapping, 2 * getpagesize()));
}
TEST_F(MemoryRemoteTest, read_fail) {
int pagesize = getpagesize();
void* src = mmap(nullptr, pagesize * 2, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,-1, 0);
@ -101,17 +134,17 @@ TEST_F(MemoryRemoteTest, read_fail) {
MemoryRemote remote(pid);
std::vector<uint8_t> dst(pagesize);
ASSERT_TRUE(remote.Read(reinterpret_cast<uint64_t>(src), dst.data(), pagesize));
ASSERT_TRUE(remote.ReadFully(reinterpret_cast<uint64_t>(src), dst.data(), pagesize));
for (size_t i = 0; i < 1024; i++) {
ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
}
ASSERT_FALSE(remote.Read(reinterpret_cast<uint64_t>(src) + pagesize, dst.data(), 1));
ASSERT_TRUE(remote.Read(reinterpret_cast<uint64_t>(src) + pagesize - 1, dst.data(), 1));
ASSERT_FALSE(remote.Read(reinterpret_cast<uint64_t>(src) + pagesize - 4, dst.data(), 8));
ASSERT_FALSE(remote.ReadFully(reinterpret_cast<uint64_t>(src) + pagesize, dst.data(), 1));
ASSERT_TRUE(remote.ReadFully(reinterpret_cast<uint64_t>(src) + pagesize - 1, dst.data(), 1));
ASSERT_FALSE(remote.ReadFully(reinterpret_cast<uint64_t>(src) + pagesize - 4, dst.data(), 8));
// Check overflow condition is caught properly.
ASSERT_FALSE(remote.Read(UINT64_MAX - 100, dst.data(), 200));
ASSERT_FALSE(remote.ReadFully(UINT64_MAX - 100, dst.data(), 200));
ASSERT_EQ(0, munmap(src, pagesize));
@ -119,11 +152,24 @@ TEST_F(MemoryRemoteTest, read_fail) {
}
TEST_F(MemoryRemoteTest, read_overflow) {
MemoryFakeRemote remote;
pid_t pid;
if ((pid = fork()) == 0) {
while (true)
;
exit(1);
}
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
ASSERT_TRUE(Attach(pid));
MemoryRemote remote(pid);
// Check overflow condition is caught properly.
std::vector<uint8_t> dst(200);
ASSERT_FALSE(remote.Read(UINT64_MAX - 100, dst.data(), 200));
ASSERT_FALSE(remote.ReadFully(UINT64_MAX - 100, dst.data(), 200));
ASSERT_TRUE(Detach(pid));
}
TEST_F(MemoryRemoteTest, read_illegal) {
@ -140,10 +186,38 @@ TEST_F(MemoryRemoteTest, read_illegal) {
MemoryRemote remote(pid);
std::vector<uint8_t> dst(100);
ASSERT_FALSE(remote.Read(0, dst.data(), 1));
ASSERT_FALSE(remote.Read(0, dst.data(), 100));
ASSERT_FALSE(remote.ReadFully(0, dst.data(), 1));
ASSERT_FALSE(remote.ReadFully(0, dst.data(), 100));
ASSERT_TRUE(Detach(pid));
}
TEST_F(MemoryRemoteTest, read_hole) {
void* mapping =
mmap(nullptr, 3 * 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
ASSERT_NE(MAP_FAILED, mapping);
memset(mapping, 0xFF, 3 * 4096);
mprotect(static_cast<char*>(mapping) + 4096, 4096, PROT_NONE);
pid_t pid;
if ((pid = fork()) == 0) {
while (true);
exit(1);
}
ASSERT_LT(0, pid);
TestScopedPidReaper reap(pid);
ASSERT_TRUE(Attach(pid));
MemoryRemote remote(pid);
std::vector<uint8_t> dst(4096 * 3, 0xCC);
ASSERT_EQ(4096U, remote.Read(reinterpret_cast<uintptr_t>(mapping), dst.data(), 4096 * 3));
for (size_t i = 0; i < 4096; ++i) {
ASSERT_EQ(0xFF, dst[i]);
}
for (size_t i = 4096; i < 4096 * 3; ++i) {
ASSERT_EQ(0xCC, dst[i]);
}
}
} // namespace unwindstack

View File

@ -174,7 +174,7 @@ void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* complete
MemoryRemote memory(pid);
// Read the remote value to see if we are ready.
bool value;
if (memory.Read(addr, &value, sizeof(value)) && value) {
if (memory.ReadFully(addr, &value, sizeof(value)) && value) {
*completed = true;
}
if (!*completed || !leave_attached) {