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 21namespace { 22 23void 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 47void 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 73void 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 90void CloseRelocsTestFile(FILE* temporary) { 91 fclose(temporary); 92} 93 94void CloseRelocsTestFiles(FILE* relocs_so, FILE* packed_relocs_so) { 95 CloseRelocsTestFile(relocs_so); 96 CloseRelocsTestFile(packed_relocs_so); 97} 98 99void 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 120namespace relocation_packer { 121 122TEST(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 143TEST(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