OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "courgette/rel32_finder_win32_x86.h" | |
6 | |
7 #include <stddef.h> | 5 #include <stddef.h> |
8 #include <stdint.h> | 6 #include <stdint.h> |
9 | 7 |
10 #include <algorithm> | 8 #include <algorithm> |
| 9 #include <memory> |
11 #include <sstream> | 10 #include <sstream> |
12 #include <string> | 11 #include <string> |
13 | 12 |
14 #include "base/macros.h" | 13 #include "base/macros.h" |
15 #include "courgette/base_test_unittest.h" | 14 #include "courgette/base_test_unittest.h" |
16 #include "courgette/image_utils.h" | 15 #include "courgette/image_utils.h" |
| 16 #include "courgette/rel32_finder_x64.h" |
| 17 #include "courgette/rel32_finder_x86.h" |
17 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
18 | 19 |
19 namespace courgette { | 20 namespace courgette { |
20 | 21 |
21 namespace { | 22 namespace { |
22 | 23 |
23 // Helper class to load and execute a Rel32FinderWin32X86 test case. | 24 // Helper class to load and execute a Rel32Finder test case. |
24 class Rel32FinderWin32X86TestCase { | 25 class Rel32FinderTestCase { |
25 public: | 26 public: |
26 Rel32FinderWin32X86TestCase(const std::string& test_data) | 27 Rel32FinderTestCase(const std::string& test_data) |
27 : text_start_rva_(0), | 28 : text_start_rva_(0), |
28 text_end_rva_(0), | 29 text_end_rva_(0), |
29 relocs_start_rva_(0), | 30 relocs_start_rva_(0), |
30 relocs_end_rva_(0), | 31 relocs_end_rva_(0), |
31 image_end_rva_(0) { | 32 image_end_rva_(0) { |
32 LoadTestFromString(test_data); | 33 LoadTestFromString(test_data); |
33 } | 34 } |
34 | 35 |
35 void RunTestBasic(std::string name) { | 36 void RunTestBasic(std::string name) { |
36 Rel32FinderWin32X86_Basic finder(relocs_start_rva_, relocs_end_rva_); | |
37 ASSERT_FALSE(text_data_.empty()); | 37 ASSERT_FALSE(text_data_.empty()); |
38 finder.Find(&text_data_[0], &text_data_[0] + text_data_.size(), | 38 finder_->Find(&text_data_[0], &text_data_[0] + text_data_.size(), |
39 text_start_rva_, text_end_rva_, abs32_locations_); | 39 text_start_rva_, text_end_rva_, abs32_locations_); |
40 std::vector<RVA> rel32_locations; | 40 std::vector<RVA> rel32_locations; |
41 finder.SwapRel32Locations(&rel32_locations); | 41 finder_->SwapRel32Locations(&rel32_locations); |
42 EXPECT_EQ(expected_rel32_locations_, rel32_locations) | 42 EXPECT_EQ(expected_rel32_locations_, rel32_locations) |
43 << "From test case " << name << " (addresses are in hex)"; | 43 << "From test case " << name << " (addresses are in hex)"; |
44 } | 44 } |
45 | 45 |
| 46 void CreateFinder(const std::string& processor_type) { |
| 47 if (processor_type == "x64") { |
| 48 finder_ = std::unique_ptr<Rel32Finder>(new Rel32FinderX64( |
| 49 relocs_start_rva_, relocs_end_rva_, image_end_rva_)); |
| 50 } else if (processor_type == "x86") { |
| 51 finder_ = std::unique_ptr<Rel32Finder>( |
| 52 new Rel32FinderX86(relocs_start_rva_, relocs_end_rva_)); |
| 53 } else { |
| 54 NOTREACHED(); |
| 55 } |
| 56 } |
| 57 |
46 private: | 58 private: |
| 59 std::unique_ptr<Rel32Finder> finder_; |
47 RVA text_start_rva_; | 60 RVA text_start_rva_; |
48 RVA text_end_rva_; | 61 RVA text_end_rva_; |
49 RVA relocs_start_rva_; | 62 RVA relocs_start_rva_; |
50 RVA relocs_end_rva_; | 63 RVA relocs_end_rva_; |
51 RVA image_end_rva_; | 64 RVA image_end_rva_; |
52 std::vector<uint8_t> text_data_; | 65 std::vector<uint8_t> text_data_; |
53 std::vector<RVA> abs32_locations_; | 66 std::vector<RVA> abs32_locations_; |
54 std::vector<RVA> expected_rel32_locations_; | 67 std::vector<RVA> expected_rel32_locations_; |
55 | 68 |
56 // Scans |iss| for the next non-empty line, after removing "#"-style comments | 69 // Scans |iss| for the next non-empty line, after removing "#"-style comments |
57 // and stripping trailing spaces. On success, returns true and writes the | 70 // and stripping trailing spaces. On success, returns true and writes the |
58 // result to |line_out|. Otherwise returns false. | 71 // result to |line_out|. Otherwise returns false. |
59 bool ReadNonEmptyLine(std::istringstream& iss, std::string* line_out) { | 72 bool ReadNonEmptyLine(std::istringstream& iss, std::string* line_out) { |
60 std::string line; | 73 std::string line; |
61 while (std::getline(iss, line)) { | 74 while (std::getline(iss, line)) { |
62 // Trim comments and trailing spaces. | 75 // Trim comments and trailing spaces. |
63 size_t end_pos = std::min(line.find("#"), line.length()); | 76 size_t end_pos = std::min(line.find("#"), line.length()); |
64 while (end_pos > 0 && line[end_pos] == ' ') | 77 while (end_pos > 0 && line[end_pos - 1] == ' ') |
65 --end_pos; | 78 --end_pos; |
66 line.resize(end_pos); | 79 line.resize(end_pos); |
67 if (!line.empty()) | 80 if (!line.empty()) |
68 break; | 81 break; |
69 } | 82 } |
70 if (line.empty()) | 83 if (line.empty()) |
71 return false; | 84 return false; |
72 line_out->swap(line); | 85 line_out->swap(line); |
73 return true; | 86 return true; |
74 } | 87 } |
75 | 88 |
76 // Scans |iss| for the next non-empty line, and reads (hex) uint32_t into |v|. | 89 // Scans |iss| for the next non-empty line, and reads (hex) uint32_t into |v|. |
77 // Returns true iff successful. | 90 // Returns true iff successful. |
78 bool ReadHexUInt32(std::istringstream& iss, uint32_t* v) { | 91 bool ReadHexUInt32(std::istringstream& iss, uint32_t* v) { |
79 std::string line; | 92 std::string line; |
80 if (!ReadNonEmptyLine(iss, &line)) | 93 if (!ReadNonEmptyLine(iss, &line)) |
81 return false; | 94 return false; |
82 return sscanf(line.c_str(), "%X", v) == 1; | 95 return sscanf(line.c_str(), "%X", v) == 1; |
83 } | 96 } |
84 | 97 |
85 // Initializes the test case by parsing the multi-line string |test_data| | 98 // Initializes the test case by parsing the multi-line string |test_data| |
86 // to extract Rel32FinderWin32X86 parameters, and read expected values. | 99 // to extract Rel32Finder parameters, and read expected values. |
87 void LoadTestFromString(const std::string& test_data) { | 100 void LoadTestFromString(const std::string& test_data) { |
88 // The first lines (ignoring empty ones) specify RVA bounds. | 101 // The first lines (ignoring empty ones) specify RVA bounds. |
89 std::istringstream iss(test_data); | 102 std::istringstream iss(test_data); |
| 103 std::string processor_type; |
| 104 ASSERT_TRUE(ReadNonEmptyLine(iss, &processor_type)); |
90 ASSERT_TRUE(ReadHexUInt32(iss, &text_start_rva_)); | 105 ASSERT_TRUE(ReadHexUInt32(iss, &text_start_rva_)); |
91 ASSERT_TRUE(ReadHexUInt32(iss, &text_end_rva_)); | 106 ASSERT_TRUE(ReadHexUInt32(iss, &text_end_rva_)); |
92 ASSERT_TRUE(ReadHexUInt32(iss, &relocs_start_rva_)); | 107 ASSERT_TRUE(ReadHexUInt32(iss, &relocs_start_rva_)); |
93 ASSERT_TRUE(ReadHexUInt32(iss, &relocs_end_rva_)); | 108 ASSERT_TRUE(ReadHexUInt32(iss, &relocs_end_rva_)); |
94 ASSERT_TRUE(ReadHexUInt32(iss, &image_end_rva_)); | 109 ASSERT_TRUE(ReadHexUInt32(iss, &image_end_rva_)); |
95 | 110 |
96 std::string line; | 111 std::string line; |
97 // The Program section specifies instruction bytes. We require lines to be | 112 // The Program section specifies instruction bytes. We require lines to be |
98 // formatted in "DUMPBIN /DISASM" style, i.e., | 113 // formatted in "DUMPBIN /DISASM" style, i.e., |
99 // "00401003: E8 00 00 00 00 call 00401008" | 114 // "00401003: E8 00 00 00 00 call 00401008" |
100 // ^ ^ ^ ^ ^ ^ | 115 // ^ ^ ^ ^ ^ ^ |
101 // We extract up to 6 bytes per line. The remaining are ignored. | 116 // We extract up to 6 bytes per line. The remaining are ignored. |
102 const int kBytesBegin = 12; | 117 const int kBytesBegin = 12; |
103 const int kBytesEnd = 17; | 118 const int kBytesEnd = 17; |
104 ReadNonEmptyLine(iss, &line); | 119 ReadNonEmptyLine(iss, &line); |
105 ASSERT_EQ("Program:", line); | 120 ASSERT_EQ("Program:", line); |
106 while (ReadNonEmptyLine(iss, &line) && line != "Abs32:") { | 121 while (ReadNonEmptyLine(iss, &line) && line != "Abs32:") { |
107 std::string toks = line.substr(kBytesBegin, kBytesEnd); | 122 std::string toks = line.substr(kBytesBegin, kBytesEnd); |
108 uint32_t vals[6]; | 123 uint32_t vals[6]; |
109 int num_read = sscanf(toks.c_str(), "%X %X %X %X %X %X", &vals[0], | 124 int num_read = sscanf(toks.c_str(), "%X %X %X %X %X %X", &vals[0], |
110 &vals[1], &vals[2], &vals[3], &vals[4], &vals[5]); | 125 &vals[1], &vals[2], &vals[3], &vals[4], &vals[5]); |
111 for (int i = 0; i < num_read; ++i) | 126 for (int i = 0; i < num_read; ++i) |
112 text_data_.push_back(static_cast<uint8_t>(vals[i] & 0xFF)); | 127 text_data_.push_back(static_cast<uint8_t>(vals[i] & 0xFF)); |
113 } | 128 } |
114 ASSERT_FALSE(text_data_.empty()); | 129 ASSERT_FALSE(text_data_.empty()); |
115 | 130 |
116 // The Abs32 section specifies hex RVAs, one per line. | 131 // The Abs32 section specifies hex RVAs, one per line. |
117 ASSERT_EQ("Abs32:", line); | 132 ASSERT_EQ("Abs32:", line); |
118 while (ReadNonEmptyLine(iss, &line) && line != "Expected:") { | 133 while (ReadNonEmptyLine(iss, &line) && line != "Expected:") { |
119 RVA abs32_location; | 134 RVA abs32_location; |
120 ASSERT_EQ(1, sscanf(line.c_str(), "%X", &abs32_location)); | 135 ASSERT_EQ(1, sscanf(line.c_str(), "%X", &abs32_location)); |
121 abs32_locations_.push_back(abs32_location); | 136 abs32_locations_.push_back(abs32_location); |
122 } | 137 } |
123 | 138 |
124 // The Expected section specifies hex Rel32 RVAs, one per line. | 139 // The Expected section specifies hex Rel32 RVAs, one per line. |
125 ASSERT_EQ("Expected:", line); | 140 ASSERT_EQ("Expected:", line); |
126 while (ReadNonEmptyLine(iss, &line)) { | 141 while (ReadNonEmptyLine(iss, &line)) { |
127 RVA rel32_location; | 142 RVA rel32_location; |
128 ASSERT_EQ(1, sscanf(line.c_str(), "%X", &rel32_location)); | 143 ASSERT_EQ(1, sscanf(line.c_str(), "%X", &rel32_location)); |
129 expected_rel32_locations_.push_back(rel32_location); | 144 expected_rel32_locations_.push_back(rel32_location); |
130 } | 145 } |
| 146 CreateFinder(processor_type); |
131 } | 147 } |
132 }; | 148 }; |
133 | 149 |
134 class Rel32FinderWin32X86Test : public BaseTest { | 150 class Rel32FinderTest : public BaseTest { |
135 public: | 151 public: |
136 void RunTest(const char* test_case_file) { | 152 void RunTest(const char* test_case_file) { |
137 Rel32FinderWin32X86TestCase test_case(FileContents(test_case_file)); | 153 Rel32FinderTestCase test_case(FileContents(test_case_file)); |
138 test_case.RunTestBasic(test_case_file); | 154 test_case.RunTestBasic(test_case_file); |
139 } | 155 } |
140 }; | 156 }; |
141 | 157 |
142 TEST_F(Rel32FinderWin32X86Test, TestBasic) { | 158 TEST_F(Rel32FinderTest, TestBasic) { |
143 RunTest("rel32_win32_x86_01.txt"); | 159 RunTest("rel32_x86_01.txt"); |
144 RunTest("rel32_win32_x86_02.txt"); | 160 RunTest("rel32_x86_02.txt"); |
145 RunTest("rel32_win32_x86_03.txt"); | 161 RunTest("rel32_x86_03.txt"); |
146 RunTest("rel32_win32_x86_04.txt"); | 162 RunTest("rel32_x86_04.txt"); |
| 163 |
| 164 RunTest("rel32_x64_01.txt"); |
| 165 RunTest("rel32_x64_02.txt"); |
| 166 RunTest("rel32_x64_03.txt"); |
147 } | 167 } |
148 | 168 |
149 } // namespace | 169 } // namespace |
150 | 170 |
151 } // namespace courgette | 171 } // namespace courgette |
OLD | NEW |