8193373: Cleanup ElfFile and family
Summary: Cleanup elf decoder and added test
Reviewed-by: minqi, coleenp
--- a/src/hotspot/os/linux/decoder_linux.cpp Wed Feb 14 16:42:00 2018 +0100
+++ b/src/hotspot/os/linux/decoder_linux.cpp Wed Feb 14 17:20:59 2018 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, 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
@@ -24,6 +24,7 @@
#include "jvm.h"
#include "utilities/decoder_elf.hpp"
+#include "utilities/elfFile.hpp"
#include <cxxabi.h>
@@ -50,3 +51,38 @@
return false;
}
+// 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.
+bool ElfFile::specifies_noexecstack(const char* filepath) {
+ if (filepath == NULL) return true;
+
+ FILE* file = fopen(filepath, "r");
+ if (file == NULL) return true;
+
+ // AARCH64 defaults to noexecstack. All others default to execstack.
+ bool result = AARCH64_ONLY(true) NOT_AARCH64(false);
+
+ // 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;
+}
--- a/src/hotspot/share/logging/logTag.hpp Wed Feb 14 16:42:00 2018 +0100
+++ b/src/hotspot/share/logging/logTag.hpp Wed Feb 14 17:20:59 2018 -0500
@@ -60,6 +60,7 @@
LOG_TAG(cset) \
LOG_TAG(data) \
LOG_TAG(datacreation) \
+ LOG_TAG(decoder) \
LOG_TAG(defaultmethods) \
LOG_TAG(dump) \
LOG_TAG(ergo) \
--- a/src/hotspot/share/prims/whitebox.cpp Wed Feb 14 16:42:00 2018 +0100
+++ b/src/hotspot/share/prims/whitebox.cpp Wed Feb 14 17:20:59 2018 -0500
@@ -60,6 +60,7 @@
#include "utilities/align.hpp"
#include "utilities/debug.hpp"
#include "utilities/exceptions.hpp"
+#include "utilities/elfFile.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_CDS
#include "prims/cdsoffsets.hpp"
@@ -1911,6 +1912,13 @@
os::print_os_info(tty);
WB_END
+// Elf decoder
+WB_ENTRY(void, WB_DisableElfSectionCache(JNIEnv* env))
+#if !defined(_WINDOWS) && !defined(__APPLE__)
+ ElfFile::_do_not_cache_elf_section = true;
+#endif
+WB_END
+
#define CC (char*)
@@ -2125,6 +2133,7 @@
(void*)&WB_CheckLibSpecifiesNoexecstack},
{CC"isContainerized", CC"()Z", (void*)&WB_IsContainerized },
{CC"printOsInfo", CC"()V", (void*)&WB_PrintOsInfo },
+ {CC"disableElfSectionCache", CC"()V", (void*)&WB_DisableElfSectionCache },
};
--- a/src/hotspot/share/utilities/decoder.hpp Wed Feb 14 16:42:00 2018 +0100
+++ b/src/hotspot/share/utilities/decoder.hpp Wed Feb 14 17:20:59 2018 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, 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
@@ -33,12 +33,10 @@
class AbstractDecoder : public CHeapObj<mtInternal> {
public:
- virtual ~AbstractDecoder() {}
-
// status code for decoding native C frame
enum decoder_status {
not_available = -10, // real decoder is not available
- no_error = 0, // successfully decoded frames
+ no_error = 0, // no error encountered
out_of_memory, // out of memory
file_invalid, // invalid elf file
file_not_found, // could not found symbol file (on windows), such as jvm.pdb or jvm.map
@@ -46,6 +44,12 @@
helper_init_error // SymInitialize failed (Windows only)
};
+protected:
+ decoder_status _decoder_status;
+
+public:
+ virtual ~AbstractDecoder() {}
+
// decode an pc address to corresponding function name and an offset from the beginning of
// the function
//
@@ -68,11 +72,8 @@
}
static bool is_error(decoder_status status) {
- return (status > 0);
+ return (status > no_error);
}
-
-protected:
- decoder_status _decoder_status;
};
// Do nothing decoder
@@ -96,10 +97,8 @@
virtual bool demangle(const char* symbol, char* buf, int buflen) {
return false;
}
-
};
-
class Decoder : AllStatic {
public:
static bool decode(address pc, char* buf, int buflen, int* offset, const char* modulepath = NULL, bool demangle = true);
--- 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__
--- a/src/hotspot/share/utilities/elfFile.hpp Wed Feb 14 16:42:00 2018 +0100
+++ b/src/hotspot/share/utilities/elfFile.hpp 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
@@ -57,7 +57,6 @@
typedef Elf32_Off Elf_Off;
typedef Elf32_Addr Elf_Addr;
-
typedef Elf32_Ehdr Elf_Ehdr;
typedef Elf32_Shdr Elf_Shdr;
typedef Elf32_Phdr Elf_Phdr;
@@ -72,46 +71,126 @@
#include "memory/allocation.hpp"
#include "utilities/decoder.hpp"
-
class ElfStringTable;
class ElfSymbolTable;
class ElfFuncDescTable;
+// ELF section, may or may not have cached data
+class ElfSection VALUE_OBJ_CLASS_SPEC {
+private:
+ Elf_Shdr _section_hdr;
+ void* _section_data;
+ NullDecoder::decoder_status _stat;
+public:
+ ElfSection(FILE* fd, const Elf_Shdr& hdr);
+ ~ElfSection();
-// On Solaris/Linux platforms, libjvm.so does contain all private symbols.
+ NullDecoder::decoder_status status() const { return _stat; }
+
+ const Elf_Shdr* section_header() const { return &_section_hdr; }
+ const void* section_data() const { return (const void*)_section_data; }
+private:
+ // load this section.
+ // it return no_error, when it fails to cache the section data due to lack of memory
+ NullDecoder::decoder_status load_section(FILE* const file, const Elf_Shdr& hdr);
+};
+
+class FileReader : public StackObj {
+protected:
+ FILE* const _fd;
+public:
+ FileReader(FILE* const fd) : _fd(fd) {};
+ bool read(void* buf, size_t size);
+ int read_buffer(void* buf, size_t size);
+ bool set_position(long offset);
+};
+
+// Mark current position, so we can get back to it after
+// reads.
+class MarkedFileReader : public FileReader {
+private:
+ long _marked_pos;
+public:
+ MarkedFileReader(FILE* const fd);
+ ~MarkedFileReader();
+
+ bool has_mark() const { return _marked_pos >= 0; }
+};
+
// ElfFile is basically an elf file parser, which can lookup the symbol
// that is the nearest to the given address.
// Beware, this code is called from vm error reporting code, when vm is already
// in "error" state, so there are scenarios, lookup will fail. We want this
// part of code to be very defensive, and bait out if anything went wrong.
-
class ElfFile: public CHeapObj<mtInternal> {
friend class ElfDecoder;
- public:
+
+private:
+ // link ElfFiles
+ ElfFile* _next;
+
+ // Elf file
+ char* _filepath;
+ FILE* _file;
+
+ // Elf header
+ Elf_Ehdr _elfHdr;
+
+ // symbol tables
+ ElfSymbolTable* _symbol_tables;
+
+ // regular string tables
+ ElfStringTable* _string_tables;
+
+ // section header string table, used for finding section name
+ ElfStringTable* _shdr_string_table;
+
+ // function descriptors table
+ ElfFuncDescTable* _funcDesc_table;
+
+ NullDecoder::decoder_status _status;
+
+public:
ElfFile(const char* filepath);
~ElfFile();
bool decode(address addr, char* buf, int buflen, int* offset);
- const char* filepath() {
- return m_filepath;
+
+ const char* filepath() const {
+ return _filepath;
+ }
+
+ bool same_elf_file(const char* filepath) const {
+ assert(filepath != NULL, "null file path");
+ return (_filepath != NULL && !strcmp(filepath, _filepath));
}
- bool same_elf_file(const char* filepath) {
- assert(filepath, "null file path");
- assert(m_filepath, "already out of memory");
- return (m_filepath && !strcmp(filepath, m_filepath));
+ NullDecoder::decoder_status get_status() const {
+ return _status;
}
- NullDecoder::decoder_status get_status() {
- return m_status;
- }
-
- private:
+ // 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.
+ // On systems other than linux it always returns false.
+ static bool specifies_noexecstack(const char* filepath) NOT_LINUX({ return false; });
+private:
// sanity check, if the file is a real elf file
static bool is_elf_file(Elf_Ehdr&);
- // load string tables from the elf file
- bool load_tables();
+ // parse this elf file
+ NullDecoder::decoder_status parse_elf(const char* filename);
+
+ // load string, symbol and function descriptor tables from the elf file
+ NullDecoder::decoder_status load_tables();
+
+ ElfFile* next() const { return _next; }
+ void set_next(ElfFile* file) { _next = file; }
+
+ // find a section by name, return section index
+ // if there is no such section, return -1
+ int section_by_name(const char* name, Elf_Shdr& hdr);
// string tables are stored in a linked list
void add_string_table(ElfStringTable* table);
@@ -122,39 +201,15 @@
// return a string table at specified section index
ElfStringTable* get_string_table(int index);
-protected:
- ElfFile* next() const { return m_next; }
- void set_next(ElfFile* file) { m_next = file; }
- public:
- // 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.
- // On systems other than linux it always returns false.
- static bool specifies_noexecstack(const char* filepath) NOT_LINUX({ return false; });
-
- protected:
- ElfFile* m_next;
+ FILE* const fd() const { return _file; }
- private:
- // file
- const char* m_filepath;
- FILE* m_file;
-
- // Elf header
- Elf_Ehdr m_elfHdr;
+ // Cleanup string, symbol and function descriptor tables
+ void cleanup_tables();
- // symbol tables
- ElfSymbolTable* m_symbol_tables;
-
- // string tables
- ElfStringTable* m_string_tables;
-
- // function descriptors table
- ElfFuncDescTable* m_funcDesc_table;
-
- NullDecoder::decoder_status m_status;
+public:
+ // For whitebox test
+ static bool _do_not_cache_elf_section;
};
#endif // !_WINDOWS && !__APPLE__
--- a/src/hotspot/share/utilities/elfFuncDescTable.cpp Wed Feb 14 16:42:00 2018 +0100
+++ b/src/hotspot/share/utilities/elfFuncDescTable.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.
* Copyright (c) 2012, 2013 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -30,7 +30,8 @@
#include "memory/allocation.inline.hpp"
#include "utilities/elfFuncDescTable.hpp"
-ElfFuncDescTable::ElfFuncDescTable(FILE* file, Elf_Shdr shdr, int index) {
+ElfFuncDescTable::ElfFuncDescTable(FILE* file, Elf_Shdr shdr, int index) :
+ _file(file), _index(index), _section(file, shdr) {
assert(file, "null file handle");
// The actual function address (i.e. function entry point) is always the
// first value in the function descriptor (on IA64 and PPC64 they look as follows):
@@ -39,62 +40,33 @@
// Unfortunately 'shdr.sh_entsize' doesn't always seem to contain this size (it's zero on PPC64) so we can't assert
// assert(IA64_ONLY(2) PPC64_ONLY(3) * sizeof(address) == shdr.sh_entsize, "Size mismatch for '.opd' section entries");
- m_funcDescs = NULL;
- m_file = file;
- m_index = index;
- m_status = NullDecoder::no_error;
-
- // try to load the function descriptor table
- long cur_offset = ftell(file);
- if (cur_offset != -1) {
- // call malloc so we can back up if memory allocation fails.
- m_funcDescs = (address*)os::malloc(shdr.sh_size, mtInternal);
- if (m_funcDescs) {
- if (fseek(file, shdr.sh_offset, SEEK_SET) ||
- fread((void*)m_funcDescs, shdr.sh_size, 1, file) != 1 ||
- fseek(file, cur_offset, SEEK_SET)) {
- m_status = NullDecoder::file_invalid;
- os::free(m_funcDescs);
- m_funcDescs = NULL;
- }
- }
- if (!NullDecoder::is_error(m_status)) {
- memcpy(&m_shdr, &shdr, sizeof(Elf_Shdr));
- }
- } else {
- m_status = NullDecoder::file_invalid;
- }
+ _status = _section.status();
}
ElfFuncDescTable::~ElfFuncDescTable() {
- if (m_funcDescs != NULL) {
- os::free(m_funcDescs);
- }
}
address ElfFuncDescTable::lookup(Elf_Word index) {
- if (NullDecoder::is_error(m_status)) {
+ if (NullDecoder::is_error(_status)) {
return NULL;
}
- if (m_funcDescs != NULL) {
- if (m_shdr.sh_size > 0 && m_shdr.sh_addr <= index && index <= m_shdr.sh_addr + m_shdr.sh_size) {
- // Notice that 'index' is a byte-offset into the function descriptor table.
- return m_funcDescs[(index - m_shdr.sh_addr) / sizeof(address)];
- }
+ address* func_descs = cached_func_descs();
+ const Elf_Shdr* shdr = _section.section_header();
+ if (!(shdr->sh_size > 0 && shdr->sh_addr <= index && index <= shdr->sh_addr + shdr->sh_size)) {
+ // don't put the whole decoder in error mode if we just tried a wrong index
return NULL;
+ }
+
+ if (func_descs != NULL) {
+ return func_descs[(index - shdr->sh_addr) / sizeof(address)];
} else {
- long cur_pos;
+ MarkedFileReader mfd(_file);
address addr;
- if (!(m_shdr.sh_size > 0 && m_shdr.sh_addr <= index && index <= m_shdr.sh_addr + m_shdr.sh_size)) {
- // don't put the whole decoder in error mode if we just tried a wrong index
- return NULL;
- }
- if ((cur_pos = ftell(m_file)) == -1 ||
- fseek(m_file, m_shdr.sh_offset + index - m_shdr.sh_addr, SEEK_SET) ||
- fread(&addr, sizeof(addr), 1, m_file) != 1 ||
- fseek(m_file, cur_pos, SEEK_SET)) {
- m_status = NullDecoder::file_invalid;
+ if (!mfd.has_mark() ||
+ !mfd.set_position(shdr->sh_offset + index - shdr->sh_addr) ||
+ !mfd.read((void*)&addr, sizeof(addr))) {
+ _status = NullDecoder::file_invalid;
return NULL;
}
return addr;
--- a/src/hotspot/share/utilities/elfFuncDescTable.hpp Wed Feb 14 16:42:00 2018 +0100
+++ b/src/hotspot/share/utilities/elfFuncDescTable.hpp 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.
* Copyright (c) 2012, 2013 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -116,32 +116,31 @@
class ElfFuncDescTable: public CHeapObj<mtInternal> {
friend class ElfFile;
- public:
+private:
+ // holds the complete function descriptor section if
+ // we can allocate enough memory
+ ElfSection _section;
+
+ // file contains string table
+ FILE* const _file;
+
+ // The section index of this function descriptor (i.e. '.opd') section in the ELF file
+ const int _index;
+
+ NullDecoder::decoder_status _status;
+public:
ElfFuncDescTable(FILE* file, Elf_Shdr shdr, int index);
~ElfFuncDescTable();
// return the function address for the function descriptor at 'index' or NULL on error
address lookup(Elf_Word index);
- int get_index() { return m_index; };
-
- NullDecoder::decoder_status get_status() { return m_status; };
-
- protected:
- // holds the complete function descriptor section if
- // we can allocate enough memory
- address* m_funcDescs;
+ int get_index() const { return _index; };
- // file contains string table
- FILE* m_file;
+ NullDecoder::decoder_status get_status() const { return _status; };
- // section header
- Elf_Shdr m_shdr;
-
- // The section index of this function descriptor (i.e. '.opd') section in the ELF file
- int m_index;
-
- NullDecoder::decoder_status m_status;
+private:
+ address* cached_func_descs() const { return (address*)_section.section_data(); }
};
#endif // !_WINDOWS && !__APPLE__
--- a/src/hotspot/share/utilities/elfStringTable.cpp Wed Feb 14 16:42:00 2018 +0100
+++ b/src/hotspot/share/utilities/elfStringTable.cpp Wed Feb 14 17:20:59 2018 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, 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
@@ -33,58 +33,44 @@
// We will try to load whole string table into memory if we can.
// Otherwise, fallback to more expensive file operation.
-ElfStringTable::ElfStringTable(FILE* file, Elf_Shdr shdr, int index) {
- assert(file, "null file handle");
- m_table = NULL;
- m_index = index;
- m_next = NULL;
- m_file = file;
- m_status = NullDecoder::no_error;
-
- // try to load the string table
- long cur_offset = ftell(file);
- m_table = (char*)os::malloc(sizeof(char) * shdr.sh_size, mtInternal);
- if (m_table != NULL) {
- // if there is an error, mark the error
- if (fseek(file, shdr.sh_offset, SEEK_SET) ||
- fread((void*)m_table, shdr.sh_size, 1, file) != 1 ||
- fseek(file, cur_offset, SEEK_SET)) {
- m_status = NullDecoder::file_invalid;
- os::free((void*)m_table);
- m_table = NULL;
- }
- } else {
- memcpy(&m_shdr, &shdr, sizeof(Elf_Shdr));
- }
+ElfStringTable::ElfStringTable(FILE* const file, Elf_Shdr& shdr, int index) :
+ _section(file, shdr), _index(index), _fd(file), _next(NULL) {
+ _status = _section.status();
}
ElfStringTable::~ElfStringTable() {
- if (m_table != NULL) {
- os::free((void*)m_table);
- }
-
- if (m_next != NULL) {
- delete m_next;
+ if (_next != NULL) {
+ delete _next;
}
}
-bool ElfStringTable::string_at(int pos, char* buf, int buflen) {
- if (NullDecoder::is_error(m_status)) {
+bool ElfStringTable::string_at(size_t pos, char* buf, int buflen) {
+ if (NullDecoder::is_error(get_status())) {
+ return false;
+ }
+
+ assert(buflen > 0, "no buffer");
+ if (pos >= _section.section_header()->sh_size) {
return false;
}
- if (m_table != NULL) {
- jio_snprintf(buf, buflen, "%s", (const char*)(m_table + pos));
+
+ const char* data = (const char*)_section.section_data();
+ if (data != NULL) {
+ jio_snprintf(buf, buflen, "%s", data + pos);
return true;
- } else {
- long cur_pos = ftell(m_file);
- if (cur_pos == -1 ||
- fseek(m_file, m_shdr.sh_offset + pos, SEEK_SET) ||
- fread(buf, 1, buflen, m_file) <= 0 ||
- fseek(m_file, cur_pos, SEEK_SET)) {
- m_status = NullDecoder::file_invalid;
+ } else { // no cache data, read from file instead
+ const Elf_Shdr* const shdr = _section.section_header();
+ MarkedFileReader mfd(_fd);
+ if (mfd.has_mark() &&
+ mfd.set_position(shdr->sh_offset + pos) &&
+ mfd.read((void*)buf, size_t(buflen))) {
+ buf[buflen - 1] = '\0';
+ return true;
+ } else {
+ // put it in error state to avoid retry
+ _status = NullDecoder::file_invalid;
return false;
}
- return true;
}
}
--- a/src/hotspot/share/utilities/elfStringTable.hpp Wed Feb 14 16:42:00 2018 +0100
+++ b/src/hotspot/share/utilities/elfStringTable.hpp Wed Feb 14 17:20:59 2018 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, 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
@@ -37,37 +37,36 @@
// one blob. Otherwise, it will load string from file when requested.
class ElfStringTable: CHeapObj<mtInternal> {
friend class ElfFile;
- public:
- ElfStringTable(FILE* file, Elf_Shdr shdr, int index);
+private:
+ ElfStringTable* _next;
+ int _index; // section index
+ ElfSection _section;
+ FILE* const _fd;
+ NullDecoder::decoder_status _status;
+
+public:
+ ElfStringTable(FILE* const file, Elf_Shdr& shdr, int index);
~ElfStringTable();
// section index
- int index() { return m_index; };
+ int index() const { return _index; };
// get string at specified offset
- bool string_at(int offset, char* buf, int buflen);
+ bool string_at(size_t offset, char* buf, int buflen);
// get status code
- NullDecoder::decoder_status get_status() { return m_status; };
-
- protected:
- ElfStringTable* m_next;
-
- // section index
- int m_index;
+ NullDecoder::decoder_status get_status() const {
+ return _status;
+ }
- // holds complete string table if can
- // allocate enough memory
- const char* m_table;
+private:
+ void set_next(ElfStringTable* next) {
+ _next = next;
+ }
- // file contains string table
- FILE* m_file;
-
- // section header
- Elf_Shdr m_shdr;
-
- // error code
- NullDecoder::decoder_status m_status;
+ ElfStringTable* next() const {
+ return _next;
+ }
};
#endif // !_WINDOWS && !__APPLE__
--- a/src/hotspot/share/utilities/elfSymbolTable.cpp Wed Feb 14 16:42:00 2018 +0100
+++ b/src/hotspot/share/utilities/elfSymbolTable.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
@@ -30,48 +30,26 @@
#include "utilities/elfFuncDescTable.hpp"
#include "utilities/elfSymbolTable.hpp"
-ElfSymbolTable::ElfSymbolTable(FILE* file, Elf_Shdr shdr) {
- assert(file, "null file handle");
- m_symbols = NULL;
- m_next = NULL;
- m_file = file;
- m_status = NullDecoder::no_error;
+ElfSymbolTable::ElfSymbolTable(FILE* const file, Elf_Shdr& shdr) :
+ _section(file, shdr), _fd(file), _next(NULL) {
+ assert(file != NULL, "null file handle");
+ _status = _section.status();
- // try to load the string table
- long cur_offset = ftell(file);
- if (cur_offset != -1) {
- // call malloc so we can back up if memory allocation fails.
- m_symbols = (Elf_Sym*)os::malloc(shdr.sh_size, mtInternal);
- if (m_symbols) {
- if (fseek(file, shdr.sh_offset, SEEK_SET) ||
- fread((void*)m_symbols, shdr.sh_size, 1, file) != 1 ||
- fseek(file, cur_offset, SEEK_SET)) {
- m_status = NullDecoder::file_invalid;
- os::free(m_symbols);
- m_symbols = NULL;
- }
- }
- if (!NullDecoder::is_error(m_status)) {
- memcpy(&m_shdr, &shdr, sizeof(Elf_Shdr));
- }
- } else {
- m_status = NullDecoder::file_invalid;
+ if (_section.section_header()->sh_size % sizeof(Elf_Sym) != 0) {
+ _status = NullDecoder::file_invalid;
}
}
ElfSymbolTable::~ElfSymbolTable() {
- if (m_symbols != NULL) {
- os::free(m_symbols);
- }
-
- if (m_next != NULL) {
- delete m_next;
+ if (_next != NULL) {
+ delete _next;
}
}
bool ElfSymbolTable::compare(const Elf_Sym* sym, address addr, int* stringtableIndex, int* posIndex, int* offset, ElfFuncDescTable* funcDescTable) {
if (STT_FUNC == ELF_ST_TYPE(sym->st_info)) {
Elf_Word st_size = sym->st_size;
+ const Elf_Shdr* shdr = _section.section_header();
address sym_addr;
if (funcDescTable != NULL && funcDescTable->get_index() == sym->st_shndx) {
// We need to go another step trough the function descriptor table (currently PPC64 only)
@@ -82,7 +60,7 @@
if (sym_addr <= addr && (Elf_Word)(addr - sym_addr) < st_size) {
*offset = (int)(addr - sym_addr);
*posIndex = sym->st_name;
- *stringtableIndex = m_shdr.sh_link;
+ *stringtableIndex = shdr->sh_link;
return true;
}
}
@@ -94,39 +72,39 @@
assert(posIndex, "null string table offset pointer");
assert(offset, "null offset pointer");
- if (NullDecoder::is_error(m_status)) {
+ if (NullDecoder::is_error(get_status())) {
return false;
}
size_t sym_size = sizeof(Elf_Sym);
- assert((m_shdr.sh_size % sym_size) == 0, "check size");
- int count = m_shdr.sh_size / sym_size;
- if (m_symbols != NULL) {
+ int count = _section.section_header()->sh_size / sym_size;
+ Elf_Sym* symbols = (Elf_Sym*)_section.section_data();
+
+ if (symbols != NULL) {
for (int index = 0; index < count; index ++) {
- if (compare(&m_symbols[index], addr, stringtableIndex, posIndex, offset, funcDescTable)) {
+ if (compare(&symbols[index], addr, stringtableIndex, posIndex, offset, funcDescTable)) {
return true;
}
}
} else {
- long cur_pos;
- if ((cur_pos = ftell(m_file)) == -1 ||
- fseek(m_file, m_shdr.sh_offset, SEEK_SET)) {
- m_status = NullDecoder::file_invalid;
+ MarkedFileReader mfd(_fd);
+
+ if (!mfd.has_mark() || !mfd.set_position(_section.section_header()->sh_offset)) {
+ _status = NullDecoder::file_invalid;
return false;
}
Elf_Sym sym;
for (int index = 0; index < count; index ++) {
- if (fread(&sym, sym_size, 1, m_file) == 1) {
- if (compare(&sym, addr, stringtableIndex, posIndex, offset, funcDescTable)) {
- return true;
- }
- } else {
- m_status = NullDecoder::file_invalid;
+ if (!mfd.read((void*)&sym, sizeof(sym))) {
+ _status = NullDecoder::file_invalid;
return false;
}
+
+ if (compare(&sym, addr, stringtableIndex, posIndex, offset, funcDescTable)) {
+ return true;
+ }
}
- fseek(m_file, cur_pos, SEEK_SET);
}
return false;
}
--- a/src/hotspot/share/utilities/elfSymbolTable.hpp Wed Feb 14 16:42:00 2018 +0100
+++ b/src/hotspot/share/utilities/elfSymbolTable.hpp 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
@@ -40,29 +40,27 @@
*/
class ElfSymbolTable: public CHeapObj<mtInternal> {
friend class ElfFile;
- public:
- ElfSymbolTable(FILE* file, Elf_Shdr shdr);
+private:
+ ElfSymbolTable* _next;
+
+ // file contains string table
+ FILE* const _fd;
+
+ // corresponding section
+ ElfSection _section;
+
+ NullDecoder::decoder_status _status;
+public:
+ ElfSymbolTable(FILE* const file, Elf_Shdr& shdr);
~ElfSymbolTable();
// search the symbol that is nearest to the specified address.
bool lookup(address addr, int* stringtableIndex, int* posIndex, int* offset, ElfFuncDescTable* funcDescTable);
- NullDecoder::decoder_status get_status() { return m_status; };
-
- protected:
- ElfSymbolTable* m_next;
-
- // holds a complete symbol table section if
- // can allocate enough memory
- Elf_Sym* m_symbols;
-
- // file contains string table
- FILE* m_file;
-
- // section header
- Elf_Shdr m_shdr;
-
- NullDecoder::decoder_status m_status;
+ NullDecoder::decoder_status get_status() const { return _status; };
+private:
+ ElfSymbolTable* next() const { return _next; }
+ void set_next(ElfSymbolTable* next) { _next = next; }
bool compare(const Elf_Sym* sym, address addr, int* stringtableIndex, int* posIndex, int* offset, ElfFuncDescTable* funcDescTable);
};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/ElfDecoder/TestElfDirectRead.java Wed Feb 14 17:20:59 2018 -0500
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8193373
+ * @summary Test reading ELF info direct from underlaying file
+ * @requires (os.family == "linux")
+ * @modules java.base/jdk.internal.misc
+ * @library /test/lib
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail TestElfDirectRead
+ */
+
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.JDKToolFinder;
+import sun.hotspot.WhiteBox;
+
+public class TestElfDirectRead {
+ public static void main(String args[]) throws Exception {
+ WhiteBox wb = WhiteBox.getWhiteBox();
+ wb.disableElfSectionCache();
+ ProcessBuilder pb = new ProcessBuilder();
+ OutputAnalyzer output;
+ // Grab my own PID
+ String pid = Long.toString(ProcessTools.getProcessId());
+
+ pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"});
+ output = new OutputAnalyzer(pb.start());
+ // This is a pre-populated stack frame, should always exist if can decode
+ output.shouldContain("MallocSiteTable::new_entry");
+ }
+}
+
--- a/test/lib/sun/hotspot/WhiteBox.java Wed Feb 14 16:42:00 2018 +0100
+++ b/test/lib/sun/hotspot/WhiteBox.java Wed Feb 14 17:20:59 2018 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -541,4 +541,6 @@
public native boolean isContainerized();
public native void printOsInfo();
+ // Decoder
+ public native void disableElfSectionCache();
}