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