1 /* 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 27 #if !defined(_WINDOWS) && !defined(__APPLE__) 28 29 #include <string.h> 30 #include <stdio.h> 31 #include <limits.h> 32 #include <new> 33 34 #include "memory/allocation.inline.hpp" 35 #include "utilities/decoder.hpp" 36 #include "utilities/elfFile.hpp" 37 #include "utilities/elfFuncDescTable.hpp" 38 #include "utilities/elfStringTable.hpp" 39 #include "utilities/elfSymbolTable.hpp" 40 41 42 ElfFile::ElfFile(const char* filepath, bool load_tbls) { 43 assert(filepath, "null file path"); 44 memset(&m_elfHdr, 0, sizeof(m_elfHdr)); 45 m_string_tables = NULL; 46 m_symbol_tables = NULL; 47 m_funcDesc_table = NULL; 48 m_next = NULL; 49 m_status = NullDecoder::no_error; 50 51 int len = strlen(filepath) + 1; 52 m_filepath = (const char*)os::malloc(len * sizeof(char), mtInternal); 53 if (m_filepath != NULL) { 54 strcpy((char*)m_filepath, filepath); 55 m_file = fopen(filepath, "r"); 56 if (m_file != NULL) { 57 if (load_tbls) { 58 load_tables(); 59 } 60 } else { 61 m_status = NullDecoder::file_not_found; 62 } 63 } else { 64 m_status = NullDecoder::out_of_memory; 65 } 66 } 67 68 ElfFile::~ElfFile() { 69 if (m_string_tables != NULL) { 70 delete m_string_tables; 71 } 72 73 if (m_symbol_tables != NULL) { 74 delete m_symbol_tables; 75 } 76 77 if (m_file != NULL) { 78 fclose(m_file); 79 } 80 81 if (m_filepath != NULL) { 82 os::free((void*)m_filepath); 83 } 84 85 if (m_next != NULL) { 86 delete m_next; 87 } 88 }; 89 90 91 //Check elf header to ensure the file is valid. 92 bool ElfFile::is_elf_file(Elf_Ehdr& hdr) { 93 return (ELFMAG0 == hdr.e_ident[EI_MAG0] && 94 ELFMAG1 == hdr.e_ident[EI_MAG1] && 95 ELFMAG2 == hdr.e_ident[EI_MAG2] && 96 ELFMAG3 == hdr.e_ident[EI_MAG3] && 97 ELFCLASSNONE != hdr.e_ident[EI_CLASS] && 98 ELFDATANONE != hdr.e_ident[EI_DATA]); 99 } 100 101 bool ElfFile::load_tables() { 102 assert(m_file, "file not open"); 103 assert(!NullDecoder::is_error(m_status), "already in error"); 104 105 // read elf file header 106 if (fread(&m_elfHdr, sizeof(m_elfHdr), 1, m_file) != 1) { 107 m_status = NullDecoder::file_invalid; 108 return false; 109 } 110 111 if (!is_elf_file(m_elfHdr)) { 112 m_status = NullDecoder::file_invalid; 113 return false; 114 } 115 116 // walk elf file's section headers, and load string tables 117 Elf_Shdr shdr; 118 if (!fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) { 119 if (NullDecoder::is_error(m_status)) return false; 120 121 for (int index = 0; index < m_elfHdr.e_shnum; index ++) { 122 if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) { 123 m_status = NullDecoder::file_invalid; 124 return false; 125 } 126 if (shdr.sh_type == SHT_STRTAB) { 127 // string tables 128 ElfStringTable* table = new (std::nothrow) ElfStringTable(m_file, shdr, index); 129 if (table == NULL) { 130 m_status = NullDecoder::out_of_memory; 131 return false; 132 } 133 add_string_table(table); 134 } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { 135 // symbol tables 136 ElfSymbolTable* table = new (std::nothrow) ElfSymbolTable(m_file, shdr); 137 if (table == NULL) { 138 m_status = NullDecoder::out_of_memory; 139 return false; 140 } 141 add_symbol_table(table); 142 } 143 } 144 145 #if defined(PPC64) && !defined(ABI_ELFv2) 146 // Now read the .opd section wich contains the PPC64 function descriptor table. 147 // The .opd section is only available on PPC64 (see for example: 148 // http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html) 149 // so this code should do no harm on other platforms but because of performance reasons we only 150 // execute it on PPC64 platforms. 151 // Notice that we can only find the .opd section after we have successfully read in the string 152 // tables in the previous loop, because we need to query the name of each section which is 153 // contained in one of the string tables (i.e. the one with the index m_elfHdr.e_shstrndx). 154 155 // Reset the file pointer 156 if (fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) { 157 m_status = NullDecoder::file_invalid; 158 return false; 159 } 160 for (int index = 0; index < m_elfHdr.e_shnum; index ++) { 161 if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) { 162 m_status = NullDecoder::file_invalid; 163 return false; 164 } 165 if (m_elfHdr.e_shstrndx != SHN_UNDEF && shdr.sh_type == SHT_PROGBITS) { 166 ElfStringTable* string_table = get_string_table(m_elfHdr.e_shstrndx); 167 if (string_table == NULL) { 168 m_status = NullDecoder::file_invalid; 169 return false; 170 } 171 char buf[8]; // '8' is enough because we only want to read ".opd" 172 if (string_table->string_at(shdr.sh_name, buf, sizeof(buf)) && !strncmp(".opd", buf, 4)) { 173 m_funcDesc_table = new (std::nothrow) ElfFuncDescTable(m_file, shdr, index); 174 if (m_funcDesc_table == NULL) { 175 m_status = NullDecoder::out_of_memory; 176 return false; 177 } 178 break; 179 } 180 } 181 } 182 #endif 183 184 } 185 return true; 186 } 187 188 bool ElfFile::decode(address addr, char* buf, int buflen, int* offset) { 189 // something already went wrong, just give up 190 if (NullDecoder::is_error(m_status)) { 191 return false; 192 } 193 ElfSymbolTable* symbol_table = m_symbol_tables; 194 int string_table_index; 195 int pos_in_string_table; 196 int off = INT_MAX; 197 bool found_symbol = false; 198 while (symbol_table != NULL) { 199 if (symbol_table->lookup(addr, &string_table_index, &pos_in_string_table, &off, m_funcDesc_table)) { 200 found_symbol = true; 201 break; 202 } 203 symbol_table = symbol_table->m_next; 204 } 205 if (!found_symbol) return false; 206 207 ElfStringTable* string_table = get_string_table(string_table_index); 208 209 if (string_table == NULL) { 210 m_status = NullDecoder::file_invalid; 211 return false; 212 } 213 if (offset) *offset = off; 214 215 return string_table->string_at(pos_in_string_table, buf, buflen); 216 } 217 218 219 void ElfFile::add_symbol_table(ElfSymbolTable* table) { 220 if (m_symbol_tables == NULL) { 221 m_symbol_tables = table; 222 } else { 223 table->m_next = m_symbol_tables; 224 m_symbol_tables = table; 225 } 226 } 227 228 void ElfFile::add_string_table(ElfStringTable* table) { 229 if (m_string_tables == NULL) { 230 m_string_tables = table; 231 } else { 232 table->m_next = m_string_tables; 233 m_string_tables = table; 234 } 235 } 236 237 ElfStringTable* ElfFile::get_string_table(int index) { 238 ElfStringTable* p = m_string_tables; 239 while (p != NULL) { 240 if (p->index() == index) return p; 241 p = p->m_next; 242 } 243 return NULL; 244 } 245 246 #ifdef LINUX 247 bool ElfFile::specifies_noexecstack() { 248 Elf_Phdr phdr; 249 if (!m_file) return true; 250 251 if (!fseek(m_file, m_elfHdr.e_phoff, SEEK_SET)) { 252 for (int index = 0; index < m_elfHdr.e_phnum; index ++) { 253 if (fread((void*)&phdr, sizeof(Elf_Phdr), 1, m_file) != 1) { 254 m_status = NullDecoder::file_invalid; 255 return false; 256 } 257 if (phdr.p_type == PT_GNU_STACK) { 258 if (phdr.p_flags == (PF_R | PF_W)) { 259 return true; 260 } else { 261 return false; 262 } 263 } 264 } 265 } 266 // AARCH64 defaults to noexecstack. All others default to execstack. 267 #ifdef AARCH64 268 return true; 269 #else 270 return false; 271 #endif 272 } 273 #endif 274 275 #endif // !_WINDOWS && !__APPLE__