1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <elf.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <signal.h> 21 #include <string.h> 22 #include <sys/mman.h> 23 #include <sys/ptrace.h> 24 #include <sys/types.h> 25 #include <unistd.h> 26 27 #include <string> 28 #include <vector> 29 30 #include <gtest/gtest.h> 31 32 #include "ElfTestUtils.h" 33 34 namespace unwindstack { 35 36 template <typename Ehdr> 37 void TestInitEhdr(Ehdr* ehdr, uint32_t elf_class, uint32_t machine_type) { 38 memset(ehdr, 0, sizeof(Ehdr)); 39 memcpy(&ehdr->e_ident[0], ELFMAG, SELFMAG); 40 ehdr->e_ident[EI_DATA] = ELFDATA2LSB; 41 ehdr->e_ident[EI_VERSION] = EV_CURRENT; 42 ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV; 43 ehdr->e_ident[EI_CLASS] = elf_class; 44 ehdr->e_type = ET_DYN; 45 ehdr->e_machine = machine_type; 46 ehdr->e_version = EV_CURRENT; 47 ehdr->e_ehsize = sizeof(Ehdr); 48 } 49 50 static std::string GetTestFileDirectory() { 51 std::string exec(testing::internal::GetArgvs()[0]); 52 auto const value = exec.find_last_of('/'); 53 if (value == std::string::npos) { 54 return "tests/files/"; 55 } 56 return exec.substr(0, value + 1) + "tests/files/"; 57 } 58 59 template <typename Ehdr, typename Shdr> 60 void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine, bool init_gnu_debugdata, 61 TestCopyFuncType copy_func) { 62 Ehdr ehdr; 63 64 TestInitEhdr(&ehdr, elf_class, machine); 65 66 uint64_t offset = sizeof(Ehdr); 67 ehdr.e_shoff = offset; 68 ehdr.e_shnum = 3; 69 ehdr.e_shentsize = sizeof(Shdr); 70 ehdr.e_shstrndx = 2; 71 copy_func(0, &ehdr, sizeof(ehdr)); 72 73 Shdr shdr; 74 memset(&shdr, 0, sizeof(shdr)); 75 shdr.sh_type = SHT_NULL; 76 copy_func(offset, &shdr, sizeof(shdr)); 77 offset += ehdr.e_shentsize; 78 79 // Skip this header, it will contain the gnu_debugdata information. 80 uint64_t gnu_offset = offset; 81 offset += ehdr.e_shentsize; 82 83 uint64_t symtab_offset = sizeof(ehdr) + ehdr.e_shnum * ehdr.e_shentsize; 84 memset(&shdr, 0, sizeof(shdr)); 85 shdr.sh_name = 1; 86 shdr.sh_type = SHT_STRTAB; 87 shdr.sh_offset = symtab_offset; 88 shdr.sh_size = 0x100; 89 copy_func(offset, &shdr, sizeof(shdr)); 90 91 char value = '\0'; 92 uint64_t symname_offset = symtab_offset; 93 copy_func(symname_offset, &value, 1); 94 symname_offset++; 95 std::string name(".shstrtab"); 96 copy_func(symname_offset, name.c_str(), name.size() + 1); 97 symname_offset += name.size() + 1; 98 name = ".gnu_debugdata"; 99 copy_func(symname_offset, name.c_str(), name.size() + 1); 100 101 ssize_t bytes = 0x100; 102 offset = symtab_offset + 0x100; 103 if (init_gnu_debugdata) { 104 // Read in the compressed elf data and copy it in. 105 name = GetTestFileDirectory(); 106 if (elf_class == ELFCLASS32) { 107 name += "elf32.xz"; 108 } else { 109 name += "elf64.xz"; 110 } 111 int fd = TEMP_FAILURE_RETRY(open(name.c_str(), O_RDONLY)); 112 ASSERT_NE(-1, fd) << "Cannot open " + name; 113 // Assumes the file is less than 1024 bytes. 114 std::vector<uint8_t> buf(1024); 115 bytes = TEMP_FAILURE_RETRY(read(fd, buf.data(), buf.size())); 116 ASSERT_GT(bytes, 0); 117 // Make sure the file isn't too big. 118 ASSERT_NE(static_cast<size_t>(bytes), buf.size()) 119 << "File " + name + " is too big, increase buffer size."; 120 close(fd); 121 buf.resize(bytes); 122 copy_func(offset, buf.data(), buf.size()); 123 } 124 125 memset(&shdr, 0, sizeof(shdr)); 126 shdr.sh_type = SHT_PROGBITS; 127 shdr.sh_name = symname_offset - symtab_offset; 128 shdr.sh_addr = offset; 129 shdr.sh_offset = offset; 130 shdr.sh_size = bytes; 131 copy_func(gnu_offset, &shdr, sizeof(shdr)); 132 } 133 134 template void TestInitEhdr<Elf32_Ehdr>(Elf32_Ehdr*, uint32_t, uint32_t); 135 template void TestInitEhdr<Elf64_Ehdr>(Elf64_Ehdr*, uint32_t, uint32_t); 136 137 template void TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(uint32_t, uint32_t, bool, 138 TestCopyFuncType); 139 template void TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(uint32_t, uint32_t, bool, 140 TestCopyFuncType); 141 142 } // namespace unwindstack 143