changeset 1935:2d4762ec74af

7003748: Decode C stack frames when symbols are presented (PhoneHome project) Summary: Implemented in-process C native stack frame decoding when symbols are available. Reviewed-by: coleenp, never
author zgu
date Sat, 11 Dec 2010 13:20:56 -0500
parents f95d63e2154a
children 54f5dd2aa1d9
files make/solaris/makefiles/vm.make src/os/linux/vm/decoder_linux.cpp src/os/linux/vm/os_linux.cpp src/os/solaris/vm/decoder_solaris.cpp src/os/solaris/vm/os_solaris.cpp src/os/windows/vm/decoder_windows.cpp src/os/windows/vm/os_windows.cpp src/share/vm/runtime/frame.cpp src/share/vm/utilities/decoder.cpp src/share/vm/utilities/decoder.hpp src/share/vm/utilities/elfFile.cpp src/share/vm/utilities/elfFile.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 src/share/vm/utilities/vmError.cpp
diffstat 17 files changed, 1177 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/make/solaris/makefiles/vm.make	Tue Nov 23 13:22:55 2010 -0800
+++ b/make/solaris/makefiles/vm.make	Sat Dec 11 13:20:56 2010 -0500
@@ -106,17 +106,17 @@
 # Not sure what the 'designed for' comment is referring too above.
 #   The order may not be too significant anymore, but I have placed this
 #   older libm before libCrun, just to make sure it's found and used first.
-LIBS += -lsocket -lsched -ldl $(LIBM) -lCrun -lthread -ldoor -lc
+LIBS += -lsocket -lsched -ldl $(LIBM) -lCrun -lthread -ldoor -lc -ldemangle
 else
 ifeq ($(COMPILER_REV_NUMERIC), 502)
 # SC6.1 has it's own libm.so: specifying anything else provokes a name conflict.
-LIBS += -ldl -lthread -lsocket -lm -lsched -ldoor
+LIBS += -ldl -lthread -lsocket -lm -lsched -ldoor -ldemangle
 else
-LIBS += -ldl -lthread -lsocket $(LIBM) -lsched -ldoor
+LIBS += -ldl -lthread -lsocket $(LIBM) -lsched -ldoor -ldemangle
 endif # 502
 endif # 505
 else
-LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc
+LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -ldemangle
 endif # sparcWorks
 
 # By default, link the *.o into the library, not the executable.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/os/linux/vm/decoder_linux.cpp	Sat Dec 11 13:20:56 2010 -0500
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1997, 2010, 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.
+ *
+ */
+
+#include "prims/jvm.h"
+#include "utilities/decoder.hpp"
+
+#include <cxxabi.h>
+
+bool Decoder::demangle(const char* symbol, char *buf, int buflen) {
+  int   status;
+  char* result;
+  size_t size = (size_t)buflen;
+
+  // 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'.
+  if ((result = abi::__cxa_demangle(symbol, NULL, NULL, &status)) != NULL) {
+    jio_snprintf(buf, buflen, "%s", result);
+      // call c library's free
+      ::free(result);
+      return true;
+  }
+  return false;
+}
--- a/src/os/linux/vm/os_linux.cpp	Tue Nov 23 13:22:55 2010 -0800
+++ b/src/os/linux/vm/os_linux.cpp	Sat Dec 11 13:20:56 2010 -0500
@@ -60,6 +60,7 @@
 #include "services/attachListener.hpp"
 #include "services/runtimeService.hpp"
 #include "thread_linux.inline.hpp"
+#include "utilities/decoder.hpp"
 #include "utilities/defaultStream.hpp"
 #include "utilities/events.hpp"
 #include "utilities/growableArray.hpp"
@@ -1671,14 +1672,23 @@
   Dl_info dlinfo;
 
   if (dladdr((void*)addr, &dlinfo) && dlinfo.dli_sname != NULL) {
-    if (buf) jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
-    if (offset) *offset = addr - (address)dlinfo.dli_saddr;
+    if (buf != NULL) {
+      if(!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) {
+        jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
+      }
+    }
+    if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
     return true;
-  } else {
-    if (buf) buf[0] = '\0';
-    if (offset) *offset = -1;
-    return false;
+  } else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) {
+    if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
+       dlinfo.dli_fname, buf, buflen, offset) == Decoder::no_error) {
+       return true;
+    }
   }
+
+  if (buf != NULL) buf[0] = '\0';
+  if (offset != NULL) *offset = -1;
+  return false;
 }
 
 struct _address_to_library_name {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/os/solaris/vm/decoder_solaris.cpp	Sat Dec 11 13:20:56 2010 -0500
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 1997, 2010, 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.
+ *
+ */
+
+#include "utilities/decoder.hpp"
+
+#include <demangle.h>
+
+bool Decoder::demangle(const char* symbol, char *buf, int buflen) {
+  return !cplus_demangle(symbol, buf, (size_t)buflen);
+}
--- a/src/os/solaris/vm/os_solaris.cpp	Tue Nov 23 13:22:55 2010 -0800
+++ b/src/os/solaris/vm/os_solaris.cpp	Sat Dec 11 13:20:56 2010 -0500
@@ -58,6 +58,7 @@
 #include "services/attachListener.hpp"
 #include "services/runtimeService.hpp"
 #include "thread_solaris.inline.hpp"
+#include "utilities/decoder.hpp"
 #include "utilities/defaultStream.hpp"
 #include "utilities/events.hpp"
 #include "utilities/growableArray.hpp"
@@ -1967,27 +1968,42 @@
       Sym * info;
       if (dladdr1_func((void *)addr, &dlinfo, (void **)&info,
                        RTLD_DL_SYMENT)) {
-          if (buf) jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
-          if (offset) *offset = addr - (address)dlinfo.dli_saddr;
-
-          // check if the returned symbol really covers addr
-          return ((char *)dlinfo.dli_saddr + info->st_size > (char *)addr);
-      } else {
-          if (buf) buf[0] = '\0';
-          if (offset) *offset  = -1;
-          return false;
+        if ((char *)dlinfo.dli_saddr + info->st_size > (char *)addr) {
+          if (buf != NULL) {
+            if (!Decoder::demangle(dlinfo.dli_sname, buf, buflen))
+              jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
+            }
+            if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
+            return true;
+        }
       }
+      if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) {
+        if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
+          dlinfo.dli_fname, buf, buflen, offset) == Decoder::no_error) {
+          return true;
+        }
+      }
+      if (buf != NULL) buf[0] = '\0';
+      if (offset != NULL) *offset  = -1;
+      return false;
   } else {
       // no, only dladdr is available
-      if(dladdr((void *)addr, &dlinfo)) {
-          if (buf) jio_snprintf(buf, buflen, dlinfo.dli_sname);
-          if (offset) *offset = addr - (address)dlinfo.dli_saddr;
+      if (dladdr((void *)addr, &dlinfo)) {
+        if (buf != NULL) {
+          if (!Decoder::demangle(dlinfo.dli_sname, buf, buflen))
+            jio_snprintf(buf, buflen, dlinfo.dli_sname);
+        }
+        if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
+        return true;
+      } else if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != 0) {
+        if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
+          dlinfo.dli_fname, buf, buflen, offset) == Decoder::no_error) {
           return true;
-      } else {
-          if (buf) buf[0] = '\0';
-          if (offset) *offset  = -1;
-          return false;
+        }
       }
+      if (buf != NULL) buf[0] = '\0';
+      if (offset != NULL) *offset  = -1;
+      return false;
   }
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/os/windows/vm/decoder_windows.cpp	Sat Dec 11 13:20:56 2010 -0500
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1997, 2010, 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "prims/jvm.h"
+#include "utilities/decoder.hpp"
+
+HMODULE                   Decoder::_dbghelp_handle = NULL;
+bool                      Decoder::_can_decode_in_vm = false;
+pfn_SymGetSymFromAddr64   Decoder::_pfnSymGetSymFromAddr64 = NULL;
+pfn_UndecorateSymbolName  Decoder::_pfnUndecorateSymbolName = NULL;
+
+void Decoder::initialize() {
+  if (!_initialized) {
+    _initialized = true;
+
+    HMODULE handle = ::LoadLibrary("dbghelp.dll");
+    if (!handle) {
+      _decoder_status = helper_not_found;
+        return;
+    }
+
+    _dbghelp_handle = handle;
+
+    pfn_SymSetOptions _pfnSymSetOptions = (pfn_SymSetOptions)::GetProcAddress(handle, "SymSetOptions");
+    pfn_SymInitialize _pfnSymInitialize = (pfn_SymInitialize)::GetProcAddress(handle, "SymInitialize");
+    _pfnSymGetSymFromAddr64 = (pfn_SymGetSymFromAddr64)::GetProcAddress(handle, "SymGetSymFromAddr64");
+    _pfnUndecorateSymbolName = (pfn_UndecorateSymbolName)GetProcAddress(handle, "UnDecorateSymbolName");
+
+    if (_pfnSymSetOptions == NULL || _pfnSymInitialize == NULL || _pfnSymGetSymFromAddr64 == NULL) {
+      _pfnSymGetSymFromAddr64 = NULL;
+      _pfnUndecorateSymbolName = NULL;
+      ::FreeLibrary(handle);
+      _dbghelp_handle = NULL;
+      _decoder_status = helper_func_error;
+      return;
+    }
+
+    _pfnSymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
+    if (!_pfnSymInitialize(GetCurrentProcess(), NULL, TRUE)) {
+      _pfnSymGetSymFromAddr64 = NULL;
+      _pfnUndecorateSymbolName = NULL;
+      ::FreeLibrary(handle);
+      _dbghelp_handle = NULL;
+      _decoder_status = helper_init_error;
+      return;
+    }
+
+     // find out if jvm.dll contains private symbols, by decoding
+     // current function and comparing the result
+     address addr = (address)Decoder::initialize;
+     char buf[MAX_PATH];
+     if (decode(addr, buf, sizeof(buf), NULL) == no_error) {
+       _can_decode_in_vm = !strcmp(buf, "Decoder::initialize");
+     }
+  }
+}
+
+void Decoder::uninitialize() {
+  assert(_initialized, "Decoder not yet initialized");
+  _pfnSymGetSymFromAddr64 = NULL;
+  _pfnUndecorateSymbolName = NULL;
+  if (_dbghelp_handle != NULL) {
+    ::FreeLibrary(_dbghelp_handle);
+  }
+  _initialized = false;
+}
+
+bool Decoder::can_decode_C_frame_in_vm() {
+  initialize();
+  return  _can_decode_in_vm;
+}
+
+
+Decoder::decoder_status Decoder::decode(address addr, char *buf, int buflen, int *offset) {
+  assert(_initialized, "Decoder not yet initialized");
+  if (_pfnSymGetSymFromAddr64 != NULL) {
+    PIMAGEHLP_SYMBOL64 pSymbol;
+    char symbolInfo[MAX_PATH + sizeof(IMAGEHLP_SYMBOL64)];
+    pSymbol = (PIMAGEHLP_SYMBOL64)symbolInfo;
+    pSymbol->MaxNameLength = MAX_PATH;
+    pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
+    DWORD64 displacement;
+    if (_pfnSymGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) {
+      if (buf != NULL) {
+        if (!demangle(pSymbol->Name, buf, buflen)) {
+          jio_snprintf(buf, buflen, "%s", pSymbol->Name);
+        }
+      }
+      if (offset != NULL) *offset = (int)displacement;
+      return no_error;
+    }
+  }
+  return helper_not_found;
+}
+
+bool Decoder::demangle(const char* symbol, char *buf, int buflen) {
+  assert(_initialized, "Decoder not yet initialized");
+  return _pfnUndecorateSymbolName != NULL &&
+         _pfnUndecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE);
+}
+
--- a/src/os/windows/vm/os_windows.cpp	Tue Nov 23 13:22:55 2010 -0800
+++ b/src/os/windows/vm/os_windows.cpp	Sat Dec 11 13:20:56 2010 -0500
@@ -63,6 +63,7 @@
 #include "services/attachListener.hpp"
 #include "services/runtimeService.hpp"
 #include "thread_windows.inline.hpp"
+#include "utilities/decoder.hpp"
 #include "utilities/defaultStream.hpp"
 #include "utilities/events.hpp"
 #include "utilities/growableArray.hpp"
@@ -1369,12 +1370,11 @@
 
 bool os::dll_address_to_function_name(address addr, char *buf,
                                       int buflen, int *offset) {
-  // Unimplemented on Windows - in order to use SymGetSymFromAddr(),
-  // we need to initialize imagehlp/dbghelp, then load symbol table
-  // for every module. That's too much work to do after a fatal error.
-  // For an example on how to implement this function, see 1.4.2.
-  if (offset)  *offset  = -1;
-  if (buf) buf[0] = '\0';
+  if (Decoder::decode(addr, buf, buflen, offset) == Decoder::no_error) {
+    return true;
+  }
+  if (offset != NULL)  *offset  = -1;
+  if (buf != NULL) buf[0] = '\0';
   return false;
 }
 
--- a/src/share/vm/runtime/frame.cpp	Tue Nov 23 13:22:55 2010 -0800
+++ b/src/share/vm/runtime/frame.cpp	Sat Dec 11 13:20:56 2010 -0500
@@ -41,6 +41,8 @@
 #include "runtime/signature.hpp"
 #include "runtime/stubCodeGenerator.hpp"
 #include "runtime/stubRoutines.hpp"
+#include "utilities/decoder.hpp"
+
 #ifdef TARGET_ARCH_x86
 # include "nativeInst_x86.hpp"
 #endif
@@ -652,7 +654,7 @@
   // names if pc is within jvm.dll or libjvm.so, because JVM only has
   // JVM_xxxx and a few other symbols in the dynamic symbol table. Do this
   // only for native libraries.
-  if (!in_vm) {
+  if (!in_vm || Decoder::can_decode_C_frame_in_vm()) {
     found = os::dll_address_to_function_name(pc, buf, buflen, &offset);
 
     if (found) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/utilities/decoder.cpp	Sat Dec 11 13:20:56 2010 -0500
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 1997, 2010, 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "prims/jvm.h"
+#include "utilities/decoder.hpp"
+
+Decoder::decoder_status  Decoder::_decoder_status = Decoder::no_error;
+bool                     Decoder::_initialized = false;
+
+#ifndef _WINDOWS
+
+// Implementation of common functionalities among Solaris and Linux
+#include "utilities/elfFile.hpp"
+
+ElfFile* Decoder::_opened_elf_files = NULL;
+
+bool Decoder::can_decode_C_frame_in_vm() {
+  return true;
+}
+
+void Decoder::initialize() {
+  _initialized = true;
+}
+
+void Decoder::uninitialize() {
+  if (_opened_elf_files != NULL) {
+    delete _opened_elf_files;
+    _opened_elf_files = NULL;
+  }
+  _initialized = false;
+}
+
+Decoder::decoder_status Decoder::decode(address addr, const char* filepath, char *buf, int buflen, int *offset) {
+  if (_decoder_status != no_error) {
+    return _decoder_status;
+  }
+
+  ElfFile* file = get_elf_file(filepath);
+  if (_decoder_status != no_error) {
+    return _decoder_status;
+  }
+
+  const char* symbol = file->decode(addr, offset);
+  if (file->get_status() == out_of_memory) {
+    _decoder_status = out_of_memory;
+    return _decoder_status;
+  } else if (symbol != NULL) {
+    if (!demangle(symbol, buf, buflen)) {
+      jio_snprintf(buf, buflen, "%s", symbol);
+    }
+    return no_error;
+  } else {
+    return symbol_not_found;
+  }
+}
+
+ElfFile* Decoder::get_elf_file(const char* filepath) {
+  if (_decoder_status != no_error) {
+    return NULL;
+  }
+  ElfFile* file = _opened_elf_files;
+  while (file != NULL) {
+    if (file->same_elf_file(filepath)) {
+      return file;
+    }
+    file = file->m_next;
+  }
+
+  file = new ElfFile(filepath);
+  if (file == NULL) {
+    _decoder_status = out_of_memory;
+  }
+  if (_opened_elf_files != NULL) {
+    file->m_next = _opened_elf_files;
+  }
+
+  _opened_elf_files = file;
+  return file;
+}
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/utilities/decoder.hpp	Sat Dec 11 13:20:56 2010 -0500
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 1997, 2010, 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.
+ *
+ */
+
+
+#ifndef __DECODER_HPP
+#define __DECODER_HPP
+
+#include "memory/allocation.hpp"
+
+#ifdef _WINDOWS
+#include <windows.h>
+#include <imagehlp.h>
+
+// functions needed for decoding symbols
+typedef DWORD (WINAPI *pfn_SymSetOptions)(DWORD);
+typedef BOOL  (WINAPI *pfn_SymInitialize)(HANDLE, PCTSTR, BOOL);
+typedef BOOL  (WINAPI *pfn_SymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
+typedef DWORD (WINAPI *pfn_UndecorateSymbolName)(const char*, char*, DWORD, DWORD);
+
+#else
+
+class ElfFile;
+
+#endif // _WINDOWS
+
+
+class Decoder: public StackObj {
+
+ public:
+  // status code for decoding native C frame
+  enum decoder_status {
+         no_error,             // successfully decoded frames
+         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
+         helper_not_found,     // could not load dbghelp.dll (Windows only)
+         helper_func_error,    // decoding functions not found (Windows only)
+         helper_init_error,    // SymInitialize failed (Windows only)
+         symbol_not_found      // could not find the symbol
+  };
+
+ public:
+  Decoder() { initialize(); };
+  ~Decoder() { uninitialize(); };
+
+  static bool can_decode_C_frame_in_vm();
+
+  static void initialize();
+  static void uninitialize();
+
+#ifdef _WINDOWS
+  static decoder_status    decode(address addr, char *buf, int buflen, int *offset);
+#else
+  static decoder_status    decode(address addr, const char* filepath, char *buf, int buflen, int *offset);
+#endif
+
+  static bool              demangle(const char* symbol, char *buf, int buflen);
+
+  static decoder_status    get_status() { return _decoder_status; };
+
+#ifndef _WINDOWS
+ private:
+  static ElfFile*         get_elf_file(const char* filepath);
+#endif // _WINDOWS
+
+
+ private:
+  static decoder_status     _decoder_status;
+  static bool               _initialized;
+
+#ifdef _WINDOWS
+  static HMODULE                   _dbghelp_handle;
+  static bool                      _can_decode_in_vm;
+  static pfn_SymGetSymFromAddr64   _pfnSymGetSymFromAddr64;
+  static pfn_UndecorateSymbolName  _pfnUndecorateSymbolName;
+#else
+  static ElfFile*                  _opened_elf_files;
+#endif // _WINDOWS
+};
+
+#endif // __DECODER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/utilities/elfFile.cpp	Sat Dec 11 13:20:56 2010 -0500
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 1997, 2010, 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.
+ *
+ */
+
+#include "precompiled.hpp"
+
+#ifndef _WINDOWS
+
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include "memory/allocation.inline.hpp"
+#include "utilities/decoder.hpp"
+#include "utilities/elfFile.hpp"
+#include "utilities/elfStringTable.hpp"
+#include "utilities/elfSymbolTable.hpp"
+
+
+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_next = NULL;
+  m_status = Decoder::no_error;
+
+  int len = strlen(filepath) + 1;
+  m_filepath = NEW_C_HEAP_ARRAY(char, len);
+  if (m_filepath != NULL) {
+    strcpy((char*)m_filepath, filepath);
+    m_file = fopen(filepath, "r");
+    if (m_file != NULL) {
+      load_tables();
+    } else {
+      m_status = Decoder::file_not_found;
+    }
+  } else {
+    m_status = Decoder::out_of_memory;
+  }
+}
+
+ElfFile::~ElfFile() {
+  if (m_string_tables != NULL) {
+    delete m_string_tables;
+  }
+
+  if (m_symbol_tables != NULL) {
+    delete m_symbol_tables;
+  }
+
+  if (m_file != NULL) {
+    fclose(m_file);
+  }
+
+  if (m_filepath != NULL) {
+    FREE_C_HEAP_ARRAY(char, m_filepath);
+  }
+
+  if (m_next != NULL) {
+    delete m_next;
+  }
+};
+
+
+//Check elf header to ensure the file is valid.
+bool ElfFile::is_elf_file(Elf_Ehdr& hdr) {
+  return (ELFMAG0 == hdr.e_ident[EI_MAG0] &&
+      ELFMAG1 == hdr.e_ident[EI_MAG1] &&
+      ELFMAG2 == hdr.e_ident[EI_MAG2] &&
+      ELFMAG3 == hdr.e_ident[EI_MAG3] &&
+      ELFCLASSNONE != hdr.e_ident[EI_CLASS] &&
+      ELFDATANONE != hdr.e_ident[EI_DATA]);
+}
+
+bool ElfFile::load_tables() {
+  assert(m_file, "file not open");
+  assert(m_status == Decoder::no_error, "already in error");
+
+  // read elf file header
+  if (fread(&m_elfHdr, sizeof(m_elfHdr), 1, m_file) != 1) {
+    m_status = Decoder::file_invalid;
+    return false;
+  }
+
+  if (!is_elf_file(m_elfHdr)) {
+    m_status = Decoder::file_invalid;
+    return false;
+  }
+
+  // walk elf file's section headers, and load string tables
+  Elf_Shdr shdr;
+  if (!fseek(m_file, m_elfHdr.e_shoff, SEEK_SET)) {
+    if (m_status != Decoder::no_error) 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 = Decoder::file_invalid;
+        return false;
+      }
+      // string table
+      if (shdr.sh_type == SHT_STRTAB) {
+        ElfStringTable* table = new ElfStringTable(m_file, shdr, index);
+        if (table == NULL) {
+          m_status = Decoder::out_of_memory;
+          return false;
+        }
+        add_string_table(table);
+      } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
+        ElfSymbolTable* table = new ElfSymbolTable(m_file, shdr);
+        if (table == NULL) {
+          m_status = Decoder::out_of_memory;
+          return false;
+        }
+        add_symbol_table(table);
+      }
+    }
+  }
+  return true;
+}
+
+const char* ElfFile::decode(address addr, int* offset) {
+  // something already went wrong, just give up
+  if (m_status != Decoder::no_error) {
+    return NULL;
+  }
+
+  ElfSymbolTable* symbol_table = m_symbol_tables;
+  int string_table_index;
+  int pos_in_string_table;
+  int off = INT_MAX;
+  bool found_symbol = false;
+  while (symbol_table != NULL) {
+    if (Decoder::no_error == symbol_table->lookup(addr, &string_table_index, &pos_in_string_table, &off)) {
+      found_symbol = true;
+    }
+    symbol_table = symbol_table->m_next;
+  }
+  if (!found_symbol) return NULL;
+
+  ElfStringTable* string_table = get_string_table(string_table_index);
+  if (string_table == NULL) {
+    m_status = Decoder::file_invalid;
+    return NULL;
+  }
+  if (offset) *offset = off;
+  return string_table->string_at(pos_in_string_table);
+}
+
+
+void ElfFile::add_symbol_table(ElfSymbolTable* table) {
+  if (m_symbol_tables == NULL) {
+    m_symbol_tables = table;
+  } else {
+    table->m_next = m_symbol_tables;
+    m_symbol_tables = table;
+  }
+}
+
+void ElfFile::add_string_table(ElfStringTable* table) {
+  if (m_string_tables == NULL) {
+    m_string_tables = table;
+  } else {
+    table->m_next = m_string_tables;
+    m_string_tables = table;
+  }
+}
+
+ElfStringTable* ElfFile::get_string_table(int index) {
+  ElfStringTable* p = m_string_tables;
+  while (p != NULL) {
+    if (p->index() == index) return p;
+    p = p->m_next;
+  }
+  return NULL;
+}
+
+#endif // _WINDOWS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/utilities/elfFile.hpp	Sat Dec 11 13:20:56 2010 -0500
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 1997, 2010, 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.
+ *
+ */
+
+#ifndef __ELF_FILE_HPP
+#define __ELF_FILE_HPP
+
+#ifndef _WINDOWS
+
+#include <elf.h>
+#include <stdio.h>
+
+#ifdef _LP64
+
+typedef Elf64_Half      Elf_Half;
+typedef Elf64_Word      Elf_Word;
+typedef Elf64_Off       Elf_Off;
+typedef Elf64_Addr      Elf_Addr;
+
+typedef Elf64_Ehdr      Elf_Ehdr;
+typedef Elf64_Shdr      Elf_Shdr;
+typedef Elf64_Sym       Elf_Sym;
+
+#define ELF_ST_TYPE ELF64_ST_TYPE
+
+#else
+
+typedef Elf32_Half      Elf_Half;
+typedef Elf32_Word      Elf_Word;
+typedef Elf32_Off       Elf_Off;
+typedef Elf32_Addr      Elf_Addr;
+
+
+typedef Elf32_Ehdr      Elf_Ehdr;
+typedef Elf32_Shdr      Elf_Shdr;
+typedef Elf32_Sym       Elf_Sym;
+
+#define ELF_ST_TYPE ELF32_ST_TYPE
+#endif
+
+#include "globalDefinitions.hpp"
+#include "memory/allocation.hpp"
+#include "utilities/decoder.hpp"
+
+
+class ElfStringTable;
+class ElfSymbolTable;
+
+
+// On Solaris/Linux platforms, libjvm.so does contain all private symbols.
+// 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 {
+  friend class Decoder;
+ public:
+  ElfFile(const char* filepath);
+  ~ElfFile();
+
+  const char* decode(address addr, int* offset);
+  const char* filepath() {
+    return m_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));
+  }
+
+  Decoder::decoder_status get_status() {
+    return m_status;
+  }
+
+ private:
+  // sanity check, if the file is a real elf file
+  bool is_elf_file(Elf_Ehdr&);
+
+  // load string tables from the elf file
+  bool load_tables();
+
+  // string tables are stored in a linked list
+  void add_string_table(ElfStringTable* table);
+
+  // symbol tables are stored in a linked list
+  void add_symbol_table(ElfSymbolTable* table);
+
+  // return a string table at specified section index
+  ElfStringTable* get_string_table(int index);
+
+  // look up an address and return the nearest symbol
+  const char* look_up(Elf_Shdr shdr, address addr, int* offset);
+
+ protected:
+    ElfFile*         m_next;
+
+ private:
+  // file
+  const char* m_filepath;
+  FILE* m_file;
+
+  // Elf header
+  Elf_Ehdr            m_elfHdr;
+
+  // symbol tables
+  ElfSymbolTable*     m_symbol_tables;
+
+  // string tables
+  ElfStringTable*     m_string_tables;
+
+  Decoder::decoder_status  m_status;
+};
+
+#endif // _WINDOWS
+
+#endif // __ELF_FILE_HPP
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/utilities/elfStringTable.cpp	Sat Dec 11 13:20:56 2010 -0500
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1997, 2010, 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.
+ *
+ */
+
+#include "precompiled.hpp"
+
+#ifndef _WINDOWS
+
+#include "memory/allocation.inline.hpp"
+#include "utilities/elfStringTable.hpp"
+
+// 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 = Decoder::no_error;
+
+  // try to load the string table
+  long cur_offset = ftell(file);
+  m_table = (char*)NEW_C_HEAP_ARRAY(char, shdr.sh_size);
+  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 = Decoder::file_invalid;
+      FREE_C_HEAP_ARRAY(char, m_table);
+      m_table = NULL;
+    }
+  } else {
+    memcpy(&m_shdr, &shdr, sizeof(Elf_Shdr));
+  }
+}
+
+ElfStringTable::~ElfStringTable() {
+  if (m_table != NULL) {
+    FREE_C_HEAP_ARRAY(char, m_table);
+  }
+
+  if (m_next != NULL) {
+    delete m_next;
+  }
+}
+
+const char* ElfStringTable::string_at(int pos) {
+  if (m_status != Decoder::no_error) {
+    return NULL;
+  }
+  if (m_table != NULL) {
+    return (const char*)(m_table + pos);
+  } else {
+    long cur_pos = ftell(m_file);
+    if (cur_pos == -1 ||
+      fseek(m_file, m_shdr.sh_offset + pos, SEEK_SET) ||
+      fread(m_symbol, 1, MAX_SYMBOL_LEN, m_file) <= 0 ||
+      fseek(m_file, cur_pos, SEEK_SET)) {
+      m_status = Decoder::file_invalid;
+      return NULL;
+    }
+    return (const char*)m_symbol;
+  }
+}
+
+#endif // _WINDOWS
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/utilities/elfStringTable.hpp	Sat Dec 11 13:20:56 2010 -0500
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1997, 2010, 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.
+ *
+ */
+
+#ifndef __ELF_STRING_TABLE_HPP
+#define __ELF_STRING_TABLE_HPP
+
+#ifndef _WINDOWS
+
+#include "memory/allocation.hpp"
+#include "utilities/decoder.hpp"
+#include "utilities/elfFile.hpp"
+
+
+// The string table represents a string table section in an elf file.
+// Whenever there is enough memory, it will load whole string table as
+// one blob. Otherwise, it will load string from file when requested.
+
+#define MAX_SYMBOL_LEN  256
+
+class ElfStringTable: CHeapObj {
+  friend class ElfFile;
+ public:
+  ElfStringTable(FILE* file, Elf_Shdr shdr, int index);
+  ~ElfStringTable();
+
+  // section index
+  int index() { return m_index; };
+
+  // get string at specified offset
+  const char* string_at(int offset);
+
+  // get status code
+  Decoder::decoder_status get_status() { return m_status; };
+
+ protected:
+  ElfStringTable*        m_next;
+
+  // section index
+  int                      m_index;
+
+  // holds complete string table if can
+  // allocate enough memory
+  const char*              m_table;
+
+  // file contains string table
+  FILE*                    m_file;
+
+  // section header
+  Elf_Shdr                 m_shdr;
+
+  // buffer for reading individual string
+  char                     m_symbol[MAX_SYMBOL_LEN];
+
+  // error code
+  Decoder::decoder_status  m_status;
+};
+
+#endif // _WINDOWS
+
+#endif // __ELF_STRING_TABLE_HPP
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/utilities/elfSymbolTable.cpp	Sat Dec 11 13:20:56 2010 -0500
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1997, 2010, 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.
+ *
+ */
+
+#include "precompiled.hpp"
+
+#ifndef _WINDOWS
+
+#include "memory/allocation.inline.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 = Decoder::no_error;
+
+  // try to load the string table
+  long cur_offset = ftell(file);
+  if (cur_offset != -1) {
+    m_symbols = (Elf_Sym*)NEW_C_HEAP_ARRAY(char, shdr.sh_size);
+    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 = Decoder::file_invalid;
+        FREE_C_HEAP_ARRAY(char, m_symbols);
+        m_symbols = NULL;
+      }
+    }
+    if (m_status == Decoder::no_error) {
+      memcpy(&m_shdr, &shdr, sizeof(Elf_Shdr));
+    }
+  } else {
+    m_status = Decoder::file_invalid;
+  }
+}
+
+ElfSymbolTable::~ElfSymbolTable() {
+  if (m_symbols != NULL) {
+    FREE_C_HEAP_ARRAY(char, m_symbols);
+  }
+
+  if (m_next != NULL) {
+    delete m_next;
+  }
+}
+
+Decoder::decoder_status ElfSymbolTable::lookup(address addr, int* stringtableIndex, int* posIndex, int* offset) {
+  assert(stringtableIndex, "null string table index pointer");
+  assert(posIndex, "null string table offset pointer");
+  assert(offset, "null offset pointer");
+
+  if (m_status != Decoder::no_error) {
+    return m_status;
+  }
+
+  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);
+          *posIndex = m_symbols[index].st_name;
+          *stringtableIndex = m_shdr.sh_link;
+        }
+      }
+    }
+  } else {
+    long cur_pos;
+    if ((cur_pos = ftell(m_file)) == -1 ||
+      fseek(m_file, m_shdr.sh_offset, SEEK_SET)) {
+      m_status = Decoder::file_invalid;
+      return m_status;
+    }
+
+    Elf_Sym sym;
+    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);
+            *posIndex = sym.st_name;
+            *stringtableIndex = m_shdr.sh_link;
+          }
+        }
+      } else {
+        m_status = Decoder::file_invalid;
+        return m_status;
+      }
+    }
+    fseek(m_file, cur_pos, SEEK_SET);
+  }
+  return m_status;
+}
+
+#endif // _WINDOWS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/utilities/elfSymbolTable.hpp	Sat Dec 11 13:20:56 2010 -0500
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1997, 2010, 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.
+ *
+ */
+
+#ifndef __ELF_SYMBOL_TABLE_HPP
+#define __ELF_SYMBOL_TABLE_HPP
+
+#ifndef _WINDOWS
+
+
+#include "memory/allocation.hpp"
+#include "utilities/decoder.hpp"
+#include "utilities/elfFile.hpp"
+
+/*
+ * symbol table object represents a symbol section in an elf file.
+ * Whenever possible, it will load all symbols from the corresponding section
+ * of the elf file into memory. Otherwise, it will walk the section in file
+ * to look up the symbol that nearest the given address.
+ */
+class ElfSymbolTable: public CHeapObj {
+  friend class ElfFile;
+ public:
+  ElfSymbolTable(FILE* file, Elf_Shdr shdr);
+  ~ElfSymbolTable();
+
+  // search the symbol that is nearest to the specified address.
+  Decoder::decoder_status lookup(address addr, int* stringtableIndex, int* posIndex, int* offset);
+
+  Decoder::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;
+
+  Decoder::decoder_status  m_status;
+};
+
+#endif // _WINDOWS
+
+#endif // __ELF_SYMBOL_TABLE_HPP
+
+
+
--- a/src/share/vm/utilities/vmError.cpp	Tue Nov 23 13:22:55 2010 -0800
+++ b/src/share/vm/utilities/vmError.cpp	Sat Dec 11 13:20:56 2010 -0500
@@ -33,6 +33,7 @@
 #include "runtime/vmThread.hpp"
 #include "runtime/vm_operations.hpp"
 #include "utilities/debug.hpp"
+#include "utilities/decoder.hpp"
 #include "utilities/defaultStream.hpp"
 #include "utilities/top.hpp"
 #include "utilities/vmError.hpp"
@@ -516,8 +517,10 @@
        if (fr.pc()) {
           st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)");
 
+          // initialize decoder to decode C frames
+          Decoder decoder;
+
           int count = 0;
-
           while (count++ < StackPrintLimit) {
              fr.print_on_error(st, buf, sizeof(buf));
              st->cr();