| // Copyright 2018 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 "components/zucchini/disassembler_elf.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <algorithm> |
| #include <random> |
| #include <string> |
| #include <vector> |
| |
| #include "components/zucchini/test_utils.h" |
| #include "components/zucchini/type_elf.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace zucchini { |
| |
| TEST(DisassemblerElfTest, IsTargetOffsetInElfSectionList) { |
| // Minimal required fields for IsTargetOffsetInElfSectionList(). |
| struct FakeElfShdr { |
| offset_t sh_offset; |
| offset_t sh_size; |
| }; |
| |
| // Calls IsTargetOffsetInElfSectionList() for fixed |sorted_list|, and sweeps |
| // offsets in [lo, hi). Renders results into a string consisting of '.' (not |
| // in list) and '*' (in list). |
| auto test = [&](const std::vector<FakeElfShdr>& sorted_list, offset_t lo, |
| offset_t hi) -> std::string { |
| // Ensure |sorted_list| is indeed sorted, without overlaps. |
| for (size_t i = 1; i < sorted_list.size(); ++i) { |
| if (sorted_list[i].sh_offset < |
| sorted_list[i - 1].sh_offset + sorted_list[i - 1].sh_size) { |
| return "(Bad input)"; |
| } |
| } |
| // The interface to IsTargetOffsetInElfSectionList() takes a list of |
| // pointers (since data can be casted from images), so make the conversion. |
| std::vector<const FakeElfShdr*> ptr_list; |
| for (const FakeElfShdr& header : sorted_list) |
| ptr_list.push_back(&header); |
| std::string result; |
| for (offset_t offset = lo; offset < hi; ++offset) { |
| result += IsTargetOffsetInElfSectionList(ptr_list, offset) ? '*' : '.'; |
| } |
| return result; |
| }; |
| |
| EXPECT_EQ("..........", test(std::vector<FakeElfShdr>(), 0, 10)); |
| EXPECT_EQ("*.........", test({{0, 1}}, 0, 10)); |
| EXPECT_EQ("...*......", test({{3, 1}}, 0, 10)); |
| EXPECT_EQ("...****...", test({{3, 4}}, 0, 10)); |
| EXPECT_EQ("...****...", test({{10003, 4}}, 10000, 10010)); |
| EXPECT_EQ("...********...", test({{3, 4}, {7, 4}}, 0, 14)); |
| EXPECT_EQ("...****.****...", test({{3, 4}, {8, 4}}, 0, 15)); |
| EXPECT_EQ("...****..****...", test({{3, 4}, {9, 4}}, 0, 16)); |
| EXPECT_EQ("..****...*****..", test({{2, 4}, {9, 5}}, 0, 16)); |
| EXPECT_EQ("...***......***..", test({{3, 3}, {12, 3}}, 0, 17)); |
| |
| // Many small ranges. |
| EXPECT_EQ("..**.**.*.*...*.*.**...**.*.**.*..", // (Comment strut). |
| test({{2, 2}, |
| {5, 2}, |
| {8, 1}, |
| {10, 1}, |
| {14, 1}, |
| {16, 1}, |
| {18, 2}, |
| {23, 2}, |
| {26, 1}, |
| {28, 2}, |
| {31, 1}}, |
| 0, 34)); |
| EXPECT_EQ("..*****.****.***.**.*..", |
| test({{137, 5}, {143, 4}, {148, 3}, {152, 2}, {155, 1}}, 135, 158)); |
| // Consecutive. |
| EXPECT_EQ("..***************..", |
| test({{137, 5}, {142, 4}, {146, 3}, {149, 2}, {151, 1}}, 135, 154)); |
| // Hover around 32 (power of 2). |
| EXPECT_EQ("..*******************************..", |
| test({{2002, 31}}, 2000, 2035)); |
| EXPECT_EQ("..********************************..", |
| test({{5002, 32}}, 5000, 5036)); |
| EXPECT_EQ("..*********************************..", |
| test({{8002, 33}}, 8000, 8037)); |
| // Consecutive + small gap. |
| EXPECT_EQ( |
| "..*****************.***********..", |
| test({{9876543, 8}, {9876551, 9}, {9876561, 11}}, 9876541, 9876574)); |
| // Sample internal of big range. |
| EXPECT_EQ("**************************************************", |
| test({{100, 1000000}}, 5000, 5050)); |
| // Sample boundaries of big range. |
| EXPECT_EQ(".........................*************************", |
| test({{100, 1000000}}, 75, 125)); |
| EXPECT_EQ("*************************.........................", |
| test({{100, 1000000}}, 1000075, 1000125)); |
| // 1E9 is still good. |
| EXPECT_EQ(".....*.....", test({{1000000000, 1}}, 999999995, 1000000006)); |
| } |
| |
| TEST(DisassemblerElfTest, QuickDetect) { |
| std::vector<uint8_t> image_data; |
| ConstBufferView image; |
| |
| // Empty. |
| EXPECT_FALSE(DisassemblerElfX86::QuickDetect(image)); |
| EXPECT_FALSE(DisassemblerElfX64::QuickDetect(image)); |
| |
| // Unrelated. |
| image_data = ParseHexString("DE AD"); |
| image = {image_data.data(), image_data.size()}; |
| EXPECT_FALSE(DisassemblerElfX86::QuickDetect(image)); |
| EXPECT_FALSE(DisassemblerElfX64::QuickDetect(image)); |
| |
| // Only Magic. |
| image_data = ParseHexString("7F 45 4C 46"); |
| image = {image_data.data(), image_data.size()}; |
| EXPECT_FALSE(DisassemblerElfX86::QuickDetect(image)); |
| EXPECT_FALSE(DisassemblerElfX64::QuickDetect(image)); |
| |
| // Only identification. |
| image_data = |
| ParseHexString("7F 45 4C 46 01 01 01 00 00 00 00 00 00 00 00 00"); |
| image = {image_data.data(), image_data.size()}; |
| EXPECT_FALSE(DisassemblerElfX86::QuickDetect(image)); |
| EXPECT_FALSE(DisassemblerElfX64::QuickDetect(image)); |
| |
| // Large enough, filled with zeros. |
| image_data.assign(sizeof(elf::Elf32_Ehdr), 0); |
| image = {image_data.data(), image_data.size()}; |
| EXPECT_FALSE(DisassemblerElfX86::QuickDetect(image)); |
| EXPECT_FALSE(DisassemblerElfX64::QuickDetect(image)); |
| |
| // Random. |
| std::random_device rd; |
| std::mt19937 gen{rd()}; |
| std::generate(image_data.begin(), image_data.end(), gen); |
| image = {image_data.data(), image_data.size()}; |
| EXPECT_FALSE(DisassemblerElfX86::QuickDetect(image)); |
| EXPECT_FALSE(DisassemblerElfX64::QuickDetect(image)); |
| |
| // Typical x86 elf header. |
| { |
| elf::Elf32_Ehdr header = {}; |
| auto e_ident = |
| ParseHexString("7F 45 4C 46 01 01 01 00 00 00 00 00 00 00 00 00"); |
| std::copy(e_ident.begin(), e_ident.end(), header.e_ident); |
| header.e_type = elf::ET_EXEC; |
| header.e_machine = elf::EM_386; |
| header.e_version = 1; |
| header.e_shentsize = sizeof(elf::Elf32_Shdr); |
| image = {reinterpret_cast<const uint8_t*>(&header), sizeof(header)}; |
| EXPECT_TRUE(DisassemblerElfX86::QuickDetect(image)); |
| EXPECT_FALSE(DisassemblerElfX64::QuickDetect(image)); |
| } |
| |
| // Typical x64 elf header. |
| { |
| elf::Elf64_Ehdr header = {}; |
| auto e_ident = |
| ParseHexString("7F 45 4C 46 02 01 01 00 00 00 00 00 00 00 00 00"); |
| std::copy(e_ident.begin(), e_ident.end(), header.e_ident); |
| header.e_type = elf::ET_EXEC; |
| header.e_machine = elf::EM_X86_64; |
| header.e_version = 1; |
| header.e_shentsize = sizeof(elf::Elf64_Shdr); |
| image = {reinterpret_cast<const uint8_t*>(&header), sizeof(header)}; |
| EXPECT_FALSE(DisassemblerElfX86::QuickDetect(image)); |
| EXPECT_TRUE(DisassemblerElfX64::QuickDetect(image)); |
| } |
| } |
| |
| } // namespace zucchini |