Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <elf.h>
     18 #include <unistd.h>
     19 
     20 #include <android-base/file.h>
     21 #include <android-base/test_utils.h>
     22 
     23 #include <gtest/gtest.h>
     24 
     25 #include <unwindstack/Elf.h>
     26 #include <unwindstack/MapInfo.h>
     27 
     28 #include "ElfTestUtils.h"
     29 #include "MemoryFake.h"
     30 
     31 namespace unwindstack {
     32 
     33 class ElfCacheTest : public ::testing::Test {
     34  protected:
     35   static void SetUpTestCase() { memory_.reset(new MemoryFake); }
     36 
     37   void SetUp() override { Elf::SetCachingEnabled(true); }
     38 
     39   void TearDown() override { Elf::SetCachingEnabled(false); }
     40 
     41   void WriteElfFile(uint64_t offset, TemporaryFile* tf, uint32_t type) {
     42     ASSERT_TRUE(type == EM_ARM || type == EM_386 || type == EM_X86_64);
     43     size_t ehdr_size;
     44     Elf32_Ehdr ehdr32;
     45     Elf64_Ehdr ehdr64;
     46     void* ptr;
     47     if (type == EM_ARM || type == EM_386) {
     48       ehdr_size = sizeof(ehdr32);
     49       ptr = &ehdr32;
     50       TestInitEhdr(&ehdr32, ELFCLASS32, type);
     51     } else {
     52       ehdr_size = sizeof(ehdr64);
     53       ptr = &ehdr64;
     54       TestInitEhdr(&ehdr64, ELFCLASS64, type);
     55     }
     56 
     57     ASSERT_EQ(offset, static_cast<uint64_t>(lseek(tf->fd, offset, SEEK_SET)));
     58     ASSERT_TRUE(android::base::WriteFully(tf->fd, ptr, ehdr_size));
     59   }
     60 
     61   void VerifyWithinSameMap(bool cache_enabled);
     62   void VerifySameMap(bool cache_enabled);
     63   void VerifyWithinSameMapNeverReadAtZero(bool cache_enabled);
     64 
     65   static std::shared_ptr<Memory> memory_;
     66 };
     67 
     68 std::shared_ptr<Memory> ElfCacheTest::memory_;
     69 
     70 void ElfCacheTest::VerifySameMap(bool cache_enabled) {
     71   if (!cache_enabled) {
     72     Elf::SetCachingEnabled(false);
     73   }
     74 
     75   TemporaryFile tf;
     76   ASSERT_TRUE(tf.fd != -1);
     77   WriteElfFile(0, &tf, EM_ARM);
     78   close(tf.fd);
     79 
     80   uint64_t start = 0x1000;
     81   uint64_t end = 0x20000;
     82   MapInfo info1(start, end, 0, 0x5, tf.path);
     83   MapInfo info2(start, end, 0, 0x5, tf.path);
     84 
     85   Elf* elf1 = info1.GetElf(memory_, true);
     86   ASSERT_TRUE(elf1->valid());
     87   Elf* elf2 = info2.GetElf(memory_, true);
     88   ASSERT_TRUE(elf2->valid());
     89 
     90   if (cache_enabled) {
     91     EXPECT_EQ(elf1, elf2);
     92   } else {
     93     EXPECT_NE(elf1, elf2);
     94   }
     95 }
     96 
     97 TEST_F(ElfCacheTest, no_caching) {
     98   VerifySameMap(false);
     99 }
    100 
    101 TEST_F(ElfCacheTest, caching_invalid_elf) {
    102   VerifySameMap(true);
    103 }
    104 
    105 void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) {
    106   if (!cache_enabled) {
    107     Elf::SetCachingEnabled(false);
    108   }
    109 
    110   TemporaryFile tf;
    111   ASSERT_TRUE(tf.fd != -1);
    112   WriteElfFile(0, &tf, EM_ARM);
    113   WriteElfFile(0x100, &tf, EM_386);
    114   WriteElfFile(0x200, &tf, EM_X86_64);
    115   lseek(tf.fd, 0x500, SEEK_SET);
    116   uint8_t value = 0;
    117   write(tf.fd, &value, 1);
    118   close(tf.fd);
    119 
    120   uint64_t start = 0x1000;
    121   uint64_t end = 0x20000;
    122   // Will have an elf at offset 0 in file.
    123   MapInfo info0_1(start, end, 0, 0x5, tf.path);
    124   MapInfo info0_2(start, end, 0, 0x5, tf.path);
    125   // Will have an elf at offset 0x100 in file.
    126   MapInfo info100_1(start, end, 0x100, 0x5, tf.path);
    127   MapInfo info100_2(start, end, 0x100, 0x5, tf.path);
    128   // Will have an elf at offset 0x200 in file.
    129   MapInfo info200_1(start, end, 0x200, 0x5, tf.path);
    130   MapInfo info200_2(start, end, 0x200, 0x5, tf.path);
    131   // Will have an elf at offset 0 in file.
    132   MapInfo info300_1(start, end, 0x300, 0x5, tf.path);
    133   MapInfo info300_2(start, end, 0x300, 0x5, tf.path);
    134 
    135   Elf* elf0_1 = info0_1.GetElf(memory_, true);
    136   ASSERT_TRUE(elf0_1->valid());
    137   EXPECT_EQ(ARCH_ARM, elf0_1->arch());
    138   Elf* elf0_2 = info0_2.GetElf(memory_, true);
    139   ASSERT_TRUE(elf0_2->valid());
    140   EXPECT_EQ(ARCH_ARM, elf0_2->arch());
    141   EXPECT_EQ(0U, info0_1.elf_offset);
    142   EXPECT_EQ(0U, info0_2.elf_offset);
    143   if (cache_enabled) {
    144     EXPECT_EQ(elf0_1, elf0_2);
    145   } else {
    146     EXPECT_NE(elf0_1, elf0_2);
    147   }
    148 
    149   Elf* elf100_1 = info100_1.GetElf(memory_, true);
    150   ASSERT_TRUE(elf100_1->valid());
    151   EXPECT_EQ(ARCH_X86, elf100_1->arch());
    152   Elf* elf100_2 = info100_2.GetElf(memory_, true);
    153   ASSERT_TRUE(elf100_2->valid());
    154   EXPECT_EQ(ARCH_X86, elf100_2->arch());
    155   EXPECT_EQ(0U, info100_1.elf_offset);
    156   EXPECT_EQ(0U, info100_2.elf_offset);
    157   if (cache_enabled) {
    158     EXPECT_EQ(elf100_1, elf100_2);
    159   } else {
    160     EXPECT_NE(elf100_1, elf100_2);
    161   }
    162 
    163   Elf* elf200_1 = info200_1.GetElf(memory_, true);
    164   ASSERT_TRUE(elf200_1->valid());
    165   EXPECT_EQ(ARCH_X86_64, elf200_1->arch());
    166   Elf* elf200_2 = info200_2.GetElf(memory_, true);
    167   ASSERT_TRUE(elf200_2->valid());
    168   EXPECT_EQ(ARCH_X86_64, elf200_2->arch());
    169   EXPECT_EQ(0U, info200_1.elf_offset);
    170   EXPECT_EQ(0U, info200_2.elf_offset);
    171   if (cache_enabled) {
    172     EXPECT_EQ(elf200_1, elf200_2);
    173   } else {
    174     EXPECT_NE(elf200_1, elf200_2);
    175   }
    176 
    177   Elf* elf300_1 = info300_1.GetElf(memory_, true);
    178   ASSERT_TRUE(elf300_1->valid());
    179   EXPECT_EQ(ARCH_ARM, elf300_1->arch());
    180   Elf* elf300_2 = info300_2.GetElf(memory_, true);
    181   ASSERT_TRUE(elf300_2->valid());
    182   EXPECT_EQ(ARCH_ARM, elf300_2->arch());
    183   EXPECT_EQ(0x300U, info300_1.elf_offset);
    184   EXPECT_EQ(0x300U, info300_2.elf_offset);
    185   if (cache_enabled) {
    186     EXPECT_EQ(elf300_1, elf300_2);
    187     EXPECT_EQ(elf0_1, elf300_1);
    188   } else {
    189     EXPECT_NE(elf300_1, elf300_2);
    190     EXPECT_NE(elf0_1, elf300_1);
    191   }
    192 }
    193 
    194 TEST_F(ElfCacheTest, no_caching_valid_elf_offset_non_zero) {
    195   VerifyWithinSameMap(false);
    196 }
    197 
    198 TEST_F(ElfCacheTest, caching_valid_elf_offset_non_zero) {
    199   VerifyWithinSameMap(true);
    200 }
    201 
    202 // Verify that when reading from multiple non-zero offsets in the same map
    203 // that when cached, all of the elf objects are the same.
    204 void ElfCacheTest::VerifyWithinSameMapNeverReadAtZero(bool cache_enabled) {
    205   if (!cache_enabled) {
    206     Elf::SetCachingEnabled(false);
    207   }
    208 
    209   TemporaryFile tf;
    210   ASSERT_TRUE(tf.fd != -1);
    211   WriteElfFile(0, &tf, EM_ARM);
    212   lseek(tf.fd, 0x500, SEEK_SET);
    213   uint8_t value = 0;
    214   write(tf.fd, &value, 1);
    215   close(tf.fd);
    216 
    217   uint64_t start = 0x1000;
    218   uint64_t end = 0x20000;
    219   // Multiple info sections at different offsets will have non-zero elf offsets.
    220   MapInfo info300_1(start, end, 0x300, 0x5, tf.path);
    221   MapInfo info300_2(start, end, 0x300, 0x5, tf.path);
    222   MapInfo info400_1(start, end, 0x400, 0x5, tf.path);
    223   MapInfo info400_2(start, end, 0x400, 0x5, tf.path);
    224 
    225   Elf* elf300_1 = info300_1.GetElf(memory_, true);
    226   ASSERT_TRUE(elf300_1->valid());
    227   EXPECT_EQ(ARCH_ARM, elf300_1->arch());
    228   Elf* elf300_2 = info300_2.GetElf(memory_, true);
    229   ASSERT_TRUE(elf300_2->valid());
    230   EXPECT_EQ(ARCH_ARM, elf300_2->arch());
    231   EXPECT_EQ(0x300U, info300_1.elf_offset);
    232   EXPECT_EQ(0x300U, info300_2.elf_offset);
    233   if (cache_enabled) {
    234     EXPECT_EQ(elf300_1, elf300_2);
    235   } else {
    236     EXPECT_NE(elf300_1, elf300_2);
    237   }
    238 
    239   Elf* elf400_1 = info400_1.GetElf(memory_, true);
    240   ASSERT_TRUE(elf400_1->valid());
    241   EXPECT_EQ(ARCH_ARM, elf400_1->arch());
    242   Elf* elf400_2 = info400_2.GetElf(memory_, true);
    243   ASSERT_TRUE(elf400_2->valid());
    244   EXPECT_EQ(ARCH_ARM, elf400_2->arch());
    245   EXPECT_EQ(0x400U, info400_1.elf_offset);
    246   EXPECT_EQ(0x400U, info400_2.elf_offset);
    247   if (cache_enabled) {
    248     EXPECT_EQ(elf400_1, elf400_2);
    249     EXPECT_EQ(elf300_1, elf400_1);
    250   } else {
    251     EXPECT_NE(elf400_1, elf400_2);
    252     EXPECT_NE(elf300_1, elf400_1);
    253   }
    254 }
    255 
    256 TEST_F(ElfCacheTest, no_caching_valid_elf_offset_non_zero_never_read_at_zero) {
    257   VerifyWithinSameMapNeverReadAtZero(false);
    258 }
    259 
    260 TEST_F(ElfCacheTest, caching_valid_elf_offset_non_zero_never_read_at_zero) {
    261   VerifyWithinSameMapNeverReadAtZero(true);
    262 }
    263 
    264 }  // namespace unwindstack
    265