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