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"
9 #include "gtest/gtest.h"
10 
11 namespace {
12 
13 template <typename T>
AddRelocation(uint32_t addr,uint32_t info,int32_t addend,std::vector<T> * relocations)14 void AddRelocation(uint32_t addr,
15                    uint32_t info,
16                    int32_t addend,
17                    std::vector<T>* relocations) {
18   T relocation;
19   relocation.r_offset = addr;
20   relocation.r_info = info;
21   relocation.r_addend = addend;
22   relocations->push_back(relocation);
23 }
24 
25 template <typename T>
CheckRelocation(uint32_t addr,uint32_t info,int32_t addend,const T & relocation)26 bool CheckRelocation(uint32_t addr,
27                      uint32_t info,
28                      int32_t addend,
29                      const T& relocation) {
30   return relocation.r_offset == addr &&
31       relocation.r_info == info &&
32       relocation.r_addend == addend;
33 }
34 
35 }  // namespace
36 
37 namespace relocation_packer {
38 
39 template <typename ELF>
encode()40 static void encode() {
41   std::vector<typename ELF::Rela> relocations;
42   std::vector<typename ELF::Addr> packed;
43 
44   RelocationDeltaCodec<ELF> codec;
45 
46   codec.Encode(relocations, &packed);
47 
48   ASSERT_EQ(0U, packed.size());
49 
50   // Initial relocation.
51   AddRelocation(0xf00d0000, 11U, 10000, &relocations);
52 
53   codec.Encode(relocations, &packed);
54 
55   // size of reloc table, size of group, flags, 3 fields, zero
56   EXPECT_EQ(7U, packed.size());
57   // One pair present.
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
67 
68   // Add a second relocation, 4 byte offset delta, 12 byte addend delta.
69   // same info
70   AddRelocation(0xf00d0004, 11U, 10012, &relocations);
71 
72   packed.clear();
73   codec.Encode(relocations, &packed);
74 
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
87 
88   // Add a third relocation, 4 byte offset delta, 12 byte addend delta.
89   // different info
90   AddRelocation(0xf00d0008, 41U, 10024, &relocations);
91 
92   // Add three more relocations, 8 byte offset deltas, -24 byte addend deltas.
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);
99 
100   packed.clear();
101   codec.Encode(relocations, &packed);
102 
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 
114   // Initial relocation.
115   EXPECT_EQ(10000U, packed[ndx++]); // addend delta
116   // Two relocations, 4 byte offset deltas, 12 byte addend deltas.
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
132   // Three relocations, 8 byte offset deltas, -24 byte addend deltas.
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);
147 }
148 
TEST(Delta,Encode32)149 TEST(Delta, Encode32) {
150   encode<ELF32_traits>();
151 }
152 
TEST(Delta,Encode64)153 TEST(Delta, Encode64) {
154   encode<ELF64_traits>();
155 }
156 
157 template <typename ELF>
decode()158 static void decode() {
159   std::vector<typename ELF::Addr> packed;
160   std::vector<typename ELF::Rela> relocations;
161 
162   RelocationDeltaCodec<ELF> codec;
163   codec.Decode(packed, &relocations);
164 
165   EXPECT_EQ(0U, relocations.size());
166 
167   // Six pairs.
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
174   // Initial relocation.
175   packed.push_back(10000U);
176   // Two relocations, 4 byte offset deltas, 12 byte addend deltas.
177   packed.push_back(12U); // addend
178   packed.push_back(12U); // addend
179 
180   // Three relocations, 8 byte offset deltas, -24 byte addend deltas.
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
195 
196   relocations.clear();
197   codec.Decode(packed, &relocations);
198 
199   EXPECT_EQ(6U, relocations.size());
200   // Initial relocation.
201   EXPECT_TRUE(CheckRelocation(0xc0de0000, 11U, 10000, relocations[0]));
202   // Two relocations, 4 byte offset deltas, 12 byte addend deltas.
203   EXPECT_TRUE(CheckRelocation(0xc0de0004, 11U, 10012, relocations[1]));
204   EXPECT_TRUE(CheckRelocation(0xc0de0008, 11U, 10024, relocations[2]));
205   // Three relocations, 8 byte offset deltas, -24 byte addend deltas.
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]));
209 }
210 
TEST(Delta,Decode32)211 TEST(Delta, Decode32) {
212   decode<ELF32_traits>();
213 }
214 
TEST(Delta,Decode64)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 
223 }  // namespace relocation_packer
224