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