Home | History | Annotate | Download | only in tests
      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 std::string TestGetFileDirectory() {
     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 = TestGetFileDirectory();
    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