elf_file_unittest.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "elf_file.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <limits.h>
890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <stdio.h>
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <unistd.h>
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <string>
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <vector>
1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "debug.h"
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Macro stringification.
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// https://gcc.gnu.org/onlinedocs/cpp/Stringification.html
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#define XSTR(S) STR(S)
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#define STR(S) #S
1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace {
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void GetDataFilePath(const char* name, std::string* path) {
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string data_dir;
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  const char* bindir = getenv("bindir");
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (bindir) {
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    data_dir = std::string(bindir);
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else {
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Test data is in the gyp INTERMEDIATE_DIR subdirectory of the directory
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // that contains the current binary.
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    char path[PATH_MAX];
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    memset(path, 0, sizeof(path));
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ASSERT_NE(-1, readlink("/proc/self/exe", path, sizeof(path) - 1));
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    data_dir = std::string(path);
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    size_t pos = data_dir.rfind('/');
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ASSERT_NE(std::string::npos, pos);
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    data_dir.erase(pos + 1);
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    data_dir += std::string(XSTR(INTERMEDIATE_DIR));
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  *path = data_dir + "/" + name;
4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OpenRelocsTestFile(const char* name, FILE** stream) {
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string path;
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  GetDataFilePath(name, &path);
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  FILE* testfile = fopen(path.c_str(), "rb");
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ASSERT_FALSE(testfile == NULL);
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  FILE* temporary = tmpfile();
5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ASSERT_FALSE(temporary == NULL);
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  static const size_t buffer_size = 4096;
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  unsigned char buffer[buffer_size];
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  size_t bytes;
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  do {
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    bytes = fread(buffer, 1, sizeof(buffer), testfile);
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    ASSERT_EQ(bytes, fwrite(buffer, 1, bytes, temporary));
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } while (bytes > 0);
6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ASSERT_EQ(0, fclose(testfile));
6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ASSERT_EQ(0, fseek(temporary, 0, SEEK_SET));
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ASSERT_EQ(0, lseek(fileno(temporary), 0, SEEK_SET));
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  *stream = temporary;
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void OpenRelocsTestFiles(FILE** relocs_so, FILE** packed_relocs_so) {
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  OpenRelocsTestFile("elf_file_unittest_relocs.so", relocs_so);
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  OpenRelocsTestFile("elf_file_unittest_relocs_packed.so", packed_relocs_so);
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void CloseRelocsTestFile(FILE* temporary) {
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  fclose(temporary);
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void CloseRelocsTestFiles(FILE* relocs_so, FILE* packed_relocs_so) {
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  CloseRelocsTestFile(relocs_so);
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  CloseRelocsTestFile(packed_relocs_so);
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void CheckFileContentsEqual(FILE* first, FILE* second) {
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ASSERT_EQ(0, fseek(first, 0, SEEK_SET));
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ASSERT_EQ(0, fseek(second, 0, SEEK_SET));
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  static const size_t buffer_size = 4096;
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  unsigned char first_buffer[buffer_size];
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  unsigned char second_buffer[buffer_size];
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  do {
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    size_t first_read = fread(first_buffer, 1, sizeof(first_buffer), first);
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    size_t second_read = fread(second_buffer, 1, sizeof(second_buffer), second);
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    EXPECT_EQ(first_read, second_read);
9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    EXPECT_EQ(0, memcmp(first_buffer, second_buffer, first_read));
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } while (!feof(first) && !feof(second));
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  EXPECT_TRUE(feof(first) && feof(second));
10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace relocation_packer {
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
10990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)TEST(ElfFile, PackRelocations) {
11090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ASSERT_NE(EV_NONE, elf_version(EV_CURRENT));
11190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  FILE* relocs_so = NULL;
11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  FILE* packed_relocs_so = NULL;
11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  OpenRelocsTestFiles(&relocs_so, &packed_relocs_so);
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (HasFatalFailure())
11690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ElfFile elf_file(fileno(relocs_so));
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Ensure unpacking fails (not packed).
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  EXPECT_FALSE(elf_file.UnpackRelocations());
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Pack relocations, and check files are now identical.
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  EXPECT_TRUE(elf_file.PackRelocations());
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  CheckFileContentsEqual(relocs_so, packed_relocs_so);
126
127  CloseRelocsTestFiles(relocs_so, packed_relocs_so);
128}
129
130TEST(ElfFile, UnpackRelocations) {
131  ASSERT_NE(EV_NONE, elf_version(EV_CURRENT));
132
133  FILE* relocs_so = NULL;
134  FILE* packed_relocs_so = NULL;
135  OpenRelocsTestFiles(&relocs_so, &packed_relocs_so);
136  if (HasFatalFailure())
137    return;
138
139  ElfFile elf_file(fileno(packed_relocs_so));
140
141  // Ensure packing fails (already packed).
142  EXPECT_FALSE(elf_file.PackRelocations());
143
144  // Unpack golden relocations, and check files are now identical.
145  EXPECT_TRUE(elf_file.UnpackRelocations());
146  CheckFileContentsEqual(packed_relocs_so, relocs_so);
147
148  CloseRelocsTestFiles(relocs_so, packed_relocs_so);
149}
150
151}  // namespace relocation_packer
152