• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetDataFilePath(const char * name,std::string * path)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 
OpenRelocsTestFile(const char * name,FILE ** stream)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 
OpenRelocsTestFiles(FILE ** relocs_so,FILE ** packed_relocs_so)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 
CloseRelocsTestFile(FILE * temporary)90 void CloseRelocsTestFile(FILE* temporary) {
91   fclose(temporary);
92 }
93 
CloseRelocsTestFiles(FILE * relocs_so,FILE * packed_relocs_so)94 void CloseRelocsTestFiles(FILE* relocs_so, FILE* packed_relocs_so) {
95   CloseRelocsTestFile(relocs_so);
96   CloseRelocsTestFile(packed_relocs_so);
97 }
98 
CheckFileContentsEqual(FILE * first,FILE * second)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 
TEST(ElfFile,PackRelocations)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 
TEST(ElfFile,UnpackRelocations)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