changeset 14441:e7cbc95179c4

8019929: PPC64 (part 107): Extend ELF-decoder to support PPC64 function descriptor tables Summary: Extend ELF-decoder to support PPC64 function descriptor tables Reviewed-by: kvn, zgu
author simonis
date Thu, 05 Dec 2013 19:19:09 +0100
parents 41b780b43b74
children 1174c8abbdb6
files make/aix/makefiles/vm.make src/os/linux/vm/decoder_linux.cpp src/share/vm/utilities/decoder_elf.cpp src/share/vm/utilities/decoder_elf.hpp src/share/vm/utilities/elfFile.cpp src/share/vm/utilities/elfFile.hpp src/share/vm/utilities/elfFuncDescTable.cpp src/share/vm/utilities/elfFuncDescTable.hpp src/share/vm/utilities/elfStringTable.cpp src/share/vm/utilities/elfStringTable.hpp src/share/vm/utilities/elfSymbolTable.cpp src/share/vm/utilities/elfSymbolTable.hpp
diffstat 12 files changed, 350 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/make/aix/makefiles/vm.make	Wed Nov 27 16:16:21 2013 -0800
+++ b/make/aix/makefiles/vm.make	Thu Dec 05 19:19:09 2013 +0100
@@ -202,8 +202,8 @@
 
 Src_Files_EXCLUDE +=  $(Src_Files_EXCLUDE/$(TYPE))
 
-# Disable 155427 on aix.
-Src_Files_EXCLUDE += decoder_elf.cpp elfFile.cpp elfStringTable.cpp elfSymbolTable.cpp
+# Disable ELF decoder on AIX (AIX uses XCOFF).
+Src_Files_EXCLUDE += decoder_elf.cpp elfFile.cpp elfStringTable.cpp elfSymbolTable.cpp elfFuncDescTable.cpp
 
 # Special handling of arch model.
 ifeq ($(Platform_arch_model), x86_32)
--- a/src/os/linux/vm/decoder_linux.cpp	Wed Nov 27 16:16:21 2013 -0800
+++ b/src/os/linux/vm/decoder_linux.cpp	Thu Dec 05 19:19:09 2013 +0100
@@ -32,6 +32,12 @@
   char* result;
   size_t size = (size_t)buflen;
 
+#ifdef PPC64
+  // On PPC64 ElfDecoder::decode() may return a dot (.) prefixed name
+  // (see elfFuncDescTable.hpp for details)
+  if (symbol && *symbol == '.') symbol += 1;
+#endif
+
   // Don't pass buf to __cxa_demangle. In case of the 'buf' is too small,
   // __cxa_demangle will call system "realloc" for additional memory, which
   // may use different malloc/realloc mechanism that allocates 'buf'.
--- a/src/share/vm/utilities/decoder_elf.cpp	Wed Nov 27 16:16:21 2013 -0800
+++ b/src/share/vm/utilities/decoder_elf.cpp	Thu Dec 05 19:19:09 2013 +0100
@@ -73,4 +73,4 @@
 
   return file;
 }
-#endif
+#endif // !_WINDOWS && !__APPLE__
--- a/src/share/vm/utilities/decoder_elf.hpp	Wed Nov 27 16:16:21 2013 -0800
+++ b/src/share/vm/utilities/decoder_elf.hpp	Thu Dec 05 19:19:09 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, 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
@@ -55,5 +55,5 @@
   ElfFile*         _opened_elf_files;
 };
 
-#endif
+#endif // !_WINDOWS && !__APPLE__
 #endif // SHARE_VM_UTILITIES_DECODER_ELF_HPP
--- a/src/share/vm/utilities/elfFile.cpp	Wed Nov 27 16:16:21 2013 -0800
+++ b/src/share/vm/utilities/elfFile.cpp	Thu Dec 05 19:19:09 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -34,6 +34,7 @@
 #include "memory/allocation.inline.hpp"
 #include "utilities/decoder.hpp"
 #include "utilities/elfFile.hpp"
+#include "utilities/elfFuncDescTable.hpp"
 #include "utilities/elfStringTable.hpp"
 #include "utilities/elfSymbolTable.hpp"
 
@@ -43,6 +44,7 @@
   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;
 
@@ -119,8 +121,8 @@
         m_status = NullDecoder::file_invalid;
         return false;
       }
-      // string table
       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;
@@ -128,6 +130,7 @@
         }
         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;
@@ -136,6 +139,46 @@
         add_symbol_table(table);
       }
     }
+
+#if defined(PPC64)
+    // 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;
+    }
+    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;
+        }
+      }
+    }
+#endif
+
   }
   return true;
 }
@@ -151,8 +194,9 @@
   int off = INT_MAX;
   bool found_symbol = false;
   while (symbol_table != NULL) {
-    if (symbol_table->lookup(addr, &string_table_index, &pos_in_string_table, &off)) {
+    if (symbol_table->lookup(addr, &string_table_index, &pos_in_string_table, &off, m_funcDesc_table)) {
       found_symbol = true;
+      break;
     }
     symbol_table = symbol_table->m_next;
   }
@@ -221,4 +265,4 @@
 }
 #endif
 
-#endif // _WINDOWS
+#endif // !_WINDOWS && !__APPLE__
--- a/src/share/vm/utilities/elfFile.hpp	Wed Nov 27 16:16:21 2013 -0800
+++ b/src/share/vm/utilities/elfFile.hpp	Thu Dec 05 19:19:09 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -75,6 +75,7 @@
 
 class ElfStringTable;
 class ElfSymbolTable;
+class ElfFuncDescTable;
 
 
 // On Solaris/Linux platforms, libjvm.so does contain all private symbols.
@@ -150,9 +151,12 @@
   // string tables
   ElfStringTable*              m_string_tables;
 
+  // function descriptors table
+  ElfFuncDescTable*            m_funcDesc_table;
+
   NullDecoder::decoder_status  m_status;
 };
 
-#endif // _WINDOWS
+#endif // !_WINDOWS && !__APPLE__
 
 #endif // SHARE_VM_UTILITIES_ELF_FILE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/utilities/elfFuncDescTable.cpp	Thu Dec 05 19:19:09 2013 +0100
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2013 SAP AG. 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.
+ *
+ */
+
+#include "precompiled.hpp"
+
+#if !defined(_WINDOWS) && !defined(__APPLE__)
+
+#include "memory/allocation.inline.hpp"
+#include "utilities/elfFuncDescTable.hpp"
+
+ElfFuncDescTable::ElfFuncDescTable(FILE* file, Elf_Shdr shdr, int index) {
+  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):
+  // PPC64: [function entry point, TOC pointer, environment pointer]
+  // IA64 : [function entry point, GP (global pointer) value]
+  // 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;
+  }
+}
+
+ElfFuncDescTable::~ElfFuncDescTable() {
+  if (m_funcDescs != NULL) {
+    os::free(m_funcDescs);
+  }
+}
+
+address ElfFuncDescTable::lookup(Elf_Word index) {
+  if (NullDecoder::is_error(m_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)];
+    }
+    return NULL;
+  } else {
+    long cur_pos;
+    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;
+      return NULL;
+    }
+    return addr;
+  }
+}
+
+#endif // !_WINDOWS && !__APPLE__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/utilities/elfFuncDescTable.hpp	Thu Dec 05 19:19:09 2013 +0100
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012, 2013 SAP AG. 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.
+ *
+ */
+
+#ifndef SHARE_VM_UTILITIES_ELF_FUNC_DESC_TABLE_HPP
+#define SHARE_VM_UTILITIES_ELF_FUNC_DESC_TABLE_HPP
+
+#if !defined(_WINDOWS) && !defined(__APPLE__)
+
+
+#include "memory/allocation.hpp"
+#include "utilities/decoder.hpp"
+#include "utilities/elfFile.hpp"
+
+/*
+
+On PowerPC-64 (and other architectures like for example IA64) a pointer to a
+function is not just a plain code address, but instead a pointer to a so called
+function descriptor (which is simply a structure containing 3 pointers).
+This fact is also reflected in the ELF ABI for PowerPC-64.
+
+On architectures like x86 or SPARC, the ELF symbol table contains the start
+address and size of an object. So for example for a function object (i.e. type
+'STT_FUNC') the symbol table's 'st_value' and 'st_size' fields directly
+represent the starting address and size of that function. On PPC64 however, the
+symbol table's 'st_value' field only contains an index into another, PPC64
+specific '.opd' (official procedure descriptors) section, while the 'st_size'
+field still holds the size of the corresponding function. In order to get the
+actual start address of a function, it is necessary to read the corresponding
+function descriptor entry in the '.opd' section at the corresponding index and
+extract the start address from there.
+
+That's exactly what this 'ElfFuncDescTable' class is used for. If the HotSpot
+runs on a PPC64 machine, and the corresponding ELF files contains an '.opd'
+section (which is actually mandatory on PPC64) it will be read into an object
+of type 'ElfFuncDescTable' just like the string and symbol table sections.
+Later on, during symbol lookup in 'ElfSymbolTable::lookup()' this function
+descriptor table will be used if available to find the real function address.
+
+All this is how things work today (2013) on contemporary Linux distributions
+(i.e. SLES 10) and new version of GCC (i.e. > 4.0). However there is a history,
+and it goes like this:
+
+In SLES 9 times (sometimes before GCC 3.4) gcc/ld on PPC64 generated two
+entries in the symbol table for every function. The value of the symbol with
+the name of the function was the address of the function descriptor while the
+dot '.' prefixed name was reserved to hold the actual address of that function
+(http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html#FUNC-DES).
+
+For a C-function 'foo' this resulted in two symbol table entries like this
+(extracted from the output of 'readelf -a <lib.so>'):
+
+Section Headers:
+  [ 9] .text             PROGBITS         0000000000000a20  00000a20
+       00000000000005a0  0000000000000000  AX       0     0     16
+  [21] .opd              PROGBITS         00000000000113b8  000013b8
+       0000000000000138  0000000000000000  WA       0     0     8
+
+Symbol table '.symtab' contains 86 entries:
+   Num:    Value          Size Type    Bind   Vis      Ndx Name
+    76: 00000000000114c0    24 FUNC    GLOBAL DEFAULT   21 foo
+    78: 0000000000000bb0    76 FUNC    GLOBAL DEFAULT    9 .foo
+
+You can see now that the '.foo' entry actually points into the '.text' segment
+('Ndx'=9) and its value and size fields represent the functions actual address
+and size. On the other hand, the entry for plain 'foo' points into the '.opd'
+section ('Ndx'=21) and its value and size fields are the index into the '.opd'
+section and the size of the corresponding '.opd' section entry (3 pointers on
+PPC64).
+
+These so called 'dot symbols' were dropped around gcc 3.4 from GCC and BINUTILS,
+see http://gcc.gnu.org/ml/gcc-patches/2004-08/msg00557.html.
+But nevertheless it may still be necessary to support both formats because we
+either run on an old system or because it is possible at any time that functions
+appear in the stack trace which come from old-style libraries.
+
+Therefore we not only have to check for the presence of the function descriptor
+table during symbol lookup in 'ElfSymbolTable::lookup()'. We additionally have
+to check that the symbol table entry references the '.opd' section. Only in
+that case we can resolve the actual function address from there. Otherwise we
+use the plain 'st_value' field from the symbol table as function address. This
+way we can also lookup the symbols in old-style ELF libraries (although we get
+the 'dotted' versions in that case). However, if present, the 'dot' will be
+conditionally removed on PPC64 from the symbol in 'ElfDecoder::demangle()' in
+decoder_linux.cpp.
+
+Notice that we can not reliably get the function address from old-style
+libraries because the 'st_value' field of the symbol table entries which point
+into the '.opd' section denote the size of the corresponding '.opd' entry and
+not that of the corresponding function. This has changed for the symbol table
+entries in new-style libraries as described at the beginning of this
+documentation.
+
+*/
+
+class ElfFuncDescTable: public CHeapObj<mtInternal> {
+  friend class ElfFile;
+ 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;
+
+  // file contains string table
+  FILE*               m_file;
+
+  // 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;
+};
+
+#endif // !_WINDOWS && !__APPLE__
+
+#endif // SHARE_VM_UTILITIES_ELF_FUNC_DESC_TABLE_HPP
--- a/src/share/vm/utilities/elfStringTable.cpp	Wed Nov 27 16:16:21 2013 -0800
+++ b/src/share/vm/utilities/elfStringTable.cpp	Thu Dec 05 19:19:09 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -87,4 +87,4 @@
   }
 }
 
-#endif // _WINDOWS
+#endif // !_WINDOWS && !__APPLE__
--- a/src/share/vm/utilities/elfStringTable.hpp	Wed Nov 27 16:16:21 2013 -0800
+++ b/src/share/vm/utilities/elfStringTable.hpp	Thu Dec 05 19:19:09 2013 +0100
@@ -70,6 +70,6 @@
   NullDecoder::decoder_status  m_status;
 };
 
-#endif // _WINDOWS and _APPLE
+#endif // !_WINDOWS && !__APPLE__
 
 #endif // SHARE_VM_UTILITIES_ELF_STRING_TABLE_HPP
--- a/src/share/vm/utilities/elfSymbolTable.cpp	Wed Nov 27 16:16:21 2013 -0800
+++ b/src/share/vm/utilities/elfSymbolTable.cpp	Thu Dec 05 19:19:09 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -27,6 +27,7 @@
 #if !defined(_WINDOWS) && !defined(__APPLE__)
 
 #include "memory/allocation.inline.hpp"
+#include "utilities/elfFuncDescTable.hpp"
 #include "utilities/elfSymbolTable.hpp"
 
 ElfSymbolTable::ElfSymbolTable(FILE* file, Elf_Shdr shdr) {
@@ -68,7 +69,7 @@
   }
 }
 
-bool ElfSymbolTable::lookup(address addr, int* stringtableIndex, int* posIndex, int* offset) {
+bool ElfSymbolTable::lookup(address addr, int* stringtableIndex, int* posIndex, int* offset, ElfFuncDescTable* funcDescTable) {
   assert(stringtableIndex, "null string table index pointer");
   assert(posIndex, "null string table offset pointer");
   assert(offset, "null offset pointer");
@@ -77,19 +78,25 @@
     return false;
   }
 
-  address pc = 0;
   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) {
     for (int index = 0; index < count; index ++) {
       if (STT_FUNC == ELF_ST_TYPE(m_symbols[index].st_info)) {
-        address sym_addr = (address)m_symbols[index].st_value;
-        if (sym_addr < addr && (addr - sym_addr) < *offset) {
-          pc = (address)m_symbols[index].st_value;
-          *offset = (int)(addr - pc);
+        Elf_Word st_size = m_symbols[index].st_size;
+        address sym_addr;
+        if (funcDescTable != NULL && funcDescTable->get_index() == m_symbols[index].st_shndx) {
+          // We need to go another step trough the function descriptor table (currently PPC64 only)
+          sym_addr = funcDescTable->lookup(m_symbols[index].st_value);
+        } else {
+          sym_addr = (address)m_symbols[index].st_value;
+        }
+        if (sym_addr <= addr && (Elf_Word)(addr - sym_addr) < st_size) {
+          *offset = (int)(addr - sym_addr);
           *posIndex = m_symbols[index].st_name;
           *stringtableIndex = m_shdr.sh_link;
+          return true;
         }
       }
     }
@@ -105,12 +112,19 @@
     for (int index = 0; index < count; index ++) {
       if (fread(&sym, sym_size, 1, m_file) == 1) {
         if (STT_FUNC == ELF_ST_TYPE(sym.st_info)) {
-          address sym_addr = (address)sym.st_value;
-          if (sym_addr < addr && (addr - sym_addr) < *offset) {
-            pc = (address)sym.st_value;
-            *offset = (int)(addr - pc);
+          Elf_Word st_size = sym.st_size;
+          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)
+            sym_addr = funcDescTable->lookup(sym.st_value);
+          } else {
+            sym_addr = (address)sym.st_value;
+          }
+          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;
+            return true;
           }
         }
       } else {
@@ -123,4 +137,4 @@
   return true;
 }
 
-#endif // _WINDOWS
+#endif // !_WINDOWS && !__APPLE__
--- a/src/share/vm/utilities/elfSymbolTable.hpp	Wed Nov 27 16:16:21 2013 -0800
+++ b/src/share/vm/utilities/elfSymbolTable.hpp	Thu Dec 05 19:19:09 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -45,7 +45,7 @@
   ~ElfSymbolTable();
 
   // search the symbol that is nearest to the specified address.
-  bool lookup(address addr, int* stringtableIndex, int* posIndex, int* offset);
+  bool lookup(address addr, int* stringtableIndex, int* posIndex, int* offset, ElfFuncDescTable* funcDescTable);
 
   NullDecoder::decoder_status get_status() { return m_status; };
 
@@ -65,6 +65,6 @@
   NullDecoder::decoder_status  m_status;
 };
 
-#endif // _WINDOWS and _APPLE
+#endif // !_WINDOWS and !__APPLE__
 
 #endif // SHARE_VM_UTILITIES_ELF_SYMBOL_TABLE_HPP