// 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