Home | History | Annotate | Download | only in src
      1 // Copyright 2014 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 "elf_file.h"
      6 
      7 #include <limits.h>
      8 #include <stdio.h>
      9 #include <unistd.h>
     10 #include <string>
     11 #include <vector>
     12 #include "debug.h"
     13 #include "elf_traits.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 
     16 // Macro stringification.
     17 // https://gcc.gnu.org/onlinedocs/cpp/Stringification.html
     18 #define XSTR(S) STR(S)
     19 #define STR(S) #S
     20 
     21 namespace {
     22 
     23 void GetDataFilePath(const char* name, std::string* path) {
     24   std::string data_dir;
     25 
     26   const char* bindir = getenv("bindir");
     27   if (bindir) {
     28     data_dir = std::string(bindir);
     29   } else {
     30     // Test data is in the gyp INTERMEDIATE_DIR subdirectory of the directory
     31     // that contains the current binary.
     32     char path[PATH_MAX];
     33     memset(path, 0, sizeof(path));
     34     ASSERT_NE(-1, readlink("/proc/self/exe", path, sizeof(path) - 1));
     35 
     36     data_dir = std::string(path);
     37     size_t pos = data_dir.rfind('/');
     38     ASSERT_NE(std::string::npos, pos);
     39 
     40     data_dir.erase(pos + 1);
     41     data_dir += std::string(XSTR(INTERMEDIATE_DIR));
     42   }
     43 
     44   *path = data_dir + "/" + name;
     45 }
     46 
     47 void OpenRelocsTestFile(const char* name, FILE** stream) {
     48   std::string path;
     49   GetDataFilePath(name, &path);
     50 
     51   FILE* testfile = fopen(path.c_str(), "rb");
     52   ASSERT_FALSE(testfile == NULL);
     53 
     54   FILE* temporary = tmpfile();
     55   ASSERT_FALSE(temporary == NULL);
     56 
     57   static const size_t buffer_size = 4096;
     58   unsigned char buffer[buffer_size];
     59 
     60   size_t bytes;
     61   do {
     62     bytes = fread(buffer, 1, sizeof(buffer), testfile);
     63     ASSERT_EQ(bytes, fwrite(buffer, 1, bytes, temporary));
     64   } while (bytes > 0);
     65 
     66   ASSERT_EQ(0, fclose(testfile));
     67   ASSERT_EQ(0, fseek(temporary, 0, SEEK_SET));
     68   ASSERT_EQ(0, lseek(fileno(temporary), 0, SEEK_SET));
     69 
     70   *stream = temporary;
     71 }
     72 
     73 void OpenRelocsTestFiles(FILE** relocs_so, FILE** packed_relocs_so) {
     74   const char* arch = NULL;
     75   if (ELF::kMachine == EM_ARM) {
     76     arch = "arm32";
     77   } else if (ELF::kMachine == EM_AARCH64) {
     78     arch = "arm64";
     79   }
     80   ASSERT_FALSE(arch == NULL);
     81 
     82   const std::string base = std::string("elf_file_unittest_relocs_") + arch;
     83   const std::string relocs = base + ".so";
     84   const std::string packed_relocs = base + "_packed.so";
     85 
     86   OpenRelocsTestFile(relocs.c_str(), relocs_so);
     87   OpenRelocsTestFile(packed_relocs.c_str(), packed_relocs_so);
     88 }
     89 
     90 void CloseRelocsTestFile(FILE* temporary) {
     91   fclose(temporary);
     92 }
     93 
     94 void CloseRelocsTestFiles(FILE* relocs_so, FILE* packed_relocs_so) {
     95   CloseRelocsTestFile(relocs_so);
     96   CloseRelocsTestFile(packed_relocs_so);
     97 }
     98 
     99 void CheckFileContentsEqual(FILE* first, FILE* second) {
    100   ASSERT_EQ(0, fseek(first, 0, SEEK_SET));
    101   ASSERT_EQ(0, fseek(second, 0, SEEK_SET));
    102 
    103   static const size_t buffer_size = 4096;
    104   unsigned char first_buffer[buffer_size];
    105   unsigned char second_buffer[buffer_size];
    106 
    107   do {
    108     size_t first_read = fread(first_buffer, 1, sizeof(first_buffer), first);
    109     size_t second_read = fread(second_buffer, 1, sizeof(second_buffer), second);
    110 
    111     EXPECT_EQ(first_read, second_read);
    112     EXPECT_EQ(0, memcmp(first_buffer, second_buffer, first_read));
    113   } while (!feof(first) && !feof(second));
    114 
    115   EXPECT_TRUE(feof(first) && feof(second));
    116 }
    117 
    118 }  // namespace
    119 
    120 namespace relocation_packer {
    121 
    122 TEST(ElfFile, PackRelocations) {
    123   ASSERT_NE(EV_NONE, elf_version(EV_CURRENT));
    124 
    125   FILE* relocs_so = NULL;
    126   FILE* packed_relocs_so = NULL;
    127   OpenRelocsTestFiles(&relocs_so, &packed_relocs_so);
    128   if (HasFatalFailure())
    129     return;
    130 
    131   ElfFile elf_file(fileno(relocs_so));
    132 
    133   // Ensure unpacking fails (not packed).
    134   EXPECT_FALSE(elf_file.UnpackRelocations());
    135 
    136   // Pack relocations, and check files are now identical.
    137   EXPECT_TRUE(elf_file.PackRelocations());
    138   CheckFileContentsEqual(relocs_so, packed_relocs_so);
    139 
    140   CloseRelocsTestFiles(relocs_so, packed_relocs_so);
    141 }
    142 
    143 TEST(ElfFile, UnpackRelocations) {
    144   ASSERT_NE(EV_NONE, elf_version(EV_CURRENT));
    145 
    146   FILE* relocs_so = NULL;
    147   FILE* packed_relocs_so = NULL;
    148   OpenRelocsTestFiles(&relocs_so, &packed_relocs_so);
    149   if (HasFatalFailure())
    150     return;
    151 
    152   ElfFile elf_file(fileno(packed_relocs_so));
    153 
    154   // Ensure packing fails (already packed).
    155   EXPECT_FALSE(elf_file.PackRelocations());
    156 
    157   // Unpack golden relocations, and check files are now identical.
    158   EXPECT_TRUE(elf_file.UnpackRelocations());
    159   CheckFileContentsEqual(packed_relocs_so, relocs_so);
    160 
    161   CloseRelocsTestFiles(relocs_so, packed_relocs_so);
    162 }
    163 
    164 }  // namespace relocation_packer
    165