xref: /aosp_15_r20/external/zucchini/reloc_elf_unittest.cc (revision a03ca8b91e029cd15055c20c78c2e087c84792e4)
1*a03ca8b9SKrzysztof Kosiński // Copyright 2018 The Chromium Authors. All rights reserved.
2*a03ca8b9SKrzysztof Kosiński // Use of this source code is governed by a BSD-style license that can be
3*a03ca8b9SKrzysztof Kosiński // found in the LICENSE file.
4*a03ca8b9SKrzysztof Kosiński 
5*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/reloc_elf.h"
6*a03ca8b9SKrzysztof Kosiński 
7*a03ca8b9SKrzysztof Kosiński #include <stdint.h>
8*a03ca8b9SKrzysztof Kosiński 
9*a03ca8b9SKrzysztof Kosiński #include <algorithm>
10*a03ca8b9SKrzysztof Kosiński #include <memory>
11*a03ca8b9SKrzysztof Kosiński #include <utility>
12*a03ca8b9SKrzysztof Kosiński #include <vector>
13*a03ca8b9SKrzysztof Kosiński 
14*a03ca8b9SKrzysztof Kosiński #include "base/numerics/safe_conversions.h"
15*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/address_translator.h"
16*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/algorithm.h"
17*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/disassembler_elf.h"
18*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/image_utils.h"
19*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/test_utils.h"
20*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/type_elf.h"
21*a03ca8b9SKrzysztof Kosiński #include "testing/gtest/include/gtest/gtest.h"
22*a03ca8b9SKrzysztof Kosiński 
23*a03ca8b9SKrzysztof Kosiński namespace zucchini {
24*a03ca8b9SKrzysztof Kosiński 
25*a03ca8b9SKrzysztof Kosiński namespace {
26*a03ca8b9SKrzysztof Kosiński 
27*a03ca8b9SKrzysztof Kosiński template <class Elf_Shdr>
MakeSectionDimensions(const BufferRegion & region,offset_t entry_size)28*a03ca8b9SKrzysztof Kosiński SectionDimensionsElf MakeSectionDimensions(const BufferRegion& region,
29*a03ca8b9SKrzysztof Kosiński                                            offset_t entry_size) {
30*a03ca8b9SKrzysztof Kosiński   using sh_offset_t = decltype(Elf_Shdr::sh_offset);
31*a03ca8b9SKrzysztof Kosiński   using sh_size_t = decltype(Elf_Shdr::sh_size);
32*a03ca8b9SKrzysztof Kosiński   using sh_entsize_t = decltype(Elf_Shdr::sh_entsize);
33*a03ca8b9SKrzysztof Kosiński   return SectionDimensionsElf{Elf_Shdr{
34*a03ca8b9SKrzysztof Kosiński       0,  // sh_name
35*a03ca8b9SKrzysztof Kosiński       0,  // sh_type
36*a03ca8b9SKrzysztof Kosiński       0,  // sh_flags
37*a03ca8b9SKrzysztof Kosiński       0,  // sh_addr
38*a03ca8b9SKrzysztof Kosiński       // sh_offset
39*a03ca8b9SKrzysztof Kosiński       base::checked_cast<sh_offset_t>(region.offset),
40*a03ca8b9SKrzysztof Kosiński       // sh_size
41*a03ca8b9SKrzysztof Kosiński       base::checked_cast<sh_size_t>(region.size),
42*a03ca8b9SKrzysztof Kosiński       0,  // sh_link
43*a03ca8b9SKrzysztof Kosiński       0,  // sh_info
44*a03ca8b9SKrzysztof Kosiński       0,  // sh_addralign
45*a03ca8b9SKrzysztof Kosiński       // sh_entsize
46*a03ca8b9SKrzysztof Kosiński       base::checked_cast<sh_entsize_t>(entry_size),
47*a03ca8b9SKrzysztof Kosiński   }};
48*a03ca8b9SKrzysztof Kosiński }
49*a03ca8b9SKrzysztof Kosiński 
50*a03ca8b9SKrzysztof Kosiński // Helper to manipulate an image with one or more relocation tables.
51*a03ca8b9SKrzysztof Kosiński template <class ELF_INTEL_TRAITS>
52*a03ca8b9SKrzysztof Kosiński class FakeImageWithReloc {
53*a03ca8b9SKrzysztof Kosiński  public:
54*a03ca8b9SKrzysztof Kosiński   using ElfIntelTraits = ELF_INTEL_TRAITS;
55*a03ca8b9SKrzysztof Kosiński   struct RelocSpec {
56*a03ca8b9SKrzysztof Kosiński     offset_t start;
57*a03ca8b9SKrzysztof Kosiński     std::vector<uint8_t> data;
58*a03ca8b9SKrzysztof Kosiński   };
59*a03ca8b9SKrzysztof Kosiński 
FakeImageWithReloc(size_t image_size,rva_t base_rva,const std::vector<RelocSpec> & reloc_specs)60*a03ca8b9SKrzysztof Kosiński   FakeImageWithReloc(size_t image_size,
61*a03ca8b9SKrzysztof Kosiński                      rva_t base_rva,
62*a03ca8b9SKrzysztof Kosiński                      const std::vector<RelocSpec>& reloc_specs)
63*a03ca8b9SKrzysztof Kosiński       : image_data_(image_size, 0xFF),
64*a03ca8b9SKrzysztof Kosiński         mutable_image_(&image_data_[0], image_data_.size()) {
65*a03ca8b9SKrzysztof Kosiński     translator_.Initialize({{0, static_cast<offset_t>(image_size), base_rva,
66*a03ca8b9SKrzysztof Kosiński                              static_cast<rva_t>(image_size)}});
67*a03ca8b9SKrzysztof Kosiński     // Set up test image with reloc sections.
68*a03ca8b9SKrzysztof Kosiński     for (const RelocSpec& reloc_spec : reloc_specs) {
69*a03ca8b9SKrzysztof Kosiński       BufferRegion reloc_region = {reloc_spec.start, reloc_spec.data.size()};
70*a03ca8b9SKrzysztof Kosiński       std::copy(reloc_spec.data.begin(), reloc_spec.data.end(),
71*a03ca8b9SKrzysztof Kosiński                 image_data_.begin() + reloc_region.lo());
72*a03ca8b9SKrzysztof Kosiński       section_dimensions_.emplace_back(
73*a03ca8b9SKrzysztof Kosiński           MakeSectionDimensions<typename ElfIntelTraits::Elf_Shdr>(
74*a03ca8b9SKrzysztof Kosiński               reloc_region, ElfIntelTraits::kVAWidth));
75*a03ca8b9SKrzysztof Kosiński       reloc_regions_.push_back(reloc_region);
76*a03ca8b9SKrzysztof Kosiński     }
77*a03ca8b9SKrzysztof Kosiński   }
78*a03ca8b9SKrzysztof Kosiński 
ExtractRelocReferences()79*a03ca8b9SKrzysztof Kosiński   std::vector<Reference> ExtractRelocReferences() {
80*a03ca8b9SKrzysztof Kosiński     const size_t image_size = image_data_.size();
81*a03ca8b9SKrzysztof Kosiński     ConstBufferView image = {image_data_.data(), image_size};
82*a03ca8b9SKrzysztof Kosiński 
83*a03ca8b9SKrzysztof Kosiński     // Make RelocReaderElf.
84*a03ca8b9SKrzysztof Kosiński     auto reader = std::make_unique<RelocReaderElf>(
85*a03ca8b9SKrzysztof Kosiński         image, ElfIntelTraits::kBitness, section_dimensions_,
86*a03ca8b9SKrzysztof Kosiński         ElfIntelTraits::kRelType, 0, image_size, translator_);
87*a03ca8b9SKrzysztof Kosiński 
88*a03ca8b9SKrzysztof Kosiński     // Read all references and check.
89*a03ca8b9SKrzysztof Kosiński     std::vector<Reference> refs;
90*a03ca8b9SKrzysztof Kosiński     for (std::optional<Reference> ref = reader->GetNext(); ref.has_value();
91*a03ca8b9SKrzysztof Kosiński          ref = reader->GetNext()) {
92*a03ca8b9SKrzysztof Kosiński       refs.push_back(ref.value());
93*a03ca8b9SKrzysztof Kosiński     }
94*a03ca8b9SKrzysztof Kosiński     return refs;
95*a03ca8b9SKrzysztof Kosiński   }
96*a03ca8b9SKrzysztof Kosiński 
MakeRelocWriter()97*a03ca8b9SKrzysztof Kosiński   std::unique_ptr<RelocWriterElf> MakeRelocWriter() {
98*a03ca8b9SKrzysztof Kosiński     return std::move(std::make_unique<RelocWriterElf>(
99*a03ca8b9SKrzysztof Kosiński         mutable_image_, ElfIntelTraits::kBitness, translator_));
100*a03ca8b9SKrzysztof Kosiński   }
101*a03ca8b9SKrzysztof Kosiński 
GetRawRelocData(int reloc_index)102*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> GetRawRelocData(int reloc_index) {
103*a03ca8b9SKrzysztof Kosiński     BufferRegion reloc_region = reloc_regions_[reloc_index];
104*a03ca8b9SKrzysztof Kosiński     return Sub(image_data_, reloc_region.lo(), reloc_region.hi());
105*a03ca8b9SKrzysztof Kosiński   }
106*a03ca8b9SKrzysztof Kosiński 
107*a03ca8b9SKrzysztof Kosiński  private:
108*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> image_data_;
109*a03ca8b9SKrzysztof Kosiński   MutableBufferView mutable_image_;
110*a03ca8b9SKrzysztof Kosiński   std::vector<BufferRegion> reloc_regions_;
111*a03ca8b9SKrzysztof Kosiński   std::vector<SectionDimensionsElf> section_dimensions_;
112*a03ca8b9SKrzysztof Kosiński   AddressTranslator translator_;
113*a03ca8b9SKrzysztof Kosiński };
114*a03ca8b9SKrzysztof Kosiński 
115*a03ca8b9SKrzysztof Kosiński }  // namespace
116*a03ca8b9SKrzysztof Kosiński 
TEST(RelocElfTest,ReadWrite32)117*a03ca8b9SKrzysztof Kosiński TEST(RelocElfTest, ReadWrite32) {
118*a03ca8b9SKrzysztof Kosiński   // Set up mock image: Size = 0x3000, .reloc at 0x600. RVA is 0x40000 + offset.
119*a03ca8b9SKrzysztof Kosiński   constexpr size_t kImageSize = 0x3000;
120*a03ca8b9SKrzysztof Kosiński   constexpr rva_t kBaseRva = 0x40000;
121*a03ca8b9SKrzysztof Kosiński 
122*a03ca8b9SKrzysztof Kosiński   constexpr offset_t kRelocStart0 = 0x600;
123*a03ca8b9SKrzysztof Kosiński   // "C0 10 04 00 08 00 00 00" represents
124*a03ca8b9SKrzysztof Kosiński   // (r_sym, r_type, r_offset) = (0x000000, 0x08, 0x000410C0).
125*a03ca8b9SKrzysztof Kosiński   // r_type = 0x08 = R_386_RELATIVE, and so |r_offset| is an RVA 0x000410C0.
126*a03ca8b9SKrzysztof Kosiński   // Zucchini does not care about |r_sym|.
127*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> reloc_data0 = ParseHexString(
128*a03ca8b9SKrzysztof Kosiński       "C0 10 04 00 08 00 00 00 "   // R_386_RELATIVE.
129*a03ca8b9SKrzysztof Kosiński       "F8 10 04 00 08 AB CD EF "   // R_386_RELATIVE.
130*a03ca8b9SKrzysztof Kosiński       "00 10 04 00 00 AB CD EF "   // R_386_NONE.
131*a03ca8b9SKrzysztof Kosiński       "00 10 04 00 07 AB CD EF");  // R_386_JMP_SLOT.
132*a03ca8b9SKrzysztof Kosiński 
133*a03ca8b9SKrzysztof Kosiński   constexpr offset_t kRelocStart1 = 0x620;
134*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> reloc_data1 = ParseHexString(
135*a03ca8b9SKrzysztof Kosiński       "BC 20 04 00 08 00 00 00 "   // R_386_RELATIVE.
136*a03ca8b9SKrzysztof Kosiński       "A0 20 04 00 08 AB CD EF");  // R_386_RELATIVE.
137*a03ca8b9SKrzysztof Kosiński 
138*a03ca8b9SKrzysztof Kosiński   FakeImageWithReloc<Elf32IntelTraits> fake_image(
139*a03ca8b9SKrzysztof Kosiński       kImageSize, kBaseRva,
140*a03ca8b9SKrzysztof Kosiński       {{kRelocStart0, reloc_data0}, {kRelocStart1, reloc_data1}});
141*a03ca8b9SKrzysztof Kosiński 
142*a03ca8b9SKrzysztof Kosiński   // Only R_386_RELATIVE references are extracted. Targets are translated from
143*a03ca8b9SKrzysztof Kosiński   // address (e.g., 0x000420BC) to offset (e.g., 0x20BC).
144*a03ca8b9SKrzysztof Kosiński   std::vector<Reference> exp_refs{
145*a03ca8b9SKrzysztof Kosiński       {0x600, 0x10C0}, {0x608, 0x10F8}, {0x620, 0x20BC}, {0x628, 0x20A0}};
146*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(exp_refs, fake_image.ExtractRelocReferences());
147*a03ca8b9SKrzysztof Kosiński 
148*a03ca8b9SKrzysztof Kosiński   // Write reference, extract bytes and check.
149*a03ca8b9SKrzysztof Kosiński   std::unique_ptr<RelocWriterElf> writer = fake_image.MakeRelocWriter();
150*a03ca8b9SKrzysztof Kosiński 
151*a03ca8b9SKrzysztof Kosiński   writer->PutNext({0x608, 0x1F83});
152*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> exp_reloc_data0 = ParseHexString(
153*a03ca8b9SKrzysztof Kosiński       "C0 10 04 00 08 00 00 00 "   // R_386_RELATIVE.
154*a03ca8b9SKrzysztof Kosiński       "83 1F 04 00 08 AB CD EF "   // R_386_RELATIVE (address modified).
155*a03ca8b9SKrzysztof Kosiński       "00 10 04 00 00 AB CD EF "   // R_386_NONE.
156*a03ca8b9SKrzysztof Kosiński       "00 10 04 00 07 AB CD EF");  // R_386_JMP_SLOT.
157*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(exp_reloc_data0, fake_image.GetRawRelocData(0));
158*a03ca8b9SKrzysztof Kosiński 
159*a03ca8b9SKrzysztof Kosiński   writer->PutNext({0x628, 0x2950});
160*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> exp_reloc_data1 = ParseHexString(
161*a03ca8b9SKrzysztof Kosiński       "BC 20 04 00 08 00 00 00 "   // R_386_RELATIVE.
162*a03ca8b9SKrzysztof Kosiński       "50 29 04 00 08 AB CD EF");  // R_386_RELATIVE (address modified).
163*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(exp_reloc_data1, fake_image.GetRawRelocData(1));
164*a03ca8b9SKrzysztof Kosiński }
165*a03ca8b9SKrzysztof Kosiński 
TEST(RelocElfTest,Limit32)166*a03ca8b9SKrzysztof Kosiński TEST(RelocElfTest, Limit32) {
167*a03ca8b9SKrzysztof Kosiński   constexpr size_t kImageSize = 0x3000;
168*a03ca8b9SKrzysztof Kosiński   constexpr offset_t kBaseRva = 0x40000;
169*a03ca8b9SKrzysztof Kosiński   constexpr offset_t kRelocStart = 0x600;
170*a03ca8b9SKrzysztof Kosiński   // All R_386_RELATIVE.
171*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> reloc_data = ParseHexString(
172*a03ca8b9SKrzysztof Kosiński       // Strictly within file.
173*a03ca8b9SKrzysztof Kosiński       "00 00 04 00 08 00 00 00 "
174*a03ca8b9SKrzysztof Kosiński       "00 10 04 00 08 00 00 00 "
175*a03ca8b9SKrzysztof Kosiński       "F0 2F 04 00 08 00 00 00 "
176*a03ca8b9SKrzysztof Kosiński       "F8 2F 04 00 08 00 00 00 "
177*a03ca8b9SKrzysztof Kosiński       "FC 2F 04 00 08 00 00 00 "
178*a03ca8b9SKrzysztof Kosiński       // Straddles end of file.
179*a03ca8b9SKrzysztof Kosiński       "FD 2F 04 00 08 00 00 00 "
180*a03ca8b9SKrzysztof Kosiński       "FE 2F 04 00 08 00 00 00 "
181*a03ca8b9SKrzysztof Kosiński       "FF 2F 04 00 08 00 00 00 "
182*a03ca8b9SKrzysztof Kosiński       // Beyond end of file.
183*a03ca8b9SKrzysztof Kosiński       "00 30 04 00 08 00 00 00 "
184*a03ca8b9SKrzysztof Kosiński       "01 30 04 00 08 00 00 00 "
185*a03ca8b9SKrzysztof Kosiński       "FC FF FF 7F 08 00 00 00 "
186*a03ca8b9SKrzysztof Kosiński       "FE FF FF 7F 08 00 00 00 "
187*a03ca8b9SKrzysztof Kosiński       "00 00 00 80 08 00 00 00 "
188*a03ca8b9SKrzysztof Kosiński       "FC FF FF FF 08 00 00 00 "
189*a03ca8b9SKrzysztof Kosiński       "FF FF FF FF 08 00 00 00 "
190*a03ca8b9SKrzysztof Kosiński       // Another good reference.
191*a03ca8b9SKrzysztof Kosiński       "34 12 04 00 08 00 00 00");
192*a03ca8b9SKrzysztof Kosiński 
193*a03ca8b9SKrzysztof Kosiński   FakeImageWithReloc<Elf32IntelTraits> fake_image(kImageSize, kBaseRva,
194*a03ca8b9SKrzysztof Kosiński                                                   {{kRelocStart, reloc_data}});
195*a03ca8b9SKrzysztof Kosiński 
196*a03ca8b9SKrzysztof Kosiński   std::vector<Reference> exp_refs{{0x600, 0x0000}, {0x608, 0x1000},
197*a03ca8b9SKrzysztof Kosiński                                   {0x610, 0x2FF0}, {0x618, 0x2FF8},
198*a03ca8b9SKrzysztof Kosiński                                   {0x620, 0x2FFC}, {0x678, 0x1234}};
199*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(exp_refs, fake_image.ExtractRelocReferences());
200*a03ca8b9SKrzysztof Kosiński }
201*a03ca8b9SKrzysztof Kosiński 
TEST(RelocElfTest,Limit64)202*a03ca8b9SKrzysztof Kosiński TEST(RelocElfTest, Limit64) {
203*a03ca8b9SKrzysztof Kosiński   constexpr size_t kImageSize = 0x3000;
204*a03ca8b9SKrzysztof Kosiński   constexpr offset_t kBaseRva = 0x40000;
205*a03ca8b9SKrzysztof Kosiński 
206*a03ca8b9SKrzysztof Kosiński   constexpr offset_t kRelocStart = 0x600;
207*a03ca8b9SKrzysztof Kosiński   // All R_X86_64_RELATIVE.
208*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> reloc_data = ParseHexString(
209*a03ca8b9SKrzysztof Kosiński       // Strictly within file.
210*a03ca8b9SKrzysztof Kosiński       "00 00 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
211*a03ca8b9SKrzysztof Kosiński       "00 10 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
212*a03ca8b9SKrzysztof Kosiński       "F0 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
213*a03ca8b9SKrzysztof Kosiński       "F4 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
214*a03ca8b9SKrzysztof Kosiński       "F8 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
215*a03ca8b9SKrzysztof Kosiński       // Straddles end of file.
216*a03ca8b9SKrzysztof Kosiński       "F9 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
217*a03ca8b9SKrzysztof Kosiński       "FC 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
218*a03ca8b9SKrzysztof Kosiński       "FF 2F 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
219*a03ca8b9SKrzysztof Kosiński       // Beyond end of file.
220*a03ca8b9SKrzysztof Kosiński       "00 30 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
221*a03ca8b9SKrzysztof Kosiński       "01 30 04 00 00 00 00 00 08 00 00 00 00 00 00 00 "
222*a03ca8b9SKrzysztof Kosiński       "FC FF FF 7F 00 00 00 00 08 00 00 00 00 00 00 00 "
223*a03ca8b9SKrzysztof Kosiński       "FE FF FF 7F 00 00 00 00 08 00 00 00 00 00 00 00 "
224*a03ca8b9SKrzysztof Kosiński       "00 00 00 80 00 00 00 00 08 00 00 00 00 00 00 00 "
225*a03ca8b9SKrzysztof Kosiński       "FC FF FF FF 00 00 00 00 08 00 00 00 00 00 00 00 "
226*a03ca8b9SKrzysztof Kosiński       "FF FF FF FF 00 00 00 00 08 00 00 00 00 00 00 00 "
227*a03ca8b9SKrzysztof Kosiński       "00 00 04 00 01 00 00 00 08 00 00 00 00 00 00 00 "
228*a03ca8b9SKrzysztof Kosiński       "FF FF FF FF FF FF FF FF 08 00 00 00 00 00 00 00 "
229*a03ca8b9SKrzysztof Kosiński       "F8 FF FF FF FF FF FF FF 08 00 00 00 00 00 00 00 "
230*a03ca8b9SKrzysztof Kosiński       // Another good reference.
231*a03ca8b9SKrzysztof Kosiński       "34 12 04 00 00 00 00 00 08 00 00 00 00 00 00 00");
232*a03ca8b9SKrzysztof Kosiński 
233*a03ca8b9SKrzysztof Kosiński   FakeImageWithReloc<Elf64IntelTraits> fake_image(kImageSize, kBaseRva,
234*a03ca8b9SKrzysztof Kosiński                                                   {{kRelocStart, reloc_data}});
235*a03ca8b9SKrzysztof Kosiński 
236*a03ca8b9SKrzysztof Kosiński   std::vector<Reference> exp_refs{{0x600, 0x0000}, {0x610, 0x1000},
237*a03ca8b9SKrzysztof Kosiński                                   {0x620, 0x2FF0}, {0x630, 0x2FF4},
238*a03ca8b9SKrzysztof Kosiński                                   {0x640, 0x2FF8}, {0x720, 0x1234}};
239*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(exp_refs, fake_image.ExtractRelocReferences());
240*a03ca8b9SKrzysztof Kosiński }
241*a03ca8b9SKrzysztof Kosiński 
242*a03ca8b9SKrzysztof Kosiński }  // namespace zucchini
243