8193373: Cleanup ElfFile and family
authorzgu
Wed, 14 Feb 2018 17:20:59 -0500
changeset 48975 2c35fd3c5789
parent 48974 66173ef5fbbf
child 48976 324105aaeddf
8193373: Cleanup ElfFile and family Summary: Cleanup elf decoder and added test Reviewed-by: minqi, coleenp
src/hotspot/os/linux/decoder_linux.cpp
src/hotspot/share/logging/logTag.hpp
src/hotspot/share/prims/whitebox.cpp
src/hotspot/share/utilities/decoder.hpp
src/hotspot/share/utilities/elfFile.cpp
src/hotspot/share/utilities/elfFile.hpp
src/hotspot/share/utilities/elfFuncDescTable.cpp
src/hotspot/share/utilities/elfFuncDescTable.hpp
src/hotspot/share/utilities/elfStringTable.cpp
src/hotspot/share/utilities/elfStringTable.hpp
src/hotspot/share/utilities/elfSymbolTable.cpp
src/hotspot/share/utilities/elfSymbolTable.hpp
test/hotspot/jtreg/runtime/ElfDecoder/TestElfDirectRead.java
test/lib/sun/hotspot/WhiteBox.java
--- 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();
 }