Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "delta_encoder.h" |
| 6 | |
| 7 | #include <vector> |
| 8 | #include "elf.h" |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 9 | #include "gtest/gtest.h" |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 10 | |
| 11 | namespace { |
| 12 | |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 13 | template <typename T> |
| 14 | void AddRelocation(uint32_t addr, |
| 15 | uint32_t info, |
| 16 | int32_t addend, |
| 17 | std::vector<T>* relocations) { |
| 18 | T relocation; |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 19 | relocation.r_offset = addr; |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 20 | relocation.r_info = info; |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 21 | relocation.r_addend = addend; |
| 22 | relocations->push_back(relocation); |
| 23 | } |
| 24 | |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 25 | template <typename T> |
| 26 | bool CheckRelocation(uint32_t addr, |
| 27 | uint32_t info, |
| 28 | int32_t addend, |
| 29 | const T& relocation) { |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 30 | return relocation.r_offset == addr && |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 31 | relocation.r_info == info && |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 32 | relocation.r_addend == addend; |
| 33 | } |
| 34 | |
| 35 | } // namespace |
| 36 | |
| 37 | namespace relocation_packer { |
| 38 | |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 39 | template <typename ELF> |
| 40 | static void encode() { |
| 41 | std::vector<typename ELF::Rela> relocations; |
| 42 | std::vector<typename ELF::Addr> packed; |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 43 | |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 44 | RelocationDeltaCodec<ELF> codec; |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 45 | |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 46 | codec.Encode(relocations, &packed); |
| 47 | |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 48 | ASSERT_EQ(0U, packed.size()); |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 49 | |
| 50 | // Initial relocation. |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 51 | AddRelocation(0xf00d0000, 11U, 10000, &relocations); |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 52 | |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 53 | codec.Encode(relocations, &packed); |
| 54 | |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 55 | // size of reloc table, size of group, flags, 3 fields, zero |
| 56 | EXPECT_EQ(7U, packed.size()); |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 57 | // One pair present. |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 58 | size_t ndx = 0; |
| 59 | EXPECT_EQ(1U, packed[ndx++]); |
| 60 | EXPECT_EQ(0xf00d0000, packed[ndx++]); |
| 61 | EXPECT_EQ(1U, packed[ndx++]); // group_size |
| 62 | EXPECT_EQ(8U, packed[ndx++]); // flags |
| 63 | // Delta from the neutral element is zero |
| 64 | EXPECT_EQ(0U, packed[ndx++]); // offset_delta |
| 65 | EXPECT_EQ(11U, packed[ndx++]); // info |
| 66 | EXPECT_EQ(10000U, packed[ndx++]); // addend_delta |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 67 | |
| 68 | // Add a second relocation, 4 byte offset delta, 12 byte addend delta. |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 69 | // same info |
| 70 | AddRelocation(0xf00d0004, 11U, 10012, &relocations); |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 71 | |
| 72 | packed.clear(); |
| 73 | codec.Encode(relocations, &packed); |
| 74 | |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 75 | ndx = 0; |
| 76 | EXPECT_EQ(8U, packed.size()); |
| 77 | |
| 78 | EXPECT_EQ(2U, packed[ndx++]); // relocs count |
| 79 | EXPECT_EQ(0xf00cfffc, packed[ndx++]); // initial offset |
| 80 | EXPECT_EQ(2U, packed[ndx++]); // group count |
| 81 | EXPECT_EQ(11U, packed[ndx++]); // flags |
| 82 | EXPECT_EQ(4U, packed[ndx++]); // group offset delta |
| 83 | EXPECT_EQ(11U, packed[ndx++]); // info |
| 84 | |
| 85 | EXPECT_EQ(10000U, packed[ndx++]); // addend delta |
| 86 | EXPECT_EQ(12U, packed[ndx++]); // addend delta |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 87 | |
| 88 | // Add a third relocation, 4 byte offset delta, 12 byte addend delta. |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 89 | // different info |
| 90 | AddRelocation(0xf00d0008, 41U, 10024, &relocations); |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 91 | |
| 92 | // Add three more relocations, 8 byte offset deltas, -24 byte addend deltas. |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 93 | AddRelocation(0xf00d0010, 42U, 10000, &relocations); |
| 94 | AddRelocation(0xf00d0018, 42U, 9976, &relocations); |
| 95 | AddRelocation(0xf00d0020, 42U, 9952, &relocations); |
| 96 | |
| 97 | AddRelocation(0xf00d2028, 1042U, 0, &relocations); |
| 98 | AddRelocation(0xf00d2030, 3442U, 0, &relocations); |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 99 | |
| 100 | packed.clear(); |
| 101 | codec.Encode(relocations, &packed); |
| 102 | |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 103 | ndx = 0; |
| 104 | EXPECT_EQ(26U, packed.size()); |
| 105 | // Total number of relocs |
| 106 | EXPECT_EQ(8U, packed[ndx++]); |
| 107 | EXPECT_EQ(0xf00cfffc, packed[ndx++]); |
| 108 | // 2 in first group |
| 109 | EXPECT_EQ(2U, packed[ndx++]); |
| 110 | EXPECT_EQ(11U, packed[ndx++]); //flags |
| 111 | EXPECT_EQ(4U, packed[ndx++]); // group offset delta |
| 112 | EXPECT_EQ(11U, packed[ndx++]); // info |
| 113 | |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 114 | // Initial relocation. |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 115 | EXPECT_EQ(10000U, packed[ndx++]); // addend delta |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 116 | // Two relocations, 4 byte offset deltas, 12 byte addend deltas. |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 117 | EXPECT_EQ(12U, packed[ndx++]); // addend delta |
| 118 | |
| 119 | // second group has only one reloc |
| 120 | EXPECT_EQ(1U, packed[ndx++]); // count |
| 121 | EXPECT_EQ(8U, packed[ndx++]); // flags |
| 122 | |
| 123 | EXPECT_EQ(4U, packed[ndx++]); // offset delta |
| 124 | EXPECT_EQ(41U, packed[ndx++]); // info |
| 125 | EXPECT_EQ(12U, packed[ndx++]); // addend delta |
| 126 | |
| 127 | // next - 3 relocs grouped by info |
| 128 | EXPECT_EQ(3U, packed[ndx++]); // count |
| 129 | EXPECT_EQ(11U, packed[ndx++]); // flags |
| 130 | EXPECT_EQ(8U, packed[ndx++]); // group offset delta |
| 131 | EXPECT_EQ(42U, packed[ndx++]); // info |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 132 | // Three relocations, 8 byte offset deltas, -24 byte addend deltas. |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 133 | EXPECT_EQ(static_cast<typename ELF::Addr>(-24), packed[ndx++]); |
| 134 | EXPECT_EQ(static_cast<typename ELF::Addr>(-24), packed[ndx++]); |
| 135 | EXPECT_EQ(static_cast<typename ELF::Addr>(-24), packed[ndx++]); |
| 136 | |
| 137 | // and last - 2 relocations without addend |
| 138 | EXPECT_EQ(2U, packed[ndx++]); |
| 139 | EXPECT_EQ(0U, packed[ndx++]); // flags |
| 140 | // offset_deltas and r_infos for next 2 relocations |
| 141 | EXPECT_EQ(0x2008U, packed[ndx++]); // offset delta |
| 142 | EXPECT_EQ(1042U, packed[ndx++]); // r_info |
| 143 | EXPECT_EQ(0x8U, packed[ndx++]); // offset delta |
| 144 | EXPECT_EQ(3442U, packed[ndx++]); // r_info |
| 145 | |
| 146 | EXPECT_EQ(packed.size(), ndx); |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 147 | } |
| 148 | |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 149 | TEST(Delta, Encode32) { |
| 150 | encode<ELF32_traits>(); |
| 151 | } |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 152 | |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 153 | TEST(Delta, Encode64) { |
| 154 | encode<ELF64_traits>(); |
| 155 | } |
| 156 | |
| 157 | template <typename ELF> |
| 158 | static void decode() { |
| 159 | std::vector<typename ELF::Addr> packed; |
| 160 | std::vector<typename ELF::Rela> relocations; |
| 161 | |
| 162 | RelocationDeltaCodec<ELF> codec; |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 163 | codec.Decode(packed, &relocations); |
| 164 | |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 165 | EXPECT_EQ(0U, relocations.size()); |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 166 | |
| 167 | // Six pairs. |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 168 | packed.push_back(6U); // count |
| 169 | packed.push_back(0xc0ddfffc); // base offset |
| 170 | packed.push_back(3U); // group count |
| 171 | packed.push_back(11U); // flags |
| 172 | packed.push_back(4U); // offset delta |
| 173 | packed.push_back(11U); // info |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 174 | // Initial relocation. |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 175 | packed.push_back(10000U); |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 176 | // Two relocations, 4 byte offset deltas, 12 byte addend deltas. |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 177 | packed.push_back(12U); // addend |
| 178 | packed.push_back(12U); // addend |
| 179 | |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 180 | // Three relocations, 8 byte offset deltas, -24 byte addend deltas. |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 181 | packed.push_back(1U); // group count |
| 182 | packed.push_back(9U); // flags |
| 183 | packed.push_back(11U); // info |
| 184 | |
| 185 | packed.push_back(8U); |
| 186 | packed.push_back(static_cast<typename ELF::Addr>(-24)); |
| 187 | // next group with 2 relocs |
| 188 | packed.push_back(2U); // group count |
| 189 | packed.push_back(11U); // flags |
| 190 | packed.push_back(8U); // offset |
| 191 | packed.push_back(42U); // info |
| 192 | |
| 193 | packed.push_back(static_cast<typename ELF::Addr>(-24)); // addend |
| 194 | packed.push_back(static_cast<typename ELF::Addr>(-24)); // addend |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 195 | |
| 196 | relocations.clear(); |
| 197 | codec.Decode(packed, &relocations); |
| 198 | |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 199 | EXPECT_EQ(6U, relocations.size()); |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 200 | // Initial relocation. |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 201 | EXPECT_TRUE(CheckRelocation(0xc0de0000, 11U, 10000, relocations[0])); |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 202 | // Two relocations, 4 byte offset deltas, 12 byte addend deltas. |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 203 | EXPECT_TRUE(CheckRelocation(0xc0de0004, 11U, 10012, relocations[1])); |
| 204 | EXPECT_TRUE(CheckRelocation(0xc0de0008, 11U, 10024, relocations[2])); |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 205 | // Three relocations, 8 byte offset deltas, -24 byte addend deltas. |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 206 | EXPECT_TRUE(CheckRelocation(0xc0de0010, 11U, 10000, relocations[3])); |
| 207 | EXPECT_TRUE(CheckRelocation(0xc0de0018, 42U, 9976, relocations[4])); |
| 208 | EXPECT_TRUE(CheckRelocation(0xc0de0020, 42U, 9952, relocations[5])); |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 209 | } |
| 210 | |
Dmitriy Ivanov | f8ff6b1 | 2015-01-27 19:32:56 -0800 | [diff] [blame] | 211 | TEST(Delta, Decode32) { |
| 212 | decode<ELF32_traits>(); |
| 213 | } |
| 214 | |
| 215 | TEST(Delta, Decode64) { |
| 216 | decode<ELF64_traits>(); |
| 217 | } |
| 218 | |
| 219 | // TODO (dimitry): add more tests (fix by 19 January 2038 03:14:07 UTC) |
| 220 | // TODO (dimtiry): 1. Incorrect packed array for decode |
| 221 | // TODO (dimtiry): 2. Try to catch situation where it is likely to get series of groups with size 1 |
| 222 | |
Dmitriy Ivanov | 87a0617 | 2015-02-06 10:56:28 -0800 | [diff] [blame] | 223 | } // namespace relocation_packer |