xref: /aosp_15_r20/external/zucchini/disassembler_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/disassembler_elf.h"
6*a03ca8b9SKrzysztof Kosiński 
7*a03ca8b9SKrzysztof Kosiński #include <stddef.h>
8*a03ca8b9SKrzysztof Kosiński #include <stdint.h>
9*a03ca8b9SKrzysztof Kosiński 
10*a03ca8b9SKrzysztof Kosiński #include <algorithm>
11*a03ca8b9SKrzysztof Kosiński #include <random>
12*a03ca8b9SKrzysztof Kosiński #include <string>
13*a03ca8b9SKrzysztof Kosiński #include <vector>
14*a03ca8b9SKrzysztof Kosiński 
15*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/test_utils.h"
16*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/type_elf.h"
17*a03ca8b9SKrzysztof Kosiński #include "testing/gtest/include/gtest/gtest.h"
18*a03ca8b9SKrzysztof Kosiński 
19*a03ca8b9SKrzysztof Kosiński namespace zucchini {
20*a03ca8b9SKrzysztof Kosiński 
TEST(DisassemblerElfTest,IsTargetOffsetInElfSectionList)21*a03ca8b9SKrzysztof Kosiński TEST(DisassemblerElfTest, IsTargetOffsetInElfSectionList) {
22*a03ca8b9SKrzysztof Kosiński   // Minimal required fields for IsTargetOffsetInElfSectionList().
23*a03ca8b9SKrzysztof Kosiński   struct FakeElfShdr {
24*a03ca8b9SKrzysztof Kosiński     offset_t sh_offset;
25*a03ca8b9SKrzysztof Kosiński     offset_t sh_size;
26*a03ca8b9SKrzysztof Kosiński   };
27*a03ca8b9SKrzysztof Kosiński 
28*a03ca8b9SKrzysztof Kosiński   // Calls IsTargetOffsetInElfSectionList() for fixed |sorted_list|, and sweeps
29*a03ca8b9SKrzysztof Kosiński   // offsets in [lo, hi). Renders results into a string consisting of '.' (not
30*a03ca8b9SKrzysztof Kosiński   // in list) and '*' (in list).
31*a03ca8b9SKrzysztof Kosiński   auto test = [&](const std::vector<FakeElfShdr>& sorted_list, offset_t lo,
32*a03ca8b9SKrzysztof Kosiński                   offset_t hi) -> std::string {
33*a03ca8b9SKrzysztof Kosiński     // Ensure |sorted_list| is indeed sorted, without overlaps.
34*a03ca8b9SKrzysztof Kosiński     for (size_t i = 1; i < sorted_list.size(); ++i) {
35*a03ca8b9SKrzysztof Kosiński       if (sorted_list[i].sh_offset <
36*a03ca8b9SKrzysztof Kosiński           sorted_list[i - 1].sh_offset + sorted_list[i - 1].sh_size) {
37*a03ca8b9SKrzysztof Kosiński         return "(Bad input)";
38*a03ca8b9SKrzysztof Kosiński       }
39*a03ca8b9SKrzysztof Kosiński     }
40*a03ca8b9SKrzysztof Kosiński     // The interface to IsTargetOffsetInElfSectionList() takes a list of
41*a03ca8b9SKrzysztof Kosiński     // pointers (since data can be casted from images), so make the conversion.
42*a03ca8b9SKrzysztof Kosiński     std::vector<const FakeElfShdr*> ptr_list;
43*a03ca8b9SKrzysztof Kosiński     for (const FakeElfShdr& header : sorted_list)
44*a03ca8b9SKrzysztof Kosiński       ptr_list.push_back(&header);
45*a03ca8b9SKrzysztof Kosiński     std::string result;
46*a03ca8b9SKrzysztof Kosiński     for (offset_t offset = lo; offset < hi; ++offset) {
47*a03ca8b9SKrzysztof Kosiński       result += IsTargetOffsetInElfSectionList(ptr_list, offset) ? '*' : '.';
48*a03ca8b9SKrzysztof Kosiński     }
49*a03ca8b9SKrzysztof Kosiński     return result;
50*a03ca8b9SKrzysztof Kosiński   };
51*a03ca8b9SKrzysztof Kosiński 
52*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("..........", test(std::vector<FakeElfShdr>(), 0, 10));
53*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("*.........", test({{0, 1}}, 0, 10));
54*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("...*......", test({{3, 1}}, 0, 10));
55*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("...****...", test({{3, 4}}, 0, 10));
56*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("...****...", test({{10003, 4}}, 10000, 10010));
57*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("...********...", test({{3, 4}, {7, 4}}, 0, 14));
58*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("...****.****...", test({{3, 4}, {8, 4}}, 0, 15));
59*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("...****..****...", test({{3, 4}, {9, 4}}, 0, 16));
60*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("..****...*****..", test({{2, 4}, {9, 5}}, 0, 16));
61*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("...***......***..", test({{3, 3}, {12, 3}}, 0, 17));
62*a03ca8b9SKrzysztof Kosiński 
63*a03ca8b9SKrzysztof Kosiński   // Many small ranges.
64*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("..**.**.*.*...*.*.**...**.*.**.*..",  // (Comment strut).
65*a03ca8b9SKrzysztof Kosiński             test({{2, 2},
66*a03ca8b9SKrzysztof Kosiński                   {5, 2},
67*a03ca8b9SKrzysztof Kosiński                   {8, 1},
68*a03ca8b9SKrzysztof Kosiński                   {10, 1},
69*a03ca8b9SKrzysztof Kosiński                   {14, 1},
70*a03ca8b9SKrzysztof Kosiński                   {16, 1},
71*a03ca8b9SKrzysztof Kosiński                   {18, 2},
72*a03ca8b9SKrzysztof Kosiński                   {23, 2},
73*a03ca8b9SKrzysztof Kosiński                   {26, 1},
74*a03ca8b9SKrzysztof Kosiński                   {28, 2},
75*a03ca8b9SKrzysztof Kosiński                   {31, 1}},
76*a03ca8b9SKrzysztof Kosiński                  0, 34));
77*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("..*****.****.***.**.*..",
78*a03ca8b9SKrzysztof Kosiński             test({{137, 5}, {143, 4}, {148, 3}, {152, 2}, {155, 1}}, 135, 158));
79*a03ca8b9SKrzysztof Kosiński   // Consecutive.
80*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("..***************..",
81*a03ca8b9SKrzysztof Kosiński             test({{137, 5}, {142, 4}, {146, 3}, {149, 2}, {151, 1}}, 135, 154));
82*a03ca8b9SKrzysztof Kosiński   // Hover around 32 (power of 2).
83*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("..*******************************..",
84*a03ca8b9SKrzysztof Kosiński             test({{2002, 31}}, 2000, 2035));
85*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("..********************************..",
86*a03ca8b9SKrzysztof Kosiński             test({{5002, 32}}, 5000, 5036));
87*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("..*********************************..",
88*a03ca8b9SKrzysztof Kosiński             test({{8002, 33}}, 8000, 8037));
89*a03ca8b9SKrzysztof Kosiński   // Consecutive + small gap.
90*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(
91*a03ca8b9SKrzysztof Kosiński       "..*****************.***********..",
92*a03ca8b9SKrzysztof Kosiński       test({{9876543, 8}, {9876551, 9}, {9876561, 11}}, 9876541, 9876574));
93*a03ca8b9SKrzysztof Kosiński   // Sample internal of big range.
94*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("**************************************************",
95*a03ca8b9SKrzysztof Kosiński             test({{100, 1000000}}, 5000, 5050));
96*a03ca8b9SKrzysztof Kosiński   // Sample boundaries of big range.
97*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(".........................*************************",
98*a03ca8b9SKrzysztof Kosiński             test({{100, 1000000}}, 75, 125));
99*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ("*************************.........................",
100*a03ca8b9SKrzysztof Kosiński             test({{100, 1000000}}, 1000075, 1000125));
101*a03ca8b9SKrzysztof Kosiński   // 1E9 is still good.
102*a03ca8b9SKrzysztof Kosiński   EXPECT_EQ(".....*.....", test({{1000000000, 1}}, 999999995, 1000000006));
103*a03ca8b9SKrzysztof Kosiński }
104*a03ca8b9SKrzysztof Kosiński 
TEST(DisassemblerElfTest,QuickDetect)105*a03ca8b9SKrzysztof Kosiński TEST(DisassemblerElfTest, QuickDetect) {
106*a03ca8b9SKrzysztof Kosiński   std::vector<uint8_t> image_data;
107*a03ca8b9SKrzysztof Kosiński   ConstBufferView image;
108*a03ca8b9SKrzysztof Kosiński 
109*a03ca8b9SKrzysztof Kosiński   // Empty.
110*a03ca8b9SKrzysztof Kosiński   EXPECT_FALSE(DisassemblerElfX86::QuickDetect(image));
111*a03ca8b9SKrzysztof Kosiński   EXPECT_FALSE(DisassemblerElfX64::QuickDetect(image));
112*a03ca8b9SKrzysztof Kosiński 
113*a03ca8b9SKrzysztof Kosiński   // Unrelated.
114*a03ca8b9SKrzysztof Kosiński   image_data = ParseHexString("DE AD");
115*a03ca8b9SKrzysztof Kosiński   image = {image_data.data(), image_data.size()};
116*a03ca8b9SKrzysztof Kosiński   EXPECT_FALSE(DisassemblerElfX86::QuickDetect(image));
117*a03ca8b9SKrzysztof Kosiński   EXPECT_FALSE(DisassemblerElfX64::QuickDetect(image));
118*a03ca8b9SKrzysztof Kosiński 
119*a03ca8b9SKrzysztof Kosiński   // Only Magic.
120*a03ca8b9SKrzysztof Kosiński   image_data = ParseHexString("7F 45 4C 46");
121*a03ca8b9SKrzysztof Kosiński   image = {image_data.data(), image_data.size()};
122*a03ca8b9SKrzysztof Kosiński   EXPECT_FALSE(DisassemblerElfX86::QuickDetect(image));
123*a03ca8b9SKrzysztof Kosiński   EXPECT_FALSE(DisassemblerElfX64::QuickDetect(image));
124*a03ca8b9SKrzysztof Kosiński 
125*a03ca8b9SKrzysztof Kosiński   // Only identification.
126*a03ca8b9SKrzysztof Kosiński   image_data =
127*a03ca8b9SKrzysztof Kosiński       ParseHexString("7F 45 4C 46 01 01 01 00 00 00 00 00 00 00 00 00");
128*a03ca8b9SKrzysztof Kosiński   image = {image_data.data(), image_data.size()};
129*a03ca8b9SKrzysztof Kosiński   EXPECT_FALSE(DisassemblerElfX86::QuickDetect(image));
130*a03ca8b9SKrzysztof Kosiński   EXPECT_FALSE(DisassemblerElfX64::QuickDetect(image));
131*a03ca8b9SKrzysztof Kosiński 
132*a03ca8b9SKrzysztof Kosiński   // Large enough, filled with zeros.
133*a03ca8b9SKrzysztof Kosiński   image_data.assign(sizeof(elf::Elf32_Ehdr), 0);
134*a03ca8b9SKrzysztof Kosiński   image = {image_data.data(), image_data.size()};
135*a03ca8b9SKrzysztof Kosiński   EXPECT_FALSE(DisassemblerElfX86::QuickDetect(image));
136*a03ca8b9SKrzysztof Kosiński   EXPECT_FALSE(DisassemblerElfX64::QuickDetect(image));
137*a03ca8b9SKrzysztof Kosiński 
138*a03ca8b9SKrzysztof Kosiński   // Random.
139*a03ca8b9SKrzysztof Kosiński   std::random_device rd;
140*a03ca8b9SKrzysztof Kosiński   std::mt19937 gen{rd()};
141*a03ca8b9SKrzysztof Kosiński   std::generate(image_data.begin(), image_data.end(), gen);
142*a03ca8b9SKrzysztof Kosiński   image = {image_data.data(), image_data.size()};
143*a03ca8b9SKrzysztof Kosiński   EXPECT_FALSE(DisassemblerElfX86::QuickDetect(image));
144*a03ca8b9SKrzysztof Kosiński   EXPECT_FALSE(DisassemblerElfX64::QuickDetect(image));
145*a03ca8b9SKrzysztof Kosiński 
146*a03ca8b9SKrzysztof Kosiński   // Typical x86 elf header.
147*a03ca8b9SKrzysztof Kosiński   {
148*a03ca8b9SKrzysztof Kosiński     elf::Elf32_Ehdr header = {};
149*a03ca8b9SKrzysztof Kosiński     auto e_ident =
150*a03ca8b9SKrzysztof Kosiński         ParseHexString("7F 45 4C 46 01 01 01 00 00 00 00 00 00 00 00 00");
151*a03ca8b9SKrzysztof Kosiński     std::copy(e_ident.begin(), e_ident.end(), header.e_ident);
152*a03ca8b9SKrzysztof Kosiński     header.e_type = elf::ET_EXEC;
153*a03ca8b9SKrzysztof Kosiński     header.e_machine = elf::EM_386;
154*a03ca8b9SKrzysztof Kosiński     header.e_version = 1;
155*a03ca8b9SKrzysztof Kosiński     header.e_shentsize = sizeof(elf::Elf32_Shdr);
156*a03ca8b9SKrzysztof Kosiński     image = {reinterpret_cast<const uint8_t*>(&header), sizeof(header)};
157*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(DisassemblerElfX86::QuickDetect(image));
158*a03ca8b9SKrzysztof Kosiński     EXPECT_FALSE(DisassemblerElfX64::QuickDetect(image));
159*a03ca8b9SKrzysztof Kosiński   }
160*a03ca8b9SKrzysztof Kosiński 
161*a03ca8b9SKrzysztof Kosiński   // Typical x64 elf header.
162*a03ca8b9SKrzysztof Kosiński   {
163*a03ca8b9SKrzysztof Kosiński     elf::Elf64_Ehdr header = {};
164*a03ca8b9SKrzysztof Kosiński     auto e_ident =
165*a03ca8b9SKrzysztof Kosiński         ParseHexString("7F 45 4C 46 02 01 01 00 00 00 00 00 00 00 00 00");
166*a03ca8b9SKrzysztof Kosiński     std::copy(e_ident.begin(), e_ident.end(), header.e_ident);
167*a03ca8b9SKrzysztof Kosiński     header.e_type = elf::ET_EXEC;
168*a03ca8b9SKrzysztof Kosiński     header.e_machine = elf::EM_X86_64;
169*a03ca8b9SKrzysztof Kosiński     header.e_version = 1;
170*a03ca8b9SKrzysztof Kosiński     header.e_shentsize = sizeof(elf::Elf64_Shdr);
171*a03ca8b9SKrzysztof Kosiński     image = {reinterpret_cast<const uint8_t*>(&header), sizeof(header)};
172*a03ca8b9SKrzysztof Kosiński     EXPECT_FALSE(DisassemblerElfX86::QuickDetect(image));
173*a03ca8b9SKrzysztof Kosiński     EXPECT_TRUE(DisassemblerElfX64::QuickDetect(image));
174*a03ca8b9SKrzysztof Kosiński   }
175*a03ca8b9SKrzysztof Kosiński }
176*a03ca8b9SKrzysztof Kosiński 
177*a03ca8b9SKrzysztof Kosiński }  // namespace zucchini
178