Add nparker to safe_browsing/OWNERS.
[chromium-blink-merge.git] / courgette / rel32_finder_win32_x86_unittest.cc
blob08eb5c23a41f366e1b4a559cf5044df138942d7f
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.
5 #include "courgette/rel32_finder_win32_x86.h"
7 #include <algorithm>
8 #include <sstream>
9 #include <string>
11 #include "base/macros.h"
12 #include "courgette/base_test_unittest.h"
13 #include "courgette/image_utils.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 namespace courgette {
18 namespace {
20 // Helper class to load and execute a Rel32FinderWin32X86 test case.
21 class Rel32FinderWin32X86TestCase {
22 public:
23 Rel32FinderWin32X86TestCase(const std::string& test_data)
24 : text_start_rva_(0),
25 text_end_rva_(0),
26 relocs_start_rva_(0),
27 relocs_end_rva_(0),
28 image_end_rva_(0) {
29 LoadTestFromString(test_data);
32 void RunTestBasic(std::string name) {
33 Rel32FinderWin32X86_Basic finder(relocs_start_rva_, relocs_end_rva_,
34 image_end_rva_);
35 ASSERT_FALSE(text_data_.empty());
36 finder.Find(&text_data_[0], &text_data_[0] + text_data_.size(),
37 text_start_rva_, text_end_rva_, abs32_locations_);
38 std::vector<RVA> rel32_locations;
39 finder.SwapRel32Locations(&rel32_locations);
40 EXPECT_EQ(expected_rel32_locations_, rel32_locations)
41 << "From test case " << name << " (addresses are in hex)";
44 private:
45 RVA text_start_rva_;
46 RVA text_end_rva_;
47 RVA relocs_start_rva_;
48 RVA relocs_end_rva_;
49 RVA image_end_rva_;
50 std::vector<uint8> text_data_;
51 std::vector<RVA> abs32_locations_;
52 std::vector<RVA> expected_rel32_locations_;
54 // Scans |iss| for the next non-empty line, after removing "#"-style comments
55 // and stripping trailing spaces. On success, returns true and writes the
56 // result to |line_out|. Otherwise returns false.
57 bool ReadNonEmptyLine(std::istringstream& iss, std::string* line_out) {
58 std::string line;
59 while (std::getline(iss, line)) {
60 // Trim comments and trailing spaces.
61 size_t end_pos = std::min(line.find("#"), line.length());
62 while (end_pos > 0 && line[end_pos] == ' ')
63 --end_pos;
64 line.resize(end_pos);
65 if (!line.empty())
66 break;
68 if (line.empty())
69 return false;
70 line_out->swap(line);
71 return true;
74 // Scans |iss| for the next non-empty line, and reads (hex) uint32 into |v|.
75 // Returns true iff successful.
76 bool ReadHexUInt32(std::istringstream& iss, uint32* v) {
77 std::string line;
78 if (!ReadNonEmptyLine(iss, &line))
79 return false;
80 return sscanf(line.c_str(), "%X", v) == 1;
83 // Initializes the test case by parsing the multi-line string |test_data|
84 // to extract Rel32FinderWin32X86 parameters, and read expected values.
85 void LoadTestFromString(const std::string& test_data) {
86 // The first lines (ignoring empty ones) specify RVA bounds.
87 std::istringstream iss(test_data);
88 ASSERT_TRUE(ReadHexUInt32(iss, &text_start_rva_));
89 ASSERT_TRUE(ReadHexUInt32(iss, &text_end_rva_));
90 ASSERT_TRUE(ReadHexUInt32(iss, &relocs_start_rva_));
91 ASSERT_TRUE(ReadHexUInt32(iss, &relocs_end_rva_));
92 ASSERT_TRUE(ReadHexUInt32(iss, &image_end_rva_));
94 std::string line;
95 // The Program section specifies instruction bytes. We require lines to be
96 // formatted in "DUMPBIN /DISASM" style, i.e.,
97 // "00401003: E8 00 00 00 00 call 00401008"
98 // ^ ^ ^ ^ ^ ^
99 // We extract up to 6 bytes per line. The remaining are ignored.
100 const int kBytesBegin = 12;
101 const int kBytesEnd = 17;
102 ReadNonEmptyLine(iss, &line);
103 ASSERT_EQ("Program:", line);
104 while (ReadNonEmptyLine(iss, &line) && line != "Abs32:") {
105 std::string toks = line.substr(kBytesBegin, kBytesEnd);
106 uint32 vals[6];
107 int num_read = sscanf(toks.c_str(), "%X %X %X %X %X %X", &vals[0],
108 &vals[1], &vals[2], &vals[3], &vals[4], &vals[5]);
109 for (int i = 0; i < num_read; ++i)
110 text_data_.push_back(static_cast<uint8>(vals[i] & 0xFF));
112 ASSERT_FALSE(text_data_.empty());
114 // The Abs32 section specifies hex RVAs, one per line.
115 ASSERT_EQ("Abs32:", line);
116 while (ReadNonEmptyLine(iss, &line) && line != "Expected:") {
117 RVA abs32_location;
118 ASSERT_EQ(1, sscanf(line.c_str(), "%X", &abs32_location));
119 abs32_locations_.push_back(abs32_location);
122 // The Expected section specifies hex Rel32 RVAs, one per line.
123 ASSERT_EQ("Expected:", line);
124 while (ReadNonEmptyLine(iss, &line)) {
125 RVA rel32_location;
126 ASSERT_EQ(1, sscanf(line.c_str(), "%X", &rel32_location));
127 expected_rel32_locations_.push_back(rel32_location);
132 class Rel32FinderWin32X86Test : public BaseTest {
133 public:
134 void RunTest(const char* test_case_file) {
135 Rel32FinderWin32X86TestCase test_case(FileContents(test_case_file));
136 test_case.RunTestBasic(test_case_file);
140 TEST_F(Rel32FinderWin32X86Test, TestBasic) {
141 RunTest("rel32_win32_x86_01.txt");
142 RunTest("rel32_win32_x86_02.txt");
143 RunTest("rel32_win32_x86_03.txt");
144 RunTest("rel32_win32_x86_04.txt");
147 } // namespace
149 } // namespace courgette