elfFile.cpp revision 5776:de6a9e811145
1218885Sdim/*
2218885Sdim * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3218885Sdim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4218885Sdim *
5218885Sdim * This code is free software; you can redistribute it and/or modify it
6218885Sdim * under the terms of the GNU General Public License version 2 only, as
7218885Sdim * published by the Free Software Foundation.
8218885Sdim *
9218885Sdim * This code is distributed in the hope that it will be useful, but WITHOUT
10218885Sdim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11218885Sdim * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12218885Sdim * version 2 for more details (a copy is included in the LICENSE file that
13218885Sdim * accompanied this code).
14218885Sdim *
15218885Sdim * You should have received a copy of the GNU General Public License version
16218885Sdim * 2 along with this work; if not, write to the Free Software Foundation,
17218885Sdim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18218885Sdim *
19218885Sdim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20218885Sdim * or visit www.oracle.com if you need additional information or have any
21218885Sdim * questions.
22234353Sdim *
23218885Sdim */
24218885Sdim
25218885Sdim#include "precompiled.hpp"
26218885Sdim
27218885Sdim#if !defined(_WINDOWS) && !defined(__APPLE__)
28218885Sdim
29218885Sdim#include <string.h>
30218885Sdim#include <stdio.h>
31218885Sdim#include <limits.h>
32218885Sdim#include <new>
33218885Sdim
34218885Sdim#include "memory/allocation.inline.hpp"
35218885Sdim#include "utilities/decoder.hpp"
36218885Sdim#include "utilities/elfFile.hpp"
37218885Sdim#include "utilities/elfStringTable.hpp"
38218885Sdim#include "utilities/elfSymbolTable.hpp"
39218885Sdim
40218885Sdim
41218885SdimElfFile::ElfFile(const char* filepath) {
42218885Sdim  assert(filepath, "null file path");
43218885Sdim  memset(&m_elfHdr, 0, sizeof(m_elfHdr));
44218885Sdim  m_string_tables = NULL;
45218885Sdim  m_symbol_tables = NULL;
46218885Sdim  m_next = NULL;
47234353Sdim  m_status = NullDecoder::no_error;
48234353Sdim
49234353Sdim  int len = strlen(filepath) + 1;
50234353Sdim  m_filepath = (const char*)os::malloc(len * sizeof(char), mtInternal);
51218885Sdim  if (m_filepath != NULL) {
52234353Sdim    strcpy((char*)m_filepath, filepath);
53234353Sdim    m_file = fopen(filepath, "r");
54234353Sdim    if (m_file != NULL) {
55218885Sdim      load_tables();
56234353Sdim    } else {
57234353Sdim      m_status = NullDecoder::file_not_found;
58234353Sdim    }
59234353Sdim  } else {
60234353Sdim    m_status = NullDecoder::out_of_memory;
61218885Sdim  }
62239462Sdim}
63239462Sdim
64234353SdimElfFile::~ElfFile() {
65234353Sdim  if (m_string_tables != NULL) {
66234353Sdim    delete m_string_tables;
67218885Sdim  }
68218885Sdim
69234353Sdim  if (m_symbol_tables != NULL) {
70234353Sdim    delete m_symbol_tables;
71234353Sdim  }
72218885Sdim
73234353Sdim  if (m_file != NULL) {
74234353Sdim    fclose(m_file);
75234353Sdim  }
76218885Sdim
77234353Sdim  if (m_filepath != NULL) {
78234353Sdim    os::free((void*)m_filepath);
79218885Sdim  }
80218885Sdim
81218885Sdim  if (m_next != NULL) {
82218885Sdim    delete m_next;
83218885Sdim  }
84234353Sdim};
85234353Sdim
86234353Sdim
87234353Sdim//Check elf header to ensure the file is valid.
88218885Sdimbool ElfFile::is_elf_file(Elf_Ehdr& hdr) {
89218885Sdim  return (ELFMAG0 == hdr.e_ident[EI_MAG0] &&
90218885Sdim      ELFMAG1 == hdr.e_ident[EI_MAG1] &&
91218885Sdim      ELFMAG2 == hdr.e_ident[EI_MAG2] &&
92218885Sdim      ELFMAG3 == hdr.e_ident[EI_MAG3] &&
93234353Sdim      ELFCLASSNONE != hdr.e_ident[EI_CLASS] &&
94234353Sdim      ELFDATANONE != hdr.e_ident[EI_DATA]);
95218885Sdim}
96234353Sdim
97234353Sdimbool ElfFile::load_tables() {
98218885Sdim  assert(m_file, "file not open");
99218885Sdim  assert(!NullDecoder::is_error(m_status), "already in error");
100218885Sdim
101218885Sdim  // read elf file header
102218885Sdim  if (fread(&m_elfHdr, sizeof(m_elfHdr), 1, m_file) != 1) {
103234353Sdim    m_status = NullDecoder::file_invalid;
104234353Sdim    return false;
105218885Sdim  }
106234353Sdim
107234353Sdim  if (!is_elf_file(m_elfHdr)) {
108218885Sdim    m_status = NullDecoder::file_invalid;
109218885Sdim    return false;
110218885Sdim  }
111218885Sdim
112218885Sdim  // walk elf file's section headers, and load string tables
113234353Sdim  Elf_Shdr shdr;
114234353Sdim  if (!fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) {
115218885Sdim    if (NullDecoder::is_error(m_status)) return false;
116234353Sdim
117234353Sdim    for (int index = 0; index < m_elfHdr.e_shnum; index ++) {
118218885Sdim      if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) {
119218885Sdim        m_status = NullDecoder::file_invalid;
120218885Sdim        return false;
121218885Sdim      }
122218885Sdim      // string table
123218885Sdim      if (shdr.sh_type == SHT_STRTAB) {
124218885Sdim        ElfStringTable* table = new (std::nothrow) ElfStringTable(m_file, shdr, index);
125218885Sdim        if (table == NULL) {
126218885Sdim          m_status = NullDecoder::out_of_memory;
127226633Sdim          return false;
128218885Sdim        }
129218885Sdim        add_string_table(table);
130      } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
131        ElfSymbolTable* table = new (std::nothrow) ElfSymbolTable(m_file, shdr);
132        if (table == NULL) {
133          m_status = NullDecoder::out_of_memory;
134          return false;
135        }
136        add_symbol_table(table);
137      }
138    }
139  }
140  return true;
141}
142
143bool ElfFile::decode(address addr, char* buf, int buflen, int* offset) {
144  // something already went wrong, just give up
145  if (NullDecoder::is_error(m_status)) {
146    return false;
147  }
148  ElfSymbolTable* symbol_table = m_symbol_tables;
149  int string_table_index;
150  int pos_in_string_table;
151  int off = INT_MAX;
152  bool found_symbol = false;
153  while (symbol_table != NULL) {
154    if (symbol_table->lookup(addr, &string_table_index, &pos_in_string_table, &off)) {
155      found_symbol = true;
156    }
157    symbol_table = symbol_table->m_next;
158  }
159  if (!found_symbol) return false;
160
161  ElfStringTable* string_table = get_string_table(string_table_index);
162
163  if (string_table == NULL) {
164    m_status = NullDecoder::file_invalid;
165    return false;
166  }
167  if (offset) *offset = off;
168
169  return string_table->string_at(pos_in_string_table, buf, buflen);
170}
171
172
173void ElfFile::add_symbol_table(ElfSymbolTable* table) {
174  if (m_symbol_tables == NULL) {
175    m_symbol_tables = table;
176  } else {
177    table->m_next = m_symbol_tables;
178    m_symbol_tables = table;
179  }
180}
181
182void ElfFile::add_string_table(ElfStringTable* table) {
183  if (m_string_tables == NULL) {
184    m_string_tables = table;
185  } else {
186    table->m_next = m_string_tables;
187    m_string_tables = table;
188  }
189}
190
191ElfStringTable* ElfFile::get_string_table(int index) {
192  ElfStringTable* p = m_string_tables;
193  while (p != NULL) {
194    if (p->index() == index) return p;
195    p = p->m_next;
196  }
197  return NULL;
198}
199
200#ifdef LINUX
201bool ElfFile::specifies_noexecstack() {
202  Elf_Phdr phdr;
203  if (!m_file)  return true;
204
205  if (!fseek(m_file, m_elfHdr.e_phoff, SEEK_SET)) {
206    for (int index = 0; index < m_elfHdr.e_phnum; index ++) {
207      if (fread((void*)&phdr, sizeof(Elf_Phdr), 1, m_file) != 1) {
208        m_status = NullDecoder::file_invalid;
209        return false;
210      }
211      if (phdr.p_type == PT_GNU_STACK) {
212        if (phdr.p_flags == (PF_R | PF_W))  {
213          return true;
214        } else {
215          return false;
216        }
217      }
218    }
219  }
220  return false;
221}
222#endif
223
224#endif // _WINDOWS
225