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