// 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. #include "delta_encoder.h" #include <vector> #include "elf.h" #include "gtest/gtest.h" namespace { template <typename T> void AddRelocation(uint32_t addr, uint32_t info, int32_t addend, std::vector<T>* relocations) { T relocation; relocation.r_offset = addr; relocation.r_info = info; relocation.r_addend = addend; relocations->push_back(relocation); } template <typename T> bool CheckRelocation(uint32_t addr, uint32_t info, int32_t addend, const T& relocation) { return relocation.r_offset == addr && relocation.r_info == info && relocation.r_addend == addend; } } // namespace namespace relocation_packer { template <typename ELF> static void encode() { std::vector<typename ELF::Rela> relocations; std::vector<typename ELF::Addr> packed; RelocationDeltaCodec<ELF> codec; codec.Encode(relocations, &packed); ASSERT_EQ(0U, packed.size()); // Initial relocation. AddRelocation(0xf00d0000, 11U, 10000, &relocations); codec.Encode(relocations, &packed); // size of reloc table, size of group, flags, 3 fields, zero EXPECT_EQ(7U, packed.size()); // One pair present. size_t ndx = 0; EXPECT_EQ(1U, packed[ndx++]); EXPECT_EQ(0xf00d0000, packed[ndx++]); EXPECT_EQ(1U, packed[ndx++]); // group_size EXPECT_EQ(8U, packed[ndx++]); // flags // Delta from the neutral element is zero EXPECT_EQ(0U, packed[ndx++]); // offset_delta EXPECT_EQ(11U, packed[ndx++]); // info EXPECT_EQ(10000U, packed[ndx++]); // addend_delta // Add a second relocation, 4 byte offset delta, 12 byte addend delta. // same info AddRelocation(0xf00d0004, 11U, 10012, &relocations); packed.clear(); codec.Encode(relocations, &packed); ndx = 0; EXPECT_EQ(8U, packed.size()); EXPECT_EQ(2U, packed[ndx++]); // relocs count EXPECT_EQ(0xf00cfffc, packed[ndx++]); // initial offset EXPECT_EQ(2U, packed[ndx++]); // group count EXPECT_EQ(11U, packed[ndx++]); // flags EXPECT_EQ(4U, packed[ndx++]); // group offset delta EXPECT_EQ(11U, packed[ndx++]); // info EXPECT_EQ(10000U, packed[ndx++]); // addend delta EXPECT_EQ(12U, packed[ndx++]); // addend delta // Add a third relocation, 4 byte offset delta, 12 byte addend delta. // different info AddRelocation(0xf00d0008, 41U, 10024, &relocations); // Add three more relocations, 8 byte offset deltas, -24 byte addend deltas. AddRelocation(0xf00d0010, 42U, 10000, &relocations); AddRelocation(0xf00d0018, 42U, 9976, &relocations); AddRelocation(0xf00d0020, 42U, 9952, &relocations); AddRelocation(0xf00d2028, 1042U, 0, &relocations); AddRelocation(0xf00d2030, 3442U, 0, &relocations); packed.clear(); codec.Encode(relocations, &packed); ndx = 0; EXPECT_EQ(26U, packed.size()); // Total number of relocs EXPECT_EQ(8U, packed[ndx++]); EXPECT_EQ(0xf00cfffc, packed[ndx++]); // 2 in first group EXPECT_EQ(2U, packed[ndx++]); EXPECT_EQ(11U, packed[ndx++]); //flags EXPECT_EQ(4U, packed[ndx++]); // group offset delta EXPECT_EQ(11U, packed[ndx++]); // info // Initial relocation. EXPECT_EQ(10000U, packed[ndx++]); // addend delta // Two relocations, 4 byte offset deltas, 12 byte addend deltas. EXPECT_EQ(12U, packed[ndx++]); // addend delta // second group has only one reloc EXPECT_EQ(1U, packed[ndx++]); // count EXPECT_EQ(8U, packed[ndx++]); // flags EXPECT_EQ(4U, packed[ndx++]); // offset delta EXPECT_EQ(41U, packed[ndx++]); // info EXPECT_EQ(12U, packed[ndx++]); // addend delta // next - 3 relocs grouped by info EXPECT_EQ(3U, packed[ndx++]); // count EXPECT_EQ(11U, packed[ndx++]); // flags EXPECT_EQ(8U, packed[ndx++]); // group offset delta EXPECT_EQ(42U, packed[ndx++]); // info // Three relocations, 8 byte offset deltas, -24 byte addend deltas. EXPECT_EQ(static_cast<typename ELF::Addr>(-24), packed[ndx++]); EXPECT_EQ(static_cast<typename ELF::Addr>(-24), packed[ndx++]); EXPECT_EQ(static_cast<typename ELF::Addr>(-24), packed[ndx++]); // and last - 2 relocations without addend EXPECT_EQ(2U, packed[ndx++]); EXPECT_EQ(0U, packed[ndx++]); // flags // offset_deltas and r_infos for next 2 relocations EXPECT_EQ(0x2008U, packed[ndx++]); // offset delta EXPECT_EQ(1042U, packed[ndx++]); // r_info EXPECT_EQ(0x8U, packed[ndx++]); // offset delta EXPECT_EQ(3442U, packed[ndx++]); // r_info EXPECT_EQ(packed.size(), ndx); } TEST(Delta, Encode32) { encode<ELF32_traits>(); } TEST(Delta, Encode64) { encode<ELF64_traits>(); } template <typename ELF> static void decode() { std::vector<typename ELF::Addr> packed; std::vector<typename ELF::Rela> relocations; RelocationDeltaCodec<ELF> codec; codec.Decode(packed, &relocations); EXPECT_EQ(0U, relocations.size()); // Six pairs. packed.push_back(6U); // count packed.push_back(0xc0ddfffc); // base offset packed.push_back(3U); // group count packed.push_back(11U); // flags packed.push_back(4U); // offset delta packed.push_back(11U); // info // Initial relocation. packed.push_back(10000U); // Two relocations, 4 byte offset deltas, 12 byte addend deltas. packed.push_back(12U); // addend packed.push_back(12U); // addend // Three relocations, 8 byte offset deltas, -24 byte addend deltas. packed.push_back(1U); // group count packed.push_back(9U); // flags packed.push_back(11U); // info packed.push_back(8U); packed.push_back(static_cast<typename ELF::Addr>(-24)); // next group with 2 relocs packed.push_back(2U); // group count packed.push_back(11U); // flags packed.push_back(8U); // offset packed.push_back(42U); // info packed.push_back(static_cast<typename ELF::Addr>(-24)); // addend packed.push_back(static_cast<typename ELF::Addr>(-24)); // addend relocations.clear(); codec.Decode(packed, &relocations); EXPECT_EQ(6U, relocations.size()); // Initial relocation. EXPECT_TRUE(CheckRelocation(0xc0de0000, 11U, 10000, relocations[0])); // Two relocations, 4 byte offset deltas, 12 byte addend deltas. EXPECT_TRUE(CheckRelocation(0xc0de0004, 11U, 10012, relocations[1])); EXPECT_TRUE(CheckRelocation(0xc0de0008, 11U, 10024, relocations[2])); // Three relocations, 8 byte offset deltas, -24 byte addend deltas. EXPECT_TRUE(CheckRelocation(0xc0de0010, 11U, 10000, relocations[3])); EXPECT_TRUE(CheckRelocation(0xc0de0018, 42U, 9976, relocations[4])); EXPECT_TRUE(CheckRelocation(0xc0de0020, 42U, 9952, relocations[5])); } TEST(Delta, Decode32) { decode<ELF32_traits>(); } TEST(Delta, Decode64) { decode<ELF64_traits>(); } // TODO (dimitry): add more tests (fix by 19 January 2038 03:14:07 UTC) // TODO (dimtiry): 1. Incorrect packed array for decode // TODO (dimtiry): 2. Try to catch situation where it is likely to get series of groups with size 1 } // namespace relocation_packer