aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #include "precompiled.hpp" aoqi@0: aoqi@0: #if !defined(_WINDOWS) && !defined(__APPLE__) aoqi@0: aoqi@0: #include aoqi@0: #include aoqi@0: #include aoqi@0: #include aoqi@0: aoqi@0: #include "memory/allocation.inline.hpp" aoqi@0: #include "utilities/decoder.hpp" aoqi@0: #include "utilities/elfFile.hpp" aoqi@0: #include "utilities/elfFuncDescTable.hpp" aoqi@0: #include "utilities/elfStringTable.hpp" aoqi@0: #include "utilities/elfSymbolTable.hpp" aoqi@0: aoqi@0: aoqi@0: ElfFile::ElfFile(const char* filepath) { aoqi@0: assert(filepath, "null file path"); aoqi@0: memset(&m_elfHdr, 0, sizeof(m_elfHdr)); aoqi@0: m_string_tables = NULL; aoqi@0: m_symbol_tables = NULL; aoqi@0: m_funcDesc_table = NULL; aoqi@0: m_next = NULL; aoqi@0: m_status = NullDecoder::no_error; aoqi@0: aoqi@0: int len = strlen(filepath) + 1; aoqi@0: m_filepath = (const char*)os::malloc(len * sizeof(char), mtInternal); aoqi@0: if (m_filepath != NULL) { aoqi@0: strcpy((char*)m_filepath, filepath); aoqi@0: m_file = fopen(filepath, "r"); aoqi@0: if (m_file != NULL) { aoqi@0: load_tables(); aoqi@0: } else { aoqi@0: m_status = NullDecoder::file_not_found; aoqi@0: } aoqi@0: } else { aoqi@0: m_status = NullDecoder::out_of_memory; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: ElfFile::~ElfFile() { aoqi@0: if (m_string_tables != NULL) { aoqi@0: delete m_string_tables; aoqi@0: } aoqi@0: aoqi@0: if (m_symbol_tables != NULL) { aoqi@0: delete m_symbol_tables; aoqi@0: } aoqi@0: aoqi@0: if (m_file != NULL) { aoqi@0: fclose(m_file); aoqi@0: } aoqi@0: aoqi@0: if (m_filepath != NULL) { aoqi@0: os::free((void*)m_filepath); aoqi@0: } aoqi@0: aoqi@0: if (m_next != NULL) { aoqi@0: delete m_next; aoqi@0: } aoqi@0: }; aoqi@0: aoqi@0: aoqi@0: //Check elf header to ensure the file is valid. aoqi@0: bool ElfFile::is_elf_file(Elf_Ehdr& hdr) { aoqi@0: return (ELFMAG0 == hdr.e_ident[EI_MAG0] && aoqi@0: ELFMAG1 == hdr.e_ident[EI_MAG1] && aoqi@0: ELFMAG2 == hdr.e_ident[EI_MAG2] && aoqi@0: ELFMAG3 == hdr.e_ident[EI_MAG3] && aoqi@0: ELFCLASSNONE != hdr.e_ident[EI_CLASS] && aoqi@0: ELFDATANONE != hdr.e_ident[EI_DATA]); aoqi@0: } aoqi@0: aoqi@0: bool ElfFile::load_tables() { aoqi@0: assert(m_file, "file not open"); aoqi@0: assert(!NullDecoder::is_error(m_status), "already in error"); aoqi@0: aoqi@0: // read elf file header aoqi@0: if (fread(&m_elfHdr, sizeof(m_elfHdr), 1, m_file) != 1) { aoqi@0: m_status = NullDecoder::file_invalid; aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: if (!is_elf_file(m_elfHdr)) { aoqi@0: m_status = NullDecoder::file_invalid; aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: // walk elf file's section headers, and load string tables aoqi@0: Elf_Shdr shdr; aoqi@0: if (!fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) { aoqi@0: if (NullDecoder::is_error(m_status)) return false; aoqi@0: aoqi@0: for (int index = 0; index < m_elfHdr.e_shnum; index ++) { aoqi@0: if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) { aoqi@0: m_status = NullDecoder::file_invalid; aoqi@0: return false; aoqi@0: } aoqi@0: if (shdr.sh_type == SHT_STRTAB) { aoqi@0: // string tables aoqi@0: ElfStringTable* table = new (std::nothrow) ElfStringTable(m_file, shdr, index); aoqi@0: if (table == NULL) { aoqi@0: m_status = NullDecoder::out_of_memory; aoqi@0: return false; aoqi@0: } aoqi@0: add_string_table(table); aoqi@0: } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { aoqi@0: // symbol tables aoqi@0: ElfSymbolTable* table = new (std::nothrow) ElfSymbolTable(m_file, shdr); aoqi@0: if (table == NULL) { aoqi@0: m_status = NullDecoder::out_of_memory; aoqi@0: return false; aoqi@0: } aoqi@0: add_symbol_table(table); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: #if defined(PPC64) && !defined(ABI_ELFv2) aoqi@0: // Now read the .opd section wich contains the PPC64 function descriptor table. aoqi@0: // The .opd section is only available on PPC64 (see for example: aoqi@0: // http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html) aoqi@0: // so this code should do no harm on other platforms but because of performance reasons we only aoqi@0: // execute it on PPC64 platforms. aoqi@0: // Notice that we can only find the .opd section after we have successfully read in the string aoqi@0: // tables in the previous loop, because we need to query the name of each section which is aoqi@0: // contained in one of the string tables (i.e. the one with the index m_elfHdr.e_shstrndx). aoqi@0: aoqi@0: // Reset the file pointer aoqi@0: if (fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) { aoqi@0: m_status = NullDecoder::file_invalid; aoqi@0: return false; aoqi@0: } aoqi@0: for (int index = 0; index < m_elfHdr.e_shnum; index ++) { aoqi@0: if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) { aoqi@0: m_status = NullDecoder::file_invalid; aoqi@0: return false; aoqi@0: } aoqi@0: if (m_elfHdr.e_shstrndx != SHN_UNDEF && shdr.sh_type == SHT_PROGBITS) { aoqi@0: ElfStringTable* string_table = get_string_table(m_elfHdr.e_shstrndx); aoqi@0: if (string_table == NULL) { aoqi@0: m_status = NullDecoder::file_invalid; aoqi@0: return false; aoqi@0: } aoqi@0: char buf[8]; // '8' is enough because we only want to read ".opd" aoqi@0: if (string_table->string_at(shdr.sh_name, buf, sizeof(buf)) && !strncmp(".opd", buf, 4)) { aoqi@0: m_funcDesc_table = new (std::nothrow) ElfFuncDescTable(m_file, shdr, index); aoqi@0: if (m_funcDesc_table == NULL) { aoqi@0: m_status = NullDecoder::out_of_memory; aoqi@0: return false; aoqi@0: } aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: #endif aoqi@0: aoqi@0: } aoqi@0: return true; aoqi@0: } aoqi@0: aoqi@0: bool ElfFile::decode(address addr, char* buf, int buflen, int* offset) { aoqi@0: // something already went wrong, just give up aoqi@0: if (NullDecoder::is_error(m_status)) { aoqi@0: return false; aoqi@0: } aoqi@0: ElfSymbolTable* symbol_table = m_symbol_tables; aoqi@0: int string_table_index; aoqi@0: int pos_in_string_table; aoqi@0: int off = INT_MAX; aoqi@0: bool found_symbol = false; aoqi@0: while (symbol_table != NULL) { aoqi@0: if (symbol_table->lookup(addr, &string_table_index, &pos_in_string_table, &off, m_funcDesc_table)) { aoqi@0: found_symbol = true; aoqi@0: break; aoqi@0: } aoqi@0: symbol_table = symbol_table->m_next; aoqi@0: } aoqi@0: if (!found_symbol) return false; aoqi@0: aoqi@0: ElfStringTable* string_table = get_string_table(string_table_index); aoqi@0: aoqi@0: if (string_table == NULL) { aoqi@0: m_status = NullDecoder::file_invalid; aoqi@0: return false; aoqi@0: } aoqi@0: if (offset) *offset = off; aoqi@0: aoqi@0: return string_table->string_at(pos_in_string_table, buf, buflen); aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void ElfFile::add_symbol_table(ElfSymbolTable* table) { aoqi@0: if (m_symbol_tables == NULL) { aoqi@0: m_symbol_tables = table; aoqi@0: } else { aoqi@0: table->m_next = m_symbol_tables; aoqi@0: m_symbol_tables = table; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void ElfFile::add_string_table(ElfStringTable* table) { aoqi@0: if (m_string_tables == NULL) { aoqi@0: m_string_tables = table; aoqi@0: } else { aoqi@0: table->m_next = m_string_tables; aoqi@0: m_string_tables = table; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: ElfStringTable* ElfFile::get_string_table(int index) { aoqi@0: ElfStringTable* p = m_string_tables; aoqi@0: while (p != NULL) { aoqi@0: if (p->index() == index) return p; aoqi@0: p = p->m_next; aoqi@0: } aoqi@0: return NULL; aoqi@0: } aoqi@0: aoqi@0: #ifdef LINUX aoqi@0: bool ElfFile::specifies_noexecstack() { aoqi@0: Elf_Phdr phdr; aoqi@0: if (!m_file) return true; aoqi@0: aoqi@0: if (!fseek(m_file, m_elfHdr.e_phoff, SEEK_SET)) { aoqi@0: for (int index = 0; index < m_elfHdr.e_phnum; index ++) { aoqi@0: if (fread((void*)&phdr, sizeof(Elf_Phdr), 1, m_file) != 1) { aoqi@0: m_status = NullDecoder::file_invalid; aoqi@0: return false; aoqi@0: } aoqi@0: if (phdr.p_type == PT_GNU_STACK) { aoqi@0: if (phdr.p_flags == (PF_R | PF_W)) { aoqi@0: return true; aoqi@0: } else { aoqi@0: return false; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } cjplummer@7857: // AARCH64 defaults to noexecstack. All others default to execstack. cjplummer@7857: #ifdef AARCH64 cjplummer@7857: return true; cjplummer@7857: #else aoqi@0: return false; cjplummer@7857: #endif aoqi@0: } aoqi@0: #endif aoqi@0: aoqi@0: #endif // !_WINDOWS && !__APPLE__