elfFile.cpp revision 5995:e7cbc95179c4
150472Speter/* 21664Sphk * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 369040Sben * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 469040Sben * 569040Sben * This code is free software; you can redistribute it and/or modify it 669040Sben * under the terms of the GNU General Public License version 2 only, as 73023Srgrimes * published by the Free Software Foundation. 83023Srgrimes * 93023Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 101664Sphk * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 113023Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 123023Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 131664Sphk * accompanied this code). 141664Sphk * 151664Sphk * You should have received a copy of the GNU General Public License version 1672679Skris * 2 along with this work; if not, write to the Free Software Foundation, 1772878Skris * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1872878Skris * 1972878Skris * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2072878Skris * or visit www.oracle.com if you need additional information or have any 2172878Skris * questions. 2272878Skris * 2372878Skris */ 2472878Skris 2572878Skris#include "precompiled.hpp" 2672878Skris 2772679Skris#if !defined(_WINDOWS) && !defined(__APPLE__) 2872878Skris 2972878Skris#include <string.h> 3072878Skris#include <stdio.h> 3158648Skris#include <limits.h> 3268917Sdougb#include <new> 3358648Skris 3468917Sdougb#include "memory/allocation.inline.hpp" 3558648Skris#include "utilities/decoder.hpp" 3658648Skris#include "utilities/elfFile.hpp" 3758648Skris#include "utilities/elfFuncDescTable.hpp" 381664Sphk#include "utilities/elfStringTable.hpp" 3929281Sjkh#include "utilities/elfSymbolTable.hpp" 401664Sphk 4159006Sobrien 4259006SobrienElfFile::ElfFile(const char* filepath) { 4359006Sobrien assert(filepath, "null file path"); 4459006Sobrien memset(&m_elfHdr, 0, sizeof(m_elfHdr)); 451664Sphk m_string_tables = NULL; 4659006Sobrien m_symbol_tables = NULL; 4759006Sobrien m_funcDesc_table = NULL; 4862136Sobrien m_next = NULL; 4962136Sobrien m_status = NullDecoder::no_error; 5062136Sobrien 5162136Sobrien int len = strlen(filepath) + 1; 5262136Sobrien m_filepath = (const char*)os::malloc(len * sizeof(char), mtInternal); 5362136Sobrien if (m_filepath != NULL) { 5462136Sobrien strcpy((char*)m_filepath, filepath); 5562136Sobrien m_file = fopen(filepath, "r"); 5662136Sobrien if (m_file != NULL) { 5768917Sdougb load_tables(); 5868263Sobrien } else { 5968263Sobrien m_status = NullDecoder::file_not_found; 6068263Sobrien } 6165380Sobrien } else { 6265380Sobrien m_status = NullDecoder::out_of_memory; 6365380Sobrien } 6442325Sobrien} 6535222Sache 6635222SacheElfFile::~ElfFile() { 6765884Sache if (m_string_tables != NULL) { 6865957Sache delete m_string_tables; 6965884Sache } 7068559Sru 7164576Simp if (m_symbol_tables != NULL) { 7234651Sjkh delete m_symbol_tables; 7350883Smarkm } 7450883Smarkm 7550883Smarkm if (m_file != NULL) { 7664803Sbrian fclose(m_file); 7764803Sbrian } 7864803Sbrian 7968705Sgreen if (m_filepath != NULL) { 8068705Sgreen os::free((void*)m_filepath); 8168705Sgreen } 8251299Speter 8357542Skris if (m_next != NULL) { 8459124Sasmodai delete m_next; 8557542Skris } 8661139Shoek}; 8758859Ssheldonh 8859884Schuckr 8957764Skris//Check elf header to ensure the file is valid. 9057542Skrisbool ElfFile::is_elf_file(Elf_Ehdr& hdr) { 9157542Skris return (ELFMAG0 == hdr.e_ident[EI_MAG0] && 9257542Skris ELFMAG1 == hdr.e_ident[EI_MAG1] && 9358418Sobrien ELFMAG2 == hdr.e_ident[EI_MAG2] && 9459338Sobrien ELFMAG3 == hdr.e_ident[EI_MAG3] && 9558280Skris ELFCLASSNONE != hdr.e_ident[EI_CLASS] && 9657553Skris ELFDATANONE != hdr.e_ident[EI_DATA]); 9757542Skris} 9857542Skris 9957542Skrisbool ElfFile::load_tables() { 10072679Skris assert(m_file, "file not open"); 10165381Sobrien assert(!NullDecoder::is_error(m_status), "already in error"); 10257553Skris 10357542Skris // read elf file header 10458390Sdan if (fread(&m_elfHdr, sizeof(m_elfHdr), 1, m_file) != 1) { 10535206Sphk m_status = NullDecoder::file_invalid; 10661744Sobrien return false; 10761744Sobrien } 10861744Sobrien 10957458Smarkm if (!is_elf_file(m_elfHdr)) { 11062482Speter m_status = NullDecoder::file_invalid; 11162482Speter return false; 11262482Speter } 11362482Speter 11462482Speter // walk elf file's section headers, and load string tables 11562482Speter Elf_Shdr shdr; 11662482Speter if (!fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) { 11762482Speter if (NullDecoder::is_error(m_status)) return false; 11862482Speter 11963123Speter for (int index = 0; index < m_elfHdr.e_shnum; index ++) { 12062482Speter if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) { 12157071Srwatson m_status = NullDecoder::file_invalid; 12257071Srwatson return false; 12357071Srwatson } 1241684Scsgr if (shdr.sh_type == SHT_STRTAB) { 1251684Scsgr // string tables 1261684Scsgr ElfStringTable* table = new (std::nothrow) ElfStringTable(m_file, shdr, index); 1279509Srgrimes if (table == NULL) { 1281697Sache m_status = NullDecoder::out_of_memory; 1291697Sache return false; 13020847Speter } 13120847Speter add_string_table(table); 13220847Speter } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { 13320847Speter // symbol tables 13420847Speter ElfSymbolTable* table = new (std::nothrow) ElfSymbolTable(m_file, shdr); 13520847Speter if (table == NULL) { 13647318Sobrien m_status = NullDecoder::out_of_memory; 13747430Sobrien return false; 13820847Speter } 13920847Speter add_symbol_table(table); 14014403Sasami } 14114403Sasami } 14214403Sasami 14314403Sasami#if defined(PPC64) 14414403Sasami // Now read the .opd section wich contains the PPC64 function descriptor table. 14514403Sasami // The .opd section is only available on PPC64 (see for example: 1461697Sache // http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html) 1471697Sache // so this code should do no harm on other platforms but because of performance reasons we only 1481697Sache // execute it on PPC64 platforms. 14925424Sandreas // Notice that we can only find the .opd section after we have successfully read in the string 1501733Sadam // tables in the previous loop, because we need to query the name of each section which is 1511733Sadam // contained in one of the string tables (i.e. the one with the index m_elfHdr.e_shstrndx). 15214102Sadam 15314102Sadam // Reset the file pointer 15414102Sadam if (fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) { 15514102Sadam m_status = NullDecoder::file_invalid; 1561733Sadam return false; 1571740Sadam } 1583023Srgrimes for (int index = 0; index < m_elfHdr.e_shnum; index ++) { 1591733Sadam if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) { 16018927Spst m_status = NullDecoder::file_invalid; 16126522Sbde return false; 16226522Sbde } 1631733Sadam if (m_elfHdr.e_shstrndx != SHN_UNDEF && shdr.sh_type == SHT_PROGBITS) { 16418927Spst ElfStringTable* string_table = get_string_table(m_elfHdr.e_shstrndx); 16549190Snik if (string_table == NULL) { 16618927Spst m_status = NullDecoder::file_invalid; 16749190Snik return false; 16849190Snik } 16918928Spst char buf[8]; // '8' is enough because we only want to read ".opd" 17018927Spst if (string_table->string_at(shdr.sh_name, buf, sizeof(buf)) && !strncmp(".opd", buf, 4)) { 17126522Sbde m_funcDesc_table = new (std::nothrow) ElfFuncDescTable(m_file, shdr, index); 17226522Sbde if (m_funcDesc_table == NULL) { 17318927Spst m_status = NullDecoder::out_of_memory; 17426522Sbde return false; 17518927Spst } 17668310Sps break; 17768310Sps } 17868310Sps } 17968310Sps } 18018927Spst#endif 18168310Sps 18268310Sps } 1834224Sphk return true; 18415334Sasami} 18515334Sasami 1863023Srgrimesbool ElfFile::decode(address addr, char* buf, int buflen, int* offset) { 1874224Sphk // something already went wrong, just give up 1883023Srgrimes if (NullDecoder::is_error(m_status)) { 1893023Srgrimes return false; 19015212Sasami } 19115212Sasami ElfSymbolTable* symbol_table = m_symbol_tables; 19215212Sasami int string_table_index; 19335221Sache int pos_in_string_table; 19415212Sasami int off = INT_MAX; 19515334Sasami bool found_symbol = false; 19615334Sasami while (symbol_table != NULL) { 19715334Sasami if (symbol_table->lookup(addr, &string_table_index, &pos_in_string_table, &off, m_funcDesc_table)) { 19815212Sasami found_symbol = true; 19915334Sasami break; 20015212Sasami } 20115212Sasami symbol_table = symbol_table->m_next; 20229949Sjkh } 20329949Sjkh if (!found_symbol) return false; 20429949Sjkh 20529949Sjkh ElfStringTable* string_table = get_string_table(string_table_index); 20622638Sjkh 20729949Sjkh if (string_table == NULL) { 20829949Sjkh m_status = NullDecoder::file_invalid; 20929949Sjkh return false; 21068481Sjkh } 21168481Sjkh if (offset) *offset = off; 21268481Sjkh 21368481Sjkh return string_table->string_at(pos_in_string_table, buf, buflen); 21435222Sache} 21535222Sache 21635222Sache 21768481Sjkhvoid ElfFile::add_symbol_table(ElfSymbolTable* table) { 21868481Sjkh if (m_symbol_tables == NULL) { 21969820Sdes m_symbol_tables = table; 22068481Sjkh } else { 22168481Sjkh table->m_next = m_symbol_tables; 22268481Sjkh m_symbol_tables = table; 22368481Sjkh } 22468481Sjkh} 22536263Sjkh 22624951Sasamivoid ElfFile::add_string_table(ElfStringTable* table) { 22724951Sasami if (m_string_tables == NULL) { 22824951Sasami m_string_tables = table; 22924951Sasami } else { 23024951Sasami table->m_next = m_string_tables; 23124951Sasami m_string_tables = table; 23224951Sasami } 23342876Sasami} 23424951Sasami 23524951SasamiElfStringTable* ElfFile::get_string_table(int index) { 23624951Sasami ElfStringTable* p = m_string_tables; 23724951Sasami while (p != NULL) { 23824951Sasami if (p->index() == index) return p; 23924951Sasami p = p->m_next; 24024951Sasami } 24124951Sasami return NULL; 24224951Sasami} 24324951Sasami 24424951Sasami#ifdef LINUX 24533880Sfennerbool ElfFile::specifies_noexecstack() { 24624951Sasami Elf_Phdr phdr; 24724951Sasami if (!m_file) return true; 24824951Sasami 24967431Sknu if (!fseek(m_file, m_elfHdr.e_phoff, SEEK_SET)) { 25024951Sasami for (int index = 0; index < m_elfHdr.e_phnum; index ++) { 25133880Sfenner if (fread((void*)&phdr, sizeof(Elf_Phdr), 1, m_file) != 1) { 25267431Sknu m_status = NullDecoder::file_invalid; 25368164Srse return false; 25433880Sfenner } 25533880Sfenner if (phdr.p_type == PT_GNU_STACK) { 25647726Sbillf if (phdr.p_flags == (PF_R | PF_W)) { 25767431Sknu return true; 25842876Sasami } else { 25942876Sasami return false; 26042876Sasami } 26144748Sbillf } 26244748Sbillf } 26367491Sknu } 26467491Sknu return false; 26567431Sknu} 26667431Sknu#endif 26724951Sasami 26867431Sknu#endif // !_WINDOWS && !__APPLE__ 26967431Sknu