--- a/src/hotspot/share/utilities/elfFile.cpp Wed Feb 14 16:42:00 2018 +0100
+++ b/src/hotspot/share/utilities/elfFile.cpp Wed Feb 14 17:20:59 2018 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,60 +31,150 @@
#include <limits.h>
#include <new>
+#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
+#include "memory/resourceArea.hpp"
#include "utilities/decoder.hpp"
#include "utilities/elfFile.hpp"
#include "utilities/elfFuncDescTable.hpp"
#include "utilities/elfStringTable.hpp"
#include "utilities/elfSymbolTable.hpp"
+#include "utilities/ostream.hpp"
+// For test only, disable elf section cache and force to read from file directly.
+bool ElfFile::_do_not_cache_elf_section = false;
+
+ElfSection::ElfSection(FILE* fd, const Elf_Shdr& hdr) : _section_data(NULL) {
+ _stat = load_section(fd, hdr);
+}
+
+ElfSection::~ElfSection() {
+ if (_section_data != NULL) {
+ os::free(_section_data);
+ }
+}
+
+NullDecoder::decoder_status ElfSection::load_section(FILE* const fd, const Elf_Shdr& shdr) {
+ memcpy((void*)&_section_hdr, (const void*)&shdr, sizeof(shdr));
+
+ if (ElfFile::_do_not_cache_elf_section) {
+ log_debug(decoder)("Elf section cache is disabled");
+ return NullDecoder::no_error;
+ }
+
+ _section_data = os::malloc(shdr.sh_size, mtInternal);
+ // No enough memory for caching. It is okay, we can try to read from
+ // file instead.
+ if (_section_data == NULL) return NullDecoder::no_error;
-ElfFile::ElfFile(const char* filepath) {
- assert(filepath, "null file path");
- memset(&m_elfHdr, 0, sizeof(m_elfHdr));
- m_string_tables = NULL;
- m_symbol_tables = NULL;
- m_funcDesc_table = NULL;
- m_next = NULL;
- m_status = NullDecoder::no_error;
+ MarkedFileReader mfd(fd);
+ if (mfd.has_mark() &&
+ mfd.set_position(shdr.sh_offset) &&
+ mfd.read(_section_data, shdr.sh_size)) {
+ return NullDecoder::no_error;
+ } else {
+ os::free(_section_data);
+ _section_data = NULL;
+ return NullDecoder::file_invalid;
+ }
+}
+
+bool FileReader::read(void* buf, size_t size) {
+ assert(buf != NULL, "no buffer");
+ assert(size > 0, "no space");
+ return fread(buf, size, 1, _fd) == 1;
+}
+
+int FileReader::read_buffer(void* buf, size_t size) {
+ assert(buf != NULL, "no buffer");
+ assert(size > 0, "no space");
+ return fread(buf, 1, size, _fd);
+}
+
+bool FileReader::set_position(long offset) {
+ return fseek(_fd, offset, SEEK_SET) == 0;
+}
+
+MarkedFileReader::MarkedFileReader(FILE* fd) : FileReader(fd) {
+ _marked_pos = ftell(fd);
+}
+
+MarkedFileReader::~MarkedFileReader() {
+ if (_marked_pos != -1) {
+ set_position(_marked_pos);
+ }
+}
+
+ElfFile::ElfFile(const char* filepath) :
+ _string_tables(NULL), _symbol_tables(NULL), _funcDesc_table(NULL),
+ _next(NULL), _status(NullDecoder::no_error),
+ _shdr_string_table(NULL), _file(NULL), _filepath(NULL) {
+ memset(&_elfHdr, 0, sizeof(_elfHdr));
int len = strlen(filepath) + 1;
- m_filepath = (const char*)os::malloc(len * sizeof(char), mtInternal);
- if (m_filepath != NULL) {
- strcpy((char*)m_filepath, filepath);
- m_file = fopen(filepath, "r");
- if (m_file != NULL) {
- load_tables();
- } else {
- m_status = NullDecoder::file_not_found;
- }
- } else {
- m_status = NullDecoder::out_of_memory;
+ _filepath = (char*)os::malloc(len * sizeof(char), mtInternal);
+ if (_filepath == NULL) {
+ _status = NullDecoder::out_of_memory;
+ return;
+ }
+ strcpy(_filepath, filepath);
+
+ _status = parse_elf(filepath);
+
+ // we no longer need section header string table
+ if (_shdr_string_table != NULL) {
+ delete _shdr_string_table;
+ _shdr_string_table = NULL;
}
}
ElfFile::~ElfFile() {
- if (m_string_tables != NULL) {
- delete m_string_tables;
+ if (_shdr_string_table != NULL) {
+ delete _shdr_string_table;
}
- if (m_symbol_tables != NULL) {
- delete m_symbol_tables;
+ cleanup_tables();
+
+ if (_file != NULL) {
+ fclose(_file);
+ }
+
+ if (_filepath != NULL) {
+ os::free((void*)_filepath);
}
- if (m_file != NULL) {
- fclose(m_file);
+ if (_next != NULL) {
+ delete _next;
+ }
+}
+
+void ElfFile::cleanup_tables() {
+ if (_string_tables != NULL) {
+ delete _string_tables;
+ _string_tables = NULL;
+ }
+
+ if (_symbol_tables != NULL) {
+ delete _symbol_tables;
+ _symbol_tables = NULL;
}
- if (m_filepath != NULL) {
- os::free((void*)m_filepath);
+ if (_funcDesc_table != NULL) {
+ delete _funcDesc_table;
+ _funcDesc_table = NULL;
}
+}
- if (m_next != NULL) {
- delete m_next;
+NullDecoder::decoder_status ElfFile::parse_elf(const char* filepath) {
+ assert(filepath, "null file path");
+
+ _file = fopen(filepath, "r");
+ if (_file != NULL) {
+ return load_tables();
+ } else {
+ return NullDecoder::file_not_found;
}
-};
-
+}
//Check elf header to ensure the file is valid.
bool ElfFile::is_elf_file(Elf_Ehdr& hdr) {
@@ -96,116 +186,134 @@
ELFDATANONE != hdr.e_ident[EI_DATA]);
}
-bool ElfFile::load_tables() {
- assert(m_file, "file not open");
- assert(!NullDecoder::is_error(m_status), "already in error");
+NullDecoder::decoder_status ElfFile::load_tables() {
+ assert(_file, "file not open");
+ assert(!NullDecoder::is_error(_status), "already in error");
+ FileReader freader(fd());
// read elf file header
- if (fread(&m_elfHdr, sizeof(m_elfHdr), 1, m_file) != 1) {
- m_status = NullDecoder::file_invalid;
- return false;
+ if (!freader.read(&_elfHdr, sizeof(_elfHdr))) {
+ return NullDecoder::file_invalid;
}
- if (!is_elf_file(m_elfHdr)) {
- m_status = NullDecoder::file_invalid;
- return false;
+ // Check signature
+ if (!is_elf_file(_elfHdr)) {
+ return NullDecoder::file_invalid;
}
// walk elf file's section headers, and load string tables
Elf_Shdr shdr;
- if (!fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) {
- if (NullDecoder::is_error(m_status)) return false;
+ if (!freader.set_position(_elfHdr.e_shoff)) {
+ return NullDecoder::file_invalid;
+ }
- for (int index = 0; index < m_elfHdr.e_shnum; index ++) {
- if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) {
- m_status = NullDecoder::file_invalid;
- return false;
- }
- if (shdr.sh_type == SHT_STRTAB) {
- // string tables
- ElfStringTable* table = new (std::nothrow) ElfStringTable(m_file, shdr, index);
- if (table == NULL) {
- m_status = NullDecoder::out_of_memory;
- return false;
- }
- add_string_table(table);
- } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
- // symbol tables
- ElfSymbolTable* table = new (std::nothrow) ElfSymbolTable(m_file, shdr);
- if (table == NULL) {
- m_status = NullDecoder::out_of_memory;
- return false;
- }
- add_symbol_table(table);
- }
+ for (int index = 0; index < _elfHdr.e_shnum; index ++) {
+ if (!freader.read(&shdr, sizeof(shdr))) {
+ return NullDecoder::file_invalid;
}
-#if defined(PPC64) && !defined(ABI_ELFv2)
- // Now read the .opd section wich contains the PPC64 function descriptor table.
- // The .opd section is only available on PPC64 (see for example:
- // http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html)
- // so this code should do no harm on other platforms but because of performance reasons we only
- // execute it on PPC64 platforms.
- // Notice that we can only find the .opd section after we have successfully read in the string
- // tables in the previous loop, because we need to query the name of each section which is
- // contained in one of the string tables (i.e. the one with the index m_elfHdr.e_shstrndx).
-
- // Reset the file pointer
- if (fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) {
- m_status = NullDecoder::file_invalid;
- return false;
+ if (shdr.sh_type == SHT_STRTAB) {
+ // string tables
+ ElfStringTable* table = new (std::nothrow) ElfStringTable(fd(), shdr, index);
+ if (table == NULL) {
+ return NullDecoder::out_of_memory;
+ }
+ if (index == _elfHdr.e_shstrndx) {
+ assert(_shdr_string_table == NULL, "Only set once");
+ _shdr_string_table = table;
+ } else {
+ add_string_table(table);
+ }
+ } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
+ // symbol tables
+ ElfSymbolTable* table = new (std::nothrow) ElfSymbolTable(fd(), shdr);
+ if (table == NULL) {
+ return NullDecoder::out_of_memory;
+ }
+ add_symbol_table(table);
}
- for (int index = 0; index < m_elfHdr.e_shnum; index ++) {
- if (fread((void*)&shdr, sizeof(Elf_Shdr), 1, m_file) != 1) {
- m_status = NullDecoder::file_invalid;
- return false;
- }
- if (m_elfHdr.e_shstrndx != SHN_UNDEF && shdr.sh_type == SHT_PROGBITS) {
- ElfStringTable* string_table = get_string_table(m_elfHdr.e_shstrndx);
- if (string_table == NULL) {
- m_status = NullDecoder::file_invalid;
- return false;
- }
- char buf[8]; // '8' is enough because we only want to read ".opd"
- if (string_table->string_at(shdr.sh_name, buf, sizeof(buf)) && !strncmp(".opd", buf, 4)) {
- m_funcDesc_table = new (std::nothrow) ElfFuncDescTable(m_file, shdr, index);
- if (m_funcDesc_table == NULL) {
- m_status = NullDecoder::out_of_memory;
- return false;
- }
- break;
- }
+ }
+#if defined(PPC64) && !defined(ABI_ELFv2)
+ // Now read the .opd section wich contains the PPC64 function descriptor table.
+ // The .opd section is only available on PPC64 (see for example:
+ // http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html)
+ // so this code should do no harm on other platforms but because of performance reasons we only
+ // execute it on PPC64 platforms.
+ // Notice that we can only find the .opd section after we have successfully read in the string
+ // tables in the previous loop, because we need to query the name of each section which is
+ // contained in one of the string tables (i.e. the one with the index m_elfHdr.e_shstrndx).
+
+ // Reset the file pointer
+ int sect_index = section_by_name(".opd", shdr);
+
+ if (sect_index == -1) {
+ return NullDecoder::file_invalid;
+ }
+
+ _funcDesc_table = new (std::nothrow) ElfFuncDescTable(_file, shdr, sect_index);
+ if (_funcDesc_table == NULL) {
+ return NullDecoder::out_of_memory;
+ }
+#endif
+ return NullDecoder::no_error;
+}
+
+int ElfFile::section_by_name(const char* name, Elf_Shdr& hdr) {
+ assert(name != NULL, "No section name");
+ size_t len = strlen(name) + 1;
+ ResourceMark rm;
+ char* buf = NEW_RESOURCE_ARRAY(char, len);
+ if (buf == NULL) {
+ return -1;
+ }
+
+ assert(_shdr_string_table != NULL, "Section header string table should be loaded");
+ ElfStringTable* const table = _shdr_string_table;
+ MarkedFileReader mfd(fd());
+ if (!mfd.has_mark() || !mfd.set_position(_elfHdr.e_shoff)) return -1;
+
+ int sect_index = -1;
+ for (int index = 0; index < _elfHdr.e_shnum; index ++) {
+ if (!mfd.read((void*)&hdr, sizeof(hdr))) {
+ break;
+ }
+ if (table->string_at(hdr.sh_name, buf, len)) {
+ if (strncmp(buf, name, len) == 0) {
+ sect_index = index;
+ break;
}
}
-#endif
-
}
- return true;
+ return sect_index;
}
bool ElfFile::decode(address addr, char* buf, int buflen, int* offset) {
// something already went wrong, just give up
- if (NullDecoder::is_error(m_status)) {
+ if (NullDecoder::is_error(_status)) {
return false;
}
- ElfSymbolTable* symbol_table = m_symbol_tables;
+
int string_table_index;
int pos_in_string_table;
int off = INT_MAX;
bool found_symbol = false;
+ ElfSymbolTable* symbol_table = _symbol_tables;
+
while (symbol_table != NULL) {
- if (symbol_table->lookup(addr, &string_table_index, &pos_in_string_table, &off, m_funcDesc_table)) {
+ if (symbol_table->lookup(addr, &string_table_index, &pos_in_string_table, &off, _funcDesc_table)) {
found_symbol = true;
break;
}
- symbol_table = symbol_table->m_next;
+ symbol_table = symbol_table->next();
}
- if (!found_symbol) return false;
+ if (!found_symbol) {
+ return false;
+ }
ElfStringTable* string_table = get_string_table(string_table_index);
if (string_table == NULL) {
- m_status = NullDecoder::file_invalid;
+ _status = NullDecoder::file_invalid;
return false;
}
if (offset) *offset = off;
@@ -213,74 +321,31 @@
return string_table->string_at(pos_in_string_table, buf, buflen);
}
-
void ElfFile::add_symbol_table(ElfSymbolTable* table) {
- if (m_symbol_tables == NULL) {
- m_symbol_tables = table;
+ if (_symbol_tables == NULL) {
+ _symbol_tables = table;
} else {
- table->m_next = m_symbol_tables;
- m_symbol_tables = table;
+ table->set_next(_symbol_tables);
+ _symbol_tables = table;
}
}
void ElfFile::add_string_table(ElfStringTable* table) {
- if (m_string_tables == NULL) {
- m_string_tables = table;
+ if (_string_tables == NULL) {
+ _string_tables = table;
} else {
- table->m_next = m_string_tables;
- m_string_tables = table;
+ table->set_next(_string_tables);
+ _string_tables = table;
}
}
ElfStringTable* ElfFile::get_string_table(int index) {
- ElfStringTable* p = m_string_tables;
+ ElfStringTable* p = _string_tables;
while (p != NULL) {
if (p->index() == index) return p;
- p = p->m_next;
+ p = p->next();
}
return NULL;
}
-#ifdef LINUX
-bool ElfFile::specifies_noexecstack(const char* filepath) {
- // Returns true if the elf file is marked NOT to require an executable stack,
- // or if the file could not be opened.
- // Returns false if the elf file requires an executable stack, the stack flag
- // is not set at all, or if the file can not be read.
- if (filepath == NULL) return true;
-
- FILE* file = fopen(filepath, "r");
- if (file == NULL) return true;
-
- // AARCH64 defaults to noexecstack. All others default to execstack.
-#ifdef AARCH64
- bool result = true;
-#else
- bool result = false;
-#endif
-
- // Read file header
- Elf_Ehdr head;
- if (fread(&head, sizeof(Elf_Ehdr), 1, file) == 1 &&
- is_elf_file(head) &&
- fseek(file, head.e_phoff, SEEK_SET) == 0) {
-
- // Read program header table
- Elf_Phdr phdr;
- for (int index = 0; index < head.e_phnum; index ++) {
- if (fread((void*)&phdr, sizeof(Elf_Phdr), 1, file) != 1) {
- result = false;
- break;
- }
- if (phdr.p_type == PT_GNU_STACK) {
- result = (phdr.p_flags == (PF_R | PF_W));
- break;
- }
- }
- }
- fclose(file);
- return result;
-}
-#endif // LINUX
-
#endif // !_WINDOWS && !__APPLE__