blob: d5648fbf50808267a39bfddaed50c35ae22e76c0 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Test memory state related classes.
#include "base/compiler_specific.h"
#include "common/backtrace.h"
#include "common/memory_state.h"
#include "gtest/gtest.h"
#include "gmock/gmock.h"
namespace arc {
using ::testing::Ge;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::_;
class ProcessMapHeaderTest : public testing::Test {
public:
virtual void SetUp() OVERRIDE;
protected:
struct dl_phdr_info info_;
ElfW(Phdr) phdr_[3];
};
void ProcessMapHeaderTest::SetUp() {
memset(&info_, 0, sizeof(info_));
memset(phdr_, 0, sizeof(phdr_));
info_.dlpi_addr = 1000000;
info_.dlpi_name = "foo.so";
info_.dlpi_phdr = phdr_;
info_.dlpi_phnum = sizeof(phdr_) / sizeof(*phdr_);
static const int types[] = {PT_LOAD, PT_DYNAMIC, PT_SHLIB};
for (int i = 0; i < info_.dlpi_phnum; ++i) {
phdr_[i].p_type = types[i];
phdr_[i].p_vaddr = 2000000 + i;
phdr_[i].p_memsz = 3000000 + i;
phdr_[i].p_offset = 4000000 + i;
phdr_[i].p_flags = 5000000 + i;
}
}
TEST_F(ProcessMapHeaderTest, ConvertToJSON) {
ProcessMapHeader pmh(&info_, 1);
EXPECT_EQ(
"{"
"\"type\":\"DYNAMIC\","
"\"library\":\"foo.so\","
"\"baseAddress\":1000000,"
"\"objectAddress\":2000001,"
"\"memorySize\":3000001,"
"\"fileOffset\":4000001,"
"\"flags\":5000001"
"}", pmh.ConvertToJSON());
}
TEST_F(ProcessMapHeaderTest, ConvertListToJSON) {
ProcessMapHeader::List list;
for (int i = 0; i < info_.dlpi_phnum; ++i) {
list.push_back(ProcessMapHeader(&info_, i));
}
EXPECT_EQ(
"["
"{"
"\"type\":\"LOAD\","
"\"library\":\"foo.so\","
"\"baseAddress\":1000000,"
"\"objectAddress\":2000000,"
"\"memorySize\":3000000,"
"\"fileOffset\":4000000,"
"\"flags\":5000000"
"},"
"{"
"\"type\":\"DYNAMIC\","
"\"library\":\"foo.so\","
"\"baseAddress\":1000000,"
"\"objectAddress\":2000001,"
"\"memorySize\":3000001,"
"\"fileOffset\":4000001,"
"\"flags\":5000001"
"},"
"{"
"\"type\":\"SHLIB\","
"\"library\":\"foo.so\","
"\"baseAddress\":1000000,"
"\"objectAddress\":2000002,"
"\"memorySize\":3000002,"
"\"fileOffset\":4000002,"
"\"flags\":5000002"
"}"
"]", ProcessMapHeader::ConvertListToJSON(list));
}
class MemoryMappingInfoTest : public testing::Test {
public:
virtual void SetUp() OVERRIDE;
protected:
struct NaClMemMappingInfo info_[3];
};
void MemoryMappingInfoTest::SetUp() {
for (uint i = 0; i < sizeof(info_) / sizeof(*info_); ++i) {
info_[i].start = 1000 + i;
info_[i].size = 2000 + i;
info_[i].prot = 3000 + i;
info_[i].max_prot = 4000 + i;
info_[i].vmmap_type = 5000 + i;
}
}
TEST_F(MemoryMappingInfoTest, ConvertToJSON) {
MemoryMappingInfo mmi(&info_[1]);
EXPECT_EQ(
"{"
"\"start\":1001,"
"\"size\":2001,"
"\"prot\":3001,"
"\"maxProt\":4001,"
"\"vmmapType\":5001,"
"\"backtrace\":[]"
"}", mmi.ConvertToJSON());
}
TEST_F(MemoryMappingInfoTest, ConvertListToJSON) {
MemoryMappingInfo::List list;
for (uint i = 0; i < sizeof(info_) / sizeof(*info_); ++i) {
list.push_back(MemoryMappingInfo(&info_[i]));
}
EXPECT_EQ(
"["
"{"
"\"start\":1000,"
"\"size\":2000,"
"\"prot\":3000,"
"\"maxProt\":4000,"
"\"vmmapType\":5000,"
"\"backtrace\":[]"
"},"
"{"
"\"start\":1001,"
"\"size\":2001,"
"\"prot\":3001,"
"\"maxProt\":4001,"
"\"vmmapType\":5001,"
"\"backtrace\":[]"
"},"
"{"
"\"start\":1002,"
"\"size\":2002,"
"\"prot\":3002,"
"\"maxProt\":4002,"
"\"vmmapType\":5002,"
"\"backtrace\":[]"
"}"
"]", MemoryMappingInfo::ConvertListToJSON(list));
}
class MockBacktracer : public BacktraceInterface {
public:
MOCK_METHOD2(Backtrace, int(void**buffer, int size));
MOCK_METHOD2(BacktraceSymbols, char**(void*const* buffer, int size));
};
class MemoryMappingBacktraceMapTest : public testing::Test {
public:
virtual void SetUp() OVERRIDE;
virtual void TearDown() OVERRIDE;
protected:
MemoryMappingBacktraceMap* map_;
MockBacktracer* backtracer_;
char** NewTrace(int interesting_items, int* out_skipped);
char** NewHalfMangledTrace();
int GetHalfMangledTraceSize();
char** NewSimpleTrace();
int GetSimpleTraceSize();
void ClippingTest(
int test_range,
int map_start, int map_size, int unmap_start, int unmap_size,
int range1_start, int range1_size, int range2_start, int range2_size);
};
void MemoryMappingBacktraceMapTest::SetUp() {
backtracer_ = new MockBacktracer;
map_ = new MemoryMappingBacktraceMap();
delete map_->backtracer_;
map_->backtracer_ = backtracer_;
}
void MemoryMappingBacktraceMapTest::TearDown() {
delete map_;
}
char** MemoryMappingBacktraceMapTest::NewTrace(
int interesting_items, int* out_skipped) {
// Using malloc because that's what backtrace_symbols uses.
int skipped = MemoryMappingBacktraceMap::GetUninterestingLayers();
char** trace = static_cast<char**>(malloc(
sizeof(*trace) * (interesting_items + skipped)));
for (int i = 0; i < skipped; ++i) {
trace[i] = const_cast<char*>("skipped");
}
*out_skipped = skipped;
return trace;
}
int MemoryMappingBacktraceMapTest::GetHalfMangledTraceSize() {
return MemoryMappingBacktraceMap::GetUninterestingLayers() + 2;
}
char** MemoryMappingBacktraceMapTest::NewHalfMangledTrace() {
int skipped;
char** trace = NewTrace(2, &skipped);
trace[skipped + 0] = const_cast<char*>("/lib/foo.so (_Z1fv) [0x12345678]");
trace[skipped + 1] = const_cast<char*>("/lib/bar.so _Z1fv [0x12345679]");
return trace;
}
int MemoryMappingBacktraceMapTest::GetSimpleTraceSize() {
return MemoryMappingBacktraceMap::GetUninterestingLayers() + 1;
}
char** MemoryMappingBacktraceMapTest::NewSimpleTrace() {
int skipped;
char** trace = NewTrace(1, &skipped);
trace[skipped + 0] = const_cast<char*>("OK");
return trace;
}
TEST_F(MemoryMappingBacktraceMapTest, Demangling) {
EXPECT_CALL(*backtracer_, Backtrace(NotNull(),
Ge(GetHalfMangledTraceSize()))).WillOnce(
Return(GetHalfMangledTraceSize()));
map_->MapCurrentStackFrame(reinterpret_cast<void*>(0x12345678), 0x10000);
EXPECT_CALL(*backtracer_,
BacktraceSymbols(NotNull(), GetHalfMangledTraceSize())).WillOnce(
Return(NewHalfMangledTrace()));
EXPECT_EQ(
"["
"\"/lib/foo.so (f()) [0x12345678]\","
"\"/lib/bar.so _Z1fv [0x12345679]\""
"]",
map_->ConvertBacktraceToJSON(reinterpret_cast<void*>(0x12345678)));
}
// These tests match the cases described in memory_state.cc (i - vi).
void MemoryMappingBacktraceMapTest::ClippingTest(
int test_range,
int map_start, int map_size, int unmap_start, int unmap_size,
int range1_start, int range1_size, int range2_start, int range2_size) {
EXPECT_CALL(*backtracer_, Backtrace(NotNull(),
Ge(GetSimpleTraceSize()))).WillOnce(
Return(GetSimpleTraceSize()));
map_->MapCurrentStackFrame(reinterpret_cast<void*>(map_start), map_size);
map_->Unmap(reinterpret_cast<void*>(unmap_start), unmap_size);
for (int i = 0; i < test_range; ++i) {
if ((i >= range1_start && i < range1_start + range1_size) ||
(i >= range2_start && i < range2_start + range2_size)) {
EXPECT_CALL(*backtracer_,
BacktraceSymbols(NotNull(), GetSimpleTraceSize())).WillOnce(
Return(NewSimpleTrace()));
}
std::string trace = map_->ConvertBacktraceToJSON(
reinterpret_cast<void*>(i));
if ((i >= range1_start && i < range1_start + range1_size) ||
(i >= range2_start && i < range2_start + range2_size)) {
EXPECT_EQ("[\"OK\"]", trace);
} else {
EXPECT_EQ("[]", trace);
}
}
}
TEST_F(MemoryMappingBacktraceMapTest, ClippingI) {
// a b c d
// |-----xxxxxxxxxxxxx-----|
// (-------------)
ClippingTest(
1000, 100, 400, 200, 200,
100, 100, 400, 100);
}
TEST_F(MemoryMappingBacktraceMapTest, ClippingII) {
// b a c d
// |xxxxxxxx-----|
// (-------------)
ClippingTest(
1000, 200, 300, 100, 300,
400, 100, 0, 0);
}
TEST_F(MemoryMappingBacktraceMapTest, ClippingIII) {
// a b d c
// |-----xxxxxxxx|
// (-------------)
ClippingTest(
1000, 100, 300, 200, 300,
100, 100, 0, 0);
}
TEST_F(MemoryMappingBacktraceMapTest, ClippingIV) {
// b a d c
// |xxxxxxxxxxxxx|
// (-----------------------)
ClippingTest(
1000, 200, 200, 100, 400,
0, 0, 0, 0);
}
TEST_F(MemoryMappingBacktraceMapTest, ClippingV) {
// a d b c
// |-----|
// (-----)
ClippingTest(
1000, 100, 100, 400, 100,
100, 100, 0, 0);
}
TEST_F(MemoryMappingBacktraceMapTest, ClippingVI) {
// b c a d
// |-----|
// (-----)
ClippingTest(
1000, 400, 100, 100, 100,
400, 100, 0, 0);
}
} // namespace arc