| David 'Digit' Turner | c1bd559 | 2012-06-19 11:21:29 +0200 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2012 The Android Open Source Project | 
 | 3 |  * All rights reserved. | 
 | 4 |  * | 
 | 5 |  * Redistribution and use in source and binary forms, with or without | 
 | 6 |  * modification, are permitted provided that the following conditions | 
 | 7 |  * are met: | 
 | 8 |  *  * Redistributions of source code must retain the above copyright | 
 | 9 |  *    notice, this list of conditions and the following disclaimer. | 
 | 10 |  *  * Redistributions in binary form must reproduce the above copyright | 
 | 11 |  *    notice, this list of conditions and the following disclaimer in | 
 | 12 |  *    the documentation and/or other materials provided with the | 
 | 13 |  *    distribution. | 
 | 14 |  * | 
 | 15 |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
 | 16 |  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
 | 17 |  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 
 | 18 |  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | 
 | 19 |  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | 
 | 20 |  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 
 | 21 |  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | 
 | 22 |  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 
 | 23 |  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
 | 24 |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | 
 | 25 |  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
 | 26 |  * SUCH DAMAGE. | 
 | 27 |  */ | 
 | 28 | #ifndef LINKER_PHDR_H | 
 | 29 | #define LINKER_PHDR_H | 
 | 30 |  | 
 | 31 | /* Declarations related to the ELF program header table and segments. | 
 | 32 |  * | 
 | 33 |  * The design goal is to provide an API that is as close as possible | 
 | 34 |  * to the ELF spec, and does not depend on linker-specific data | 
 | 35 |  * structures (e.g. the exact layout of struct soinfo). | 
 | 36 |  */ | 
 | 37 |  | 
 | 38 | #include "linker.h" | 
| Dmitriy Ivanov | cf1cbbe | 2015-10-19 16:57:46 -0700 | [diff] [blame] | 39 | #include "linker_mapped_file_fragment.h" | 
| David 'Digit' Turner | c1bd559 | 2012-06-19 11:21:29 +0200 | [diff] [blame] | 40 |  | 
| Elliott Hughes | 650be4e | 2013-03-05 18:47:58 -0800 | [diff] [blame] | 41 | class ElfReader { | 
 | 42 |  public: | 
| Dmitriy Ivanov | 4f7a7ad | 2015-10-15 12:07:25 -0700 | [diff] [blame] | 43 |   ElfReader(); | 
| David 'Digit' Turner | c1bd559 | 2012-06-19 11:21:29 +0200 | [diff] [blame] | 44 |  | 
| Dmitriy Ivanov | 4f7a7ad | 2015-10-15 12:07:25 -0700 | [diff] [blame] | 45 |   bool Read(const char* name, int fd, off64_t file_offset, off64_t file_size); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 46 |   bool Load(const android_dlextinfo* extinfo); | 
| David 'Digit' Turner | c1bd559 | 2012-06-19 11:21:29 +0200 | [diff] [blame] | 47 |  | 
| Dmitriy Ivanov | 4f7a7ad | 2015-10-15 12:07:25 -0700 | [diff] [blame] | 48 |   const char* name() const { return name_.c_str(); } | 
 | 49 |   size_t phdr_count() const { return phdr_num_; } | 
 | 50 |   ElfW(Addr) load_start() const { return reinterpret_cast<ElfW(Addr)>(load_start_); } | 
 | 51 |   size_t load_size() const { return load_size_; } | 
 | 52 |   ElfW(Addr) load_bias() const { return load_bias_; } | 
 | 53 |   const ElfW(Phdr)* loaded_phdr() const { return loaded_phdr_; } | 
 | 54 |   const ElfW(Dyn)* dynamic() const { return dynamic_; } | 
 | 55 |   const char* get_string(ElfW(Word) index) const; | 
| Dimitry Ivanov | f45b0e9 | 2016-01-15 11:13:35 -0800 | [diff] [blame] | 56 |   bool is_mapped_by_caller() const { return mapped_by_caller_; } | 
| David 'Digit' Turner | c1bd559 | 2012-06-19 11:21:29 +0200 | [diff] [blame] | 57 |  | 
| Elliott Hughes | 650be4e | 2013-03-05 18:47:58 -0800 | [diff] [blame] | 58 |  private: | 
 | 59 |   bool ReadElfHeader(); | 
 | 60 |   bool VerifyElfHeader(); | 
| Dmitriy Ivanov | 4f7a7ad | 2015-10-15 12:07:25 -0700 | [diff] [blame] | 61 |   bool ReadProgramHeaders(); | 
 | 62 |   bool ReadSectionHeaders(); | 
 | 63 |   bool ReadDynamicSection(); | 
| Torne (Richard Coles) | 12bbb91 | 2014-02-06 14:34:21 +0000 | [diff] [blame] | 64 |   bool ReserveAddressSpace(const android_dlextinfo* extinfo); | 
| Elliott Hughes | 650be4e | 2013-03-05 18:47:58 -0800 | [diff] [blame] | 65 |   bool LoadSegments(); | 
 | 66 |   bool FindPhdr(); | 
| Elliott Hughes | 0266ae5 | 2014-02-10 17:46:57 -0800 | [diff] [blame] | 67 |   bool CheckPhdr(ElfW(Addr)); | 
| Dimitry Ivanov | 7e2d49a | 2016-08-08 17:12:18 -0700 | [diff] [blame] | 68 |   bool CheckFileRange(ElfW(Addr) offset, size_t size, size_t alignment); | 
| David 'Digit' Turner | c1bd559 | 2012-06-19 11:21:29 +0200 | [diff] [blame] | 69 |  | 
| Dmitriy Ivanov | 4f7a7ad | 2015-10-15 12:07:25 -0700 | [diff] [blame] | 70 |   bool did_read_; | 
 | 71 |   bool did_load_; | 
 | 72 |   std::string name_; | 
| Elliott Hughes | 650be4e | 2013-03-05 18:47:58 -0800 | [diff] [blame] | 73 |   int fd_; | 
| Dmitriy Ivanov | 07e5bc1 | 2014-10-03 17:52:44 -0700 | [diff] [blame] | 74 |   off64_t file_offset_; | 
| Dmitriy Ivanov | 3f987f5 | 2015-06-25 15:51:41 -0700 | [diff] [blame] | 75 |   off64_t file_size_; | 
| Elliott Hughes | 650be4e | 2013-03-05 18:47:58 -0800 | [diff] [blame] | 76 |  | 
| Elliott Hughes | 0266ae5 | 2014-02-10 17:46:57 -0800 | [diff] [blame] | 77 |   ElfW(Ehdr) header_; | 
| Elliott Hughes | 650be4e | 2013-03-05 18:47:58 -0800 | [diff] [blame] | 78 |   size_t phdr_num_; | 
 | 79 |  | 
| Dmitriy Ivanov | cf1cbbe | 2015-10-19 16:57:46 -0700 | [diff] [blame] | 80 |   MappedFileFragment phdr_fragment_; | 
 | 81 |   const ElfW(Phdr)* phdr_table_; | 
| Elliott Hughes | 650be4e | 2013-03-05 18:47:58 -0800 | [diff] [blame] | 82 |  | 
| Dmitriy Ivanov | 4f7a7ad | 2015-10-15 12:07:25 -0700 | [diff] [blame] | 83 |   MappedFileFragment shdr_fragment_; | 
 | 84 |   const ElfW(Shdr)* shdr_table_; | 
 | 85 |   size_t shdr_num_; | 
 | 86 |  | 
 | 87 |   MappedFileFragment dynamic_fragment_; | 
 | 88 |   const ElfW(Dyn)* dynamic_; | 
 | 89 |  | 
 | 90 |   MappedFileFragment strtab_fragment_; | 
 | 91 |   const char* strtab_; | 
 | 92 |   size_t strtab_size_; | 
 | 93 |  | 
| Elliott Hughes | 650be4e | 2013-03-05 18:47:58 -0800 | [diff] [blame] | 94 |   // First page of reserved address space. | 
 | 95 |   void* load_start_; | 
 | 96 |   // Size in bytes of reserved address space. | 
| Elliott Hughes | c00f2cb | 2013-10-04 17:01:33 -0700 | [diff] [blame] | 97 |   size_t load_size_; | 
| Elliott Hughes | 650be4e | 2013-03-05 18:47:58 -0800 | [diff] [blame] | 98 |   // Load bias. | 
| Elliott Hughes | 0266ae5 | 2014-02-10 17:46:57 -0800 | [diff] [blame] | 99 |   ElfW(Addr) load_bias_; | 
| Elliott Hughes | 650be4e | 2013-03-05 18:47:58 -0800 | [diff] [blame] | 100 |  | 
 | 101 |   // Loaded phdr. | 
| Elliott Hughes | 0266ae5 | 2014-02-10 17:46:57 -0800 | [diff] [blame] | 102 |   const ElfW(Phdr)* loaded_phdr_; | 
| Dimitry Ivanov | f45b0e9 | 2016-01-15 11:13:35 -0800 | [diff] [blame] | 103 |  | 
 | 104 |   // Is map owned by the caller | 
 | 105 |   bool mapped_by_caller_; | 
| Elliott Hughes | 650be4e | 2013-03-05 18:47:58 -0800 | [diff] [blame] | 106 | }; | 
 | 107 |  | 
| Elliott Hughes | 0266ae5 | 2014-02-10 17:46:57 -0800 | [diff] [blame] | 108 | size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count, | 
| Dmitriy Ivanov | 851135b | 2014-08-29 12:02:36 -0700 | [diff] [blame] | 109 |                                 ElfW(Addr)* min_vaddr = nullptr, ElfW(Addr)* max_vaddr = nullptr); | 
| David 'Digit' Turner | c1bd559 | 2012-06-19 11:21:29 +0200 | [diff] [blame] | 110 |  | 
| Dimitry Ivanov | 56be6ed | 2015-04-01 21:18:48 +0000 | [diff] [blame] | 111 | int phdr_table_protect_segments(const ElfW(Phdr)* phdr_table, | 
 | 112 |                                 size_t phdr_count, ElfW(Addr) load_bias); | 
 | 113 |  | 
 | 114 | int phdr_table_unprotect_segments(const ElfW(Phdr)* phdr_table, size_t phdr_count, | 
 | 115 |                                   ElfW(Addr) load_bias); | 
 | 116 |  | 
| Dmitriy Ivanov | 20d89cb | 2015-03-30 18:43:38 -0700 | [diff] [blame] | 117 | int phdr_table_protect_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, | 
 | 118 |                                  ElfW(Addr) load_bias); | 
| David 'Digit' Turner | c1bd559 | 2012-06-19 11:21:29 +0200 | [diff] [blame] | 119 |  | 
| Dmitriy Ivanov | 20d89cb | 2015-03-30 18:43:38 -0700 | [diff] [blame] | 120 | int phdr_table_serialize_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, | 
 | 121 |                                    ElfW(Addr) load_bias, int fd); | 
| Torne (Richard Coles) | 183ad9d | 2014-02-27 13:18:00 +0000 | [diff] [blame] | 122 |  | 
| Dmitriy Ivanov | 20d89cb | 2015-03-30 18:43:38 -0700 | [diff] [blame] | 123 | int phdr_table_map_gnu_relro(const ElfW(Phdr)* phdr_table, size_t phdr_count, | 
 | 124 |                              ElfW(Addr) load_bias, int fd); | 
| David 'Digit' Turner | c1bd559 | 2012-06-19 11:21:29 +0200 | [diff] [blame] | 125 |  | 
| Elliott Hughes | 4eeb1f1 | 2013-10-25 17:38:02 -0700 | [diff] [blame] | 126 | #if defined(__arm__) | 
| Elliott Hughes | 0266ae5 | 2014-02-10 17:46:57 -0800 | [diff] [blame] | 127 | int phdr_table_get_arm_exidx(const ElfW(Phdr)* phdr_table, size_t phdr_count, ElfW(Addr) load_bias, | 
| Dmitriy Ivanov | 1649e7e | 2015-01-22 16:04:25 -0800 | [diff] [blame] | 128 |                              ElfW(Addr)** arm_exidx, size_t* arm_exidix_count); | 
| David 'Digit' Turner | c1bd559 | 2012-06-19 11:21:29 +0200 | [diff] [blame] | 129 | #endif | 
 | 130 |  | 
| Elliott Hughes | 0266ae5 | 2014-02-10 17:46:57 -0800 | [diff] [blame] | 131 | void phdr_table_get_dynamic_section(const ElfW(Phdr)* phdr_table, size_t phdr_count, | 
| Ningsheng Jian | e93be99 | 2014-09-16 15:22:10 +0800 | [diff] [blame] | 132 |                                     ElfW(Addr) load_bias, ElfW(Dyn)** dynamic, | 
 | 133 |                                     ElfW(Word)* dynamic_flags); | 
| David 'Digit' Turner | c1bd559 | 2012-06-19 11:21:29 +0200 | [diff] [blame] | 134 |  | 
| Evgenii Stepanov | d640b22 | 2015-07-10 17:54:01 -0700 | [diff] [blame] | 135 | const char* phdr_table_get_interpreter_name(const ElfW(Phdr) * phdr_table, size_t phdr_count, | 
 | 136 |                                             ElfW(Addr) load_bias); | 
 | 137 |  | 
| David 'Digit' Turner | c1bd559 | 2012-06-19 11:21:29 +0200 | [diff] [blame] | 138 | #endif /* LINKER_PHDR_H */ |