Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright (C) 2016 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 <stdint.h>
     18 
     19 #include <gmock/gmock.h>
     20 #include <gtest/gtest.h>
     21 
     22 #include <unwindstack/DwarfSection.h>
     23 
     24 #include "MemoryFake.h"
     25 
     26 namespace unwindstack {
     27 
     28 class MockDwarfSection : public DwarfSection {
     29  public:
     30   MockDwarfSection(Memory* memory) : DwarfSection(memory) {}
     31   virtual ~MockDwarfSection() = default;
     32 
     33   MOCK_METHOD4(Log, bool(uint8_t, uint64_t, uint64_t, const DwarfFde*));
     34 
     35   MOCK_METHOD5(Eval, bool(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*));
     36 
     37   MOCK_METHOD3(GetCfaLocationInfo, bool(uint64_t, const DwarfFde*, dwarf_loc_regs_t*));
     38 
     39   MOCK_METHOD2(Init, bool(uint64_t, uint64_t));
     40 
     41   MOCK_METHOD2(GetFdeOffsetFromPc, bool(uint64_t, uint64_t*));
     42 
     43   MOCK_METHOD1(GetFdeFromOffset, const DwarfFde*(uint64_t));
     44 
     45   MOCK_METHOD1(GetFdeFromIndex, const DwarfFde*(size_t));
     46 
     47   MOCK_METHOD1(IsCie32, bool(uint32_t));
     48 
     49   MOCK_METHOD1(IsCie64, bool(uint64_t));
     50 
     51   MOCK_METHOD1(GetCieOffsetFromFde32, uint64_t(uint32_t));
     52 
     53   MOCK_METHOD1(GetCieOffsetFromFde64, uint64_t(uint64_t));
     54 
     55   MOCK_METHOD1(AdjustPcFromFde, uint64_t(uint64_t));
     56 };
     57 
     58 class DwarfSectionTest : public ::testing::Test {
     59  protected:
     60   MemoryFake memory_;
     61 };
     62 
     63 TEST_F(DwarfSectionTest, GetFdeOffsetFromPc_fail_from_pc) {
     64   MockDwarfSection mock_section(&memory_);
     65 
     66   EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
     67       .WillOnce(::testing::Return(false));
     68 
     69   // Verify nullptr when GetFdeOffsetFromPc fails.
     70   ASSERT_TRUE(mock_section.GetFdeFromPc(0x1000) == nullptr);
     71 }
     72 
     73 TEST_F(DwarfSectionTest, GetFdeOffsetFromPc_fail_fde_pc_end) {
     74   MockDwarfSection mock_section(&memory_);
     75 
     76   DwarfFde fde{};
     77   fde.pc_end = 0x500;
     78 
     79   EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
     80       .WillOnce(::testing::Return(true));
     81   EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
     82 
     83   // Verify nullptr when GetFdeOffsetFromPc fails.
     84   ASSERT_TRUE(mock_section.GetFdeFromPc(0x1000) == nullptr);
     85 }
     86 
     87 TEST_F(DwarfSectionTest, GetFdeOffsetFromPc_pass) {
     88   MockDwarfSection mock_section(&memory_);
     89 
     90   DwarfFde fde{};
     91   fde.pc_end = 0x2000;
     92 
     93   EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
     94       .WillOnce(::testing::Return(true));
     95   EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
     96 
     97   // Verify nullptr when GetFdeOffsetFromPc fails.
     98   ASSERT_EQ(&fde, mock_section.GetFdeFromPc(0x1000));
     99 }
    100 
    101 TEST_F(DwarfSectionTest, Step_fail_fde) {
    102   MockDwarfSection mock_section(&memory_);
    103 
    104   EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
    105       .WillOnce(::testing::Return(false));
    106 
    107   bool finished;
    108   ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished));
    109 }
    110 
    111 TEST_F(DwarfSectionTest, Step_fail_cie_null) {
    112   MockDwarfSection mock_section(&memory_);
    113 
    114   DwarfFde fde{};
    115   fde.pc_end = 0x2000;
    116   fde.cie = nullptr;
    117 
    118   EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
    119       .WillOnce(::testing::Return(true));
    120   EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
    121 
    122   bool finished;
    123   ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished));
    124 }
    125 
    126 TEST_F(DwarfSectionTest, Step_fail_cfa_location) {
    127   MockDwarfSection mock_section(&memory_);
    128 
    129   DwarfCie cie{};
    130   DwarfFde fde{};
    131   fde.pc_end = 0x2000;
    132   fde.cie = &cie;
    133 
    134   EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
    135       .WillOnce(::testing::Return(true));
    136   EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
    137 
    138   EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
    139       .WillOnce(::testing::Return(false));
    140 
    141   bool finished;
    142   ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished));
    143 }
    144 
    145 TEST_F(DwarfSectionTest, Step_pass) {
    146   MockDwarfSection mock_section(&memory_);
    147 
    148   DwarfCie cie{};
    149   DwarfFde fde{};
    150   fde.pc_end = 0x2000;
    151   fde.cie = &cie;
    152 
    153   EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
    154       .WillOnce(::testing::Return(true));
    155   EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
    156 
    157   EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
    158       .WillOnce(::testing::Return(true));
    159 
    160   MemoryFake process;
    161   EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
    162       .WillOnce(::testing::Return(true));
    163 
    164   bool finished;
    165   ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
    166 }
    167 
    168 static bool MockGetCfaLocationInfo(::testing::Unused, const DwarfFde* fde,
    169                                    dwarf_loc_regs_t* loc_regs) {
    170   loc_regs->pc_start = fde->pc_start;
    171   loc_regs->pc_end = fde->pc_end;
    172   return true;
    173 }
    174 
    175 TEST_F(DwarfSectionTest, Step_cache) {
    176   MockDwarfSection mock_section(&memory_);
    177 
    178   DwarfCie cie{};
    179   DwarfFde fde{};
    180   fde.pc_start = 0x500;
    181   fde.pc_end = 0x2000;
    182   fde.cie = &cie;
    183 
    184   EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
    185       .WillOnce(::testing::Return(true));
    186   EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
    187 
    188   EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
    189       .WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
    190 
    191   MemoryFake process;
    192   EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
    193       .WillRepeatedly(::testing::Return(true));
    194 
    195   bool finished;
    196   ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
    197   ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
    198   ASSERT_TRUE(mock_section.Step(0x1500, nullptr, &process, &finished));
    199 }
    200 
    201 TEST_F(DwarfSectionTest, Step_cache_not_in_pc) {
    202   MockDwarfSection mock_section(&memory_);
    203 
    204   DwarfCie cie{};
    205   DwarfFde fde0{};
    206   fde0.pc_start = 0x1000;
    207   fde0.pc_end = 0x2000;
    208   fde0.cie = &cie;
    209   EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
    210       .WillOnce(::testing::Return(true));
    211   EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde0));
    212   EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde0, ::testing::_))
    213       .WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
    214 
    215   MemoryFake process;
    216   EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
    217       .WillRepeatedly(::testing::Return(true));
    218 
    219   bool finished;
    220   ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
    221 
    222   DwarfFde fde1{};
    223   fde1.pc_start = 0x500;
    224   fde1.pc_end = 0x800;
    225   fde1.cie = &cie;
    226   EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x600, ::testing::_))
    227       .WillOnce(::testing::Return(true));
    228   EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde1));
    229   EXPECT_CALL(mock_section, GetCfaLocationInfo(0x600, &fde1, ::testing::_))
    230       .WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
    231 
    232   ASSERT_TRUE(mock_section.Step(0x600, nullptr, &process, &finished));
    233   ASSERT_TRUE(mock_section.Step(0x700, nullptr, &process, &finished));
    234 }
    235 
    236 }  // namespace unwindstack
    237