elfutils.cc
1 // Copyright 2012 Google LLC 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google LLC nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 #ifdef HAVE_CONFIG_H 30 #include <config.h> // Must come first 31 #endif 32 33 #include "common/linux/elfutils.h" 34 35 #include <assert.h> 36 #include <string.h> 37 38 #include "common/linux/linux_libc_support.h" 39 #include "common/linux/elfutils-inl.h" 40 41 namespace google_breakpad { 42 43 namespace { 44 45 template<typename ElfClass> 46 void FindElfClassSection(const char* elf_base, 47 const char* section_name, 48 typename ElfClass::Word section_type, 49 const void** section_start, 50 size_t* section_size) { 51 typedef typename ElfClass::Ehdr Ehdr; 52 typedef typename ElfClass::Shdr Shdr; 53 54 assert(elf_base); 55 assert(section_start); 56 assert(section_size); 57 58 assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0); 59 60 const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base); 61 assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass); 62 63 if (elf_header->e_shoff == 0) { 64 *section_start = NULL; 65 *section_size = 0; 66 return; 67 } 68 69 const Shdr* sections = 70 GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff); 71 const Shdr* section_names = sections + elf_header->e_shstrndx; 72 const char* names = 73 GetOffset<ElfClass, char>(elf_header, section_names->sh_offset); 74 const char* names_end = names + section_names->sh_size; 75 76 const Shdr* section = 77 FindElfSectionByName<ElfClass>(section_name, section_type, 78 sections, names, names_end, 79 elf_header->e_shnum); 80 81 if (section != NULL && section->sh_size > 0) { 82 *section_start = elf_base + section->sh_offset; 83 *section_size = section->sh_size; 84 } 85 } 86 87 template<typename ElfClass> 88 void FindElfClassSegment(const char* elf_base, 89 typename ElfClass::Word segment_type, 90 wasteful_vector<ElfSegment>* segments) { 91 typedef typename ElfClass::Ehdr Ehdr; 92 typedef typename ElfClass::Phdr Phdr; 93 94 assert(elf_base); 95 assert(segments); 96 97 assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0); 98 99 const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base); 100 assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass); 101 102 const Phdr* phdrs = 103 GetOffset<ElfClass, Phdr>(elf_header, elf_header->e_phoff); 104 105 for (int i = 0; i < elf_header->e_phnum; ++i) { 106 if (phdrs[i].p_type == segment_type) { 107 ElfSegment seg = {}; 108 seg.start = elf_base + phdrs[i].p_offset; 109 seg.size = phdrs[i].p_filesz; 110 segments->push_back(seg); 111 } 112 } 113 } 114 115 } // namespace 116 117 bool IsValidElf(const void* elf_base) { 118 return my_strncmp(reinterpret_cast<const char*>(elf_base), 119 ELFMAG, SELFMAG) == 0; 120 } 121 122 int ElfClass(const void* elf_base) { 123 const ElfW(Ehdr)* elf_header = 124 reinterpret_cast<const ElfW(Ehdr)*>(elf_base); 125 126 return elf_header->e_ident[EI_CLASS]; 127 } 128 129 bool FindElfSection(const void* elf_mapped_base, 130 const char* section_name, 131 uint32_t section_type, 132 const void** section_start, 133 size_t* section_size) { 134 assert(elf_mapped_base); 135 assert(section_start); 136 assert(section_size); 137 138 *section_start = NULL; 139 *section_size = 0; 140 141 if (!IsValidElf(elf_mapped_base)) 142 return false; 143 144 int cls = ElfClass(elf_mapped_base); 145 const char* elf_base = 146 static_cast<const char*>(elf_mapped_base); 147 148 if (cls == ELFCLASS32) { 149 FindElfClassSection<ElfClass32>(elf_base, section_name, section_type, 150 section_start, section_size); 151 return *section_start != NULL; 152 } else if (cls == ELFCLASS64) { 153 FindElfClassSection<ElfClass64>(elf_base, section_name, section_type, 154 section_start, section_size); 155 return *section_start != NULL; 156 } 157 158 return false; 159 } 160 161 bool FindElfSegments(const void* elf_mapped_base, 162 uint32_t segment_type, 163 wasteful_vector<ElfSegment>* segments) { 164 assert(elf_mapped_base); 165 assert(segments); 166 167 if (!IsValidElf(elf_mapped_base)) 168 return false; 169 170 int cls = ElfClass(elf_mapped_base); 171 const char* elf_base = 172 static_cast<const char*>(elf_mapped_base); 173 174 if (cls == ELFCLASS32) { 175 FindElfClassSegment<ElfClass32>(elf_base, segment_type, segments); 176 return true; 177 } else if (cls == ELFCLASS64) { 178 FindElfClassSegment<ElfClass64>(elf_base, segment_type, segments); 179 return true; 180 } 181 182 return false; 183 } 184 185 template <typename ElfClass> 186 bool FindElfSoNameFromDynamicSection(const void* section_start, 187 size_t section_size, 188 const void* dynstr_start, 189 size_t dynstr_size, 190 char* soname, 191 size_t soname_size) { 192 typedef typename ElfClass::Dyn Dyn; 193 194 auto* dynamic = static_cast<const Dyn*>(section_start); 195 size_t dcount = section_size / sizeof(Dyn); 196 for (const Dyn* dyn = dynamic; dyn < dynamic + dcount; ++dyn) { 197 if (dyn->d_tag == DT_SONAME) { 198 const char* dynstr = static_cast<const char*>(dynstr_start); 199 if (dyn->d_un.d_val >= dynstr_size) { 200 // Beyond the end of the dynstr section 201 return false; 202 } 203 const char* str = dynstr + dyn->d_un.d_val; 204 const size_t maxsize = dynstr_size - dyn->d_un.d_val; 205 my_strlcpy(soname, str, maxsize < soname_size ? maxsize : soname_size); 206 return true; 207 } 208 } 209 210 return false; 211 } 212 213 bool ElfFileSoNameFromMappedFile(const void* elf_base, 214 char* soname, 215 size_t soname_size) { 216 if (!IsValidElf(elf_base)) { 217 // Not ELF 218 return false; 219 } 220 221 const void* segment_start; 222 size_t segment_size; 223 if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC, &segment_start, 224 &segment_size)) { 225 // No dynamic section 226 return false; 227 } 228 229 const void* dynstr_start; 230 size_t dynstr_size; 231 if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB, &dynstr_start, 232 &dynstr_size)) { 233 // No dynstr section 234 return false; 235 } 236 237 int cls = ElfClass(elf_base); 238 return cls == ELFCLASS32 ? FindElfSoNameFromDynamicSection<ElfClass32>( 239 segment_start, segment_size, dynstr_start, 240 dynstr_size, soname, soname_size) 241 : FindElfSoNameFromDynamicSection<ElfClass64>( 242 segment_start, segment_size, dynstr_start, 243 dynstr_size, soname, soname_size); 244 } 245 246 } // namespace google_breakpad