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 42ElfFile::ElfFile(const char* filepath) { 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 load_tables(); 58 } else { 59 m_status = NullDecoder::file_not_found; 60 } 61 } else { 62 m_status = NullDecoder::out_of_memory; 63 } 64} 65 66ElfFile::~ElfFile() { 67 if (m_string_tables != NULL) { 68 delete m_string_tables; 69 } 70 71 if (m_symbol_tables != NULL) { 72 delete m_symbol_tables; 73 } 74 75 if (m_file != NULL) { 76 fclose(m_file); 77 } 78 79 if (m_filepath != NULL) { 80 os::free((void*)m_filepath); 81 } 82 83 if (m_next != NULL) { 84 delete m_next; 85 } 86}; 87 88 89//Check elf header to ensure the file is valid. 90bool ElfFile::is_elf_file(Elf_Ehdr& hdr) { 91 return (ELFMAG0 == hdr.e_ident[EI_MAG0] && 92 ELFMAG1 == hdr.e_ident[EI_MAG1] && 93 ELFMAG2 == hdr.e_ident[EI_MAG2] && 94 ELFMAG3 == hdr.e_ident[EI_MAG3] && 95 ELFCLASSNONE != hdr.e_ident[EI_CLASS] && 96 ELFDATANONE != hdr.e_ident[EI_DATA]); 97} 98 99bool ElfFile::load_tables() { 100 assert(m_file, "file not open"); 101 assert(!NullDecoder::is_error(m_status), "already in error"); 102 103 // read elf file header 104 if (fread(&m_elfHdr, sizeof(m_elfHdr), 1, m_file) != 1) { 105 m_status = NullDecoder::file_invalid; 106 return false; 107 } 108 109 if (!is_elf_file(m_elfHdr)) { 110 m_status = NullDecoder::file_invalid; 111 return false; 112 } 113 114 // walk elf file's section headers, and load string tables 115 Elf_Shdr shdr; 116 if (!fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) { 117 if (NullDecoder::is_error(m_status)) return false; 118 119 for (int index = 0; index < m_elfHdr.e_shnum; index ++) { 120 if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) { 121 m_status = NullDecoder::file_invalid; 122 return false; 123 } 124 if (shdr.sh_type == SHT_STRTAB) { 125 // string tables 126 ElfStringTable* table = new (std::nothrow) ElfStringTable(m_file, shdr, index); 127 if (table == NULL) { 128 m_status = NullDecoder::out_of_memory; 129 return false; 130 } 131 add_string_table(table); 132 } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { 133 // symbol tables 134 ElfSymbolTable* table = new (std::nothrow) ElfSymbolTable(m_file, shdr); 135 if (table == NULL) { 136 m_status = NullDecoder::out_of_memory; 137 return false; 138 } 139 add_symbol_table(table); 140 } 141 } 142 143#if defined(PPC64) && !defined(ABI_ELFv2) 144 // Now read the .opd section wich contains the PPC64 function descriptor table. 145 // The .opd section is only available on PPC64 (see for example: 146 // http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html) 147 // so this code should do no harm on other platforms but because of performance reasons we only 148 // execute it on PPC64 platforms. 149 // Notice that we can only find the .opd section after we have successfully read in the string 150 // tables in the previous loop, because we need to query the name of each section which is 151 // contained in one of the string tables (i.e. the one with the index m_elfHdr.e_shstrndx). 152 153 // Reset the file pointer 154 if (fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) { 155 m_status = NullDecoder::file_invalid; 156 return false; 157 } 158 for (int index = 0; index < m_elfHdr.e_shnum; index ++) { 159 if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) { 160 m_status = NullDecoder::file_invalid; 161 return false; 162 } 163 if (m_elfHdr.e_shstrndx != SHN_UNDEF && shdr.sh_type == SHT_PROGBITS) { 164 ElfStringTable* string_table = get_string_table(m_elfHdr.e_shstrndx); 165 if (string_table == NULL) { 166 m_status = NullDecoder::file_invalid; 167 return false; 168 } 169 char buf[8]; // '8' is enough because we only want to read ".opd" 170 if (string_table->string_at(shdr.sh_name, buf, sizeof(buf)) && !strncmp(".opd", buf, 4)) { 171 m_funcDesc_table = new (std::nothrow) ElfFuncDescTable(m_file, shdr, index); 172 if (m_funcDesc_table == NULL) { 173 m_status = NullDecoder::out_of_memory; 174 return false; 175 } 176 break; 177 } 178 } 179 } 180#endif 181 182 } 183 return true; 184} 185 186bool ElfFile::decode(address addr, char* buf, int buflen, int* offset) { 187 // something already went wrong, just give up 188 if (NullDecoder::is_error(m_status)) { 189 return false; 190 } 191 ElfSymbolTable* symbol_table = m_symbol_tables; 192 int string_table_index; 193 int pos_in_string_table; 194 int off = INT_MAX; 195 bool found_symbol = false; 196 while (symbol_table != NULL) { 197 if (symbol_table->lookup(addr, &string_table_index, &pos_in_string_table, &off, m_funcDesc_table)) { 198 found_symbol = true; 199 break; 200 } 201 symbol_table = symbol_table->m_next; 202 } 203 if (!found_symbol) return false; 204 205 ElfStringTable* string_table = get_string_table(string_table_index); 206 207 if (string_table == NULL) { 208 m_status = NullDecoder::file_invalid; 209 return false; 210 } 211 if (offset) *offset = off; 212 213 return string_table->string_at(pos_in_string_table, buf, buflen); 214} 215 216 217void ElfFile::add_symbol_table(ElfSymbolTable* table) { 218 if (m_symbol_tables == NULL) { 219 m_symbol_tables = table; 220 } else { 221 table->m_next = m_symbol_tables; 222 m_symbol_tables = table; 223 } 224} 225 226void ElfFile::add_string_table(ElfStringTable* table) { 227 if (m_string_tables == NULL) { 228 m_string_tables = table; 229 } else { 230 table->m_next = m_string_tables; 231 m_string_tables = table; 232 } 233} 234 235ElfStringTable* ElfFile::get_string_table(int index) { 236 ElfStringTable* p = m_string_tables; 237 while (p != NULL) { 238 if (p->index() == index) return p; 239 p = p->m_next; 240 } 241 return NULL; 242} 243 244#ifdef LINUX 245bool ElfFile::specifies_noexecstack(const char* filepath) { 246 // Returns true if the elf file is marked NOT to require an executable stack, 247 // or if the file could not be opened. 248 // Returns false if the elf file requires an executable stack, the stack flag 249 // is not set at all, or if the file can not be read. 250 if (filepath == NULL) return true; 251 252 FILE* file = fopen(filepath, "r"); 253 if (file == NULL) return true; 254 255 // AARCH64 defaults to noexecstack. All others default to execstack. 256#ifdef AARCH64 257 bool result = true; 258#else 259 bool result = false; 260#endif 261 262 // Read file header 263 Elf_Ehdr head; 264 if (fread(&head, sizeof(Elf_Ehdr), 1, file) == 1 && 265 is_elf_file(head) && 266 fseek(file, head.e_phoff, SEEK_SET) == 0) { 267 268 // Read program header table 269 Elf_Phdr phdr; 270 for (int index = 0; index < head.e_phnum; index ++) { 271 if (fread((void*)&phdr, sizeof(Elf_Phdr), 1, file) != 1) { 272 result = false; 273 break; 274 } 275 if (phdr.p_type == PT_GNU_STACK) { 276 result = (phdr.p_flags == (PF_R | PF_W)); 277 break; 278 } 279 } 280 } 281 fclose(file); 282 return result; 283} 284#endif // LINUX 285 286#endif // !_WINDOWS && !__APPLE__ 287