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