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 // Tool to pack and unpack relative relocations in a shared library. 6 // 7 // Invoke with -v to trace actions taken when packing or unpacking. 8 // Invoke with -p to pad removed relocations with R_*_NONE. Suppresses 9 // shrinking of .rel.dyn. 10 // See PrintUsage() below for full usage details. 11 // 12 // NOTE: Breaks with libelf 0.152, which is buggy. libelf 0.158 works. 13 14 #include <errno.h> 15 #include <fcntl.h> 16 #include <getopt.h> 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <sys/types.h> 20 #include <unistd.h> 21 #include <string> 22 23 #include "debug.h" 24 #include "elf_file.h" 25 #include "elf_traits.h" 26 #include "libelf.h" 27 28 #include "nativehelper/ScopedFd.h" 29 30 static void PrintUsage(const char* argv0) { 31 std::string temporary = argv0; 32 const size_t last_slash = temporary.find_last_of("/"); 33 if (last_slash != temporary.npos) { 34 temporary.erase(0, last_slash + 1); 35 } 36 const char* basename = temporary.c_str(); 37 38 printf( 39 "Usage: %s [-u] [-v] [-p] file\n\n" 40 "Pack or unpack relative relocations in a shared library.\n\n" 41 " -u, --unpack unpack previously packed relative relocations\n" 42 " -v, --verbose trace object file modifications (for debugging)\n" 43 " -p, --pad do not shrink relocations, but pad (for debugging)\n\n", 44 basename); 45 46 printf( 47 "Debug sections are not handled, so packing should not be used on\n" 48 "shared libraries compiled for debugging or otherwise unstripped.\n"); 49 } 50 51 int main(int argc, char* argv[]) { 52 bool is_unpacking = false; 53 bool is_verbose = false; 54 bool is_padding = false; 55 56 static const option options[] = { 57 {"unpack", 0, 0, 'u'}, {"verbose", 0, 0, 'v'}, {"pad", 0, 0, 'p'}, 58 {"help", 0, 0, 'h'}, {NULL, 0, 0, 0} 59 }; 60 bool has_options = true; 61 while (has_options) { 62 int c = getopt_long(argc, argv, "uvph", options, NULL); 63 switch (c) { 64 case 'u': 65 is_unpacking = true; 66 break; 67 case 'v': 68 is_verbose = true; 69 break; 70 case 'p': 71 is_padding = true; 72 break; 73 case 'h': 74 PrintUsage(argv[0]); 75 return 0; 76 case '?': 77 LOG(INFO) << "Try '" << argv[0] << " --help' for more information."; 78 return 1; 79 case -1: 80 has_options = false; 81 break; 82 default: 83 NOTREACHED(); 84 return 1; 85 } 86 } 87 if (optind != argc - 1) { 88 LOG(INFO) << "Try '" << argv[0] << " --help' for more information."; 89 return 1; 90 } 91 92 if (elf_version(EV_CURRENT) == EV_NONE) { 93 LOG(WARNING) << "Elf Library is out of date!"; 94 } 95 96 const char* file = argv[argc - 1]; 97 ScopedFd fd(open(file, O_RDWR)); 98 if (fd.get() == -1) { 99 LOG(ERROR) << file << ": " << strerror(errno); 100 return 1; 101 } 102 103 if (is_verbose) 104 relocation_packer::Logger::SetVerbose(1); 105 106 // We need to detect elf class in order to create 107 // correct implementation 108 uint8_t e_ident[EI_NIDENT]; 109 if (TEMP_FAILURE_RETRY(read(fd.get(), e_ident, EI_NIDENT) != EI_NIDENT)) { 110 LOG(ERROR) << file << ": failed to read elf header:" << strerror(errno); 111 return 1; 112 } 113 114 if (TEMP_FAILURE_RETRY(lseek(fd.get(), 0, SEEK_SET)) != 0) { 115 LOG(ERROR) << file << ": lseek to 0 failed:" << strerror(errno); 116 return 1; 117 } 118 119 bool status = false; 120 121 if (e_ident[EI_CLASS] == ELFCLASS32) { 122 relocation_packer::ElfFile<ELF32_traits> elf_file(fd.get()); 123 elf_file.SetPadding(is_padding); 124 125 if (is_unpacking) { 126 status = elf_file.UnpackRelocations(); 127 } else { 128 status = elf_file.PackRelocations(); 129 } 130 } else if (e_ident[EI_CLASS] == ELFCLASS64) { 131 relocation_packer::ElfFile<ELF64_traits> elf_file(fd.get()); 132 elf_file.SetPadding(is_padding); 133 134 if (is_unpacking) { 135 status = elf_file.UnpackRelocations(); 136 } else { 137 status = elf_file.PackRelocations(); 138 } 139 } else { 140 LOG(ERROR) << file << ": unknown ELFCLASS: " << e_ident[EI_CLASS]; 141 return 1; 142 } 143 144 if (!status) { 145 LOG(ERROR) << file << ": failed to pack/unpack file"; 146 return 1; 147 } 148 149 return 0; 150 } 151