2017-04-19 22:42:19 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* 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 <elf.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/ptrace.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include <android-base/file.h>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
2017-07-14 17:37:19 +00:00
|
|
|
#include <unwindstack/Elf.h>
|
|
|
|
#include <unwindstack/MapInfo.h>
|
2018-10-02 04:01:09 +00:00
|
|
|
#include <unwindstack/Maps.h>
|
2017-07-14 17:37:19 +00:00
|
|
|
#include <unwindstack/Memory.h>
|
|
|
|
|
2018-10-02 04:01:09 +00:00
|
|
|
#include "ElfTestUtils.h"
|
2017-09-01 18:17:16 +00:00
|
|
|
#include "MemoryFake.h"
|
|
|
|
|
2017-07-14 17:37:19 +00:00
|
|
|
namespace unwindstack {
|
2017-04-19 22:42:19 +00:00
|
|
|
|
2017-07-01 00:18:16 +00:00
|
|
|
class MapInfoCreateMemoryTest : public ::testing::Test {
|
2017-04-19 22:42:19 +00:00
|
|
|
protected:
|
2017-08-30 20:15:19 +00:00
|
|
|
template <typename Ehdr, typename Shdr>
|
|
|
|
static void InitElf(int fd, uint64_t file_offset, uint64_t sh_offset, uint8_t class_type) {
|
|
|
|
std::vector<uint8_t> buffer(20000);
|
|
|
|
memset(buffer.data(), 0, buffer.size());
|
|
|
|
|
|
|
|
Ehdr ehdr;
|
|
|
|
memset(&ehdr, 0, sizeof(ehdr));
|
|
|
|
memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
|
|
|
|
ehdr.e_ident[EI_CLASS] = class_type;
|
|
|
|
ehdr.e_shoff = sh_offset;
|
|
|
|
ehdr.e_shentsize = sizeof(Shdr) + 100;
|
|
|
|
ehdr.e_shnum = 4;
|
|
|
|
memcpy(&buffer[file_offset], &ehdr, sizeof(ehdr));
|
|
|
|
|
|
|
|
ASSERT_TRUE(android::base::WriteFully(fd, buffer.data(), buffer.size()));
|
|
|
|
}
|
|
|
|
|
2017-04-19 22:42:19 +00:00
|
|
|
static void SetUpTestCase() {
|
|
|
|
std::vector<uint8_t> buffer(1024);
|
2017-08-30 20:15:19 +00:00
|
|
|
memset(buffer.data(), 0, buffer.size());
|
2017-04-19 22:42:19 +00:00
|
|
|
memcpy(buffer.data(), ELFMAG, SELFMAG);
|
2017-08-30 20:15:19 +00:00
|
|
|
buffer[EI_CLASS] = ELFCLASS32;
|
2017-04-19 22:42:19 +00:00
|
|
|
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
|
|
|
|
|
2017-08-30 20:15:19 +00:00
|
|
|
memset(buffer.data(), 0, buffer.size());
|
2017-04-19 22:42:19 +00:00
|
|
|
memcpy(&buffer[0x100], ELFMAG, SELFMAG);
|
2017-08-30 20:15:19 +00:00
|
|
|
buffer[0x100 + EI_CLASS] = ELFCLASS64;
|
2017-04-19 22:42:19 +00:00
|
|
|
ASSERT_TRUE(android::base::WriteFully(elf_at_100_.fd, buffer.data(), buffer.size()));
|
2017-08-30 20:15:19 +00:00
|
|
|
|
|
|
|
InitElf<Elf32_Ehdr, Elf32_Shdr>(elf32_at_map_.fd, 0x1000, 0x2000, ELFCLASS32);
|
|
|
|
InitElf<Elf64_Ehdr, Elf64_Shdr>(elf64_at_map_.fd, 0x2000, 0x3000, ELFCLASS64);
|
2017-04-19 22:42:19 +00:00
|
|
|
}
|
|
|
|
|
2017-09-01 18:17:16 +00:00
|
|
|
void SetUp() override {
|
|
|
|
memory_ = new MemoryFake;
|
|
|
|
process_memory_.reset(memory_);
|
|
|
|
}
|
|
|
|
|
|
|
|
MemoryFake* memory_;
|
|
|
|
std::shared_ptr<Memory> process_memory_;
|
|
|
|
|
2017-04-19 22:42:19 +00:00
|
|
|
static TemporaryFile elf_;
|
|
|
|
|
|
|
|
static TemporaryFile elf_at_100_;
|
2017-08-30 20:15:19 +00:00
|
|
|
|
|
|
|
static TemporaryFile elf32_at_map_;
|
|
|
|
static TemporaryFile elf64_at_map_;
|
2017-04-19 22:42:19 +00:00
|
|
|
};
|
2017-07-01 00:18:16 +00:00
|
|
|
TemporaryFile MapInfoCreateMemoryTest::elf_;
|
|
|
|
TemporaryFile MapInfoCreateMemoryTest::elf_at_100_;
|
2017-08-30 20:15:19 +00:00
|
|
|
TemporaryFile MapInfoCreateMemoryTest::elf32_at_map_;
|
|
|
|
TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_;
|
2017-04-19 22:42:19 +00:00
|
|
|
|
2017-07-01 00:18:16 +00:00
|
|
|
TEST_F(MapInfoCreateMemoryTest, end_le_start) {
|
2018-10-02 04:01:09 +00:00
|
|
|
MapInfo info(nullptr, 0x100, 0x100, 0, 0, elf_.path);
|
2017-04-19 22:42:19 +00:00
|
|
|
|
2017-09-01 18:17:16 +00:00
|
|
|
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
|
2017-04-19 22:42:19 +00:00
|
|
|
ASSERT_TRUE(memory.get() == nullptr);
|
|
|
|
|
|
|
|
info.end = 0xff;
|
2017-09-01 18:17:16 +00:00
|
|
|
memory.reset(info.CreateMemory(process_memory_));
|
2017-04-19 22:42:19 +00:00
|
|
|
ASSERT_TRUE(memory.get() == nullptr);
|
|
|
|
|
|
|
|
// Make sure this test is valid.
|
|
|
|
info.end = 0x101;
|
2017-09-01 18:17:16 +00:00
|
|
|
memory.reset(info.CreateMemory(process_memory_));
|
2017-06-19 20:42:04 +00:00
|
|
|
ASSERT_TRUE(memory.get() != nullptr);
|
2017-04-19 22:42:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Verify that if the offset is non-zero but there is no elf at the offset,
|
|
|
|
// that the full file is used.
|
2017-07-01 00:18:16 +00:00
|
|
|
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
|
2018-10-02 04:01:09 +00:00
|
|
|
MapInfo info(nullptr, 0x100, 0x200, 0x100, 0, elf_.path);
|
2017-04-19 22:42:19 +00:00
|
|
|
|
2017-09-01 18:17:16 +00:00
|
|
|
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
|
2017-04-19 22:42:19 +00:00
|
|
|
ASSERT_TRUE(memory.get() != nullptr);
|
|
|
|
ASSERT_EQ(0x100U, info.elf_offset);
|
|
|
|
|
|
|
|
// Read the entire file.
|
|
|
|
std::vector<uint8_t> buffer(1024);
|
2017-10-18 18:44:51 +00:00
|
|
|
ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 1024));
|
2017-04-19 22:42:19 +00:00
|
|
|
ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0);
|
2017-08-30 20:15:19 +00:00
|
|
|
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;
|
2017-04-19 22:42:19 +00:00
|
|
|
}
|
|
|
|
|
2017-10-18 18:44:51 +00:00
|
|
|
ASSERT_FALSE(memory->ReadFully(1024, buffer.data(), 1));
|
2017-04-19 22:42:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Verify that if the offset is non-zero and there is an elf at that
|
|
|
|
// offset, that only part of the file is used.
|
2017-07-01 00:18:16 +00:00
|
|
|
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
|
2018-10-02 04:01:09 +00:00
|
|
|
MapInfo info(nullptr, 0x100, 0x200, 0x100, 0, elf_at_100_.path);
|
2017-04-19 22:42:19 +00:00
|
|
|
|
2017-09-01 18:17:16 +00:00
|
|
|
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
|
2017-04-19 22:42:19 +00:00
|
|
|
ASSERT_TRUE(memory.get() != nullptr);
|
|
|
|
ASSERT_EQ(0U, info.elf_offset);
|
|
|
|
|
|
|
|
// Read the valid part of the file.
|
|
|
|
std::vector<uint8_t> buffer(0x100);
|
2017-10-18 18:44:51 +00:00
|
|
|
ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 0x100));
|
2017-04-19 22:42:19 +00:00
|
|
|
ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0);
|
2017-08-30 20:15:19 +00:00
|
|
|
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;
|
2017-04-19 22:42:19 +00:00
|
|
|
}
|
|
|
|
|
2017-10-18 18:44:51 +00:00
|
|
|
ASSERT_FALSE(memory->ReadFully(0x100, buffer.data(), 1));
|
2017-04-19 22:42:19 +00:00
|
|
|
}
|
|
|
|
|
2017-08-30 20:15:19 +00:00
|
|
|
// Verify that if the offset is non-zero and there is an elf at that
|
|
|
|
// offset, that only part of the file is used. Further verify that if the
|
|
|
|
// embedded elf is bigger than the initial map, the new object is larger
|
|
|
|
// than the original map size. Do this for a 32 bit elf and a 64 bit elf.
|
|
|
|
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
|
2018-10-02 04:01:09 +00:00
|
|
|
MapInfo info(nullptr, 0x5000, 0x6000, 0x1000, 0, elf32_at_map_.path);
|
2017-08-30 20:15:19 +00:00
|
|
|
|
2017-09-01 18:17:16 +00:00
|
|
|
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
|
2017-08-30 20:15:19 +00:00
|
|
|
ASSERT_TRUE(memory.get() != nullptr);
|
|
|
|
ASSERT_EQ(0U, info.elf_offset);
|
|
|
|
|
|
|
|
// Verify the memory is a valid elf.
|
|
|
|
uint8_t e_ident[SELFMAG + 1];
|
2017-10-18 18:44:51 +00:00
|
|
|
ASSERT_TRUE(memory->ReadFully(0, e_ident, SELFMAG));
|
2017-08-30 20:15:19 +00:00
|
|
|
ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG));
|
|
|
|
|
|
|
|
// Read past the end of what would normally be the size of the map.
|
2017-10-18 18:44:51 +00:00
|
|
|
ASSERT_TRUE(memory->ReadFully(0x1000, e_ident, 1));
|
2017-08-30 20:15:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
|
2018-10-02 04:01:09 +00:00
|
|
|
MapInfo info(nullptr, 0x7000, 0x8000, 0x2000, 0, elf64_at_map_.path);
|
2017-08-30 20:15:19 +00:00
|
|
|
|
2017-09-01 18:17:16 +00:00
|
|
|
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
|
2017-08-30 20:15:19 +00:00
|
|
|
ASSERT_TRUE(memory.get() != nullptr);
|
|
|
|
ASSERT_EQ(0U, info.elf_offset);
|
|
|
|
|
|
|
|
// Verify the memory is a valid elf.
|
|
|
|
uint8_t e_ident[SELFMAG + 1];
|
2017-10-18 18:44:51 +00:00
|
|
|
ASSERT_TRUE(memory->ReadFully(0, e_ident, SELFMAG));
|
2017-08-30 20:15:19 +00:00
|
|
|
ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG));
|
|
|
|
|
|
|
|
// Read past the end of what would normally be the size of the map.
|
2017-10-18 18:44:51 +00:00
|
|
|
ASSERT_TRUE(memory->ReadFully(0x1000, e_ident, 1));
|
2017-08-30 20:15:19 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 22:42:19 +00:00
|
|
|
// Verify that device file names will never result in Memory object creation.
|
2017-07-01 00:18:16 +00:00
|
|
|
TEST_F(MapInfoCreateMemoryTest, check_device_maps) {
|
2017-04-19 22:42:19 +00:00
|
|
|
// Set up some memory so that a valid local memory object would
|
|
|
|
// be returned if the file mapping fails, but the device check is incorrect.
|
|
|
|
std::vector<uint8_t> buffer(1024);
|
2018-10-02 04:01:09 +00:00
|
|
|
uint64_t start = reinterpret_cast<uint64_t>(buffer.data());
|
|
|
|
MapInfo info(nullptr, start, start + buffer.size(), 0, 0x8000, "/dev/something");
|
2017-04-19 22:42:19 +00:00
|
|
|
|
2017-09-01 18:17:16 +00:00
|
|
|
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
|
2017-04-19 22:42:19 +00:00
|
|
|
ASSERT_TRUE(memory.get() == nullptr);
|
|
|
|
}
|
|
|
|
|
2017-09-01 18:17:16 +00:00
|
|
|
TEST_F(MapInfoCreateMemoryTest, process_memory) {
|
2018-10-02 04:01:09 +00:00
|
|
|
MapInfo info(nullptr, 0x2000, 0x3000, 0, PROT_READ, "");
|
|
|
|
|
|
|
|
Elf32_Ehdr ehdr = {};
|
|
|
|
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
|
|
|
|
std::vector<uint8_t> buffer(1024);
|
|
|
|
memcpy(buffer.data(), &ehdr, sizeof(ehdr));
|
2017-04-19 22:42:19 +00:00
|
|
|
|
2017-09-01 18:17:16 +00:00
|
|
|
// Verify that the the process_memory object is used, so seed it
|
|
|
|
// with memory.
|
2018-10-02 04:01:09 +00:00
|
|
|
for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
|
2017-09-01 18:17:16 +00:00
|
|
|
buffer[i] = i % 256;
|
2017-04-19 22:42:19 +00:00
|
|
|
}
|
2017-09-01 18:17:16 +00:00
|
|
|
memory_->SetMemory(info.start, buffer.data(), buffer.size());
|
2017-04-19 22:42:19 +00:00
|
|
|
|
2017-09-01 18:17:16 +00:00
|
|
|
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
|
2017-04-19 22:42:19 +00:00
|
|
|
ASSERT_TRUE(memory.get() != nullptr);
|
|
|
|
|
2017-09-01 18:17:16 +00:00
|
|
|
memset(buffer.data(), 0, buffer.size());
|
2017-10-18 18:44:51 +00:00
|
|
|
ASSERT_TRUE(memory->ReadFully(0, buffer.data(), buffer.size()));
|
2018-10-02 04:01:09 +00:00
|
|
|
ASSERT_EQ(0, memcmp(&ehdr, buffer.data(), sizeof(ehdr)));
|
|
|
|
for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
|
2017-09-01 18:17:16 +00:00
|
|
|
ASSERT_EQ(i % 256, buffer[i]) << "Failed at byte " << i;
|
|
|
|
}
|
2017-04-19 22:42:19 +00:00
|
|
|
|
2017-09-01 18:17:16 +00:00
|
|
|
// Try to read outside of the map size.
|
2017-10-18 18:44:51 +00:00
|
|
|
ASSERT_FALSE(memory->ReadFully(buffer.size(), buffer.data(), 1));
|
2017-04-19 22:42:19 +00:00
|
|
|
}
|
2017-07-14 17:37:19 +00:00
|
|
|
|
2018-10-02 04:01:09 +00:00
|
|
|
TEST_F(MapInfoCreateMemoryTest, valid_rosegment_zero_offset) {
|
|
|
|
Maps maps;
|
|
|
|
maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0);
|
|
|
|
maps.Add(0x1000, 0x2600, 0, PROT_READ, "/only/in/memory.so", 0);
|
|
|
|
maps.Add(0x3000, 0x5000, 0x4000, PROT_READ | PROT_EXEC, "/only/in/memory.so", 0);
|
|
|
|
|
|
|
|
Elf32_Ehdr ehdr = {};
|
|
|
|
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
|
|
|
|
memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr));
|
|
|
|
memory_->SetMemoryBlock(0x1000 + sizeof(ehdr), 0x1600 - sizeof(ehdr), 0xab);
|
|
|
|
|
|
|
|
// Set the memory in the r-x map.
|
|
|
|
memory_->SetMemoryBlock(0x3000, 0x2000, 0x5d);
|
|
|
|
|
|
|
|
MapInfo* map_info = maps.Find(0x3000);
|
|
|
|
ASSERT_TRUE(map_info != nullptr);
|
|
|
|
|
|
|
|
std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
|
|
|
|
ASSERT_TRUE(mem.get() != nullptr);
|
|
|
|
EXPECT_EQ(0x4000UL, map_info->elf_offset);
|
|
|
|
EXPECT_EQ(0x4000UL, map_info->offset);
|
|
|
|
|
|
|
|
// Verify that reading values from this memory works properly.
|
|
|
|
std::vector<uint8_t> buffer(0x4000);
|
|
|
|
size_t bytes = mem->Read(0, buffer.data(), buffer.size());
|
|
|
|
ASSERT_EQ(0x1600UL, bytes);
|
|
|
|
ASSERT_EQ(0, memcmp(&ehdr, buffer.data(), sizeof(ehdr)));
|
|
|
|
for (size_t i = sizeof(ehdr); i < bytes; i++) {
|
|
|
|
ASSERT_EQ(0xab, buffer[i]) << "Failed at byte " << i;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytes = mem->Read(0x4000, buffer.data(), buffer.size());
|
|
|
|
ASSERT_EQ(0x2000UL, bytes);
|
|
|
|
for (size_t i = 0; i < bytes; i++) {
|
|
|
|
ASSERT_EQ(0x5d, buffer[i]) << "Failed at byte " << i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(MapInfoCreateMemoryTest, valid_rosegment_non_zero_offset) {
|
|
|
|
Maps maps;
|
|
|
|
maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0);
|
|
|
|
maps.Add(0x1000, 0x2000, 0, PROT_READ, "/only/in/memory.apk", 0);
|
|
|
|
maps.Add(0x2000, 0x3000, 0x1000, PROT_READ | PROT_EXEC, "/only/in/memory.apk", 0);
|
|
|
|
maps.Add(0x3000, 0x4000, 0xa000, PROT_READ, "/only/in/memory.apk", 0);
|
|
|
|
maps.Add(0x4000, 0x5000, 0xb000, PROT_READ | PROT_EXEC, "/only/in/memory.apk", 0);
|
|
|
|
|
|
|
|
Elf32_Ehdr ehdr = {};
|
|
|
|
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
|
|
|
|
|
|
|
|
// Setup an elf at offset 0x1000 in memory.
|
|
|
|
memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr));
|
|
|
|
memory_->SetMemoryBlock(0x1000 + sizeof(ehdr), 0x2000 - sizeof(ehdr), 0x12);
|
|
|
|
memory_->SetMemoryBlock(0x2000, 0x1000, 0x23);
|
|
|
|
|
|
|
|
// Setup an elf at offset 0x3000 in memory..
|
|
|
|
memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
|
|
|
|
memory_->SetMemoryBlock(0x3000 + sizeof(ehdr), 0x4000 - sizeof(ehdr), 0x34);
|
|
|
|
memory_->SetMemoryBlock(0x4000, 0x1000, 0x43);
|
|
|
|
|
|
|
|
MapInfo* map_info = maps.Find(0x4000);
|
|
|
|
ASSERT_TRUE(map_info != nullptr);
|
|
|
|
|
|
|
|
std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
|
|
|
|
ASSERT_TRUE(mem.get() != nullptr);
|
|
|
|
EXPECT_EQ(0x1000UL, map_info->elf_offset);
|
|
|
|
EXPECT_EQ(0xb000UL, map_info->offset);
|
|
|
|
|
|
|
|
// Verify that reading values from this memory works properly.
|
|
|
|
std::vector<uint8_t> buffer(0x4000);
|
|
|
|
size_t bytes = mem->Read(0, buffer.data(), buffer.size());
|
|
|
|
ASSERT_EQ(0x1000UL, bytes);
|
|
|
|
ASSERT_EQ(0, memcmp(&ehdr, buffer.data(), sizeof(ehdr)));
|
|
|
|
for (size_t i = sizeof(ehdr); i < bytes; i++) {
|
|
|
|
ASSERT_EQ(0x34, buffer[i]) << "Failed at byte " << i;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytes = mem->Read(0x1000, buffer.data(), buffer.size());
|
|
|
|
ASSERT_EQ(0x1000UL, bytes);
|
|
|
|
for (size_t i = 0; i < bytes; i++) {
|
|
|
|
ASSERT_EQ(0x43, buffer[i]) << "Failed at byte " << i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-14 17:37:19 +00:00
|
|
|
} // namespace unwindstack
|